fix: recognize descendant gitops revisions
This commit is contained in:
@@ -88,6 +88,7 @@ function renderNodeStatus(result: Record<string, unknown>, full: boolean): Rende
|
||||
short(stringValue(row.sourceCommit)),
|
||||
short(stringValue(row.gitopsCommit)),
|
||||
`${stringValue(record(row.argo).sync)}/${stringValue(record(row.argo).health)}`,
|
||||
stringValue(record(record(row.argo).revisionRelation).relation),
|
||||
runtimeText(record(row.runtime)),
|
||||
stringValue(row.reason),
|
||||
]);
|
||||
@@ -110,7 +111,7 @@ function renderNodeStatus(result: Record<string, unknown>, full: boolean): Rende
|
||||
]]),
|
||||
"",
|
||||
"CONSUMERS",
|
||||
...(rows.length === 0 ? ["-"] : table(["CONSUMER", "READY", "PIPELINE", "DUR", "SOURCE", "GITOPS", "ARGO", "RUNTIME", "REASON"], rows)),
|
||||
...(rows.length === 0 ? ["-"] : table(["CONSUMER", "READY", "PIPELINE", "DUR", "SOURCE", "GITOPS", "ARGO", "RELATION", "RUNTIME", "REASON"], rows)),
|
||||
"",
|
||||
...(full ? [
|
||||
"DETAIL",
|
||||
|
||||
@@ -693,6 +693,10 @@ for (const line of lines) {
|
||||
}
|
||||
const publish = [...records].reverse().find((item) => item.phase === 'gitops-publish' || item.gitopsCommit);
|
||||
const image = publish || [...records].reverse().find((item) => item.imageStatus || item.status === 'reused' || item.status === 'built');
|
||||
const gitopsCommit = image?.gitopsCommit
|
||||
|| [...lines].reverse().map((line) => line.match(/^\[[^\]]+\s+([0-9a-f]{7,64})\]/u)?.[1] || null).find(Boolean)
|
||||
|| null;
|
||||
const loggedDigests = [...new Set(lines.flatMap((line) => [...line.matchAll(/"(?:digest|environmentDigest)"\s*:\s*"(sha256:[0-9a-f]{64})"/gu)].map((match) => match[1])))];
|
||||
const envHeaderIndex = lines.findIndex((line) => /^ENV_REUSE\s+NODE_DEPS\s+/u.test(line.trim()));
|
||||
let humanEnv = null;
|
||||
if (envHeaderIndex >= 0) {
|
||||
@@ -719,22 +723,24 @@ if (image) {
|
||||
envReuse: envReuseOf(image),
|
||||
nodeDepsReuse: null,
|
||||
buildCache: null,
|
||||
digest: digestOf(image),
|
||||
gitopsCommit: image.gitopsCommit || null,
|
||||
digest: digestOf(image) || (loggedDigests.length === 1 ? loggedDigests[0] : null),
|
||||
digests: loggedDigests,
|
||||
gitopsCommit,
|
||||
sourceCommit: image.sourceCommit || null,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
} else if (humanEnv) {
|
||||
} else if (humanEnv || gitopsCommit || loggedDigests.length > 0) {
|
||||
out = {
|
||||
imageStatus: 'published',
|
||||
imageStatus: humanEnv ? 'published' : null,
|
||||
envIdentity: null,
|
||||
envReuse: humanEnv.envReuse,
|
||||
nodeDepsReuse: humanEnv.nodeDeps,
|
||||
buildCache: humanEnv.cache,
|
||||
buildPackage: humanEnv.buildPackage,
|
||||
buildNetwork: humanEnv.buildNetwork,
|
||||
digest: null,
|
||||
gitopsCommit: null,
|
||||
envReuse: humanEnv?.envReuse || null,
|
||||
nodeDepsReuse: humanEnv?.nodeDeps || null,
|
||||
buildCache: humanEnv?.cache || null,
|
||||
buildPackage: humanEnv?.buildPackage || null,
|
||||
buildNetwork: humanEnv?.buildNetwork || null,
|
||||
digest: loggedDigests.length === 1 ? loggedDigests[0] : null,
|
||||
digests: loggedDigests,
|
||||
gitopsCommit,
|
||||
sourceCommit: null,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
@@ -795,6 +801,124 @@ NODE
|
||||
rm -f "$deploy_file"
|
||||
}
|
||||
|
||||
resolve_git_service_url() {
|
||||
repo_url="$1"
|
||||
host=$(UNIDESK_PAC_GIT_URL="$repo_url" node <<'NODE'
|
||||
try {
|
||||
process.stdout.write(new URL(process.env.UNIDESK_PAC_GIT_URL || '').hostname);
|
||||
} catch {}
|
||||
NODE
|
||||
)
|
||||
case "$host" in
|
||||
*.svc.cluster.local)
|
||||
service=${host%%.*}
|
||||
rest=${host#*.}
|
||||
namespace=${rest%%.*}
|
||||
cluster_ip=$(kubectl -n "$namespace" get svc "$service" -o jsonpath='{.spec.clusterIP}' 2>/dev/null || true)
|
||||
if [ -z "$cluster_ip" ]; then
|
||||
return 1
|
||||
fi
|
||||
UNIDESK_PAC_GIT_URL="$repo_url" UNIDESK_PAC_GIT_CLUSTER_IP="$cluster_ip" node <<'NODE'
|
||||
try {
|
||||
const url = new URL(process.env.UNIDESK_PAC_GIT_URL || '');
|
||||
url.hostname = process.env.UNIDESK_PAC_GIT_CLUSTER_IP || '';
|
||||
process.stdout.write(url.toString());
|
||||
} catch {
|
||||
process.exit(1);
|
||||
}
|
||||
NODE
|
||||
;;
|
||||
*) printf '%s' "$repo_url" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
gitops_revision_relation() {
|
||||
artifact_json="${1:-}"
|
||||
argo_json="${2:-}"
|
||||
[ -n "$artifact_json" ] || artifact_json='{}'
|
||||
[ -n "$argo_json" ] || argo_json='{}'
|
||||
fields=$(UNIDESK_PAC_ARTIFACT_JSON="$artifact_json" UNIDESK_PAC_ARGO_JSON="$argo_json" node <<'NODE'
|
||||
function parse(value) {
|
||||
try { return JSON.parse(value || '{}'); } catch { return {}; }
|
||||
}
|
||||
function line(key, value) {
|
||||
process.stdout.write(`${key}=${Buffer.from(String(value || ''), 'utf8').toString('base64')}\n`);
|
||||
}
|
||||
const artifact = parse(process.env.UNIDESK_PAC_ARTIFACT_JSON);
|
||||
const argo = parse(process.env.UNIDESK_PAC_ARGO_JSON);
|
||||
line('expected', artifact.gitopsCommit);
|
||||
line('observed', argo.revision);
|
||||
line('repoUrl', argo.repoURL);
|
||||
line('targetRevision', argo.targetRevision);
|
||||
NODE
|
||||
)
|
||||
expected=$(printf '%s\n' "$fields" | sed -n 's/^expected=//p' | base64 -d 2>/dev/null || true)
|
||||
observed=$(printf '%s\n' "$fields" | sed -n 's/^observed=//p' | base64 -d 2>/dev/null || true)
|
||||
repo_url=$(printf '%s\n' "$fields" | sed -n 's/^repoUrl=//p' | base64 -d 2>/dev/null || true)
|
||||
target_revision=$(printf '%s\n' "$fields" | sed -n 's/^targetRevision=//p' | base64 -d 2>/dev/null || true)
|
||||
relation=unknown
|
||||
proof=unavailable
|
||||
reason=missing-revision-context
|
||||
fetch_ok=false
|
||||
if printf '%s\n%s\n' "$expected" "$observed" | grep -Eqv '^[0-9a-fA-F]{7,64}$'; then
|
||||
reason=invalid-or-missing-revision
|
||||
elif [ -z "$repo_url" ] \
|
||||
|| ! git check-ref-format "refs/heads/$target_revision" >/dev/null 2>&1; then
|
||||
reason=invalid-or-missing-git-context
|
||||
else
|
||||
repo_dir=$(mktemp -d)
|
||||
if resolved_url=$(resolve_git_service_url "$repo_url") \
|
||||
&& git init --bare -q "$repo_dir/repo.git" \
|
||||
&& timeout "$UNIDESK_PAC_WAIT_TIMEOUT_SECONDS" git --git-dir="$repo_dir/repo.git" fetch -q --no-tags "$resolved_url" "+refs/heads/$target_revision:refs/remotes/origin/$target_revision" >/dev/null 2>&1; then
|
||||
fetch_ok=true
|
||||
if git --git-dir="$repo_dir/repo.git" cat-file -e "$expected^{commit}" 2>/dev/null \
|
||||
&& git --git-dir="$repo_dir/repo.git" cat-file -e "$observed^{commit}" 2>/dev/null; then
|
||||
proof=owning-git-commit-graph
|
||||
expected=$(git --git-dir="$repo_dir/repo.git" rev-parse "$expected^{commit}")
|
||||
observed=$(git --git-dir="$repo_dir/repo.git" rev-parse "$observed^{commit}")
|
||||
if [ "$expected" = "$observed" ]; then
|
||||
relation=exact
|
||||
reason=commits-equal
|
||||
elif git --git-dir="$repo_dir/repo.git" merge-base --is-ancestor "$expected" "$observed" >/dev/null 2>&1; then
|
||||
relation=descendant
|
||||
reason=observed-descends-from-selected
|
||||
elif git --git-dir="$repo_dir/repo.git" merge-base --is-ancestor "$observed" "$expected" >/dev/null 2>&1; then
|
||||
relation=stale
|
||||
reason=observed-precedes-selected
|
||||
else
|
||||
relation=diverged
|
||||
reason=commits-have-diverged
|
||||
fi
|
||||
else
|
||||
reason=commit-object-missing
|
||||
fi
|
||||
else
|
||||
reason=owning-git-fetch-failed
|
||||
fi
|
||||
rm -rf "$repo_dir"
|
||||
fi
|
||||
UNIDESK_PAC_GITOPS_EXPECTED="$expected" \
|
||||
UNIDESK_PAC_GITOPS_OBSERVED="$observed" \
|
||||
UNIDESK_PAC_GITOPS_REPO_URL="$repo_url" \
|
||||
UNIDESK_PAC_GITOPS_TARGET_REVISION="$target_revision" \
|
||||
UNIDESK_PAC_GITOPS_RELATION="$relation" \
|
||||
UNIDESK_PAC_GITOPS_PROOF="$proof" \
|
||||
UNIDESK_PAC_GITOPS_REASON="$reason" \
|
||||
UNIDESK_PAC_GITOPS_FETCH_OK="$fetch_ok" node <<'NODE'
|
||||
process.stdout.write(JSON.stringify({
|
||||
relation: process.env.UNIDESK_PAC_GITOPS_RELATION || 'unknown',
|
||||
expectedRevision: process.env.UNIDESK_PAC_GITOPS_EXPECTED || null,
|
||||
observedRevision: process.env.UNIDESK_PAC_GITOPS_OBSERVED || null,
|
||||
repoURL: process.env.UNIDESK_PAC_GITOPS_REPO_URL || null,
|
||||
targetRevision: process.env.UNIDESK_PAC_GITOPS_TARGET_REVISION || null,
|
||||
proof: process.env.UNIDESK_PAC_GITOPS_PROOF || 'unavailable',
|
||||
reason: process.env.UNIDESK_PAC_GITOPS_REASON || null,
|
||||
fetchOk: process.env.UNIDESK_PAC_GITOPS_FETCH_OK === 'true',
|
||||
valuesPrinted: false,
|
||||
}));
|
||||
NODE
|
||||
}
|
||||
|
||||
cicd_diagnostics() {
|
||||
params_file=$(mktemp)
|
||||
pipelines_file=$(mktemp)
|
||||
@@ -926,12 +1050,17 @@ const expectedDigest = registryDigest || artifactDigest;
|
||||
const runtimeImage = runtime.image || null;
|
||||
const runtimeDigest = runtime.digest || (typeof runtimeImage === 'string' && runtimeImage.includes('@') ? runtimeImage.split('@').slice(1).join('@') : null);
|
||||
const runtimeMatches = !expectedDigest || runtimeDigest === expectedDigest;
|
||||
const runtimeReady = Number.isInteger(runtime.replicas) && runtime.replicas > 0 && runtime.readyReplicas === runtime.replicas;
|
||||
const selectedArtifactDigests = [...new Set([artifactDigest, ...(Array.isArray(artifact.digests) ? artifact.digests : [])].filter(Boolean))];
|
||||
const selectedArtifactMatchesRuntime = Boolean(runtimeDigest && selectedArtifactDigests.includes(runtimeDigest));
|
||||
const registryMatchesArtifact = !registryDigest || !artifactDigest || registryDigest === artifactDigest;
|
||||
const healthUrl = process.env.UNIDESK_PAC_DIAG_HEALTH_URL || null;
|
||||
const healthStatus = process.env.UNIDESK_PAC_DIAG_HEALTH_STATUS || null;
|
||||
const healthReady = !healthUrl || healthStatus === '200';
|
||||
const gitopsReady = Boolean(artifact.gitopsCommit || argo.revision);
|
||||
const gitopsRevisionMatches = !artifact.gitopsCommit || artifact.gitopsCommit === argo.revision;
|
||||
const revisionRelation = argo.revisionRelation || { relation: 'unknown' };
|
||||
const gitopsRelation = revisionRelation.relation || 'unknown';
|
||||
const gitopsReady = Boolean(artifact.gitopsCommit && argo.revision);
|
||||
const gitopsRevisionAligned = gitopsRelation === 'exact' || gitopsRelation === 'descendant';
|
||||
const deliveryDisabled = artifact.imageStatus === 'disabled';
|
||||
let code = 'pac-diagnostics-not-applicable';
|
||||
let phase = 'not-applicable';
|
||||
@@ -949,14 +1078,22 @@ if (deliveryDisabled) {
|
||||
ok = false; code = 'pac-gitops-missing'; phase = 'artifact-ready-gitops-missing'; hint = 'PipelineRun completed but its GitOps commit is not visible';
|
||||
} else if (argo.sync !== 'Synced' || argo.health !== 'Healthy') {
|
||||
ok = false; code = 'pac-argo-not-ready'; phase = 'gitops-ready-argo-pending'; hint = 'GitOps exists but Argo is not Synced/Healthy';
|
||||
} else if (!gitopsRevisionMatches) {
|
||||
ok = false; code = 'pac-argo-revision-not-aligned'; phase = 'gitops-ready-argo-revision-mismatch'; hint = 'Argo has not observed the GitOps commit produced by the selected PipelineRun';
|
||||
} else if (!gitopsRevisionAligned) {
|
||||
ok = false; code = `pac-argo-revision-${gitopsRelation}`; phase = `gitops-ready-argo-revision-${gitopsRelation}`; hint = `Argo revision relation is ${gitopsRelation}; only exact or commit-graph-proven descendant is deployable`;
|
||||
} else if (gitopsRelation === 'descendant' && !selectedArtifactMatchesRuntime) {
|
||||
ok = false; code = 'pac-descendant-artifact-runtime-mismatch'; phase = 'argo-descendant-runtime-mismatch'; hint = 'a GitOps descendant is ready only when the selected PipelineRun artifact digest exactly matches the runtime digest';
|
||||
} else if (!runtimeMatches) {
|
||||
ok = false; code = 'pac-runtime-not-aligned'; phase = 'argo-ready-runtime-mismatch'; hint = 'runtime image digest does not match the artifact digest produced by the selected PipelineRun';
|
||||
} else if (!runtimeReady) {
|
||||
ok = false; code = 'pac-runtime-not-ready'; phase = 'runtime-replicas-not-ready'; hint = 'runtime ready replicas do not match the desired replica count';
|
||||
} else if (!healthReady) {
|
||||
ok = false; code = 'pac-health-not-ready'; phase = 'runtime-ready-health-pending'; hint = 'runtime image is aligned but the configured health endpoint is not ready';
|
||||
} else if (artifactDigest || process.env.UNIDESK_PAC_DIAG_IMAGE_REPOSITORY) {
|
||||
code = 'pac-ready'; phase = 'ready'; hint = 'source, artifact, GitOps, Argo and runtime are aligned';
|
||||
} else if (artifactDigest || selectedArtifactDigests.length > 0 || process.env.UNIDESK_PAC_DIAG_IMAGE_REPOSITORY) {
|
||||
code = gitopsRelation === 'descendant' ? 'pac-ready-gitops-descendant' : 'pac-ready-gitops-exact';
|
||||
phase = 'ready';
|
||||
hint = gitopsRelation === 'descendant'
|
||||
? 'Argo is on a commit-graph-proven GitOps descendant and the selected artifact, runtime, Argo and health are aligned'
|
||||
: 'Argo is on the exact selected GitOps commit and the artifact, runtime and health are aligned';
|
||||
}
|
||||
process.stdout.write(JSON.stringify({
|
||||
ok,
|
||||
@@ -972,12 +1109,21 @@ process.stdout.write(JSON.stringify({
|
||||
digest: registryDigest,
|
||||
url: process.env.UNIDESK_PAC_DIAG_REGISTRY_URL || null,
|
||||
},
|
||||
selectedArtifactDigests,
|
||||
gitops: {
|
||||
branch: process.env.UNIDESK_PAC_DIAG_GITOPS_BRANCH || null,
|
||||
manifestPath: process.env.UNIDESK_PAC_DIAG_GITOPS_MANIFEST_PATH || null,
|
||||
commit: artifact.gitopsCommit || argo.revision || null,
|
||||
revisionRelation,
|
||||
},
|
||||
argo: {
|
||||
sync: argo.sync || null,
|
||||
health: argo.health || null,
|
||||
revision: argo.revision || null,
|
||||
repoURL: argo.repoURL || null,
|
||||
targetRevision: argo.targetRevision || null,
|
||||
revisionRelation,
|
||||
},
|
||||
argo: { sync: argo.sync || null, health: argo.health || null, revision: argo.revision || null },
|
||||
runtime: { image: runtimeImage, digest: runtimeDigest, readyReplicas: runtime.readyReplicas ?? null, replicas: runtime.replicas ?? null },
|
||||
health: { url: healthUrl, status: healthStatus, ready: healthReady },
|
||||
pipelineRun: latest.name || null,
|
||||
@@ -1008,8 +1154,21 @@ status_action() {
|
||||
tasks=$(task_rows)
|
||||
artifact=$(json_normalize "$(artifact_summary)")
|
||||
hooks=$(hook_summary)
|
||||
argo=$(kubectl -n "$UNIDESK_PAC_ARGO_NAMESPACE" get application "$UNIDESK_PAC_ARGO_APPLICATION" -o json 2>/dev/null | node -e 'const fs=require("fs"); const s=fs.readFileSync(0,"utf8").trim(); if(!s){process.stdout.write("{}"); process.exit(0)} const a=JSON.parse(s); process.stdout.write(JSON.stringify({sync:a.status?.sync?.status||null, health:a.status?.health?.status||null, revision:a.status?.sync?.revision||null}))' || echo '{}')
|
||||
argo=$(kubectl -n "$UNIDESK_PAC_ARGO_NAMESPACE" get application "$UNIDESK_PAC_ARGO_APPLICATION" -o json 2>/dev/null | node -e 'const fs=require("fs"); const s=fs.readFileSync(0,"utf8").trim(); if(!s){process.stdout.write("{}"); process.exit(0)} const a=JSON.parse(s); const source=a.spec?.source || a.spec?.sources?.[0] || {}; let repoURL=source.repoURL||null; try { const url=new URL(repoURL); url.username=""; url.password=""; repoURL=url.toString(); } catch {} process.stdout.write(JSON.stringify({sync:a.status?.sync?.status||null, health:a.status?.health?.status||null, revision:a.status?.sync?.revision||null, repoURL, targetRevision:source.targetRevision||null}))' || echo '{}')
|
||||
argo=$(json_normalize "$argo")
|
||||
revision_relation=$(gitops_revision_relation "$artifact" "$argo")
|
||||
artifact=$(UNIDESK_PAC_ARTIFACT_JSON="$artifact" UNIDESK_PAC_REVISION_RELATION_JSON="$revision_relation" node <<'NODE'
|
||||
const artifact = JSON.parse(process.env.UNIDESK_PAC_ARTIFACT_JSON || '{}');
|
||||
const revisionRelation = JSON.parse(process.env.UNIDESK_PAC_REVISION_RELATION_JSON || '{}');
|
||||
process.stdout.write(JSON.stringify({ ...artifact, gitopsCommit: revisionRelation.expectedRevision || artifact.gitopsCommit || null }));
|
||||
NODE
|
||||
)
|
||||
argo=$(UNIDESK_PAC_ARGO_JSON="$argo" UNIDESK_PAC_REVISION_RELATION_JSON="$revision_relation" node <<'NODE'
|
||||
const argo = JSON.parse(process.env.UNIDESK_PAC_ARGO_JSON || '{}');
|
||||
const revisionRelation = JSON.parse(process.env.UNIDESK_PAC_REVISION_RELATION_JSON || '{"relation":"unknown"}');
|
||||
process.stdout.write(JSON.stringify({ ...argo, revisionRelation }));
|
||||
NODE
|
||||
)
|
||||
runtime=$(json_normalize "$(runtime_summary)")
|
||||
diagnostics=$(cicd_diagnostics "$pipelines" "$artifact" "$argo" "$runtime")
|
||||
printf '{"ok":%s,"crdPresent":%s,"controllerReady":"%s","repository":{"name":"%s","repo":"%s/%s","url":"%s","condition":"%s"},"repositoryCondition":"%s","webhooks":%s,"pipelineRuns":%s,"taskRuns":%s,"artifact":%s,"argo":%s,"runtime":%s,"diagnostics":%s,"valuesPrinted":false}\n' \
|
||||
|
||||
@@ -925,6 +925,9 @@ function nodeStatusRow(targetId: string, consumer: PacConsumer, repository: PacR
|
||||
sync: stringValue(argo.sync),
|
||||
health: stringValue(argo.health),
|
||||
revision: stringValue(argo.revision),
|
||||
repoURL: stringValue(argo.repoURL),
|
||||
targetRevision: stringValue(argo.targetRevision),
|
||||
revisionRelation: record(argo.revisionRelation),
|
||||
},
|
||||
runtime: {
|
||||
deployment: stringValue(runtime.deployment),
|
||||
@@ -1141,7 +1144,14 @@ function renderStatus(result: Record<string, unknown>): RenderedCliResult {
|
||||
...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))]]),
|
||||
"",
|
||||
"ARGO",
|
||||
...table(["SYNC", "HEALTH", "REVISION"], [[stringValue(argo.sync), stringValue(argo.health), short(stringValue(argo.revision))]]),
|
||||
...table(["SYNC", "HEALTH", "REVISION", "RELATION", "TARGET_REVISION"], [[
|
||||
stringValue(argo.sync),
|
||||
stringValue(argo.health),
|
||||
short(stringValue(argo.revision)),
|
||||
stringValue(record(argo.revisionRelation).relation),
|
||||
stringValue(argo.targetRevision),
|
||||
]]),
|
||||
` repo-url: ${compactLine(stringValue(argo.repoURL))}`,
|
||||
"",
|
||||
"CICD DIAGNOSIS",
|
||||
...table(["OK", "CODE", "PHASE", "SOURCE", "REGISTRY", "GITOPS", "RUNTIME"], [[
|
||||
@@ -1195,7 +1205,15 @@ function renderCloseout(result: Record<string, unknown>): RenderedCliResult {
|
||||
...table(["EXPECTED", "OBSERVED", "PIPELINERUN", "STATUS", "DURATION_S"], [[short(stringValue(result.sourceCommit), 16), short(stringValue(result.observedSourceCommit), 16), stringValue(latest.name), stringValue(latest.reason ?? latest.status), stringValue(latest.durationSeconds)]]),
|
||||
"",
|
||||
"RUNTIME",
|
||||
...table(["IMAGE_STATUS", "ENV_REUSE", "DIGEST", "GITOPS", "ARGO", "RUNTIME"], [[stringValue(artifact.imageStatus), stringValue(artifact.envReuse), short(stringValue(artifact.digest), 18), short(stringValue(artifact.gitopsCommit), 12), `${stringValue(argo.sync)}/${stringValue(argo.health)}`, runtimeText(runtime)]]),
|
||||
...table(["IMAGE_STATUS", "ENV_REUSE", "DIGEST", "GITOPS", "ARGO", "RELATION", "RUNTIME"], [[
|
||||
stringValue(artifact.imageStatus),
|
||||
stringValue(artifact.envReuse),
|
||||
short(stringValue(artifact.digest), 18),
|
||||
short(stringValue(artifact.gitopsCommit), 12),
|
||||
`${stringValue(argo.sync)}/${stringValue(argo.health)}`,
|
||||
stringValue(record(argo.revisionRelation).relation),
|
||||
runtimeText(runtime),
|
||||
]]),
|
||||
"",
|
||||
"CICD DIAGNOSIS",
|
||||
...table(["OK", "CODE", "PHASE", "HINT"], [[boolText(diagnostics.ok !== false), stringValue(diagnostics.code), stringValue(diagnostics.phase), compactLine(stringValue(diagnostics.hint))]]),
|
||||
|
||||
Reference in New Issue
Block a user