fix(cicd): add NC01 PaC status closeout
This commit is contained in:
@@ -130,6 +130,13 @@ interface CommonOptions {
|
||||
raw: boolean;
|
||||
}
|
||||
|
||||
export interface PipelinesAsCodeNodeStatusOptions {
|
||||
targetId: string | null;
|
||||
nodeId: string | null;
|
||||
full: boolean;
|
||||
raw: boolean;
|
||||
}
|
||||
|
||||
interface HistoryOptions extends CommonOptions {
|
||||
limit: number;
|
||||
detailId: string | null;
|
||||
@@ -446,6 +453,75 @@ async function status(config: UniDeskConfig, options: CommonOptions): Promise<Re
|
||||
};
|
||||
}
|
||||
|
||||
export async function getPlatformInfraPipelinesAsCodeNodeStatus(config: UniDeskConfig, options: PipelinesAsCodeNodeStatusOptions): Promise<Record<string, unknown>> {
|
||||
const pac = readPacConfig();
|
||||
const target = resolveTarget(pac, options.targetId ?? options.nodeId);
|
||||
const nodeId = options.nodeId ?? target.id;
|
||||
const consumers = pac.consumers.filter((consumer) => consumer.node.toLowerCase() === nodeId.toLowerCase());
|
||||
if (consumers.length === 0) {
|
||||
throw new Error(`no Pipelines-as-Code consumers are configured for node ${nodeId}; known nodes: ${Array.from(new Set(pac.consumers.map((item) => item.node))).sort().join(", ")}`);
|
||||
}
|
||||
const startedAt = Date.now();
|
||||
const statuses = await Promise.all(consumers.map(async (consumer) => {
|
||||
const repository = resolveRepository(pac, consumer.repositoryRef);
|
||||
try {
|
||||
const current = await status(config, { targetId: target.id, consumerId: consumer.id, full: false, raw: false });
|
||||
return nodeStatusRow(target.id, consumer, repository, current);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return {
|
||||
consumer: consumer.id,
|
||||
node: consumer.node,
|
||||
lane: consumer.lane,
|
||||
repository: `${repository.owner}/${repository.repo}`,
|
||||
namespace: consumer.namespace,
|
||||
pipeline: consumer.pipeline,
|
||||
argoApplication: consumer.argoApplication,
|
||||
ready: false,
|
||||
ciReady: false,
|
||||
argoReady: false,
|
||||
runtimeReady: false,
|
||||
diagnosticsReady: false,
|
||||
reason: "status-read-failed",
|
||||
hint: message,
|
||||
error: message,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
}));
|
||||
const ready = statuses.every((row) => row.ready === true);
|
||||
return {
|
||||
ok: ready,
|
||||
action: "cicd-node-status",
|
||||
mutation: false,
|
||||
node: nodeId,
|
||||
target: targetSummary(target),
|
||||
config: {
|
||||
path: configLabel,
|
||||
source: "Gitea Repository CR + Tekton PipelineRun/TaskRun + Argo + runtime live objects.",
|
||||
displayTimeZone: pac.display.timeZone,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
consumers: statuses,
|
||||
summary: {
|
||||
ready,
|
||||
total: statuses.length,
|
||||
readyCount: statuses.filter((row) => row.ready === true).length,
|
||||
blockedCount: statuses.filter((row) => row.ready !== true).length,
|
||||
elapsedMs: Date.now() - startedAt,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
next: {
|
||||
status: `bun scripts/cli.ts cicd status --node ${nodeId}`,
|
||||
history: `bun scripts/cli.ts platform-infra pipelines-as-code history --target ${target.id} --limit 10`,
|
||||
closeout: `bun scripts/cli.ts platform-infra pipelines-as-code closeout --target ${target.id} --wait`,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
details: options.full || options.raw ? statuses : undefined,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
async function closeout(config: UniDeskConfig, options: CloseoutOptions): Promise<Record<string, unknown>> {
|
||||
const pac = readPacConfig();
|
||||
const target = resolveTarget(pac, options.targetId);
|
||||
@@ -723,6 +799,75 @@ function statusSummary(payload: Record<string, unknown>): Record<string, unknown
|
||||
};
|
||||
}
|
||||
|
||||
function nodeStatusRow(targetId: string, consumer: PacConsumer, repository: PacRepository, current: Record<string, unknown>): Record<string, unknown> {
|
||||
const summary = record(current.summary);
|
||||
const latest = record(summary.latestPipelineRun);
|
||||
const artifact = record(summary.artifact);
|
||||
const argo = record(summary.argo);
|
||||
const runtime = record(summary.runtime);
|
||||
const diagnostics = record(summary.diagnostics);
|
||||
const pipelineGate = record(summary.pipelineRunGate);
|
||||
const desired = numericValue(runtime.replicas);
|
||||
const readyReplicas = numericValue(runtime.readyReplicas);
|
||||
const runtimeReady = desired !== null && desired > 0 && readyReplicas === desired;
|
||||
const argoReady = stringValue(argo.sync) === "Synced" && stringValue(argo.health) === "Healthy";
|
||||
const ciReady = pipelineGate.ok === true;
|
||||
const diagnosticsReady = diagnostics.ok !== false;
|
||||
const ready = current.ok === true && ciReady && argoReady && runtimeReady && diagnosticsReady;
|
||||
return {
|
||||
consumer: consumer.id,
|
||||
node: consumer.node,
|
||||
lane: consumer.lane,
|
||||
repository: `${repository.owner}/${repository.repo}`,
|
||||
namespace: consumer.namespace,
|
||||
pipeline: consumer.pipeline,
|
||||
argoApplication: consumer.argoApplication,
|
||||
ready,
|
||||
ciReady,
|
||||
argoReady,
|
||||
runtimeReady,
|
||||
diagnosticsReady,
|
||||
latestPipelineRun: stringValue(latest.name),
|
||||
pipelineStatus: statusText(latest),
|
||||
durationSeconds: latest.durationSeconds ?? null,
|
||||
sourceCommit: stringValue(latest.sourceCommit),
|
||||
imageStatus: stringValue(artifact.imageStatus),
|
||||
envReuse: envReuseText(record(artifact.envReuse)),
|
||||
digest: stringValue(artifact.digest),
|
||||
gitopsCommit: stringValue(artifact.gitopsCommit),
|
||||
argo: {
|
||||
sync: stringValue(argo.sync),
|
||||
health: stringValue(argo.health),
|
||||
revision: stringValue(argo.revision),
|
||||
},
|
||||
runtime: {
|
||||
deployment: stringValue(runtime.deployment),
|
||||
readyReplicas: runtime.readyReplicas ?? null,
|
||||
replicas: runtime.replicas ?? null,
|
||||
digest: stringValue(runtime.digest),
|
||||
image: stringValue(runtime.image),
|
||||
},
|
||||
diagnostics: {
|
||||
ok: diagnostics.ok !== false,
|
||||
code: stringValue(diagnostics.code),
|
||||
phase: stringValue(diagnostics.phase),
|
||||
hint: compactLine(stringValue(diagnostics.hint)),
|
||||
},
|
||||
reason: ready ? "ready" : nodeStatusReason({ ciReady, argoReady, runtimeReady, diagnosticsReady, pipelineStatus: statusText(latest), diagnostics }),
|
||||
statusCommand: `bun scripts/cli.ts platform-infra pipelines-as-code status --target ${targetId} --consumer ${consumer.id}`,
|
||||
historyCommand: `bun scripts/cli.ts platform-infra pipelines-as-code history --target ${targetId} --consumer ${consumer.id} --limit 10`,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function nodeStatusReason(input: { ciReady: boolean; argoReady: boolean; runtimeReady: boolean; diagnosticsReady: boolean; pipelineStatus: string; diagnostics: Record<string, unknown> }): string {
|
||||
if (!input.ciReady) return `ci:${input.pipelineStatus}`;
|
||||
if (!input.argoReady) return "argo-not-ready";
|
||||
if (!input.runtimeReady) return "runtime-not-ready";
|
||||
if (!input.diagnosticsReady) return stringValue(input.diagnostics.code, "diagnostics-not-ready");
|
||||
return "not-ready";
|
||||
}
|
||||
|
||||
function policyChecks(repository: PacRepository): Array<Record<string, unknown>> {
|
||||
return [
|
||||
{ name: "single-path", ok: true, detail: "Gitea webhook -> Pipelines-as-Code -> Tekton -> Argo/k8s runtime; no Gitea Actions/act_runner/branch-follower fallback." },
|
||||
|
||||
Reference in New Issue
Block a user