* fix(#4106): drop the orphaned test:mutation:since script `"test:mutation:since": "stryker run --incremental --since origin/next"` could not run. Stryker has no `--since` flag — verified against the pinned `@stryker-mutator/core` 9.6.1, whose options schema has no `since` property and whose CLI exits `error: unknown option '--since'`. It went unnoticed because nothing invokes it. `.github/workflows/mutation.yml` uses the per-module matrix instead: `scripts/mutation-matrix.cjs` computes the changed covered modules and each shard runs its own `npx stryker run --incremental --mutate "${MUTATE_GLOB}"`. That path works, so no gate ever exercised the script. It is still worth removing rather than leaving: its name makes it the obvious thing to reach for when a reviewer asks for a mutation score on changed scope, and the Commander parse error it produces says nothing about the matrix being the real entry point — the next person has to reverse-engineer mutation.yml to find that out. Delete rather than repoint. The issue offered both, and the maintainer had not picked; delete is the option that stays scoped to the reported bug. The suggested replacement (`node scripts/mutation-matrix.cjs --base origin/next`) emits a CI matrix rather than running mutants, so shipping it under a `test:mutation:*` name would be a second, differently-shaped claim, and documenting the per-module invocation in CONTRIBUTING.md is enhancement-shaped work that belongs in its own issue. The discovery command is named in the changeset instead. Flipping this PR to the pointer script is a one-line change if that is preferred. The regression test asserts that every `stryker` script in package.json passes only flags Stryker's own options schema defines. It carries its own control — the historical `--incremental --since origin/next` string is checked to still be rejected by the same predicate — so the sweep cannot go quietly vacuous if the remaining invocations lose their flags. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017zgWzB96uz3LVKdJePYTLR * chore(#4106): backfill the changeset PR number Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017zgWzB96uz3LVKdJePYTLR * docs(#4106): mark the changeset docs-exempt `type: Removed` makes docs-lint require a `docs/` change. Nothing under `docs/` or in CONTRIBUTING.md ever referenced `test:mutation:since` — the script was orphaned and could not run — so there is no documented behaviour to update. Using the gate's own per-fragment escape hatch rather than weakening the changeset type to dodge the requirement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017zgWzB96uz3LVKdJePYTLR --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
This commit is contained in:
7
.changeset/curious-foxes-fly.md
Normal file
7
.changeset/curious-foxes-fly.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
type: Removed
|
||||
pr: 4179
|
||||
---
|
||||
**Dropped the `test:mutation:since` npm script** — it passed `--since`, which Stryker 9.x does not accept (`error: unknown option '--since'`), so it could not run at all. Nothing invoked it: the mutation gate runs the per-module matrix from `scripts/mutation-matrix.cjs` instead, so no workflow regresses. To see which modules a change puts in scope, run `node scripts/mutation-matrix.cjs --base origin/next --print`. (#4106)
|
||||
|
||||
<!-- docs-exempt: contributor tooling only — no docs/ page or CONTRIBUTING.md section referenced this script (grep for `test:mutation` across docs/ and CONTRIBUTING.md returns nothing), and it could never run, so there is no documented behaviour to update. -->
|
||||
@@ -155,7 +155,6 @@
|
||||
"test:coverage:report": "c8 report --reporter text --reporter json-summary --merge-async --include 'gsd-core/bin/lib/**/*.cjs' --exclude 'tests/**' --all && node scripts/check-coverage-gate.cjs",
|
||||
"test:coverage:all": "npm run test:coverage",
|
||||
"test:mutation": "stryker run",
|
||||
"test:mutation:since": "stryker run --incremental --since origin/next",
|
||||
"gen:features": "node scripts/gen-features.cjs",
|
||||
"gen:state-md-docs": "node scripts/gen-state-md-docs.cjs"
|
||||
},
|
||||
|
||||
@@ -431,3 +431,76 @@ test('--cwd pointing at a non-existent path fails uniformly across families', ()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
// #4106 — every Stryker flag in package.json is one Stryker actually accepts
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
{
|
||||
const { describe: __d, test: __t } = require('node:test');
|
||||
const __assert = require('node:assert/strict');
|
||||
const __fs = require('node:fs');
|
||||
const __path = require('node:path');
|
||||
|
||||
const __ROOT = __path.resolve(__dirname, '..');
|
||||
const __PKG = require(__path.join(__ROOT, 'package.json'));
|
||||
const __SCHEMA = __path.join(
|
||||
__ROOT, 'node_modules', '@stryker-mutator', 'core', 'schema', 'stryker-schema.json',
|
||||
);
|
||||
|
||||
// Stryker's CLI options are generated from its own options schema, so the schema's
|
||||
// property names ARE the accepted long flags. Three commander-level flags have no
|
||||
// schema entry because they are not run options.
|
||||
const __CLI_ONLY = new Set(['files', 'help', 'version']);
|
||||
|
||||
/** Long flags a `stryker …` npm script passes, normalised (`--mutate=x` → `mutate`). */
|
||||
function __strykerFlags(script) {
|
||||
if (!/(^|\s)(npx\s+)?stryker(\s|$)/.test(script)) return null;
|
||||
return script
|
||||
.split(/\s+/)
|
||||
.filter((tok) => tok.startsWith('--'))
|
||||
.map((tok) => tok.slice(2).split('=')[0]);
|
||||
}
|
||||
|
||||
__d('package.json Stryker scripts pass only flags Stryker accepts (#4106)', () => {
|
||||
const accepted = new Set([
|
||||
...Object.keys(JSON.parse(__fs.readFileSync(__SCHEMA, 'utf-8')).properties || {}),
|
||||
...__CLI_ONLY,
|
||||
]);
|
||||
|
||||
// Guard: a moved/renamed schema would otherwise reject every flag for the wrong reason.
|
||||
__assert.ok(
|
||||
accepted.size > 20,
|
||||
`no options schema at ${__SCHEMA} — @stryker-mutator/core may have moved it`,
|
||||
);
|
||||
|
||||
__t('the checker rejects the flag this bug shipped', () => {
|
||||
// `--since` is what `test:mutation:since` carried; Stryker 9.x exits with
|
||||
// "error: unknown option '--since'". Pinning it here keeps this suite honest
|
||||
// if every real invocation later drops its flags.
|
||||
const flags = __strykerFlags('stryker run --incremental --since origin/next');
|
||||
__assert.deepEqual(flags, ['incremental', 'since']);
|
||||
__assert.equal(accepted.has('incremental'), true);
|
||||
__assert.equal(accepted.has('since'), false, '--since is not a Stryker option');
|
||||
});
|
||||
|
||||
__t('every stryker script in package.json is runnable', () => {
|
||||
const offenders = [];
|
||||
let scanned = 0;
|
||||
for (const [name, script] of Object.entries(__PKG.scripts || {})) {
|
||||
const flags = __strykerFlags(script);
|
||||
if (flags === null) continue;
|
||||
scanned += 1;
|
||||
for (const flag of flags) {
|
||||
if (!accepted.has(flag)) offenders.push(`${name}: --${flag}`);
|
||||
}
|
||||
}
|
||||
__assert.ok(scanned > 0, 'no stryker script found — the sweep matched nothing');
|
||||
__assert.deepEqual(
|
||||
offenders,
|
||||
[],
|
||||
`package.json scripts pass flags Stryker does not accept: ${offenders.join(', ')}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user