Files
dohooo__helmor/scripts/extract-release-notes.mjs
Caspian Zhao 4745c10619 fix(release): extract-release-notes works when target section is last
The regex used `\Z` for end-of-string, which JavaScript does not support
(it is treated as the literal character `Z`). When the requested version
had no subsequent section in CHANGELOG.md — i.e., the newest release,
which is the common case — the lookahead could never match, the regex
returned null, and publish.yml fell back to
"See CHANGELOG.md for release details." instead of the real body.

Rewritten as two separate matches: find the heading line, then read to
the next `^## ` heading or EOF. Verified locally:
- `0.1.0` → "Hello Helmor." (was "See CHANGELOG.md for release details.")
- non-existent version → correct fallback
- multi-section CHANGELOG → extracts the requested section in isolation
2026-04-17 22:35:08 +08:00

42 lines
1.5 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
const requestedVersion = process.argv.slice(2).find((arg) => arg !== "--");
const packageJson = JSON.parse(
fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8"),
);
const version = requestedVersion ?? packageJson.version;
const changelogPath = path.join(process.cwd(), "CHANGELOG.md");
if (!fs.existsSync(changelogPath)) {
console.log("See CHANGELOG.md for release details.");
process.exit(0);
}
const changelog = fs.readFileSync(changelogPath, "utf8");
const escapedVersion = version.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// Find the heading line for this version. Done in two steps because
// JavaScript regex does not support `\Z` (end-of-string) — the previous
// single-regex approach silently fell through to the fallback whenever
// the section happened to be the last one in the file (which is the
// common case: the newest release is always on top).
const headingPattern = new RegExp(`^##\\s+${escapedVersion}\\b.*$`, "m");
const headingMatch = changelog.match(headingPattern);
if (!headingMatch || headingMatch.index === undefined) {
console.log("See CHANGELOG.md for release details.");
process.exit(0);
}
const afterHeading = changelog.slice(
headingMatch.index + headingMatch[0].length,
);
const nextHeadingMatch = afterHeading.match(/^##\s+/m);
const body = (
nextHeadingMatch && nextHeadingMatch.index !== undefined
? afterHeading.slice(0, nextHeadingMatch.index)
: afterHeading
).trim();
console.log(body || "See CHANGELOG.md for release details.");