diff --git a/scripts/lib/ci-changed-node-test-plan.mts b/scripts/lib/ci-changed-node-test-plan.mts index 8b21a762731e..2e7b0e449bec 100644 --- a/scripts/lib/ci-changed-node-test-plan.mts +++ b/scripts/lib/ci-changed-node-test-plan.mts @@ -353,6 +353,15 @@ function createChangedExtensionConfigShards(extensionRoots: string[]) { }); } +function createChangedExtensionConfigShardsForPaths(changedPaths: string[], cwd: string) { + const relevantPaths = changedPaths.filter( + (changedPath) => + changedPath.startsWith("extensions/") && + (existsSync(path.join(cwd, changedPath)) || !isTestFileTarget(changedPath)), + ); + return createChangedExtensionConfigShards(resolveChangedExtensionRoots(relevantPaths)); +} + /** * The fail-safe cause leaves the non-extension diff's extension impact unbounded, * so whole extension configs are required; precise targets would under-cover. @@ -362,19 +371,7 @@ export function createChangedExtensionFallbackShards( options: CwdOptions = {}, ): ChangedNodeTestShard[] { const cwd = options.cwd ?? process.cwd(); - const extensionPaths = changedPaths.filter((changedPath) => - changedPath.startsWith("extensions/"), - ); - if (extensionPaths.length === 0) { - return []; - } - const relevantPaths = extensionPaths.filter( - (changedPath) => existsSync(path.join(cwd, changedPath)) || !isTestFileTarget(changedPath), - ); - if (relevantPaths.length === 0) { - return []; - } - return createChangedExtensionConfigShards(resolveChangedExtensionRoots(relevantPaths)); + return createChangedExtensionConfigShardsForPaths(changedPaths, cwd); } /** @@ -404,9 +401,13 @@ export function createChangedNodeTestShards( } const policyTargetsByPath = new Map( - livePaths.map((changedPath) => [changedPath, resolvePolicyTestTargets([changedPath])]), + livePaths + .filter((changedPath) => !changedPath.startsWith("extensions/")) + .map((changedPath) => [changedPath, resolvePolicyTestTargets([changedPath])]), + ); + const regularLivePaths = livePaths.filter( + (changedPath) => !changedPath.startsWith("extensions/") && !isPolicyTestOwnedPath(changedPath), ); - const regularLivePaths = livePaths.filter((changedPath) => !isPolicyTestOwnedPath(changedPath)); // Workspace package consumers often use package specifiers, which the // relative import graph cannot connect back to the changed package source. @@ -436,6 +437,7 @@ export function createChangedNodeTestShards( // Boundary-config targets run as regular nondist targets: the boundary // suite scans the checked-out tree and never consumes the built dist. const shards = [ + ...createChangedExtensionConfigShardsForPaths(livePaths, cwd), ...createChangedTargetShards(targets, { checkName: "checks-node-changed", shardName: "changed", diff --git a/test/scripts/ci-changed-node-test-plan.test.ts b/test/scripts/ci-changed-node-test-plan.test.ts index 5256ea3e8b48..d479981a7982 100644 --- a/test/scripts/ci-changed-node-test-plan.test.ts +++ b/test/scripts/ci-changed-node-test-plan.test.ts @@ -283,6 +283,22 @@ describe("CI changed Node test plan", () => { ]); }); + it.each([ + { + changedPath: "extensions/browser/src/browser/cdp.helpers.test.ts", + config: "test/vitest/vitest.extension-browser.config.ts", + }, + { + changedPath: "extensions/codex/src/session-upstream-marker.ts", + config: "test/vitest/vitest.extension-codex.config.ts", + }, + ])("runs the whole owning extension config for $changedPath", ({ changedPath, config }) => { + const shards = createChangedNodeTestShards([changedPath]); + + expect(shards).not.toBeNull(); + expect(shards?.flatMap((shard) => shard.configs)).toContain(config); + }); + it("preserves Matrix process bounds in mixed package fallbacks", () => { const shards = createChangedExtensionFallbackShards([ "packages/gateway-protocol/src/frame-guards.ts", @@ -406,20 +422,19 @@ describe("CI changed Node test plan", () => { expect(new Set(targets).size).toBe(targets.length); }); - it("serializes changed-test chunks that contain Memory Core integration tests", () => { + it("serializes the owning Memory Core extension config for direct changes", () => { const shards = createChangedNodeTestShards([ "extensions/memory-core/src/memory/mmr.ts", "extensions/memory-core/src/memory/mmr.test.ts", ]); expect(shards).not.toBeNull(); - const targetShards = shards?.filter((shard) => shard.targets) ?? []; - expect(targetShards.length).toBeGreaterThan(0); - expect( - targetShards - .filter((shard) => - shard.targets?.some((target) => target.startsWith("extensions/memory-core/")), - ) - .every((shard) => shard.planConcurrency === 1), - ).toBe(true); + expect(shards).toContainEqual({ + checkName: "checks-node-changed-extensions-config", + configs: ["test/vitest/vitest.extension-memory.config.ts"], + planConcurrency: 1, + requiresDist: false, + runner: "blacksmith-8vcpu-ubuntu-2404", + shardName: "changed-extensions-config", + }); }); });