From 7d2c66bebd4f6ec5b85159007254918f134465e0 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 21 Jul 2026 12:41:02 +0200 Subject: [PATCH] fix(cicd): preserve semantic package scope --- package.json | 1 + scripts/ci-plan.test.mjs | 10 ++++++++-- scripts/src/ci-plan-lib.mjs | 11 ++++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f1696a95..00f261b8 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "harnessrl:native:l1-smoke": "node scripts/harnessrl-native-l1-smoke.mjs", "tasktree:backup:l1-smoke": "bun scripts/tasktree-backup-native-l1-smoke.mjs", "tasktree:backup:restore:l1-smoke": "bun scripts/tasktree-backup-restore-l1-smoke.mjs", + "tasktree:schema:concurrency-smoke": "bun scripts/tasktree-schema-concurrency-smoke.mjs", "workbench:api:dev": "bun --watch cmd/hwlab-workbench-api/main.ts", "workbench:worker:dev": "bun --watch cmd/hwlab-workbench-worker/main.ts", "workbench:web:dev": "cd web/hwlab-cloud-web && WORKBENCH_VITE_USE_POLLING=1 bun run dev", diff --git a/scripts/ci-plan.test.mjs b/scripts/ci-plan.test.mjs index 9e4623ca..6b1f6956 100644 --- a/scripts/ci-plan.test.mjs +++ b/scripts/ci-plan.test.mjs @@ -1159,8 +1159,13 @@ test("v02 planner treats shared trace renderer changes as cloud-web code rollout assert.deepEqual(cloudWeb.reason, ["code-input-changed", "component-path-changed"]); }); -test("planner ignores package script cleanup for runtime images", async () => { +test("planner ignores package scripts-only changes even when package is a component path", async () => { const repo = await createFixtureRepo(); + const deployPath = path.join(repo, "deploy/deploy.yaml"); + const deploy = await readStructuredFile(repo, deployPath); + deploy.lanes.v02.serviceDeclarations["hwlab-cloud-api"].componentPaths.push("package.json"); + deploy.lanes.v02.serviceDeclarations["hwlab-cloud-web"].componentPaths.push("package.json"); + await writeStructuredFile(repo, deployPath, deploy); await writeFile(path.join(repo, "package.json"), JSON.stringify({ type: "module", scripts: { @@ -1170,7 +1175,7 @@ test("planner ignores package script cleanup for runtime images", async () => { "@openai/codex": "^0.128.0" } }, null, 2)); - await git(repo, ["add", "package.json"]); + await git(repo, ["add", "deploy/deploy.yaml", "package.json"]); await git(repo, ["commit", "-m", "seed package scripts"]); await refreshFixtureCatalogForHead(repo); @@ -1191,6 +1196,7 @@ test("planner ignores package script cleanup for runtime images", async () => { const plan = await planV02CoreServices(repo, { baseRef: "HEAD~1", targetRef: "HEAD" }); assert.deepEqual(plan.affectedServices, []); assert.deepEqual(plan.buildServices, []); + assert.equal(plan.services.every((service) => !service.changedPaths.includes("package.json")), true); assert.equal(plan.imageBuildRequired, false); assert.equal(plan.buildSkippedCount, 2); }); diff --git a/scripts/src/ci-plan-lib.mjs b/scripts/src/ci-plan-lib.mjs index 37a1a644..3215a98f 100644 --- a/scripts/src/ci-plan-lib.mjs +++ b/scripts/src/ci-plan-lib.mjs @@ -124,7 +124,8 @@ export async function createCiPlan(options = {}) { const services = []; for (const model of componentModels) { - const directMatches = matchingPaths(normalizedChangedPaths, model.componentPaths); + const directMatches = matchingPaths(normalizedChangedPaths, model.componentPaths) + .filter((item) => !model.runtimeDeps.includes(item) || semanticRuntimeDepPaths.has(item)); const sharedMatches = matchingPaths(normalizedChangedPaths, model.sharedPaths); const rawRuntimeDepMatches = matchingPaths(normalizedChangedPaths, model.runtimeDeps); const runtimeDepMatches = rawRuntimeDepMatches.filter((item) => semanticRuntimeDepPaths.has(item)); @@ -147,7 +148,10 @@ export async function createCiPlan(options = {}) { ? matchingPaths(normalizedChangedPaths, envInputPaths) .filter((item) => !model.runtimeDeps.includes(item) || semanticRuntimeDepPaths.has(item)) : []; - const codeMatches = envReuse ? matchingPaths(normalizedChangedPaths, codeInputPaths) : []; + const codeMatches = envReuse + ? matchingPaths(normalizedChangedPaths, codeInputPaths) + .filter((item) => !model.runtimeDeps.includes(item) || semanticRuntimeDepPaths.has(item)) + : []; const relevantEnvMatches = envMatches.filter((item) => !isTestOnlyPath(item) && !isDocsOnlyPath(item)); const relevantCodeMatches = codeMatches.filter((item) => !isTestOnlyPath(item) && !isDocsOnlyPath(item)); const imageRelevantChangedPaths = uniqueSorted([ @@ -162,7 +166,8 @@ export async function createCiPlan(options = {}) { semanticPackageJson: true }) : null; const codeInputHash = envReuse ? await hashGitPaths(repoRoot, targetRef, codeInputPaths, { - skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath) + skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath), + semanticPackageJson: true }) : null; const currentEnvironmentImage = envReuse ? envReuseImageRef(registryPrefix, model.serviceId, environmentInputHash, envArtifactGroup) : null; const catalogEnvironmentImage = envReuse ? environmentImageFromCatalog(model.serviceId, catalogRecord) : null;