Files
pikasTech-unidesk/scripts/src/cicd-taskruns.ts
T
2026-07-03 20:17:21 +00:00

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;
}