From 4cc6ae460a7c57bf9267c30f271401963ce204a8 Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 26 Jun 2026 11:24:02 +0000 Subject: [PATCH] fix: bound ci benchmark logs --- scripts/src/hwlab-node-control-plane.ts | 32 ++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/scripts/src/hwlab-node-control-plane.ts b/scripts/src/hwlab-node-control-plane.ts index 7f55cb64..599c9a1e 100644 --- a/scripts/src/hwlab-node-control-plane.ts +++ b/scripts/src/hwlab-node-control-plane.ts @@ -591,7 +591,7 @@ function runCiBuildBenchmarkCommand(_config: ControlPlaneConfig, node: ControlPl const parsed = parseRemoteJson(result.stdout); const job = typeof parsed === "object" && parsed !== null ? parsed as Record : { stdoutPreview: result.stdout.slice(0, 2000) }; return renderCiBuildBenchmarkResult({ - ok: result.exitCode === 0 && ciBuildBenchmarkLiveOk(job, runtime.serviceIds), + ok: result.exitCode === 0 && ciBuildBenchmarkLiveOk(job, runtime.serviceIds, profile), command: `hwlab nodes control-plane infra ci-build-benchmark ${options.action}`, configPath: HWLAB_NODE_CONTROL_PLANE_CONFIG_PATH, node: node.id, @@ -790,7 +790,7 @@ function renderCiBuildBenchmarkResult(result: Record): Rendered const pipelineRun = record(job.pipelineRun); const taskRows = ciBuildBenchmarkTaskRows(job); const serviceRows = ciBuildBenchmarkServiceRows(job, benchmark.services); - const failures = ciBuildBenchmarkFailureRows(job, serviceRows); + const failures = ciBuildBenchmarkFailureRows(job, serviceRows, benchmark); const profile = renderCell(result.profile ?? benchmark.profile ?? plan.profile, "unknown"); const node = renderCell(result.node); const lane = renderCell(result.lane); @@ -3149,6 +3149,7 @@ tmp_dir=pathlib.Path(sys.argv[3]) pipeline_run=sys.argv[4] include_logs=sys.argv[5] == "true" tail_lines=int(sys.argv[6]) +log_tail_limit=min(6000, max(2000, tail_lines * 80)) def read_json(path): try: @@ -3234,7 +3235,7 @@ payload={ "pods": read_text(tmp_dir / "pods.err"), "logs": read_text(tmp_dir / "logs.err") if include_logs else "", }, - "logTail": read_text(tmp_dir / "logs.txt", max(4000, tail_lines * 300)) if include_logs else "", + "logTail": read_text(tmp_dir / "logs.txt", log_tail_limit) if include_logs else "", } print(json.dumps(payload, ensure_ascii=False)) PY @@ -3348,7 +3349,7 @@ function ciBuildBenchmarkStateDir(target: ControlPlaneTargetSpec, profile: strin return `/tmp/unidesk-hwlab-node-control-plane/${target.id}/ci-build-benchmark-${profile}`; } -function ciBuildBenchmarkLiveOk(job: Record, expectedServices: readonly string[]): boolean { +function ciBuildBenchmarkLiveOk(job: Record, expectedServices: readonly string[], profile: CiBuildBenchmarkProfileSpec): boolean { const pipelineRun = record(job.pipelineRun); const pipelineStatus = renderCell(pipelineRun.status, ""); if (pipelineStatus === "False") return false; @@ -3357,7 +3358,7 @@ function ciBuildBenchmarkLiveOk(job: Record, expectedServices: for (const service of expectedServices) { if (!taskRuns.some((task) => task.pipelineTask === `build-${service}`)) return false; } - return true; + return ciBuildBenchmarkPolicyOk(job, profile.cachePolicy); } function ciBuildBenchmarkTaskRows(job: Record): Record[] { @@ -3415,7 +3416,7 @@ function ciBuildBenchmarkServiceRows(job: Record, servicesValue }); } -function ciBuildBenchmarkFailureRows(job: Record, serviceRows: readonly Record[]): Record[] { +function ciBuildBenchmarkFailureRows(job: Record, serviceRows: readonly Record[], benchmark: Record): Record[] { const counts = new Map(); const add = (family: string, scope: string): void => { if (family === "-" || family.length === 0) return; @@ -3429,9 +3430,28 @@ function ciBuildBenchmarkFailureRows(job: Record, serviceRows: if (pipelineRun.status === "False") { add(classifyCiBuildBenchmarkFailure(`${renderCell(pipelineRun.reason, "")}\n${renderCell(pipelineRun.message, "")}`), "pipeline"); } + const cachePolicy = record(benchmark.cachePolicy); + if (cachePolicy.forbidBuildkitCache === true && ciBuildBenchmarkLogHasBuildkitCache(job)) add("cache-hit-forbidden", "buildkit-cache"); + if (cachePolicy.forbidGitopsCatalogReuse === true && ciBuildBenchmarkLogHasReuse(job)) add("cache-hit-forbidden", "artifact-reuse"); return [...counts.entries()].map(([family, value]) => ({ family, count: String(value.count), scope: value.scopes.join(",") })); } +function ciBuildBenchmarkPolicyOk(job: Record, cachePolicy: CiBuildBenchmarkCachePolicy): boolean { + if (cachePolicy.forbidBuildkitCache && ciBuildBenchmarkLogHasBuildkitCache(job)) return false; + if (cachePolicy.forbidGitopsCatalogReuse && ciBuildBenchmarkLogHasReuse(job)) return false; + return true; +} + +function ciBuildBenchmarkLogHasBuildkitCache(job: Record): boolean { + const logTail = typeof job.logTail === "string" ? job.logTail : ""; + return /buildkitCacheRef|--import-cache|--export-cache|writing cache image manifest/iu.test(logTail); +} + +function ciBuildBenchmarkLogHasReuse(job: Record): boolean { + const logTail = typeof job.logTail === "string" ? job.logTail : ""; + return /"reusedFrom"\s*:\s*"(?!null)|"status"\s*:\s*"reused"/iu.test(logTail); +} + function ciBuildBenchmarkTaskRunRecords(job: Record): Record[] { return Array.isArray(job.taskRuns) ? job.taskRuns.map(record) : []; }