From 9ea9abf0a1a848667baba4ccc6cbaa332752eecb Mon Sep 17 00:00:00 2001 From: Andrew Mikofalvy <5668128+amikofalvy@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:14:37 -0700 Subject: [PATCH] fix(release): keep de-indented code-span lines in beta release notes (#2712) parseSection in compute-next-beta.mjs ended the current changelog entry on any column-0 line while an entry was open, silently dropping that line and everything after it. When a changeset wraps an inline code span across a hard line break, prettier (run by changeset version over CHANGELOG.md) de-indents the span's second physical line to column 0, so the entry was truncated at that point. This shipped as the truncated v0.34.0 stable release note (cut off at "ok diagnose"). Treat any line that is not a group heading or a new top-level bullet as a continuation of the open entry, keeping column-0 lines verbatim. Add regression tests covering the de-indented continuation directly and end to end through renderNotes. GitOrigin-RevId: 7c9142dd380e081cdfda64d6c48b04c74062188b --- scripts/compute-next-beta.mjs | 21 +++++++++--- scripts/compute-next-beta.test.mjs | 55 ++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/scripts/compute-next-beta.mjs b/scripts/compute-next-beta.mjs index 3a07adf52..59e2f10e3 100644 --- a/scripts/compute-next-beta.mjs +++ b/scripts/compute-next-beta.mjs @@ -200,9 +200,11 @@ export function extractDeltaSection(content) { export function parseSection(section) { // Parse a CHANGELOG-section body into { 'Patch Changes': [{hash, body}, ...], ... }. - // Entries are bullets opened by `- ` at column 0; continuation lines start - // with two spaces of indentation. The Changesets renderer prefixes each - // direct entry with the short commit hash (`- 67028e1: foo...`). + // Entries are bullets opened by `- ` at column 0; continuation lines are + // 2-space-indented (or blank). The Changesets renderer prefixes each direct + // entry with the short commit hash (`- 67028e1: foo...`). Inside an open + // entry, only a `### ` group heading or a new top-level `- ` bullet ends it — + // every other line is continuation, even at column 0 (see below). const groups = {}; let currentGroup = null; let currentEntry = null; @@ -223,9 +225,18 @@ export function parseSection(section) { const m = /^- (?:([a-f0-9]{6,}): )?([\s\S]*)$/.exec(line); currentEntry = { hash: m?.[1] ?? null, body: m?.[2] ?? line.slice(2) }; groups[currentGroup].push(currentEntry); - } else if (currentEntry && (line.startsWith(' ') || line === '')) { - currentEntry.body += `\n${line.startsWith(' ') ? line.slice(2) : ''}`; + } else if (currentEntry) { + // Continuation of the open entry. Strip one list-indent level from the + // canonical 2-space form so renderNotes can re-apply it uniformly; keep a + // column-0 line verbatim. A column-0 non-blank line reaches here only + // when prettier — which `changeset version` runs over CHANGELOG.md — + // de-indented the second physical line of an inline code span that a + // changeset wrapped across a hard line break. Folding it into the entry + // instead of terminating on it keeps that line, and everything after it, + // from being dropped from the release notes. + currentEntry.body += `\n${line.startsWith(' ') ? line.slice(2) : line}`; } else { + // A stray line before any bullet is opened: nothing to attach it to. commit(); } } diff --git a/scripts/compute-next-beta.test.mjs b/scripts/compute-next-beta.test.mjs index 8bf57674d..dee451e34 100644 --- a/scripts/compute-next-beta.test.mjs +++ b/scripts/compute-next-beta.test.mjs @@ -114,6 +114,22 @@ describe('parseSection', () => { expect(groups['Patch Changes'][0].hash).toBeNull(); expect(groups['Patch Changes'][0].body.startsWith('Updated dependencies')).toBe(true); }); + + test('keeps a de-indented continuation line without truncating the entry', () => { + // When a changeset wraps an inline code span across a hard line break, + // prettier (run by `changeset version` over CHANGELOG.md) de-indents the + // second physical line to column 0. It is still part of the bullet, not a + // new entry — dropping it silently truncated a shipped release note. + const section = `### Patch Changes + +- abc1234: intro sentence with a wrapped span \`ok diagnose +--redact\` and a tail sentence that must survive. +`; + const groups = parseSection(section); + expect(groups['Patch Changes']).toHaveLength(1); + const body = groups['Patch Changes'][0].body; + expect(body).toContain('--redact` and a tail sentence that must survive.'); + }); }); describe('renderNotes', () => { @@ -315,6 +331,45 @@ describe('round-trip: extractDeltaSection → parseSection → renderNotes', () // Marker at end. expect(notes).toMatch(/$/); }); + + test('does not truncate an entry whose body has a prettier-de-indented code-span wrap', () => { + // Reproduces the shape that truncated the v0.34.0 release note: a changeset + // wrapped an inline code span across a hard line break, and prettier — which + // `changeset version` runs over CHANGELOG.md — emitted the span's second + // line flush-left (column 0) while the surrounding lines stayed 2-space + // indented. The whole tail of the entry (and anything after it) was dropped. + const cliChangelog = `# @inkeep/open-knowledge + +## 0.34.0 + +### Patch Changes + +- abc1234: Migrate the toolchain from Bun to pnpm 10 and Vitest 4. + + Two small behavioral deltas ride along with the swap: \`ok diagnose +--redact\` bundles now derive doc-name tokens with sha256 instead of BLAKE2b-256; + and the file-copy API now returns HTTP 409 (previously an unhandled 500). + +## 0.33.0 + +### Patch Changes + +- old: prior beta entry +`; + const notes = renderNotes({ + packageDeltas: { cli: extractDeltaSection(cliChangelog) }, + newConsumedSet: ['remove-bun-toolchain-migration'], + prevBetaTag: 'v0.33.0-beta.12', + newCount: 1, + }); + // Everything after the wrapped span must survive to the release notes. + expect(notes).toContain('`ok diagnose'); + expect(notes).toContain('--redact` bundles now derive'); + expect(notes).toContain('HTTP 409'); + expect(notes).toContain('unhandled 500'); + // Prior-version content across the second ## heading must NOT leak in. + expect(notes).not.toContain('prior beta entry'); + }); }); describe('bumpSemver', () => {