Skip to content

Commit 7094771

Browse files
authored
fix(release-pr): stop dropping changeset entries and stripping code blocks (#3954)
## Summary The script that generates the changeset release PR description was silently dropping some changelog entries and stripping code examples. In [#3932](#3932), entry [#3937](#3937) was missing entirely from the Improvements list and [#3952](#3952 code block was gone, even though both were present in the raw changeset output. ## Root cause `parsePrBody` parsed the raw changeset body line by line: - The dependency-bump filter matched any entry whose text *began* with a backticked package name, so a real changelog entry like `` `@trigger.dev/sdk` now bundles... `` got thrown out along with the genuine version-bump lines. - Only the first line of each bullet was kept, so fenced code blocks, sub-bullets, and continuation paragraphs were discarded. ## Fix Group each top-level bullet with its indented continuation (code blocks, sub-bullets, paragraphs), dedent it, and re-emit it intact. The dependency filter is now anchored so it only matches lines that are *entirely* a package bump, leaving real entries that merely start with a package name. Verified by replaying #3932's raw body through the script: #3937 returns to the list, #3952's code block is preserved, and #3936's sub-bullets nest correctly under their parent.
1 parent 545ecf7 commit 7094771

1 file changed

Lines changed: 65 additions & 20 deletions

File tree

scripts/enhance-release-pr.mjs

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,70 @@ function parsePrBody(body) {
3939
const seen = new Set();
4040
const prPattern = /\[#(\d+)\]\(([^)]+)\)/;
4141

42+
// A standalone dependency-bump list item, e.g. "`@trigger.dev/core@4.5.0-rc.7`"
43+
// or "trigger.dev@4.5.0-rc.7". These normally appear nested under
44+
// "Updated dependencies:" (and so get swallowed into that item below), but we
45+
// guard against them showing up on their own too. Crucially this only matches
46+
// a line that is *entirely* a package bump, so a real changeset that merely
47+
// begins with a package name (e.g. "`@trigger.dev/sdk` now bundles ...") is
48+
// kept.
49+
const depBumpPattern = /^`?(?:@trigger\.dev\/[\w-]+|trigger\.dev)@[\w.+-]+`?$/;
50+
51+
// Group lines into top-level list items. A top-level item starts with a bullet
52+
// at column 0 ("- " / "* "); every indented or blank line below it (sub-bullets,
53+
// fenced code blocks, continuation paragraphs) belongs to that same item.
54+
const items = [];
55+
let current = null;
56+
57+
const flush = () => {
58+
if (!current) return;
59+
while (current.length > 1 && current[current.length - 1].trim() === "") {
60+
current.pop();
61+
}
62+
items.push(current);
63+
current = null;
64+
};
65+
4266
for (const line of body.split("\n")) {
43-
const trimmed = line.trim();
44-
if (!trimmed.startsWith("- ") && !trimmed.startsWith("* ")) continue;
67+
const isTopLevelBullet = /^[-*]\s+/.test(line);
68+
if (isTopLevelBullet) {
69+
flush();
70+
current = [line];
71+
} else if (current) {
72+
if (line.trim() === "" || /^\s/.test(line)) {
73+
current.push(line);
74+
} else {
75+
// A non-indented, non-blank, non-bullet line (heading or prose) ends the item
76+
flush();
77+
}
78+
}
79+
}
80+
flush();
4581

46-
let text = trimmed.replace(/^[-*]\s+/, "").trim();
47-
if (!text) continue;
82+
for (const itemLines of items) {
83+
const headLine = itemLines[0].replace(/^[-*]\s+/, "").trim();
84+
if (!headLine) continue;
4885

49-
// Skip dependency-only updates (e.g. "Updated dependencies:" or "@trigger.dev/core@4.4.2")
50-
if (text.startsWith("Updated dependencies")) continue;
51-
if (text.startsWith("`@trigger.dev/")) continue;
52-
if (text.startsWith("@trigger.dev/")) continue;
53-
if (text.startsWith("`trigger.dev@")) continue;
54-
if (text.startsWith("trigger.dev@")) continue;
86+
// Skip dependency-only updates
87+
if (headLine.startsWith("Updated dependencies")) continue;
88+
if (depBumpPattern.test(headLine)) continue;
5589

56-
const prMatch = trimmed.match(prPattern);
90+
// Deduplicate by PR number (the changeset link lives on the head line)
91+
const prMatch = itemLines[0].match(prPattern);
5792
if (prMatch) {
5893
const prNumber = prMatch[1];
5994
if (seen.has(prNumber)) continue;
6095
seen.add(prNumber);
6196
}
6297

63-
// Categorize
64-
const lower = text.toLowerCase();
98+
// Reconstruct the full item: head line + dedented continuation lines, so
99+
// code blocks and sub-bullets survive. Continuation under a "- " item is
100+
// indented 4 spaces; strip up to 4 to bring it back to the base level.
101+
const continuation = itemLines.slice(1).map((l) => l.replace(/^ {1,4}/, ""));
102+
const text = [headLine, ...continuation].join("\n").replace(/\s+$/, "");
103+
104+
// Categorize off the head line
105+
const lower = headLine.toLowerCase();
65106
let type = "improvement";
66107
if (lower.startsWith("fix") || lower.includes("bug fix")) {
67108
type = "fix";
@@ -206,6 +247,12 @@ function parseFrontmatter(content) {
206247

207248
// --- Format the enhanced PR body ---
208249

250+
// Render an entry as a list item, re-indenting continuation lines (code blocks,
251+
// sub-bullets, paragraphs) by 2 spaces so they stay inside the "- " bullet.
252+
function renderEntry(text) {
253+
return `- ${text.replace(/\n/g, "\n ")}`;
254+
}
255+
209256
function formatPrBody({ version, packageEntries, serverEntries, rawBody }) {
210257
const lines = [];
211258

@@ -238,7 +285,7 @@ function formatPrBody({ version, packageEntries, serverEntries, rawBody }) {
238285
// Breaking changes
239286
if (breaking.length > 0 || serverBreaking.length > 0) {
240287
lines.push("## Breaking changes");
241-
for (const entry of [...breaking, ...serverBreaking]) lines.push(`- ${entry.text}`);
288+
for (const entry of [...breaking, ...serverBreaking]) lines.push(renderEntry(entry.text));
242289
lines.push("");
243290
}
244291

@@ -247,22 +294,22 @@ function formatPrBody({ version, packageEntries, serverEntries, rawBody }) {
247294
lines.push("## Highlights");
248295
lines.push("");
249296
for (const entry of features) {
250-
lines.push(`- ${entry.text}`);
297+
lines.push(renderEntry(entry.text));
251298
}
252299
lines.push("");
253300
}
254301

255302
// Improvements
256303
if (improvements.length > 0) {
257304
lines.push("## Improvements");
258-
for (const entry of improvements) lines.push(`- ${entry.text}`);
305+
for (const entry of improvements) lines.push(renderEntry(entry.text));
259306
lines.push("");
260307
}
261308

262309
// Bug fixes
263310
if (fixes.length > 0) {
264311
lines.push("## Bug fixes");
265-
for (const entry of fixes) lines.push(`- ${entry.text}`);
312+
for (const entry of fixes) lines.push(renderEntry(entry.text));
266313
lines.push("");
267314
}
268315

@@ -274,9 +321,7 @@ function formatPrBody({ version, packageEntries, serverEntries, rawBody }) {
274321
lines.push("These changes affect the self-hosted Docker image and Trigger.dev Cloud:");
275322
lines.push("");
276323
for (const entry of allServer) {
277-
// Indent continuation lines so multi-line entries stay inside the list item
278-
const indented = entry.text.replace(/\n/g, "\n ");
279-
lines.push(`- ${indented}`);
324+
lines.push(renderEntry(entry.text));
280325
}
281326
lines.push("");
282327
}

0 commit comments

Comments
 (0)