chore: address Copilot review round 17
- ciRunsUnconditionally never looked at the workflow-level `on:` trigger, so a
workflow switched to `on: release` still contained the step and reported as
wired while no PR ever ran the validator. It now requires `push` or
`pull_request`, handling all three shapes `on:` takes. The positive fixtures
had no trigger at all, so they could not assert the "on every push" half of
the contract; they carry one now, alongside a release-only negative. Verified
by mutation.
- Stale JSDoc from the round-16 version change: `probeClaudeVersion` is now
generic in its parser's result rather than hard-coding `number[]`,
`validatorCommand` documents `{ parts, prerelease }`, and `runValidator`
documents the `platform` option it already accepted. Annotations that lie make
valid call sites look type-invalid.
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
c26995bf82
commit
1203246537
1 changed files with 82 additions and 22 deletions
|
|
@ -209,7 +209,7 @@ const WIRED_SCRIPTS = {
|
|||
"verify:skills:cli": "node scripts/verify-skills-cli.mjs",
|
||||
};
|
||||
const WIRED_WORKFLOW =
|
||||
"jobs:\n build:\n steps:\n - run: npm run verify:skills:cli\n";
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - run: npm run verify:skills:cli\n";
|
||||
|
||||
test("checkWiring is silent when both gates are wired", () => {
|
||||
assert.deepEqual(checkWiring(WIRED_SCRIPTS, WIRED_WORKFLOW), []);
|
||||
|
|
@ -238,7 +238,7 @@ test("checkWiring catches the authoritative validator dropped from CI", () => {
|
|||
assert.match(
|
||||
checkWiring(
|
||||
WIRED_SCRIPTS,
|
||||
"jobs:\n build:\n steps:\n - run: npm run validate\n",
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - run: npm run validate\n",
|
||||
).join(),
|
||||
/has no unconditional step that runs/,
|
||||
);
|
||||
|
|
@ -272,9 +272,9 @@ test("checkWiring is not satisfied by a mention outside an executable step", ()
|
|||
// including on a step whose NAME describes the check it no longer performs,
|
||||
// which is exactly how a wiring guard goes quietly vacuous.
|
||||
const mentions = [
|
||||
"# npm run verify:skills:cli\njobs:\n build:\n steps:\n - run: npm run validate\n",
|
||||
"jobs:\n build:\n steps:\n - name: npm run verify:skills:cli\n run: npm run validate\n",
|
||||
"on:\n workflow_dispatch:\n inputs:\n cmd:\n default: npm run verify:skills:cli\njobs:\n build:\n steps:\n - run: npm run validate\n",
|
||||
"# npm run verify:skills:cli\non:\n push:\njobs:\n build:\n steps:\n - run: npm run validate\n",
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - name: npm run verify:skills:cli\n run: npm run validate\n",
|
||||
"on:\n push:\n workflow_dispatch:\n inputs:\n cmd:\n default: npm run verify:skills:cli\njobs:\n build:\n steps:\n - run: npm run validate\n",
|
||||
];
|
||||
for (const workflow of mentions) {
|
||||
assert.match(
|
||||
|
|
@ -287,20 +287,20 @@ test("checkWiring is not satisfied by a mention outside an executable step", ()
|
|||
|
||||
test("checkWiring accepts the command inside a multi-line run step", () => {
|
||||
const workflow =
|
||||
"jobs:\n build:\n steps:\n - run: |\n npm run validate\n npm run verify:skills:cli\n";
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - run: |\n npm run validate\n npm run verify:skills:cli\n";
|
||||
assert.deepEqual(checkWiring(WIRED_SCRIPTS, workflow), []);
|
||||
});
|
||||
|
||||
test("ciRunsUnconditionally requires a step that runs on every push", () => {
|
||||
const C = "npm run verify:skills:cli";
|
||||
const wired =
|
||||
"jobs:\n build:\n steps:\n - run: npm run verify:skills:cli\n";
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - run: npm run verify:skills:cli\n";
|
||||
assert.equal(ciRunsUnconditionally(wired, C), true);
|
||||
|
||||
// A multi-line `run:` block is the obvious way to over-correct; it counts.
|
||||
assert.equal(
|
||||
ciRunsUnconditionally(
|
||||
"jobs:\n build:\n steps:\n - run: |\n npm run validate\n npm run verify:skills:cli\n",
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - run: |\n npm run validate\n npm run verify:skills:cli\n",
|
||||
C,
|
||||
),
|
||||
true,
|
||||
|
|
@ -312,9 +312,9 @@ test("ciRunsUnconditionally rejects a step that only runs sometimes", () => {
|
|||
// Both are syntactically `run:` steps, so an executable-position check alone
|
||||
// reports them as wired while PR CI validates nothing.
|
||||
const releaseOnly =
|
||||
"jobs:\n publish:\n if: github.event_name == 'release'\n steps:\n - run: npm run verify:skills:cli\n";
|
||||
"on:\n push:\njobs:\n publish:\n if: github.event_name == 'release'\n steps:\n - run: npm run verify:skills:cli\n";
|
||||
const stepGated =
|
||||
"jobs:\n build:\n steps:\n - if: false\n run: npm run verify:skills:cli\n";
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - if: false\n run: npm run verify:skills:cli\n";
|
||||
assert.equal(ciRunsUnconditionally(releaseOnly, C), false);
|
||||
assert.equal(ciRunsUnconditionally(stepGated, C), false);
|
||||
});
|
||||
|
|
@ -324,7 +324,7 @@ test("ciRunsUnconditionally is not satisfied by an unrelated or absent command",
|
|||
// `verify:skills` must not satisfy a search for `verify:skills:cli`.
|
||||
assert.equal(
|
||||
ciRunsUnconditionally(
|
||||
"jobs:\n build:\n steps:\n - run: npm run verify:skills\n",
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - run: npm run verify:skills\n",
|
||||
C,
|
||||
),
|
||||
false,
|
||||
|
|
@ -378,9 +378,33 @@ test("ciRunsUnconditionally inherits the exact-invocation rule", () => {
|
|||
const C = "npm run verify:skills:cli";
|
||||
assert.equal(
|
||||
ciRunsUnconditionally(
|
||||
"jobs:\n build:\n steps:\n - run: npm run verify:skills:cli:disabled\n",
|
||||
"on:\n push:\njobs:\n build:\n steps:\n - run: npm run verify:skills:cli:disabled\n",
|
||||
C,
|
||||
),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("ciRunsUnconditionally requires the workflow to fire on ordinary changes", () => {
|
||||
const C = "npm run verify:skills:cli";
|
||||
const step =
|
||||
"jobs:\n build:\n steps:\n - run: npm run verify:skills:cli\n";
|
||||
|
||||
// `on:` takes three shapes, and any of them may name the event.
|
||||
assert.equal(ciRunsUnconditionally(`on:\n push:\n${step}`, C), true);
|
||||
assert.equal(ciRunsUnconditionally(`on: push\n${step}`, C), true);
|
||||
assert.equal(ciRunsUnconditionally(`on: [push, release]\n${step}`, C), true);
|
||||
assert.equal(ciRunsUnconditionally(`on:\n pull_request:\n${step}`, C), true);
|
||||
|
||||
// A workflow switched to release-only still CONTAINS the step, and an
|
||||
// unconditional-step check alone reports it as wired — while no PR ever runs
|
||||
// the validator (Copilot).
|
||||
assert.equal(
|
||||
ciRunsUnconditionally(
|
||||
`on:\n release:\n types: [published]\n${step}`,
|
||||
C,
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(ciRunsUnconditionally(step, C), false);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue