Merge pull request #1508 from pikasTech/fix/1499-hwlab-pipeline-evidence
feat: add bounded branch-follower pipeline evidence
This commit is contained in:
@@ -25,6 +25,7 @@ import { renderControllerManifests, renderControllerReconcileJob, waitForJobShel
|
||||
import { buildDebugStep } from "./cicd-debug";
|
||||
import { runNativeHwlabControlPlaneRefresh } from "./cicd-hwlab-refresh";
|
||||
import { nativeCicdScriptLoadShell, readNativeObjectBundle } from "./cicd-native-bundle";
|
||||
import { compactRefreshEvidence, followerEvidenceSummary } from "./cicd-evidence";
|
||||
import { runNativeK8sJob, runNativeTektonPipelineRun } from "./cicd-native";
|
||||
import { argoApplicationReady, nativeArgoSummary, nativeGitMirrorReady, nativeGitMirrorRequired, nativeGitMirrorSummary, nativePipelineRunSummary, nativeRuntimeSummary, pipelineRunSucceeded, runtimeTargetShaFromWorkloads, runtimeWorkloadsReady } from "./cicd-native-summary";
|
||||
import { invalidRuntimeReuseConfig, missingRuntimeReuseConfig, parseRuntimeReuseConfig, RUNTIME_REUSE_CONFIG_PATH, runtimeReuseService, summarizeRuntimeReuseConfig, type RuntimeReuseConfig } from "./cicd-reuse-config";
|
||||
@@ -634,6 +635,7 @@ async function applyController(registry: BranchFollowerRegistry, options: Parsed
|
||||
|
||||
async function buildStatus(registry: BranchFollowerRegistry, options: ParsedOptions): Promise<Record<string, unknown>> {
|
||||
let k8s = readK8sState(registry, options);
|
||||
const beforeRefreshStateByFollower = k8s.stateByFollower;
|
||||
const wantsLive = options.live || (!options.noLive && Object.keys(k8s.stateByFollower).length === 0);
|
||||
const refresh = wantsLive && !options.inCluster ? runControllerReconcileJob(registry, options, { dryRun: true, wait: true, recordState: true }) : null;
|
||||
if (refresh !== null) k8s = readK8sState(registry, options);
|
||||
@@ -643,8 +645,9 @@ async function buildStatus(registry: BranchFollowerRegistry, options: ParsedOpti
|
||||
const detailedFollowers = options.followerId !== null || options.full;
|
||||
for (const follower of selected) {
|
||||
const stored = k8s.stateByFollower[follower.id] ?? {};
|
||||
const fallbackStored = refresh === null ? {} : beforeRefreshStateByFollower[follower.id] ?? {};
|
||||
const live = shouldLive && follower.enabled ? await readAdapterStatus(registry, follower, options) : null;
|
||||
followers.push(mergeFollowerStatus(registry, follower, stored, live, shouldLive, detailedFollowers));
|
||||
followers.push(mergeFollowerStatus(registry, follower, stored, live, shouldLive, detailedFollowers, fallbackStored));
|
||||
}
|
||||
return {
|
||||
ok: k8s.ok && followers.every((item) => item.ok !== false),
|
||||
@@ -665,6 +668,7 @@ async function buildStatus(registry: BranchFollowerRegistry, options: ParsedOpti
|
||||
|
||||
async function runOnce(registry: BranchFollowerRegistry, options: ParsedOptions): Promise<Record<string, unknown>> {
|
||||
if (!options.inCluster) {
|
||||
const before = readK8sState(registry, options);
|
||||
const refresh = runControllerReconcileJob(registry, options, { dryRun: options.dryRun, wait: true, recordState: true });
|
||||
const k8s = readK8sState(registry, options);
|
||||
const selected = selectFollowers(registry, options, { includeDisabled: false });
|
||||
@@ -678,7 +682,7 @@ async function runOnce(registry: BranchFollowerRegistry, options: ParsedOptions)
|
||||
execution: "k8s-native-reconcile-job",
|
||||
registry: registrySummary(registry),
|
||||
job: refresh,
|
||||
followers: selected.map((follower) => mergeFollowerStatus(registry, follower, k8s.stateByFollower[follower.id] ?? {}, null, false)),
|
||||
followers: selected.map((follower) => mergeFollowerStatus(registry, follower, k8s.stateByFollower[follower.id] ?? {}, null, false, false, before.stateByFollower[follower.id] ?? {})),
|
||||
warnings: refresh.ok ? [] : [`reconcile job failed: ${refresh.message}`],
|
||||
next: {
|
||||
status: "bun scripts/cli.ts cicd branch-follower status",
|
||||
@@ -1884,6 +1888,7 @@ async function readAdapterStatus(registry: BranchFollowerRegistry, follower: Fol
|
||||
reuseConfig: observedSha === null ? null : summarizeRuntimeReuseConfig(requireFollowerRuntimeReuseConfig(follower, observedSha, Math.min(timeoutSeconds, 5))),
|
||||
gitMirror: nativeGitMirrorSummary(bundle.gitMirror),
|
||||
tekton: nativePipelineRunSummary(bundle.pipelineRun),
|
||||
pipeline: bundle.pipeline,
|
||||
taskRuns: bundle.taskRuns,
|
||||
planArtifacts: bundle.planArtifacts,
|
||||
argo: nativeArgoSummary(bundle.argoApplication),
|
||||
@@ -1941,6 +1946,7 @@ function mergeFollowerStatus(
|
||||
live: AdapterSummary | null,
|
||||
liveRequested: boolean,
|
||||
detailed: boolean,
|
||||
fallbackStored: Record<string, unknown> = {},
|
||||
): Record<string, unknown> {
|
||||
const storedSource = asOptionalRecord(stored.source);
|
||||
const storedTarget = asOptionalRecord(stored.target);
|
||||
@@ -1950,6 +1956,12 @@ function mergeFollowerStatus(
|
||||
const lastTriggeredSha = live?.lastTriggeredSha ?? stringOrNull(stored.lastTriggeredSha);
|
||||
const lastSucceededSha = live?.lastSucceededSha ?? stringOrNull(stored.lastSucceededSha);
|
||||
const timings = live === null ? storedFollowerTimingsForStatus(follower, asOptionalRecord(stored.timings), phase, observedSha) : buildFollowerTimings(follower, live, undefined, asOptionalRecord(stored.timings), phase);
|
||||
const evidence = followerEvidenceSummary({
|
||||
observedSha,
|
||||
livePayload: asOptionalRecord(live?.payload),
|
||||
storedCommand: asOptionalRecord(stored.command),
|
||||
fallbackStoredCommand: asOptionalRecord(fallbackStored.command),
|
||||
});
|
||||
const reconcileTimeline = compactReconcileTimeline(asOptionalRecord(stored.command)?.reconcileTimeline, follower.id) ?? {
|
||||
bounded: true,
|
||||
missingReason: "stored state lacks reconcileTimeline; old data cannot be reconstructed",
|
||||
@@ -1981,6 +1993,7 @@ function mergeFollowerStatus(
|
||||
live: liveRequested,
|
||||
message: live?.message ?? stringOrNull(stored.decision) ?? "no controller state yet",
|
||||
timings: detailed ? timings : compactListTimings(timings),
|
||||
evidence: detailed ? evidence : null,
|
||||
reconcileTimeline: detailed ? reconcileTimeline : null,
|
||||
rawStateDiagnostic: detailed ? asOptionalRecord(stored.rawStateDiagnostic) : null,
|
||||
drilldown: `bun scripts/cli.ts cicd branch-follower status --follower ${follower.id} --live`,
|
||||
@@ -2286,10 +2299,12 @@ function compactNativePayload(payload: Record<string, unknown> | null): Record<s
|
||||
reuseConfig: summarizeRuntimeReuseConfigFromRecord(asOptionalRecord(payload.reuseConfig)),
|
||||
gitMirror: asOptionalRecord(payload.gitMirror),
|
||||
tekton: asOptionalRecord(payload.tekton),
|
||||
pipeline: asOptionalRecord(payload.pipeline),
|
||||
taskRuns: compactTaskRunsPayload(asOptionalRecord(payload.taskRuns)),
|
||||
planArtifacts: compactPlanArtifactsPayload(asOptionalRecord(payload.planArtifacts)),
|
||||
argo: asOptionalRecord(payload.argo),
|
||||
runtime: asOptionalRecord(payload.runtime),
|
||||
refreshEvidence: compactRefreshEvidence(asOptionalRecord(asOptionalRecord(payload.nativeCapabilities)?.controlPlaneRefresh)),
|
||||
errors: Array.isArray(payload.errors) ? payload.errors.slice(0, 5) : [],
|
||||
statusAuthority: stringOrNull(payload.statusAuthority),
|
||||
parsedDownstreamCliOutput: false,
|
||||
|
||||
Reference in New Issue
Block a user