Files
Codeman/scripts/lib/whats-new.mjs
T
Codeman maintainer e9b2ecd552 ci(release): turn the GitHub release body into a readable page
changesets/action copies a CHANGELOG.md section into the release as it stands,
so a whole release rendered as one bullet behind its commit hash, with
`### Thanks` as literal text and "Minor Changes" as the only real heading.

The Release workflow now rebuilds the body from that section: Thanks first,
then What's new with a heading per change, Fixes, Also in this release and a
compare link, with "Behaviour change:" and "Breaking:" in bold. The release is
titled `Codeman <x.y.z>`; the tag stays `codeman@<x.y.z>`, which is what the
updater and the update toast read.

This cannot be written into CHANGELOG.md instead: `### <Type> Changes` is
hardcoded upstream, and a `## ` line would end the section for changesets/action
and versionSection(). So the changelog keeps its format and the toast is
unaffected. npm has already published when the step runs, so a formatter failure
leaves the changesets text with a warning and the retag still happens.

SECTION_LABELS is now shared with whats-new.mjs so the toast and the page agree
on what counts as a headline. docs/releasing.md records the changeset shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 13:11:22 +01:00

47 lines
2.1 KiB
JavaScript

/**
* Pulls the headline of each change out of one version's section of CHANGELOG.md.
*
* Release notes here lead each change with a bold phrase ("**Tab layouts (#538, optional).** ..."),
* so a highlight is that phrase. The Thanks block is credit, not a feature.
*/
const MAX_HIGHLIGHTS = 8;
/** The text between `## <version>` and the next `## ` heading, or '' when absent. */
export function versionSection(changelog, version) {
const lines = changelog.split(/\r?\n/);
const start = lines.findIndex((l) => l.trim() === `## ${version}`);
if (start === -1) return '';
let end = lines.findIndex((l, i) => i > start && /^## /.test(l));
if (end === -1) end = lines.length;
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.
// Shared with release-notes.mjs, so the toast and the release page agree on what is a headline.
export const SECTION_LABELS =
/^(?:thanks\b.*|fixes|fixes applied while landing|docs|docs and tests|new features|also in this release)$/i;
/** A bold lead-in without its closing punctuation. */
export const cleanLead = (text) => text.replace(/[\s.:]+$/, '').trim();
/** 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')) {
// `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 = cleanLead(m[1]);
if (!text || SECTION_LABELS.test(text)) continue;
if (!out.includes(text)) out.push(text);
}
return out.slice(0, MAX_HIGHLIGHTS);
}
export function buildWhatsNew(changelog, version) {
return { version, highlights: extractHighlights(versionSection(changelog, version)) };
}