fix: expose AgentRun branch-follower CI reuse evidence
This commit is contained in:
@@ -24,11 +24,12 @@ import { configRefGraph, resolveConfigRefString } from "./ops/config-refs";
|
||||
import { renderControllerManifests, renderControllerReconcileJob, waitForJobShell } from "./cicd-controller-render";
|
||||
import { buildDebugStep } from "./cicd-debug";
|
||||
import { runNativeHwlabControlPlaneRefresh } from "./cicd-hwlab-refresh";
|
||||
import { agentRunCiConsumptionEvidence, agentRunManagerDecision, applyAgentRunReuseConfig, buildAgentRunReusePlan, compactAgentRunPayload, compactAgentRunReusePlan, reusableAgentRunImageArtifact, skippedAgentRunImageBuildResult } from "./cicd-agentrun-reuse";
|
||||
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";
|
||||
import { invalidRuntimeReuseConfig, missingRuntimeReuseConfig, parseRuntimeReuseConfig, requiredReuseServiceError, RUNTIME_REUSE_CONFIG_PATH, summarizeRuntimeReuseConfig, type RuntimeReuseConfig } from "./cicd-reuse-config";
|
||||
import { prioritizedTaskRunItems } from "./cicd-taskruns";
|
||||
import { runBranchFollowerTaskRunDrillDown } from "./cicd-taskrun-drilldown";
|
||||
import { runBranchFollowerJobDrillDown, runBranchFollowerRuntimeDrillDown } from "./cicd-job-runtime-drilldown";
|
||||
@@ -1275,15 +1276,30 @@ async function executeNativeAgentRunTrigger(registry: BranchFollowerRegistry, fo
|
||||
const agentRunReuseError = requiredReuseServiceError(reuseConfig, ["agentrun-mgr", "manager"], "envReuse");
|
||||
if (agentRunReuseError !== null) return nativeReuseConfigFailure(follower, observedSha, invalidRuntimeReuseConfig(reuseConfig, agentRunReuseError), startedAt);
|
||||
const effectiveSpec = applyAgentRunReuseConfig(spec, reuseConfig);
|
||||
const reusePlan = buildAgentRunReusePlan(follower, reuseConfig, observedSha);
|
||||
const managerDecision = agentRunManagerDecision(reusePlan);
|
||||
const buildJob = `${jobPrefix}-build-${observedSha.slice(0, 12)}`.slice(0, 63);
|
||||
const build = runNativeK8sJob(effectiveSpec.ci.namespace, buildJob, yamlLaneK3sBuildImageJobManifest(effectiveSpec, observedSha, buildJob), Math.min(remainingSeconds(startedAt, timeoutSeconds), effectiveSpec.deployment.manager.imageBuild.timeoutSeconds), "buildkit", registry.controller.budgets);
|
||||
const buildPayload = yamlLaneGitopsPublishPayloadFromProbe({ logsTail: stringOrNull(build.logsTail) ?? "" });
|
||||
const buildSkipped = managerDecision?.skipImageBuild === true;
|
||||
const reusedArtifact = buildSkipped ? reusableAgentRunImageArtifact(effectiveSpec, follower.nativeStatus.source.repoPath, observedSha) : null;
|
||||
if (buildSkipped && reusedArtifact?.image === null) {
|
||||
return nativeTriggerError(follower, `native AgentRun image reuse failed: ${stringOrNull(reusedArtifact.evidence.reason) ?? "reusable image artifact missing"}`, "agentrun-reusable-image-missing");
|
||||
}
|
||||
const build = buildSkipped && reusedArtifact !== null
|
||||
? skippedAgentRunImageBuildResult(effectiveSpec.ci.namespace, buildJob, { decision: "skipImageBuild", reason: managerDecision?.reason ?? "reuse-plan-hit", artifact: reusedArtifact.evidence })
|
||||
: runNativeK8sJob(effectiveSpec.ci.namespace, buildJob, yamlLaneK3sBuildImageJobManifest(effectiveSpec, observedSha, buildJob), Math.min(remainingSeconds(startedAt, timeoutSeconds), effectiveSpec.deployment.manager.imageBuild.timeoutSeconds), "buildkit", registry.controller.budgets);
|
||||
const buildPayload = buildSkipped && reusedArtifact !== null
|
||||
? { ok: true, status: "skipped", sourceCommit: observedSha, skipImageBuild: true, buildDecision: "skipImageBuild", reason: managerDecision?.reason ?? "reuse-plan-hit", artifact: reusedArtifact.evidence, valuesPrinted: false }
|
||||
: yamlLaneGitopsPublishPayloadFromProbe({ logsTail: stringOrNull(build.logsTail) ?? "" });
|
||||
const digest = stringOrNull(buildPayload.digest);
|
||||
const envIdentity = stringOrNull(buildPayload.envIdentity);
|
||||
if (!build.ok || digest === null || envIdentity === null) {
|
||||
const image = buildSkipped && reusedArtifact !== null
|
||||
? reusedArtifact.image
|
||||
: digest !== null && envIdentity !== null
|
||||
? agentRunImageArtifact(effectiveSpec, { sourceCommit: observedSha, envIdentity, digest, status: stringOrNull(buildPayload.status) ?? "built" })
|
||||
: null;
|
||||
if (!build.ok || image === null) {
|
||||
return nativeK8sStageFailure(follower, observedSha, "image-build", buildJob, build, buildPayload, "native AgentRun image build failed", startedAt);
|
||||
}
|
||||
const image = agentRunImageArtifact(effectiveSpec, { sourceCommit: observedSha, envIdentity, digest, status: stringOrNull(buildPayload.status) ?? "built" });
|
||||
const renderedFiles = renderAgentRunGitopsFiles(effectiveSpec, { sourceCommit: observedSha, image });
|
||||
const publishJob = `${jobPrefix}-gitops-${observedSha.slice(0, 12)}`.slice(0, 63);
|
||||
const publish = runNativeK8sJob(effectiveSpec.gitMirror.namespace, publishJob, yamlLaneGitopsPublishJobManifest(effectiveSpec, renderedFiles, publishJob), remainingSeconds(startedAt, timeoutSeconds), "publish", registry.controller.budgets);
|
||||
@@ -1291,6 +1307,12 @@ async function executeNativeAgentRunTrigger(registry: BranchFollowerRegistry, fo
|
||||
if (!publish.ok || publishPayload.ok === false || stringOrNull(publishPayload.gitopsCommit) === null) {
|
||||
return nativeK8sStageFailure(follower, observedSha, "gitops-publish", publishJob, publish, publishPayload, "native AgentRun GitOps publish failed", startedAt);
|
||||
}
|
||||
const ciConsumption = agentRunCiConsumptionEvidence({
|
||||
sourceCommit: observedSha,
|
||||
plan: reusePlan,
|
||||
imageBuild: { jobName: buildJob, result: build, payload: buildPayload },
|
||||
gitopsPublish: { jobName: publishJob, result: publish, payload: publishPayload },
|
||||
});
|
||||
const flush = runNativeGitMirrorStage(registry, follower, observedSha, "flush", remainingSeconds(startedAt, timeoutSeconds));
|
||||
if (flush !== null && !flush.result.ok) {
|
||||
return nativeK8sStageFailure(follower, observedSha, "git-mirror-flush", flush.jobName, flush.result, { action: "flush" }, "native AgentRun git-mirror flush failed", startedAt);
|
||||
@@ -1316,7 +1338,10 @@ async function executeNativeAgentRunTrigger(registry: BranchFollowerRegistry, fo
|
||||
...tektonPayload,
|
||||
agentrun: {
|
||||
configPath,
|
||||
sourceCommit: observedSha,
|
||||
reuseConfig: summarizeRuntimeReuseConfig(reuseConfig),
|
||||
reusePlan: compactAgentRunReusePlan(reusePlan),
|
||||
ciConsumption,
|
||||
gitMirrorSync: sync === null ? null : { jobName: sync.jobName, payload: sync.result },
|
||||
imageBuild: { jobName: buildJob, result: build, payload: buildPayload },
|
||||
gitopsPublish: { jobName: publishJob, result: publish, payload: publishPayload },
|
||||
@@ -1692,21 +1717,6 @@ function nativeReuseConfigFailure(follower: FollowerSpec, observedSha: string, r
|
||||
};
|
||||
}
|
||||
|
||||
function requiredReuseServiceError(reuseConfig: RuntimeReuseConfig, ids: readonly string[], mode: "runtimeReuse" | "envReuse"): string | null {
|
||||
const service = runtimeReuseService(reuseConfig, ids);
|
||||
if (service === null) return `${RUNTIME_REUSE_CONFIG_PATH} must declare service ${ids.join("|")}`;
|
||||
if (mode === "runtimeReuse") {
|
||||
if (service.runtimeReuse === null) return `${RUNTIME_REUSE_CONFIG_PATH} service ${service.id} must declare runtimeReuse`;
|
||||
if (service.runtimeReuse.enabled === false) return `${RUNTIME_REUSE_CONFIG_PATH} service ${service.id} runtimeReuse is disabled`;
|
||||
if (service.runtimeReuse.codeIdentityPaths.length === 0 && service.runtimeReuse.envIdentityPaths.length === 0) return `${RUNTIME_REUSE_CONFIG_PATH} service ${service.id} runtimeReuse must declare codeIdentity or envIdentity paths`;
|
||||
return null;
|
||||
}
|
||||
if (service.envReuse === null) return `${RUNTIME_REUSE_CONFIG_PATH} service ${service.id} must declare envReuse`;
|
||||
if (service.envReuse.enabled === false) return `${RUNTIME_REUSE_CONFIG_PATH} service ${service.id} envReuse is disabled`;
|
||||
if (service.envReuse.envIdentityFiles.length === 0 && service.envReuse.nodeDepsPath === null) return `${RUNTIME_REUSE_CONFIG_PATH} service ${service.id} envReuse must declare envIdentityFiles or nodeDepsPath`;
|
||||
return null;
|
||||
}
|
||||
|
||||
function annotatePipelineRunReuseConfig(manifest: Record<string, unknown>, reuseConfig: RuntimeReuseConfig): Record<string, unknown> {
|
||||
const metadata = asOptionalRecord(manifest.metadata) ?? {};
|
||||
const annotations = asOptionalRecord(metadata.annotations) ?? {};
|
||||
@@ -1719,28 +1729,6 @@ function annotatePipelineRunReuseConfig(manifest: Record<string, unknown>, reuse
|
||||
return manifest;
|
||||
}
|
||||
|
||||
function applyAgentRunReuseConfig(spec: ReturnType<typeof resolveAgentRunLaneTarget>["spec"], reuseConfig: RuntimeReuseConfig): ReturnType<typeof resolveAgentRunLaneTarget>["spec"] {
|
||||
const service = runtimeReuseService(reuseConfig, ["agentrun-mgr", "manager"]);
|
||||
const envReuse = service?.envReuse;
|
||||
if (envReuse === undefined || envReuse === null) return spec;
|
||||
if (envReuse.enabled === false) return spec;
|
||||
const imageBuild = spec.deployment.manager.imageBuild;
|
||||
return {
|
||||
...spec,
|
||||
deployment: {
|
||||
...spec.deployment,
|
||||
manager: {
|
||||
...spec.deployment.manager,
|
||||
imageBuild: {
|
||||
...imageBuild,
|
||||
buildArgs: Object.keys(envReuse.buildArgs).length === 0 ? imageBuild.buildArgs : envReuse.buildArgs,
|
||||
envIdentityFiles: envReuse.envIdentityFiles.length === 0 ? imageBuild.envIdentityFiles : envReuse.envIdentityFiles,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function shouldFlushNativeGitMirrorDuringCloseout(follower: FollowerSpec, gitMirror: Record<string, unknown> | null): boolean {
|
||||
if (!nativeGitMirrorRequired(follower) || gitMirror === null) return false;
|
||||
if (gitMirror.sourceSnapshotReady === false) return false;
|
||||
@@ -2333,6 +2321,7 @@ function compactNativePayload(payload: Record<string, unknown> | null): Record<s
|
||||
pipeline: asOptionalRecord(payload.pipeline),
|
||||
taskRuns: compactTaskRunsPayload(asOptionalRecord(payload.taskRuns)),
|
||||
planArtifacts: compactPlanArtifactsPayload(asOptionalRecord(payload.planArtifacts)),
|
||||
agentrun: compactAgentRunPayload(asOptionalRecord(payload.agentrun)),
|
||||
argo: asOptionalRecord(payload.argo),
|
||||
runtime: asOptionalRecord(payload.runtime),
|
||||
refreshEvidence: compactRefreshEvidence(asOptionalRecord(asOptionalRecord(payload.nativeCapabilities)?.controlPlaneRefresh)),
|
||||
|
||||
Reference in New Issue
Block a user