Merge pull request #703 from Luca-Timo/ci/whatsnew-highlights-workflow

ci(whatsnew): generate release highlights via GitHub Models
This commit is contained in:
Paul Nothaft
2026-06-30 22:33:00 +02:00
committed by GitHub
5 changed files with 96 additions and 25 deletions
+15
View File
@@ -33,6 +33,21 @@ describe('parseWhatsNew', () => {
]);
});
it('decodes HTML entities release-please escapes into changelog text', () => {
const body = '### Features\n* **gallery:** supports A & B <tags> "quoted" ([#1](http://x))';
expect(parseWhatsNew(body)).toEqual(['supports A & B <tags> "quoted"']);
});
it('trims a trailing "— implementation detail" clause to the headline', () => {
const body = '### Features\n* **gallery:** branded URL shortener — /s/&lt;slug&gt; with OG injection ([#699](http://x))';
expect(parseWhatsNew(body)).toEqual(['branded URL shortener']);
});
it('leaves hyphenated words and dash-free bullets intact', () => {
const body = '### Features\n* **invoices:** mark-paid now supports bank transfer ([#2](http://x))';
expect(parseWhatsNew(body)).toEqual(['mark-paid now supports bank transfer']);
});
it('excludes Bug Fixes from the fallback', () => {
const body = '### Features\n* **a:** feature one\n### Bug Fixes\n* **b:** fix one';
expect(parseWhatsNew(body)).toEqual(['feature one']);
+23 -2
View File
@@ -14,14 +14,35 @@
const MAX_BULLETS = 8;
/**
* Decode the handful of HTML entities release-please escapes into changelog
* text (a raw "/s/<slug>" in a commit subject lands as "/s/&lt;slug&gt;").
* Without this the banner shows the literal entity, since React renders text
* nodes verbatim. `&amp;` is decoded last so "&amp;lt;" stays "&lt;".
*/
function decodeEntities(s) {
return s
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace(/&#0*39;|&#x0*27;|&apos;/gi, "'")
.replace(/&amp;/g, '&');
}
/** Strip list markers, conventional-commit scope, and trailing PR/sha links. */
function cleanBullet(line) {
return line
return decodeEntities(line
.replace(/^\s*[-*]\s+/, '') // "- " / "* " marker
.replace(/^\*\*([^:*]+):\*\*\s*/, '') // "**scope:** " prefix
.replace(/\s*\(\[[^\]]*\]\([^)]*\)\)/g, '') // " ([#41](url))" / " ([sha](url))"
.replace(/\s*\(#\d+\)/g, '') // bare " (#41)"
.replace(/`/g, '')
.replace(/`/g, ''))
// Drop a trailing "— implementation detail" clause so a release highlight
// reads as the headline ("branded URL shortener"), not the commit subject
// ("branded URL shortener — /s/<slug> with OG injection"). Em dash only, so
// hyphenated words ("mark-paid") are untouched. Skipped if it would empty
// the bullet (i.e. nothing before the dash).
.replace(/^(.+?\S)\s+—\s+.*$/, '$1')
.replace(/\s+/g, ' ')
.trim();
}