diff --git a/scripts/lib/whats-new.mjs b/scripts/lib/whats-new.mjs index c5eaabd9..81d01182 100644 --- a/scripts/lib/whats-new.mjs +++ b/scripts/lib/whats-new.mjs @@ -17,14 +17,21 @@ export function versionSection(changelog, version) { return lines.slice(start + 1, end).join('\n'); } +// Bold phrases the release notes use as group labels rather than as the headline of a change: +// "**Fixes.**" heads the list of fixes, "**Fixes applied while landing.**" the review fixes. +const SECTION_LABELS = + /^(?:thanks\b.*|fixes|fixes applied while landing|docs|docs and tests|new features|also in this release)$/i; + /** Bold lead-ins at the start of a paragraph or bullet, cleaned for display. */ export function extractHighlights(section) { const out = []; for (const line of section.split('\n')) { - const m = /^\s*(?:[-*]\s+)?\*\*([^*]{3,120})\*\*/.exec(line); + // `changeset version` prefixes the first line of a committed changeset with its commit + // ("- d18deed: **Lead.** text"), which is the shape every changesets-bot release has. + const m = /^\s*(?:[-*]\s+)?(?:[0-9a-f]{7,40}:\s+)?\*\*([^*]{3,120})\*\*/.exec(line); if (!m) continue; const text = m[1].replace(/[\s.:]+$/, '').trim(); - if (!text || /^thanks\b/i.test(text)) continue; + if (!text || SECTION_LABELS.test(text)) continue; if (!out.includes(text)) out.push(text); } return out.slice(0, MAX_HIGHLIGHTS); diff --git a/test/whats-new.test.ts b/test/whats-new.test.ts index 435de7cb..84264a5c 100644 --- a/test/whats-new.test.ts +++ b/test/whats-new.test.ts @@ -43,6 +43,27 @@ describe('whats-new extraction', () => { ]); }); + it('reads a lead-in behind the commit prefix changesets writes for a committed changeset', () => { + const section = '- d18deed: **Each release announces itself (#618).** Text.\n- 13e652e: A fix with no lead-in.'; + expect(extractHighlights(section)).toEqual(['Each release announces itself (#618)']); + }); + + it('skips group labels the release notes put in bold (Fixes, Fixes applied while landing)', () => { + const section = [ + ' **Tab layouts (#538).** Text.', + ' **Fixes.**', + ' - **Shells reload cleanly (#601).** Text.', + ' **Fixes applied while landing.** Remote tabs keep their scrollback.', + ].join('\n'); + expect(extractHighlights(section)).toEqual(['Tab layouts (#538)', 'Shells reload cleanly (#601)']); + }); + + it('yields no highlights for a release written without bold lead-ins', () => { + const changelog = + '## 1.32.1\n\n### Patch Changes\n\n- 13e652e: Terminal copy: no gutter on the clipboard (#469).\n'; + expect(buildWhatsNew(changelog, '1.32.1')).toEqual({ version: '1.32.1', highlights: [] }); + }); + it('caps the list', () => { const many = Array.from({ length: 20 }, (_, i) => `**Feature number ${i}.** text`).join('\n\n'); expect(extractHighlights(many)).toHaveLength(8);