From ec9bb9fcce448eeda3d2de2c674d83f19192db3c Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 10 Jul 2026 04:02:58 +0200 Subject: [PATCH] fix: make unidesk host pac diagnostics actionable --- .tekton/unidesk-host-pac.yaml | 6 +-- ...platform-infra-pipelines-as-code-remote.sh | 48 ++++++++++++++++--- .../src/platform-infra-pipelines-as-code.ts | 15 +++++- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/.tekton/unidesk-host-pac.yaml b/.tekton/unidesk-host-pac.yaml index 1d4b30c0..3ec1fe05 100644 --- a/.tekton/unidesk-host-pac.yaml +++ b/.tekton/unidesk-host-pac.yaml @@ -79,7 +79,7 @@ spec: value: --oci-worker-no-process-sandbox --oci-worker-net=host --allow-insecure-entitlement network.host script: | #!/bin/sh - exec scripts/native/cicd/build-unidesk-host-image.sh + exec /workspace/source/scripts/native/cicd/build-unidesk-host-image.sh securityContext: privileged: true runAsUser: 1000 @@ -100,8 +100,8 @@ spec: value: "{{revision}}" script: | #!/bin/sh - exec bun scripts/native/cicd/publish-unidesk-host-gitops.mjs \ - --config config/unidesk-host-k8s.yaml \ + exec bun /workspace/source/scripts/native/cicd/publish-unidesk-host-gitops.mjs \ + --config /workspace/source/config/unidesk-host-k8s.yaml \ --source-root /workspace/source \ --metadata /workspace/build-metadata.json \ --source-commit "$SOURCE_COMMIT" \ diff --git a/scripts/src/platform-infra-pipelines-as-code-remote.sh b/scripts/src/platform-infra-pipelines-as-code-remote.sh index 931fc8b3..4b98f2a5 100644 --- a/scripts/src/platform-infra-pipelines-as-code-remote.sh +++ b/scripts/src/platform-infra-pipelines-as-code-remote.sh @@ -398,7 +398,7 @@ function kubectlJson(args, fallback, context) { function condition(item) { const c = (item.status?.conditions || []).find((x) => x.type === 'Succeeded') || {}; - return { status: c.status || '', reason: c.reason || '' }; + return { status: c.status || '', reason: c.reason || '', message: c.message || '' }; } function durationSeconds(start, done) { @@ -523,7 +523,20 @@ function envReuseForPipelineRun(namespace, name) { return state; } -function taskSummary(taskRuns, name) { +function failedStep(item) { + const steps = (item.status?.steps || []).map((step) => ({ + name: step.name || null, + container: step.container || null, + exitCode: Number.isInteger(step.terminated?.exitCode) ? step.terminated.exitCode : null, + reason: step.terminated?.reason || null, + terminationReason: step.terminationReason || null, + })); + return steps.find((step) => step.exitCode !== null && step.exitCode !== 0 && step.terminationReason !== 'Skipped') + || steps.find((step) => step.terminationReason === 'Error') + || null; +} + +function taskSummary(taskRuns, name, namespace) { const rows = (taskRuns.items || []) .filter((item) => item.metadata?.labels?.['tekton.dev/pipelineRun'] === name) .map((item) => { @@ -532,19 +545,31 @@ function taskSummary(taskRuns, name) { name: item.metadata?.name || '', status: c.status || null, reason: c.reason || null, + message: c.message || null, + failedStep: failedStep(item), startTime: item.status?.startTime || null, completionTime: item.status?.completionTime || null, durationSeconds: durationSeconds(item.status?.startTime, item.status?.completionTime), }; }); const longest = [...rows].sort((a, b) => (b.durationSeconds || 0) - (a.durationSeconds || 0))[0] || null; - return { count: rows.length, longest }; + const failed = rows.find((row) => row.status === 'False') || null; + const target = process.env.UNIDESK_PAC_TARGET_ID || ''; + return { + count: rows.length, + longest, + failed, + details: detailId ? rows : undefined, + logsCommand: target && namespace + ? `trans ${target}:k3s logs -n ${namespace} -l tekton.dev/pipelineRun=${name} --all-containers --tail=240` + : null, + }; } function rowFor(consumer, item, taskRuns) { const params = mapParams(item.spec?.params); const c = condition(item); - const tasks = taskSummary(taskRuns, item.metadata.name); + const tasks = taskSummary(taskRuns, item.metadata.name, consumer.namespace); const labels = item.metadata?.labels || {}; const annotations = item.metadata?.annotations || {}; return { @@ -618,7 +643,18 @@ if (!pr) { } function cond(item) { const c = (item.status?.conditions || []).find((x) => x.type === 'Succeeded') || {}; - return { status: c.status || '', reason: c.reason || '' }; + return { status: c.status || '', reason: c.reason || '', message: c.message || '' }; +} +function failedStep(item) { + const steps = (item.status?.steps || []).map((step) => ({ + name: step.name || null, + exitCode: Number.isInteger(step.terminated?.exitCode) ? step.terminated.exitCode : null, + reason: step.terminated?.reason || null, + terminationReason: step.terminationReason || null, + })); + return steps.find((step) => step.exitCode !== null && step.exitCode !== 0 && step.terminationReason !== 'Skipped') + || steps.find((step) => step.terminationReason === 'Error') + || null; } function durationSeconds(item) { const start = item.status?.startTime; @@ -632,7 +668,7 @@ const rows = (data.items || []) .slice(0, 20) .map((item) => { const c = cond(item); - return { name: item.metadata.name, pipelineRun: item.metadata.labels?.['tekton.dev/pipelineRun'] || null, status: c.status, reason: c.reason, startTime: item.status?.startTime || null, completionTime: item.status?.completionTime || null, durationSeconds: durationSeconds(item) }; + return { name: item.metadata.name, pipelineRun: item.metadata.labels?.['tekton.dev/pipelineRun'] || null, status: c.status, reason: c.reason, message: c.message || null, failedStep: failedStep(item), startTime: item.status?.startTime || null, completionTime: item.status?.completionTime || null, durationSeconds: durationSeconds(item) }; }); process.stdout.write(JSON.stringify(rows)); NODE diff --git a/scripts/src/platform-infra-pipelines-as-code.ts b/scripts/src/platform-infra-pipelines-as-code.ts index 276df7f2..3dd6eb93 100644 --- a/scripts/src/platform-infra-pipelines-as-code.ts +++ b/scripts/src/platform-infra-pipelines-as-code.ts @@ -1104,7 +1104,10 @@ function renderStatus(result: Record): RenderedCliResult { ...table(["NAME", "STATUS", "REASON", "DURATION_S", "SOURCE"], [[stringValue(latest.name), stringValue(latest.status), stringValue(latest.reason), stringValue(latest.durationSeconds), short(stringValue(latest.sourceCommit))]]), "", "TASKRUN DURATIONS", - ...(taskRuns.length === 0 ? ["-"] : table(["TASKRUN", "STATUS", "REASON", "DURATION_S"], taskRuns.map((item) => [short(stringValue(item.name), 56), stringValue(item.status), stringValue(item.reason), stringValue(item.durationSeconds)]))), + ...(taskRuns.length === 0 ? ["-"] : table(["TASKRUN", "STATUS", "REASON", "FAILED_STEP", "EXIT", "DURATION_S"], taskRuns.map((item) => { + const failedStep = record(item.failedStep); + return [short(stringValue(item.name), 48), stringValue(item.status), stringValue(item.reason), stringValue(failedStep.name), stringValue(failedStep.exitCode), stringValue(item.durationSeconds)]; + }))), "", "IMAGE / GITOPS", ...table(["IMAGE_STATUS", "ENV_REUSE", "ENV_ID", "DIGEST", "GITOPS"], [[stringValue(artifact.imageStatus), stringValue(artifact.envReuse), stringValue(artifact.envIdentity), short(stringValue(artifact.digest), 18), short(stringValue(artifact.gitopsCommit))]]), @@ -1693,6 +1696,8 @@ function renderHistoryDetail(row: Record): string[] { const envReuse = record(row.envReuse); const taskRuns = record(row.taskRuns); const longest = record(taskRuns.longest); + const failed = record(taskRuns.failed); + const failedStep = record(failed.failedStep); return [ "", "DETAIL", @@ -1706,8 +1711,16 @@ function renderHistoryDetail(row: Record): string[] { ["taskRuns", stringValue(taskRuns.count)], ["longestTask", stringValue(longest.name)], ["longestTaskDurationS", stringValue(longest.durationSeconds)], + ["failedTask", stringValue(failed.name)], + ["failedStep", stringValue(failedStep.name)], + ["failedStepExit", stringValue(failedStep.exitCode)], + ["failedStepTermination", stringValue(failedStep.terminationReason ?? failedStep.reason)], + ["failure", compactLine(stringValue(failed.message))], ["envReuseSource", stringValue(envReuse.source)], ]), + "", + "LOGS", + ` ${stringValue(taskRuns.logsCommand)}`, ]; }