Skip to content

Commit 30d6825

Browse files
committed
fix(ci): align mutation selectors with merge result
1 parent 291964e commit 30d6825

2 files changed

Lines changed: 79 additions & 6 deletions

File tree

.github/workflows/mutation-testing.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
if: github.event_name == 'pull_request'
3030
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3131
with:
32-
ref: refs/pull/${{ github.event.pull_request.number }}/merge
32+
ref: ${{ github.sha }}
3333
fetch-depth: 0
3434
persist-credentials: false
3535

@@ -54,7 +54,7 @@ jobs:
5454
if: github.event_name == 'pull_request'
5555
env:
5656
BASE_SHA: ${{ github.event.pull_request.base.sha }}
57-
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
57+
HEAD_SHA: ${{ github.sha }}
5858
run: node scripts/stryker-diff.mjs ci --base "$BASE_SHA" --head "$HEAD_SHA"
5959

6060
- name: Upload mutation reports
@@ -72,6 +72,8 @@ jobs:
7272
env:
7373
ARTIFACT_URL: ${{ steps.mutation_report.outputs.artifact-url }}
7474
run: |
75-
echo "" >> "$GITHUB_STEP_SUMMARY"
76-
echo "### Download mutation reports" >> "$GITHUB_STEP_SUMMARY"
77-
echo "[Open the changed-code-mutation-report artifact]($ARTIFACT_URL), then open the package's mutation.html file." >> "$GITHUB_STEP_SUMMARY"
75+
{
76+
echo ""
77+
echo "### Download mutation reports"
78+
echo "[Open the changed-code-mutation-report artifact]($ARTIFACT_URL), then open the package's mutation.html file."
79+
} >> "$GITHUB_STEP_SUMMARY"

scripts/stryker-diff.test.mjs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
preferDirectTestFiles,
2626
resolveVitestBinary,
2727
packageForPath,
28+
runManifest,
2829
selectFromGit,
2930
testsFromMutationReport,
3031
validateDisableDirectives,
@@ -40,11 +41,14 @@ describe("mutation testing workflow", () => {
4041
assert.ok(!workflow.includes("pull_request_target:"))
4142
assert.ok(workflow.includes(" contents: read"))
4243
assert.ok(workflow.includes("- name: Checkout pull request merge result"))
43-
assert.ok(workflow.includes("ref: refs/pull/${{ github.event.pull_request.number }}/merge"))
44+
assert.ok(workflow.includes("ref: ${{ github.sha }}"))
45+
assert.ok(!workflow.includes("ref: refs/pull/${{ github.event.pull_request.number }}/merge"))
4446
assert.ok(workflow.includes("fetch-depth: 0"))
4547
assert.ok(workflow.includes("persist-credentials: false"))
4648
assert.ok(!workflow.includes("repository: ${{ github.event.pull_request.head.repo.full_name }}"))
4749
assert.ok(!workflow.includes("ref: ${{ github.event.pull_request.head.sha }}"))
50+
assert.ok(workflow.includes("HEAD_SHA: ${{ github.sha }}"))
51+
assert.ok(!workflow.includes("HEAD_SHA: ${{ github.event.pull_request.head.sha }}"))
4852
assert.ok(workflow.includes("steps.mutation_report.outputs.artifact-url"))
4953
assert.ok(workflow.includes("open the package's mutation.html file"))
5054
})
@@ -291,6 +295,43 @@ describe("selectFromGit", () => {
291295
fs.rmSync(repo, { recursive: true, force: true })
292296
}
293297
})
298+
299+
it("uses merge-result line coordinates when the base shifts a pull request edit", () => {
300+
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "stryker-merge-diff-"))
301+
const runGit = (...args) => execFileSync("git", args, { cwd: repo, encoding: "utf8" }).trim()
302+
303+
try {
304+
runGit("init", "--initial-branch=main")
305+
runGit("config", "user.name", "Mutation Test")
306+
runGit("config", "user.email", "mutation@example.com")
307+
fs.mkdirSync(path.join(repo, "packages/core/src"), { recursive: true })
308+
fs.writeFileSync(path.join(repo, "packages/core/src/value.ts"), "const first = 1\nconst changed = true\n")
309+
runGit("add", ".")
310+
runGit("commit", "-m", "initial")
311+
312+
runGit("checkout", "-b", "feature")
313+
fs.writeFileSync(path.join(repo, "packages/core/src/value.ts"), "const first = 1\nconst changed = false\n")
314+
runGit("commit", "-am", "change value")
315+
316+
runGit("checkout", "main")
317+
fs.writeFileSync(
318+
path.join(repo, "packages/core/src/value.ts"),
319+
"const inserted = 0\nconst first = 1\nconst changed = true\n",
320+
)
321+
runGit("commit", "-am", "shift source lines")
322+
const baseSha = runGit("rev-parse", "HEAD")
323+
runGit("merge", "--no-ff", "feature", "-m", "merge feature")
324+
const mergeSha = runGit("rev-parse", "HEAD")
325+
326+
const manifest = selectFromGit(repo, baseSha, mergeSha)
327+
assert.deepEqual(
328+
manifest.packages.map(({ id, selectors }) => ({ id, selectors })),
329+
[{ id: "core", selectors: ["src/value.ts:3-3"] }],
330+
)
331+
} finally {
332+
fs.rmSync(repo, { recursive: true, force: true })
333+
}
334+
})
294335
})
295336

296337
describe("mutation exclusions", () => {
@@ -446,6 +487,36 @@ describe("failure output", () => {
446487
)
447488
})
448489

490+
it("reports a Stryker preflight launch error when the binary is missing", () => {
491+
const repo = fs.mkdtempSync(path.join(os.tmpdir(), "stryker-launch-"))
492+
const reportRoot = path.join(repo, "reports")
493+
494+
try {
495+
fs.mkdirSync(path.join(repo, "packages/core"), { recursive: true })
496+
assert.throws(
497+
() =>
498+
runManifest(
499+
repo,
500+
{
501+
packages: [
502+
{
503+
id: "core",
504+
root: "packages/core",
505+
vitestConfig: "vitest.unit.config.ts",
506+
selectors: ["src/value.ts:1-1"],
507+
changedExecutableLines: 1,
508+
},
509+
],
510+
},
511+
reportRoot,
512+
),
513+
/core Stryker preflight could not start:.*ENOENT/,
514+
)
515+
} finally {
516+
fs.rmSync(repo, { recursive: true, force: true })
517+
}
518+
})
519+
449520
it("uses the actual tests recorded by Stryker", () => {
450521
assert.deepEqual(
451522
testsFromMutationReport({ testFiles: { "src/value.test.ts": {}, "src/other.spec.ts": {} } }, [

0 commit comments

Comments
 (0)