fix: compact branch follower state

This commit is contained in:
Codex
2026-07-03 09:01:47 +00:00
parent af7eadfe9e
commit 291e61e638
+99 -6
View File
@@ -1971,6 +1971,7 @@ function kubeConfigMapFollowerState(registry: BranchFollowerRegistry, options: P
return { ok: true, stateByFollower: {}, present: false, error: "" };
}
present = true;
if (result.omitted) continue;
if (result.value === null || result.value.length === 0) continue;
const parsed = parseJsonObject(result.value);
if (parsed === null) {
@@ -1987,8 +1988,9 @@ function kubeConfigMapFollowerState(registry: BranchFollowerRegistry, options: P
};
}
function kubeConfigMapDataValue(registry: BranchFollowerRegistry, options: ParsedOptions, key: string): { ok: boolean; present: boolean; value: string | null; error: string } {
function kubeConfigMapDataValue(registry: BranchFollowerRegistry, options: ParsedOptions, key: string): { ok: boolean; present: boolean; value: string | null; omitted: boolean; error: string } {
const template = `{{ with index .data ${JSON.stringify(key)} }}{{ . }}{{ end }}`;
const maxValueBytes = 4096;
const script = [
"set -eu",
"tmpdir=$(mktemp -d)",
@@ -1996,18 +1998,24 @@ function kubeConfigMapDataValue(registry: BranchFollowerRegistry, options: Parse
"trap cleanup EXIT INT TERM",
`NAMESPACE=${shQuote(registry.controller.namespace)}`,
`CONFIGMAP=${shQuote(registry.controller.stateConfigMapName)}`,
"export NAMESPACE CONFIGMAP",
`MAX_VALUE_BYTES=${maxValueBytes}`,
"export NAMESPACE CONFIGMAP MAX_VALUE_BYTES",
`if ! value=$(kubectl -n "$NAMESPACE" get configmap "$CONFIGMAP" -o go-template=${shQuote(template)} 2>"$tmpdir/error"); then`,
" error_b64=$(tail -c 800 \"$tmpdir/error\" | base64 | tr -d '\\n')",
" if grep -qi 'not found' \"$tmpdir/error\"; then",
" printf '{\"ok\":true,\"present\":false,\"valueB64\":null,\"errorB64\":\"%s\"}' \"$error_b64\"",
" printf '{\"ok\":true,\"present\":false,\"valueB64\":null,\"omitted\":false,\"errorB64\":\"%s\"}' \"$error_b64\"",
" exit 0",
" fi",
" printf '{\"ok\":false,\"present\":false,\"valueB64\":null,\"errorB64\":\"%s\"}' \"$error_b64\"",
" printf '{\"ok\":false,\"present\":false,\"valueB64\":null,\"omitted\":false,\"errorB64\":\"%s\"}' \"$error_b64\"",
" exit 0",
"fi",
"value_bytes=$(printf '%s' \"$value\" | wc -c | tr -d ' ')",
"if [ \"${value_bytes:-0}\" -gt \"$MAX_VALUE_BYTES\" ]; then",
" printf '{\"ok\":true,\"present\":true,\"valueB64\":null,\"omitted\":true,\"valueBytes\":%s,\"errorB64\":\"\"}' \"$value_bytes\"",
" exit 0",
"fi",
"value_b64=$(printf '%s' \"$value\" | base64 | tr -d '\\n')",
"printf '{\"ok\":true,\"present\":true,\"valueB64\":\"%s\",\"errorB64\":\"\"}' \"$value_b64\"",
"printf '{\"ok\":true,\"present\":true,\"valueB64\":\"%s\",\"omitted\":false,\"valueBytes\":%s,\"errorB64\":\"\"}' \"$value_b64\" \"$value_bytes\"",
].join("\n");
const result = runKubeScript(registry, options, script, "", 10_000);
const parsed = result.exitCode === 0 ? parseJsonObject(result.stdout) : null;
@@ -2016,6 +2024,7 @@ function kubeConfigMapDataValue(registry: BranchFollowerRegistry, options: Parse
ok: false,
present: false,
value: null,
omitted: false,
error: redactText(tailText(result.stderr || result.stdout, 800)),
};
}
@@ -2023,11 +2032,13 @@ function kubeConfigMapDataValue(registry: BranchFollowerRegistry, options: Parse
const error = errorB64.length === 0 ? "" : Buffer.from(errorB64, "base64").toString("utf8");
const ok = parsed.ok === true;
const present = parsed.present === true;
const omitted = parsed.omitted === true;
const valueB64 = typeof parsed.valueB64 === "string" ? parsed.valueB64 : null;
return {
ok,
present,
value: valueB64 === null ? null : Buffer.from(valueB64, "base64").toString("utf8"),
omitted,
error: redactText(error),
};
}
@@ -2089,8 +2100,90 @@ function runKubeScript(registry: BranchFollowerRegistry, options: ParsedOptions,
return runCommand([transPath(), registry.controller.kubeRoute, "sh"], repoRoot, { input: `${script}\n`, timeoutMs });
}
function compactFollowerStateForConfigMap(state: FollowerState): Record<string, unknown> {
return {
id: state.id,
adapter: state.adapter,
enabled: state.enabled,
phase: state.phase,
source: state.source,
target: state.target,
lastTriggeredSha: state.lastTriggeredSha,
lastSucceededSha: state.lastSucceededSha,
pipelineRun: state.pipelineRun,
inFlightJob: state.inFlightJob,
budgetSource: state.budgetSource,
controller: state.controller,
decision: state.decision,
dryRun: state.dryRun,
updatedAt: state.updatedAt,
warnings: state.warnings.slice(0, 6),
stateFormat: "compact-v1",
command: compactStateCommand(state.command),
};
}
function compactStateCommand(command: Record<string, unknown> | undefined): Record<string, unknown> | undefined {
if (command === undefined) return undefined;
const closeout = asOptionalRecord(command.closeout);
const closeoutSummary = asOptionalRecord(closeout?.summary);
const payload = compactNativePayload(asOptionalRecord(command.payload)) ?? closeoutSummary;
return {
mode: stringOrNull(command.mode) ?? stringOrNull(command.status),
namespace: stringOrNull(command.namespace),
pipelineRun: stringOrNull(command.pipelineRun),
sourceCommit: stringOrNull(command.sourceCommit),
sourceStageRef: stringOrNull(command.sourceStageRef),
wait: command.wait === true ? true : undefined,
pipelineRunCompleted: command.pipelineRunCompleted === true ? true : undefined,
stillRunning: command.stillRunning === true ? true : undefined,
closeout: closeout === null
? null
: {
ok: closeout.ok === true,
completed: closeout.completed === true,
timedOut: closeout.timedOut === true,
polls: numberOrNull(closeout.polls),
elapsedMs: numberOrNull(closeout.elapsedMs),
summary: closeoutSummary,
statusAuthority: stringOrNull(closeout.statusAuthority),
parsedDownstreamCliOutput: false,
},
payload,
exitCode: numberOrNull(command.exitCode),
timedOut: command.timedOut === true,
statusAuthority: stringOrNull(command.statusAuthority),
parsedDownstreamCliOutput: false,
};
}
function compactNativePayload(payload: Record<string, unknown> | null): Record<string, unknown> | null {
if (payload === null) return null;
return {
source: compactSourcePayload(asOptionalRecord(payload.source)),
tekton: asOptionalRecord(payload.tekton),
argo: asOptionalRecord(payload.argo),
runtime: asOptionalRecord(payload.runtime),
errors: Array.isArray(payload.errors) ? payload.errors.slice(0, 5) : [],
statusAuthority: stringOrNull(payload.statusAuthority),
parsedDownstreamCliOutput: false,
};
}
function compactSourcePayload(source: Record<string, unknown> | null): Record<string, unknown> | null {
if (source === null) return null;
return {
commit: stringOrNull(source.commit),
branch: stringOrNull(source.branch),
repository: stringOrNull(source.repository),
stageRef: stringOrNull(source.stageRef),
sourceAuthority: stringOrNull(source.sourceAuthority),
repoPath: stringOrNull(source.repoPath),
};
}
function writeFollowerState(registry: BranchFollowerRegistry, state: FollowerState, options: ParsedOptions): CommandResult {
const json = JSON.stringify(state);
const json = JSON.stringify(compactFollowerStateForConfigMap(state));
const dataPatch = JSON.stringify({ data: { [state.id]: json, _updatedAt: new Date().toISOString(), _specRef: SPEC_REF } });
if (options.controller) {
const patchBase64 = Buffer.from(dataPatch, "utf8").toString("base64");