fix: stabilize sentinel BuildKit evidence
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{"event":"sentinel-publish-stage","stage":"source-fetch","status":"succeeded","elapsedMs":2000,"traceId":"6e6e899d3e812891140aedfd974d524e","valuesRedacted":true}
|
||||
{"event":"sentinel-publish-stage","stage":"monitor-web-verify","status":"succeeded","elapsedMs":0,"traceId":"6e6e899d3e812891140aedfd974d524e","valuesRedacted":true}
|
||||
{"event":"sentinel-publish-stage","stage":"image-build","status":"running","elapsedMs":0,"traceId":"6e6e899d3e812891140aedfd974d524e","valuesRedacted":true}
|
||||
could not connect to unix:///run/user/1000/buildkit/buildkitd.sock after 10 trials
|
||||
time="2026-07-13T13:49:56Z" level=info msg="running server on /run/user/1000/buildkit/buildkitd.sock"
|
||||
{"event":"sentinel-publish-stage","stage":"image-build","status":"failed","elapsedMs":9000,"traceId":"6e6e899d3e812891140aedfd974d524e","valuesRedacted":true}
|
||||
{"ok":false,"status":"failed","traceId":"6e6e899d3e812891140aedfd974d524e","firstBreak":{"code":"child-process-exit-nonzero","phase":"image-build","reason":"image build command exited non-zero","valuesRedacted":true},"error":{"type":"ChildProcessError","code":"EXIT_NONZERO","phase":"image-build","exitCode":1,"stderrSummary":"bounded step logs contain the command failure","valuesRedacted":true},"exitCode":1,"jobName":"hwlab-web-probe-sentinel-nc01-r5ww2","valuesRedacted":true}
|
||||
@@ -732,7 +732,13 @@ export function sentinelPublishImageBuildShell(state: SentinelCicdState, jobName
|
||||
"now_ms() { seconds=$(date +%s); printf '%s\\n' $((seconds * 1000)); }",
|
||||
"write_meta() { printf '%s' \"$2\" > \"$meta_dir/$1\"; }",
|
||||
"emit_stage() { stage=$1; status=$2; started=$3; current_phase=$stage; export current_phase; finished=$(now_ms); elapsed=$((finished - started)); trace_id=$(printf '%s' \"${TRACEPARENT:-}\" | cut -d- -f2); printf '{\"event\":\"sentinel-publish-stage\",\"stage\":\"%s\",\"status\":\"%s\",\"elapsedMs\":%s,\"traceId\":\"%s\",\"valuesRedacted\":true}\\n' \"$stage\" \"$status\" \"$elapsed\" \"$trace_id\" | tee -a \"$event_log\"; }",
|
||||
"emit_failed() { code=$?; if [ \"$code\" -ne 0 ]; then trace_id=$(printf '%s' \"${TRACEPARENT:-}\" | cut -d- -f2); printf '{\"ok\":false,\"status\":\"failed\",\"traceId\":\"%s\",\"firstBreak\":{\"code\":\"child-process-exit-nonzero\",\"phase\":\"%s\",\"reason\":\"image build command exited non-zero\",\"valuesRedacted\":true},\"error\":{\"type\":\"ChildProcessError\",\"code\":\"EXIT_NONZERO\",\"phase\":\"%s\",\"exitCode\":%s,\"stderrSummary\":\"bounded step logs contain the command failure\",\"valuesRedacted\":true},\"exitCode\":%s,\"jobName\":\"%s\",\"valuesRedacted\":true}\\n' \"$trace_id\" \"${current_phase:-image-build}\" \"${current_phase:-image-build}\" \"$code\" \"$code\" \"$job_name\" | tee -a \"$event_log\"; fi; exit \"$code\"; }",
|
||||
"failure_code=child-process-exit-nonzero",
|
||||
"failure_reason='image build command exited non-zero'",
|
||||
"failure_error_type=ChildProcessError",
|
||||
"failure_error_code=EXIT_NONZERO",
|
||||
"buildkitd_pid=''",
|
||||
"cleanup_buildkitd() { if [ -n \"$buildkitd_pid\" ] && kill -0 \"$buildkitd_pid\" 2>/dev/null; then kill -TERM \"$buildkitd_pid\" 2>/dev/null || true; cleanup_attempt=0; while [ \"$cleanup_attempt\" -lt 5 ] && kill -0 \"$buildkitd_pid\" 2>/dev/null; do cleanup_attempt=$((cleanup_attempt + 1)); sleep 1; done; if kill -0 \"$buildkitd_pid\" 2>/dev/null; then kill -KILL \"$buildkitd_pid\" 2>/dev/null || true; fi; wait \"$buildkitd_pid\" 2>/dev/null || true; fi; }",
|
||||
"emit_failed() { code=$?; cleanup_buildkitd; if [ \"$code\" -ne 0 ]; then trace_id=$(printf '%s' \"${TRACEPARENT:-}\" | cut -d- -f2); printf '{\"ok\":false,\"status\":\"failed\",\"traceId\":\"%s\",\"firstBreak\":{\"code\":\"%s\",\"phase\":\"%s\",\"reason\":\"%s\",\"valuesRedacted\":true},\"error\":{\"type\":\"%s\",\"code\":\"%s\",\"phase\":\"%s\",\"exitCode\":%s,\"stderrSummary\":\"bounded step logs contain the command failure\",\"valuesRedacted\":true},\"exitCode\":%s,\"jobName\":\"%s\",\"valuesRedacted\":true}\\n' \"$trace_id\" \"$failure_code\" \"${current_phase:-image-build}\" \"$failure_reason\" \"$failure_error_type\" \"$failure_error_code\" \"${current_phase:-image-build}\" \"$code\" \"$code\" \"$job_name\" | tee -a \"$event_log\"; fi; exit \"$code\"; }",
|
||||
"trap emit_failed EXIT",
|
||||
"cd /workspace/source",
|
||||
"image_build_http_proxy_present=false; if [ -n \"$image_build_http_proxy\" ]; then image_build_http_proxy_present=true; fi",
|
||||
@@ -750,8 +756,19 @@ export function sentinelPublishImageBuildShell(state: SentinelCicdState, jobName
|
||||
"image_build_started_ms=$(now_ms)",
|
||||
"write_meta image_build_started_ms \"$image_build_started_ms\"",
|
||||
"emit_stage image-build running \"$image_build_started_ms\"",
|
||||
"buildkit_socket=/run/user/$(id -u)/buildkit/buildkitd.sock",
|
||||
"buildkit_address=unix://$buildkit_socket",
|
||||
"buildkit_log=/workspace/buildkitd.log",
|
||||
"mkdir -p \"$(dirname \"$buildkit_socket\")\"",
|
||||
"rm -f \"$buildkit_socket\"",
|
||||
"buildkitd --addr \"$buildkit_address\" ${BUILDKITD_FLAGS:-} > \"$buildkit_log\" 2>&1 &",
|
||||
"buildkitd_pid=$!",
|
||||
"buildkit_ready=false",
|
||||
"buildkit_probe_attempt=0",
|
||||
"while [ \"$buildkit_probe_attempt\" -lt 30 ]; do buildkit_probe_attempt=$((buildkit_probe_attempt + 1)); if [ -S \"$buildkit_socket\" ] && buildctl --addr \"$buildkit_address\" debug workers >/dev/null 2>&1; then buildkit_ready=true; break; fi; if ! kill -0 \"$buildkitd_pid\" 2>/dev/null; then break; fi; sleep 1; done",
|
||||
"if [ \"$buildkit_ready\" != true ]; then cat \"$buildkit_log\"; failure_code=buildkit-not-ready; failure_reason=readiness-timeout; failure_error_type=BuildKitReadinessError; failure_error_code=BUILDKIT_NOT_READY; emit_stage image-build failed \"$image_build_started_ms\"; exit 1; fi",
|
||||
"build_status=0",
|
||||
"env HTTP_PROXY=\"$image_build_http_proxy\" HTTPS_PROXY=\"$image_build_https_proxy\" ALL_PROXY=\"$image_build_all_proxy\" NO_PROXY=\"$image_build_no_proxy\" http_proxy=\"$image_build_http_proxy\" https_proxy=\"$image_build_https_proxy\" all_proxy=\"$image_build_all_proxy\" no_proxy=\"$image_build_no_proxy\" buildctl-daemonless.sh build --allow network.host --frontend dockerfile.v0 --local context=/workspace/source --local dockerfile=/workspace/source --opt filename=Containerfile.web-probe-sentinel --opt \"network=$image_build_network_mode\" --opt \"build-arg:HTTP_PROXY=$image_build_http_proxy\" --opt \"build-arg:HTTPS_PROXY=$image_build_https_proxy\" --opt \"build-arg:ALL_PROXY=$image_build_all_proxy\" --opt \"build-arg:NO_PROXY=$image_build_no_proxy\" --opt \"build-arg:http_proxy=$image_build_http_proxy\" --opt \"build-arg:https_proxy=$image_build_https_proxy\" --opt \"build-arg:all_proxy=$image_build_all_proxy\" --opt \"build-arg:no_proxy=$image_build_no_proxy\" --metadata-file /workspace/build-metadata.json --output \"type=image,name=$image_ref,push=true,registry.insecure=true\" > \"$build_log\" 2>&1 || build_status=$?",
|
||||
"env HTTP_PROXY=\"$image_build_http_proxy\" HTTPS_PROXY=\"$image_build_https_proxy\" ALL_PROXY=\"$image_build_all_proxy\" NO_PROXY=\"$image_build_no_proxy\" http_proxy=\"$image_build_http_proxy\" https_proxy=\"$image_build_https_proxy\" all_proxy=\"$image_build_all_proxy\" no_proxy=\"$image_build_no_proxy\" buildctl --addr \"$buildkit_address\" build --allow network.host --frontend dockerfile.v0 --local context=/workspace/source --local dockerfile=/workspace/source --opt filename=Containerfile.web-probe-sentinel --opt \"network=$image_build_network_mode\" --opt \"build-arg:HTTP_PROXY=$image_build_http_proxy\" --opt \"build-arg:HTTPS_PROXY=$image_build_https_proxy\" --opt \"build-arg:ALL_PROXY=$image_build_all_proxy\" --opt \"build-arg:NO_PROXY=$image_build_no_proxy\" --opt \"build-arg:http_proxy=$image_build_http_proxy\" --opt \"build-arg:https_proxy=$image_build_https_proxy\" --opt \"build-arg:all_proxy=$image_build_all_proxy\" --opt \"build-arg:no_proxy=$image_build_no_proxy\" --metadata-file /workspace/build-metadata.json --output \"type=image,name=$image_ref,push=true,registry.insecure=true\" > \"$build_log\" 2>&1 || build_status=$?",
|
||||
"cat \"$build_log\"",
|
||||
"image_build_finished_ms=$(now_ms)",
|
||||
"write_meta image_build_finished_ms \"$image_build_finished_ms\"",
|
||||
@@ -767,6 +784,8 @@ export function sentinelPublishImageBuildShell(state: SentinelCicdState, jobName
|
||||
"write_meta digest \"$digest\"",
|
||||
"write_meta digest_ref \"$digest_ref\"",
|
||||
"emit_stage image-build succeeded \"$image_build_started_ms\"",
|
||||
"cleanup_buildkitd",
|
||||
"buildkitd_pid=''",
|
||||
"trap - EXIT",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { createRequire } from "node:module";
|
||||
import { compactHistoryJson, compactStatusSummary, renderDebugStep, renderHistory, renderStatus } from "./platform-infra-pipelines-as-code";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const { parsePacLogRecords } = require("../native/cicd/pac-status-evaluator.cjs") as {
|
||||
parsePacLogRecords(value: string): Array<Record<string, unknown>>;
|
||||
};
|
||||
|
||||
describe("PaC 失败证据合同", () => {
|
||||
test("真实 sentinel TaskRun 日志保留 typed 首断点", () => {
|
||||
const fixture = resolve(import.meta.dir, "fixtures/pac/hwlab-web-probe-sentinel-nc01-r5ww2.log");
|
||||
const record = parsePacLogRecords(readFileSync(fixture, "utf8")).find((item) => item.ok === false);
|
||||
expect(record).toMatchObject({
|
||||
traceId: "6e6e899d3e812891140aedfd974d524e",
|
||||
firstBreak: { code: "child-process-exit-nonzero", phase: "image-build" },
|
||||
error: { type: "ChildProcessError", code: "EXIT_NONZERO", phase: "image-build", exitCode: 1 },
|
||||
});
|
||||
});
|
||||
|
||||
test("history、debug-step、status 默认显示 typed 失败字段", () => {
|
||||
const fixture = resolve(import.meta.dir, "fixtures/pac/hwlab-web-probe-sentinel-nc01-r5ww2.log");
|
||||
const failure = parsePacLogRecords(readFileSync(fixture, "utf8")).find((item) => item.ok === false) ?? {};
|
||||
const row = {
|
||||
id: "hwlab-web-probe-sentinel-nc01-r5ww2",
|
||||
consumer: "sentinel-nc01-v03",
|
||||
deliveryClass: "outer-pac-event",
|
||||
status: "False",
|
||||
traceId: failure.traceId,
|
||||
firstBreak: failure.firstBreak,
|
||||
error: failure.error,
|
||||
};
|
||||
const history = renderHistory({ rows: [row], config: {}, historyErrors: [], next: {} }).renderedText;
|
||||
const debug = renderDebugStep({ realRun: { found: true, pipelineRun: row, firstBreak: row.firstBreak, error: row.error, traceId: row.traceId }, checks: [], target: {}, next: {} }).renderedText;
|
||||
const status = renderStatus({ summary: { latestPipelineRun: row, artifact: row, diagnostics: {} }, consumer: {}, deliveryAuthority: {}, config: {}, coverage: [], target: {}, next: {} }).renderedText;
|
||||
for (const output of [history, debug, status]) {
|
||||
expect(output).toContain("6e6e899d3e8128");
|
||||
expect(output).toContain("child-process-exit-nonzero");
|
||||
expect(output).toContain("ChildProcessError");
|
||||
expect(output).toContain("image-build");
|
||||
expect(output).toContain("EXIT_NONZERO");
|
||||
expect(output).toContain("1");
|
||||
}
|
||||
const compactHistory = compactHistoryJson({ rows: [{ ...row, collector: { matchingTaskCount: 1 } }], detailId: row.id });
|
||||
const compactStatus = compactStatusSummary({ latestPipelineRun: row, artifact: row });
|
||||
expect(compactHistory).toMatchObject({ rows: [{ traceId: row.traceId, firstBreak: row.firstBreak, error: row.error, collector: { matchingTaskCount: 1 } }] });
|
||||
expect(compactStatus).toMatchObject({ artifact: { traceId: row.traceId, firstBreak: row.firstBreak, error: row.error } });
|
||||
});
|
||||
|
||||
test("collector 遍历全部 matching TaskRun,terminal record 仍限定合同任务", () => {
|
||||
const remote = readFileSync(resolve(import.meta.dir, "platform-infra-pipelines-as-code-remote.sh"), "utf8");
|
||||
expect(remote).toContain("for (const item of matching)");
|
||||
expect(remote).toContain("const contractTaskRuns = matching.filter((item) => taskTerminalRecord(item) !== null)");
|
||||
expect(remote).toContain("Object.keys(record(row.firstBreak)).length > 0");
|
||||
expect(remote).toContain("traceId: row.traceId || null");
|
||||
});
|
||||
|
||||
test("sentinel image build 显式等待 socket 与 worker readiness 并清理 daemon", () => {
|
||||
const source = readFileSync(resolve(import.meta.dir, "hwlab-node-web-sentinel-cicd-jobs.ts"), "utf8");
|
||||
expect(source).toContain("mkdir -p \\\"$(dirname \\\"$buildkit_socket\\\")\\\"");
|
||||
expect(source).toContain("buildkitd --addr");
|
||||
expect(source).toContain("debug workers");
|
||||
expect(source).toContain("failure_error_type=BuildKitReadinessError");
|
||||
expect(source).toContain("failure_error_code=BUILDKIT_NOT_READY");
|
||||
expect(source).toContain("cleanup_buildkitd");
|
||||
expect(source).not.toContain("buildctl-daemonless.sh build");
|
||||
});
|
||||
});
|
||||
@@ -748,7 +748,7 @@ function envReuseForPipelineRun(namespace, name, taskRuns) {
|
||||
const terminalRecords = contractTaskRuns.map(taskTerminalRecord).filter(Boolean);
|
||||
const logErrors = [];
|
||||
let logs = '';
|
||||
for (const item of contractTaskRuns) {
|
||||
for (const item of matching) {
|
||||
const podName = item.status?.podName;
|
||||
if (!podName) {
|
||||
logErrors.push({ taskRun: item.metadata?.name || null, reason: 'pod-name-missing' });
|
||||
@@ -792,6 +792,7 @@ function envReuseForPipelineRun(namespace, name, taskRuns) {
|
||||
state.sourceObservation = state.artifact.sourceObservation;
|
||||
state.collector = {
|
||||
mode: state.source,
|
||||
matchingTaskCount: matching.length,
|
||||
contractTaskCount: contractTaskRuns.length,
|
||||
terminalRecordCount: terminalRecords.length,
|
||||
logErrorCount: logErrors.length,
|
||||
@@ -1006,7 +1007,7 @@ const contractTaskRuns = taskRuns.filter((item) => taskTerminalRecord(item) !==
|
||||
const terminalRecords = contractTaskRuns.map(taskTerminalRecord).filter(Boolean);
|
||||
const logErrors = [];
|
||||
let logText = '';
|
||||
for (const item of contractTaskRuns) {
|
||||
for (const item of taskRuns) {
|
||||
const podName = item.status?.podName;
|
||||
if (!podName) {
|
||||
logErrors.push({ taskRun: item.metadata?.name || null, reason: 'pod-name-missing' });
|
||||
@@ -1064,6 +1065,7 @@ out.firstBreak = diagnostic.firstBreak;
|
||||
out.error = diagnostic.error;
|
||||
out.collector = {
|
||||
mode,
|
||||
matchingTaskCount: taskRuns.length,
|
||||
contractTaskCount: contractTaskRuns.length,
|
||||
terminalRecordCount: terminalRecords.length,
|
||||
logErrorCount: logErrors.length,
|
||||
@@ -1701,6 +1703,10 @@ function breakAt(code, stage, reason) {
|
||||
if (historyErrors.length > 0) breakAt('target-read-failed', 'target-read', historyErrors[0]?.error || historyErrors[0]?.stderr || 'target-side history read failed');
|
||||
if (Object.keys(row).length === 0) breakAt('pipeline-run-not-found', 'pipeline-run', `PipelineRun ${process.env.UNIDESK_PAC_HISTORY_ID || '-'} was not found for the selected consumer`);
|
||||
if (Object.keys(row).length > 0 && row.deliveryAuthorityEligible !== true) breakAt('pipeline-run-not-delivery-authority', 'pipeline-run', `PipelineRun is classified as ${row.deliveryClass || 'unknown'}; only an outer PaC event can drive delivery closeout`);
|
||||
if (Object.keys(row).length > 0 && Object.keys(record(row.firstBreak)).length > 0) {
|
||||
const typed = record(row.firstBreak);
|
||||
breakAt(typed.code || 'pipeline-run-not-succeeded', typed.phase || typed.stage || 'pipeline-run', typed.reason || `PipelineRun terminal status is ${row.status || row.reason || 'unknown'}`);
|
||||
}
|
||||
if (Object.keys(row).length > 0 && row.status !== 'True') breakAt('pipeline-run-not-succeeded', 'pipeline-run', `PipelineRun terminal status is ${row.status || row.reason || 'unknown'}`);
|
||||
if (Object.keys(row).length > 0 && Object.keys(sourceObservation).length === 0) breakAt('source-observation-missing', 'plan-artifacts', 'delivery plan structured evidence is missing');
|
||||
if (sourceObservation.sourceMatched !== true) breakAt('source-observation-mismatch', 'plan-artifacts', 'delivery plan source commit does not match the selected PipelineRun');
|
||||
@@ -1756,12 +1762,15 @@ const realRun = {
|
||||
},
|
||||
collector: {
|
||||
mode: collector.mode || null,
|
||||
matchingTaskCount: collector.matchingTaskCount ?? null,
|
||||
contractTaskCount: collector.contractTaskCount ?? null,
|
||||
terminalRecordCount: collector.terminalRecordCount ?? null,
|
||||
logErrorCount: collector.logErrorCount ?? null,
|
||||
logErrors: Array.isArray(collector.logErrors) ? collector.logErrors : [],
|
||||
valuesPrinted: false,
|
||||
},
|
||||
traceId: row.traceId || null,
|
||||
error: Object.keys(record(row.error)).length === 0 ? null : record(row.error),
|
||||
firstBreak,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
|
||||
@@ -1951,7 +1951,7 @@ function compactStatusJson(result: Record<string, unknown>): Record<string, unkn
|
||||
};
|
||||
}
|
||||
|
||||
function compactStatusSummary(summary: Record<string, unknown>): Record<string, unknown> {
|
||||
export function compactStatusSummary(summary: Record<string, unknown>): Record<string, unknown> {
|
||||
const latest = record(summary.latestPipelineRun);
|
||||
const artifact = record(summary.artifact);
|
||||
const argo = record(summary.argo);
|
||||
@@ -1992,6 +1992,9 @@ function compactStatusSummary(summary: Record<string, unknown>): Record<string,
|
||||
digest: artifact.digest,
|
||||
gitopsCommit: artifact.gitopsCommit,
|
||||
provenanceRelation: artifact.provenanceRelation,
|
||||
traceId: artifact.traceId ?? latest.traceId,
|
||||
firstBreak: artifact.firstBreak ?? latest.firstBreak,
|
||||
error: artifact.error ?? latest.error,
|
||||
},
|
||||
argo: {
|
||||
sync: argo.sync,
|
||||
@@ -2051,7 +2054,7 @@ function compactCloseoutJson(result: Record<string, unknown>): Record<string, un
|
||||
};
|
||||
}
|
||||
|
||||
function compactHistoryJson(result: Record<string, unknown>, includeTaskDetails = false): Record<string, unknown> {
|
||||
export function compactHistoryJson(result: Record<string, unknown>, includeTaskDetails = false): Record<string, unknown> {
|
||||
const detailRequested = stringValue(result.detailId) !== "-";
|
||||
return {
|
||||
ok: result.ok === true,
|
||||
@@ -2088,6 +2091,9 @@ function compactHistoryJson(result: Record<string, unknown>, includeTaskDetails
|
||||
classification: row.classification,
|
||||
envReuse: row.envReuse,
|
||||
sourceObservation: row.sourceObservation,
|
||||
traceId: row.traceId,
|
||||
firstBreak: row.firstBreak,
|
||||
error: row.error,
|
||||
artifact: detailRequested ? {
|
||||
imageStatus: artifact.imageStatus,
|
||||
envReuse: artifact.envReuse,
|
||||
@@ -2113,6 +2119,7 @@ function compactHistoryJson(result: Record<string, unknown>, includeTaskDetails
|
||||
} : undefined,
|
||||
collector: detailRequested ? {
|
||||
mode: collector.mode,
|
||||
matchingTaskCount: collector.matchingTaskCount,
|
||||
contractTaskCount: collector.contractTaskCount,
|
||||
terminalRecordCount: collector.terminalRecordCount,
|
||||
logErrorCount: collector.logErrorCount,
|
||||
@@ -2237,7 +2244,7 @@ function renderBootstrap(result: Record<string, unknown>): RenderedCliResult {
|
||||
return rendered(result, "platform-infra pipelines-as-code bootstrap", lines);
|
||||
}
|
||||
|
||||
function renderStatus(result: Record<string, unknown>): RenderedCliResult {
|
||||
export function renderStatus(result: Record<string, unknown>): RenderedCliResult {
|
||||
const summary = record(result.summary);
|
||||
const consumer = record(result.consumer);
|
||||
const deliveryAuthority = record(result.deliveryAuthority);
|
||||
@@ -2248,6 +2255,9 @@ function renderStatus(result: Record<string, unknown>): RenderedCliResult {
|
||||
const artifact = record(summary.artifact);
|
||||
const argo = record(summary.argo);
|
||||
const diagnostics = record(summary.diagnostics);
|
||||
const latestFirstBreak = record(artifact.firstBreak ?? latest.firstBreak);
|
||||
const latestError = record(artifact.error ?? latest.error);
|
||||
const latestTraceId = stringValue(artifact.traceId ?? latest.traceId);
|
||||
const admissionProvenance = record(summary.admissionProvenance);
|
||||
const consumerBootstrap = record(summary.consumerBootstrap);
|
||||
const bootstrapRunner = record(consumerBootstrap.runner);
|
||||
@@ -2318,10 +2328,14 @@ function renderStatus(result: Record<string, unknown>): RenderedCliResult {
|
||||
` repo-url: ${compactLine(stringValue(argo.repoURL))}`,
|
||||
"",
|
||||
"CICD DIAGNOSIS",
|
||||
...table(["OK", "CODE", "PHASE", "SOURCE", "REGISTRY", "GITOPS", "RUNTIME"], [[
|
||||
...table(["OK", "CODE", "PHASE", "TRACE", "FIRST_BREAK", "ERROR", "EXIT", "SOURCE", "REGISTRY", "GITOPS", "RUNTIME"], [[
|
||||
boolText(diagnostics.ok !== false),
|
||||
stringValue(diagnostics.code),
|
||||
stringValue(diagnostics.phase),
|
||||
stringValue(latestFirstBreak.phase ?? latestError.phase ?? diagnostics.phase),
|
||||
short(latestTraceId, 16),
|
||||
stringValue(latestFirstBreak.code),
|
||||
`${stringValue(latestError.type)}/${stringValue(latestError.code)}`,
|
||||
stringValue(latestError.exitCode),
|
||||
short(stringValue(diagnostics.sourceCommit)),
|
||||
registryText(record(diagnostics.registry)),
|
||||
short(stringValue(record(diagnostics.gitops).commit)),
|
||||
@@ -2407,7 +2421,7 @@ function renderCloseout(result: Record<string, unknown>): RenderedCliResult {
|
||||
return rendered(result, "platform-infra pipelines-as-code closeout", lines);
|
||||
}
|
||||
|
||||
function renderHistory(result: Record<string, unknown>): RenderedCliResult {
|
||||
export function renderHistory(result: Record<string, unknown>): RenderedCliResult {
|
||||
const rows = arrayRecords(result.rows);
|
||||
const config = record(result.config);
|
||||
const historyErrors = arrayRecords(result.historyErrors);
|
||||
@@ -2424,17 +2438,26 @@ function renderHistory(result: Record<string, unknown>): RenderedCliResult {
|
||||
]),
|
||||
"",
|
||||
"TRIGGERS",
|
||||
...(rows.length === 0 ? ["-"] : table([timeHeader, "CONSUMER", "CLASS", "OWNER", "STATUS", "DUR_S", "COMMIT", "ENV_REUSE", "ID"], rows.map((row) => [
|
||||
...(rows.length === 0 ? ["-"] : table([timeHeader, "CONSUMER", "CLASS", "OWNER", "STATUS", "TRACE", "FIRST_BREAK", "PHASE", "ERROR", "EXIT", "DUR_S", "COMMIT", "ENV_REUSE", "ID"], rows.map((row) => {
|
||||
const firstBreak = record(row.firstBreak);
|
||||
const error = record(row.error);
|
||||
return [
|
||||
stringValue(row.displayTime) === "-" ? isoShort(stringValue(row.triggeredAt)) : stringValue(row.displayTime),
|
||||
stringValue(row.consumer),
|
||||
stringValue(row.deliveryClass),
|
||||
stringValue(row.deliveryOwner ?? row.executionOwner),
|
||||
statusText(row),
|
||||
short(stringValue(row.traceId), 16),
|
||||
stringValue(firstBreak.code),
|
||||
stringValue(firstBreak.phase ?? error.phase),
|
||||
`${stringValue(error.type)}/${stringValue(error.code)}`,
|
||||
stringValue(error.exitCode),
|
||||
stringValue(row.durationSeconds),
|
||||
short(stringValue(row.commit)),
|
||||
envReuseText(record(row.envReuse)),
|
||||
stringValue(row.id ?? row.pipelineRun),
|
||||
]))),
|
||||
];
|
||||
}))),
|
||||
...(detailId === "-" || rows.length !== 1 ? [] : renderHistoryDetail(rows[0] ?? {})),
|
||||
"",
|
||||
"NEXT",
|
||||
@@ -2444,7 +2467,7 @@ function renderHistory(result: Record<string, unknown>): RenderedCliResult {
|
||||
return rendered(result, "platform-infra pipelines-as-code history", lines.filter((line): line is string => line !== null));
|
||||
}
|
||||
|
||||
function renderDebugStep(result: Record<string, unknown>): RenderedCliResult {
|
||||
export function renderDebugStep(result: Record<string, unknown>): RenderedCliResult {
|
||||
const checks = arrayRecords(result.checks);
|
||||
const realRun = record(result.realRun);
|
||||
const pipelineRun = record(realRun.pipelineRun);
|
||||
@@ -2452,6 +2475,7 @@ function renderDebugStep(result: Record<string, unknown>): RenderedCliResult {
|
||||
const catalog = record(artifact.catalog);
|
||||
const terminal = arrayRecords(realRun.terminal);
|
||||
const firstBreak = record(realRun.firstBreak);
|
||||
const typedError = record(realRun.error);
|
||||
const fixturePassed = checks.filter((item) => item.ok === true).length;
|
||||
const lines = [
|
||||
"PLATFORM-INFRA PIPELINES-AS-CODE DEBUG STEP",
|
||||
@@ -2466,11 +2490,15 @@ function renderDebugStep(result: Record<string, unknown>): RenderedCliResult {
|
||||
...(Object.keys(realRun).length === 0 ? [] : [
|
||||
"",
|
||||
"REAL PIPELINERUN EVIDENCE",
|
||||
...table(["FOUND", "CLASS", "AUTHORITY", "STATUS", "SOURCE", "MODE", "VALID", "FIRST_BREAK"], [[
|
||||
...table(["FOUND", "CLASS", "AUTHORITY", "STATUS", "TRACE", "PHASE", "ERROR", "EXIT", "SOURCE", "MODE", "VALID", "FIRST_BREAK"], [[
|
||||
boolText(realRun.found),
|
||||
stringValue(pipelineRun.deliveryClass),
|
||||
boolText(pipelineRun.deliveryAuthorityEligible),
|
||||
stringValue(pipelineRun.status ?? pipelineRun.reason),
|
||||
short(stringValue(realRun.traceId), 16),
|
||||
stringValue(firstBreak.phase ?? firstBreak.stage),
|
||||
`${stringValue(typedError.type)}/${stringValue(typedError.code)}`,
|
||||
stringValue(typedError.exitCode),
|
||||
short(stringValue(pipelineRun.sourceCommit), 16),
|
||||
stringValue(realRun.mode),
|
||||
boolText(realRun.valid),
|
||||
|
||||
Reference in New Issue
Block a user