75 lines
3.2 KiB
TypeScript
75 lines
3.2 KiB
TypeScript
// SPEC: PJ2026-01060703 CI/CD TaskRun summaries.
|
|
// Responsibility: shared bounded TaskRun prioritization for branch-follower status/debug visibility.
|
|
|
|
export type TaskRunMode = "failed" | "active" | "slow";
|
|
|
|
export function taskRunItems(taskRuns: Record<string, unknown>, mode: TaskRunMode, limit = 5): Record<string, unknown>[] {
|
|
const explicit = mode === "failed" ? taskRuns.failedItems : mode === "active" ? taskRuns.activeItems : taskRuns.slowItems;
|
|
const explicitItems = arrayRecords(explicit);
|
|
if (explicitItems.length > 0) return explicitItems.slice(0, limit).map(compactTaskRunItem);
|
|
const items = arrayRecords(taskRuns.items);
|
|
if (mode === "failed") return items.filter((item) => item.status === "False").slice(0, limit).map(compactTaskRunItem);
|
|
if (mode === "active") return items.filter((item) => item.status !== "True" && item.status !== "False").slice(0, limit).map(compactTaskRunItem);
|
|
const slowItems = arrayRecords(asOptionalRecord(taskRuns.performance)?.slowTaskRuns);
|
|
if (slowItems.length > 0) return slowItems.slice(0, limit).map(compactTaskRunItem);
|
|
return items.filter((item) => {
|
|
const seconds = numberOrNull(item.durationSeconds);
|
|
return seconds !== null && seconds > 60;
|
|
}).slice(0, limit).map(compactTaskRunItem);
|
|
}
|
|
|
|
export function prioritizedTaskRunItems(taskRuns: Record<string, unknown>, limit = 16): Record<string, unknown>[] {
|
|
const prioritized = [
|
|
...taskRunItems(taskRuns, "failed", limit),
|
|
...taskRunItems(taskRuns, "active", limit),
|
|
...taskRunItems(taskRuns, "slow", limit),
|
|
...arrayRecords(taskRuns.items).map(compactTaskRunItem),
|
|
];
|
|
const seen = new Set<string>();
|
|
const out: Record<string, unknown>[] = [];
|
|
for (const item of prioritized) {
|
|
const key = taskRunKey(item);
|
|
if (seen.has(key)) continue;
|
|
seen.add(key);
|
|
out.push(item);
|
|
if (out.length >= limit) break;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
export function compactTaskRunItem(item: Record<string, unknown>): Record<string, unknown> {
|
|
return {
|
|
name: stringOrNull(item.name),
|
|
pipelineTask: stringOrNull(item.pipelineTask),
|
|
status: stringOrNull(item.status),
|
|
reason: stringOrNull(item.reason),
|
|
durationSeconds: numberOrNull(item.durationSeconds),
|
|
};
|
|
}
|
|
|
|
function taskRunKey(item: Record<string, unknown>): string {
|
|
const key = [
|
|
stringOrNull(item.name),
|
|
stringOrNull(item.pipelineTask),
|
|
stringOrNull(item.status),
|
|
stringOrNull(item.reason),
|
|
].filter((value) => value !== null).join("|");
|
|
return key.length > 0 ? key : JSON.stringify(item);
|
|
}
|
|
|
|
function asOptionalRecord(value: unknown): Record<string, unknown> | null {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : null;
|
|
}
|
|
|
|
function arrayRecords(value: unknown): Record<string, unknown>[] {
|
|
return Array.isArray(value) ? value.filter((item): item is Record<string, unknown> => typeof item === "object" && item !== null && !Array.isArray(item)) : [];
|
|
}
|
|
|
|
function stringOrNull(value: unknown): string | null {
|
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
}
|
|
|
|
function numberOrNull(value: unknown): number | null {
|
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
}
|