From edc7f4534c2eae84a370d3062230088d31f24798 Mon Sep 17 00:00:00 2001 From: Carlos Villela Date: Thu, 16 Jul 2026 00:37:12 -0700 Subject: [PATCH 1/3] fix(ci): select migrated E2E parity entrypoint Signed-off-by: Carlos Villela --- .../actions/ci-cli-coverage-shard/action.yaml | 10 ++- test/e2e-mock-parity.test.ts | 75 +++++++++++++++++++ test/pr-workflow-contract.test.ts | 6 +- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/.github/actions/ci-cli-coverage-shard/action.yaml b/.github/actions/ci-cli-coverage-shard/action.yaml index 4bb786089b1..e94a74e2b75 100644 --- a/.github/actions/ci-cli-coverage-shard/action.yaml +++ b/.github/actions/ci-cli-coverage-shard/action.yaml @@ -91,7 +91,15 @@ runs: exit 0 ;; esac - npx tsx scripts/checks/e2e-mock-parity.ts --base "$base" --head "$head" + parity_check=scripts/checks/e2e-mock-parity.mts + if [ ! -f "$parity_check" ]; then + parity_check=scripts/checks/e2e-mock-parity.ts + fi + if [ ! -f "$parity_check" ]; then + echo "::error title=Missing E2E mock parity entrypoint::Expected scripts/checks/e2e-mock-parity.mts or scripts/checks/e2e-mock-parity.ts." + exit 1 + fi + npx tsx "$parity_check" --base "$base" --head "$head" - name: Build TypeScript plugin shell: bash diff --git a/test/e2e-mock-parity.test.ts b/test/e2e-mock-parity.test.ts index 0de972be19b..964f7a45673 100644 --- a/test/e2e-mock-parity.test.ts +++ b/test/e2e-mock-parity.test.ts @@ -1,12 +1,17 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +import { spawnSync } from "node:child_process"; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { describe, expect, it } from "vitest"; import { isMockParityRelevantSourceChange, type MockParityManifest, validateMockParity, } from "../scripts/checks/e2e-mock-parity"; +import { type CompositeAction, readYaml } from "./helpers/e2e-workflow-contract"; const live = "test/e2e/live/example.test.ts"; const fast = "test/e2e/support/example.test.ts"; @@ -108,3 +113,73 @@ describe("changed live E2E mock parity", () => { ).toEqual([`${live}: liveOnlyReason must be a string`]); }); }); + +describe("trusted E2E parity entrypoint selection", () => { + const action = readYaml(".github/actions/ci-cli-coverage-shard/action.yaml"); + const parityStep = action.runs.steps.find( + (step) => step.name === "Validate changed live E2E mock parity", + ); + if (!parityStep) throw new Error("Missing E2E mock parity action step"); + + it("prefers .mts, falls back to .ts, and rejects a missing check (#6921)", () => { + const stem = "scripts/checks/e2e-mock-parity"; + const variants = [ + { extensions: ["mts", "ts"], expected: `${stem}.mts`, status: 0 }, + { extensions: ["mts"], expected: `${stem}.mts`, status: 0 }, + { extensions: ["ts"], expected: `${stem}.ts`, status: 0 }, + { extensions: [], expected: null, status: 1 }, + ] as const; + + for (const variant of variants) { + const temp = mkdtempSync(join(tmpdir(), "nemoclaw-e2e-parity-entrypoint-")); + const fakeBin = join(temp, "bin"); + const commandLog = join(temp, "command.json"); + mkdirSync(fakeBin); + mkdirSync(join(temp, "scripts", "checks"), { recursive: true }); + writeFileSync( + join(fakeBin, "npx"), + [ + "#!/usr/bin/env node", + 'const fs = require("node:fs");', + "fs.appendFileSync(process.env.COMMAND_LOG, `${JSON.stringify(process.argv.slice(2))}\\n`);", + ].join("\n"), + { mode: 0o755 }, + ); + for (const extension of variant.extensions) { + writeFileSync(join(temp, `${stem}.${extension}`), "// fixture\n"); + } + + try { + const result = spawnSync("bash", ["-c", parityStep.run ?? ""], { + cwd: temp, + encoding: "utf8", + env: { + ...process.env, + ...parityStep.env, + COMMAND_LOG: commandLog, + EVENT_NAME: "pull_request", + PATH: `${fakeBin}:${process.env.PATH ?? ""}`, + PUSH_BASE_SHA: "unused", + }, + timeout: 5_000, + }); + + expect(result.status, String(result.stderr)).toBe(variant.status); + if (variant.expected) { + const commands = readFileSync(commandLog, "utf8") + .trim() + .split("\n") + .map((line) => JSON.parse(line)); + expect(commands).toEqual([ + ["tsx", variant.expected, "--base", "HEAD^1", "--head", "HEAD^2"], + ]); + } else { + expect(existsSync(commandLog)).toBe(false); + expect(String(result.stdout)).toContain("Missing E2E mock parity entrypoint"); + } + } finally { + rmSync(temp, { force: true, recursive: true }); + } + } + }); +}); diff --git a/test/pr-workflow-contract.test.ts b/test/pr-workflow-contract.test.ts index e8cbf54e243..79c64bc897e 100644 --- a/test/pr-workflow-contract.test.ts +++ b/test/pr-workflow-contract.test.ts @@ -975,9 +975,9 @@ describe("pull request and main workflow contracts", () => { expect(parityStep.run).toContain("base=HEAD^1"); expect(parityStep.run).toContain("head=HEAD^2"); expect(parityStep.run).toContain('base="$PUSH_BASE_SHA"'); - expect(parityStep.run).toContain( - 'npx tsx scripts/checks/e2e-mock-parity.ts --base "$base" --head "$head"', - ); + expect(parityStep.run).toContain("parity_check=scripts/checks/e2e-mock-parity.mts"); + expect(parityStep.run).toContain("parity_check=scripts/checks/e2e-mock-parity.ts"); + expect(parityStep.run).toContain('npx tsx "$parity_check" --base "$base" --head "$head"'); const trustedCapabilityProbe = requiredWorkflowStep( prWorkflow.jobs["cli-test-shards"], From c7a934d2cd955daa7946c1a80d2a1c0c6f51c335 Mon Sep 17 00:00:00 2001 From: Carlos Villela Date: Thu, 16 Jul 2026 08:41:40 -0700 Subject: [PATCH 2/3] test(ci): keep parity entrypoint cases linear --- test/e2e-mock-parity.test.ts | 112 +++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 50 deletions(-) diff --git a/test/e2e-mock-parity.test.ts b/test/e2e-mock-parity.test.ts index 964f7a45673..525b6ce651a 100644 --- a/test/e2e-mock-parity.test.ts +++ b/test/e2e-mock-parity.test.ts @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -import { spawnSync } from "node:child_process"; +import { type SpawnSyncReturns, spawnSync } from "node:child_process"; import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -119,67 +119,79 @@ describe("trusted E2E parity entrypoint selection", () => { const parityStep = action.runs.steps.find( (step) => step.name === "Validate changed live E2E mock parity", ); - if (!parityStep) throw new Error("Missing E2E mock parity action step"); + const parityRun = parityStep?.run ?? ""; + const parityEnv = parityStep?.env ?? {}; + const stem = "scripts/checks/e2e-mock-parity"; - it("prefers .mts, falls back to .ts, and rejects a missing check (#6921)", () => { - const stem = "scripts/checks/e2e-mock-parity"; - const variants = [ - { extensions: ["mts", "ts"], expected: `${stem}.mts`, status: 0 }, - { extensions: ["mts"], expected: `${stem}.mts`, status: 0 }, - { extensions: ["ts"], expected: `${stem}.ts`, status: 0 }, - { extensions: [], expected: null, status: 1 }, - ] as const; - - for (const variant of variants) { - const temp = mkdtempSync(join(tmpdir(), "nemoclaw-e2e-parity-entrypoint-")); - const fakeBin = join(temp, "bin"); - const commandLog = join(temp, "command.json"); - mkdirSync(fakeBin); - mkdirSync(join(temp, "scripts", "checks"), { recursive: true }); - writeFileSync( - join(fakeBin, "npx"), - [ - "#!/usr/bin/env node", - 'const fs = require("node:fs");', - "fs.appendFileSync(process.env.COMMAND_LOG, `${JSON.stringify(process.argv.slice(2))}\\n`);", - ].join("\n"), - { mode: 0o755 }, - ); - for (const extension of variant.extensions) { - writeFileSync(join(temp, `${stem}.${extension}`), "// fixture\n"); - } + function withParityEntrypoints( + extensions: readonly string[], + verify: (result: SpawnSyncReturns, commandLog: string) => void, + ): void { + const temp = mkdtempSync(join(tmpdir(), "nemoclaw-e2e-parity-entrypoint-")); + const fakeBin = join(temp, "bin"); + const commandLog = join(temp, "command.json"); + mkdirSync(fakeBin); + mkdirSync(join(temp, "scripts", "checks"), { recursive: true }); + writeFileSync( + join(fakeBin, "npx"), + [ + "#!/usr/bin/env node", + 'const fs = require("node:fs");', + "fs.appendFileSync(process.env.COMMAND_LOG, `${JSON.stringify(process.argv.slice(2))}\\n`);", + ].join("\n"), + { mode: 0o755 }, + ); + for (const extension of extensions) { + writeFileSync(join(temp, `${stem}.${extension}`), "// fixture\n"); + } - try { - const result = spawnSync("bash", ["-c", parityStep.run ?? ""], { + try { + verify( + spawnSync("bash", ["-c", parityRun], { cwd: temp, encoding: "utf8", env: { ...process.env, - ...parityStep.env, + ...parityEnv, COMMAND_LOG: commandLog, EVENT_NAME: "pull_request", PATH: `${fakeBin}:${process.env.PATH ?? ""}`, PUSH_BASE_SHA: "unused", }, timeout: 5_000, - }); - - expect(result.status, String(result.stderr)).toBe(variant.status); - if (variant.expected) { - const commands = readFileSync(commandLog, "utf8") - .trim() - .split("\n") - .map((line) => JSON.parse(line)); - expect(commands).toEqual([ - ["tsx", variant.expected, "--base", "HEAD^1", "--head", "HEAD^2"], - ]); - } else { - expect(existsSync(commandLog)).toBe(false); - expect(String(result.stdout)).toContain("Missing E2E mock parity entrypoint"); - } - } finally { - rmSync(temp, { force: true, recursive: true }); - } + }), + commandLog, + ); + } finally { + rmSync(temp, { force: true, recursive: true }); } + } + + it.each([ + { + extensions: ["mts", "ts"], + expected: `${stem}.mts`, + title: "prefers .mts when both entrypoints exist", + }, + { extensions: ["mts"], expected: `${stem}.mts`, title: "runs the migrated .mts entrypoint" }, + { extensions: ["ts"], expected: `${stem}.ts`, title: "falls back to the .ts entrypoint" }, + ])("$title (#6921)", ({ extensions, expected }) => { + withParityEntrypoints(extensions, (result, commandLog) => { + expect(result.status, String(result.stderr)).toBe(0); + expect( + readFileSync(commandLog, "utf8") + .trim() + .split("\n") + .map((line) => JSON.parse(line)), + ).toEqual([["tsx", expected, "--base", "HEAD^1", "--head", "HEAD^2"]]); + }); + }); + + it("rejects a missing parity entrypoint (#6921)", () => { + withParityEntrypoints([], (result, commandLog) => { + expect(result.status, String(result.stderr)).toBe(1); + expect(existsSync(commandLog)).toBe(false); + expect(String(result.stdout)).toContain("Missing E2E mock parity entrypoint"); + }); }); }); From 6d6ab6606204aa1659f1e98adae773da0aa55431 Mon Sep 17 00:00:00 2001 From: Carlos Villela Date: Thu, 16 Jul 2026 08:44:20 -0700 Subject: [PATCH 3/3] test(ci): rely on parity action behavior --- test/pr-workflow-contract.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/pr-workflow-contract.test.ts b/test/pr-workflow-contract.test.ts index 79c64bc897e..23b0246c907 100644 --- a/test/pr-workflow-contract.test.ts +++ b/test/pr-workflow-contract.test.ts @@ -975,9 +975,6 @@ describe("pull request and main workflow contracts", () => { expect(parityStep.run).toContain("base=HEAD^1"); expect(parityStep.run).toContain("head=HEAD^2"); expect(parityStep.run).toContain('base="$PUSH_BASE_SHA"'); - expect(parityStep.run).toContain("parity_check=scripts/checks/e2e-mock-parity.mts"); - expect(parityStep.run).toContain("parity_check=scripts/checks/e2e-mock-parity.ts"); - expect(parityStep.run).toContain('npx tsx "$parity_check" --base "$base" --head "$head"'); const trustedCapabilityProbe = requiredWorkflowStep( prWorkflow.jobs["cli-test-shards"],