test: terminate the ci.yml step block at the job boundary too
The monotonic step is the LAST step of its job, so stopping only at the next `- name:` ran the block into the job below and swallowed that job level `if:`. Unanchored `grep -q "if:"` then fired on it — the same bug the scoping was meant to fix, moved from "any step in the file" to "this step plus the head of the next job". Terminates on a new step OR a new job now, and the key is anchored so an `if:` inside a `run:` line is not mistaken for a step condition. Found by claude-bot-andresmgsl on heavy-duty/box#144; this port carried the identical awk. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
84c592e961
commit
7022894358
1 changed files with 16 additions and 3 deletions
|
|
@ -695,12 +695,25 @@ describe("changelog-monotonic.sh — release headings are append-only (#133)", (
|
||||||
// would fail citing #133 when one legitimately is — #133 constrains this
|
// would fail citing #133 when one legitimately is — #133 constrains this
|
||||||
// step, not the file. The companion assert below keeps the extractor from
|
// step, not the file. The companion assert below keeps the extractor from
|
||||||
// silently matching nothing and turning the negative into a tautology.
|
// silently matching nothing and turning the negative into a tautology.
|
||||||
const monoBlock = CI.split(/^ {6}- name: /m).find((b) =>
|
// Bounded by the next STEP *or* the next JOB. The job boundary is not
|
||||||
b.startsWith("no shipped changelog heading"),
|
// optional: the monotonic step is the LAST step of its job, so splitting on
|
||||||
|
// steps alone runs the block into the job below and swallows that job's
|
||||||
|
// level `if:` — reintroducing the bug this scoping fixed, moved from "any
|
||||||
|
// step in the file" to "this step plus the head of the next job".
|
||||||
|
const ciLines = CI.split("\n");
|
||||||
|
const monoStart = ciLines.findIndex((l) =>
|
||||||
|
/^ {6}- name: no shipped changelog heading/.test(l),
|
||||||
);
|
);
|
||||||
|
const after = ciLines.slice(monoStart + 1);
|
||||||
|
const monoEnd = after.findIndex((l) => /^ {6}- /.test(l) || /^ {2}\S/.test(l));
|
||||||
|
const monoBlock =
|
||||||
|
monoStart < 0
|
||||||
|
? undefined
|
||||||
|
: [ciLines[monoStart], ...after.slice(0, monoEnd < 0 ? after.length : monoEnd)].join("\n");
|
||||||
expect(monoBlock).toBeDefined();
|
expect(monoBlock).toBeDefined();
|
||||||
expect(monoBlock).toContain("changelog-monotonic.sh");
|
expect(monoBlock).toContain("changelog-monotonic.sh");
|
||||||
expect(monoBlock).not.toContain("if:");
|
// Anchored: an `if:` inside a `run:` line is not a step condition.
|
||||||
|
expect(monoBlock).not.toMatch(/^ {8}if:/m);
|
||||||
// ...and dropping that gate is only safe WITH the fallback: on a push
|
// ...and dropping that gate is only safe WITH the fallback: on a push
|
||||||
// `github.base_ref` is empty, a bare `origin/` does not resolve, and
|
// `github.base_ref` is empty, a bare `origin/` does not resolve, and
|
||||||
// STRICT promotes that to a hard failure on every push to main.
|
// STRICT promotes that to a hard failure on every push to main.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue