Two docs tests located this delivery's CHANGELOG section by the literal heading `## Unreleased` (one also required it to be the first section). The release commit renames it to `## v6.4.0 — <date> — <title>` (docs/release-runbook.md § 1.4), so all 16 content pins failed on the release commit while the content was the same. One shared helper, tests/helpers/changelog-section.mjs, now finds the section by its title under either heading, wherever it stands (a later delivery's section above it does not move the pins), with a trailing \r or spaces tolerated, and only when it stands exactly once. Every content assertion is unchanged; their messages no longer say "Unreleased". New tests pin the accepted headings and seven near misses (version, date, title, the literal dot in 1.9), and the helper on a later section, a \r, a duplicate and a missing section. Measured: 46/46 pass against main's CHANGELOG and against the release commit's CHANGELOG; before the change, 16 failed on the release commit. Three mutants of the helper (a looser date, no escaping, no trim) are each failed by one test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 lines
1.5 KiB
JavaScript
30 lines
1.5 KiB
JavaScript
// The CHANGELOG section of the plan_version 1.9 / converging critic loop
|
|
// delivery, found by its title. Before the release its heading is
|
|
// `## Unreleased — <title>`; the release commit makes it
|
|
// `## vX.Y.Z — <date> — <title>` (docs/release-runbook.md § 1.4). The section
|
|
// is found wherever it stands, so a later delivery's section above it does not
|
|
// move the pins, and it must stand exactly once.
|
|
import assert from 'node:assert/strict';
|
|
|
|
export const SECTION_TITLE = 'plan_version 1.9, the trial-4 findings, session-clean tests, the converging critic loop';
|
|
|
|
const escaped = SECTION_TITLE.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
export const SECTION_HEADING = new RegExp(`^## (?:Unreleased|v\\d+\\.\\d+\\.\\d+ — \\d{4}-\\d{2}-\\d{2}) — ${escaped}$`);
|
|
|
|
// A heading line as written, without a trailing `\r` or trailing spaces.
|
|
const bare = line => line.replace(/\s+$/, '');
|
|
|
|
// { heading, body } of the delivery's section in CHANGELOG text, up to the
|
|
// next `## ` heading. Fails unless exactly one heading matches.
|
|
export function deliverySection(text) {
|
|
const lines = text.split('\n');
|
|
const at = [];
|
|
lines.forEach((l, i) => { if (SECTION_HEADING.test(bare(l))) at.push(i); });
|
|
assert.equal(at.length, 1, `CHANGELOG.md has the "${SECTION_TITLE}" section exactly once (found ${at.length})`);
|
|
const start = at[0];
|
|
let end = lines.length;
|
|
for (let i = start + 1; i < lines.length; i++) {
|
|
if (/^## /.test(lines[i])) { end = i; break; }
|
|
}
|
|
return { heading: bare(lines[start]), body: lines.slice(start + 1, end).join('\n') };
|
|
}
|