ci(release): share changelog release notes

This commit is contained in:
Vincent Koc 2026-04-27 21:34:13 -07:00
parent ae08c3cc10
commit f8073df320
No known key found for this signature in database
5 changed files with 112 additions and 13 deletions

View File

@ -76,19 +76,7 @@ jobs:
run: |
set -euo pipefail
NOTES_FILE="$(mktemp)"
RELEASE_VERSION="${RELEASE_VERSION}" node <<'NODE' > "${NOTES_FILE}"
const fs = require("fs");
const version = process.env.RELEASE_VERSION;
const lines = fs.readFileSync("CHANGELOG.md", "utf8").split(/\r?\n/);
const start = lines.findIndex((line) => line.startsWith(`## ${version} - `));
if (start === -1) {
console.error(`CHANGELOG.md is missing a ${version} release section`);
process.exit(1);
}
const end = lines.findIndex((line, index) => index > start && line.startsWith("## "));
const body = lines.slice(start + 1, end === -1 ? lines.length : end).join("\n").trim();
process.stdout.write(`## plugin-inspector v${version}\n\n${body}\n`);
NODE
node scripts/release-notes.mjs "${RELEASE_VERSION}" > "${NOTES_FILE}"
release_flags=(--title "plugin-inspector ${RELEASE_TAG}" --notes-file "${NOTES_FILE}" --verify-tag)
if [[ "${RELEASE_TAG}" =~ (alpha|beta|rc) ]]; then

View File

@ -73,6 +73,12 @@ versioned section like `## 0.3.1 - 2026-04-28`, update `package.json` to the
same version, and update Crabpot's `pluginInspectorRef` to the exact release
commit.
Draft release notes from the current `Unreleased` section with:
```bash
npm run release:notes
```
## Crabpot follow-through
Before tagging a release, update Crabpot's `pluginInspectorRef` to the

View File

@ -52,6 +52,7 @@
"release:crabpot": "node scripts/check-crabpot-followthrough.mjs",
"release:readiness": "npm run release:local && npm run release:crabpot",
"release:local": "npm run check",
"release:notes": "node scripts/release-notes.mjs --unreleased",
"test": "node --test test/*.test.js"
},
"keywords": [

66
scripts/release-notes.mjs Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env node
import { readFileSync } from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
const options = parseArgs(process.argv.slice(2));
const changelogText = readFileSync(options.changelogPath, "utf8");
process.stdout.write(extractReleaseNotes({ changelogText, version: options.version }));
}
export function extractReleaseNotes({ changelogText, version }) {
const lines = changelogText.split(/\r?\n/);
const start = findReleaseStart(lines, version);
if (start === -1) {
throw new Error(`CHANGELOG.md is missing a ${version} release section`);
}
const end = lines.findIndex((line, index) => index > start && line.startsWith("## "));
const body = lines.slice(start + 1, end === -1 ? lines.length : end).join("\n").trim();
const title = version === "Unreleased" ? "plugin-inspector unreleased" : `plugin-inspector v${version}`;
return `## ${title}\n\n${body}\n`;
}
function findReleaseStart(lines, version) {
if (version === "Unreleased") {
return lines.findIndex((line) => line.trim() === "## Unreleased");
}
return lines.findIndex((line) => line.startsWith(`## ${version} - `));
}
function parseArgs(argv) {
const options = {
changelogPath: path.resolve("CHANGELOG.md"),
version: undefined,
};
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (arg === "--changelog") {
options.changelogPath = path.resolve(argv[index + 1]);
index += 1;
continue;
}
if (arg === "--unreleased") {
options.version = "Unreleased";
continue;
}
if (arg === "--version") {
options.version = argv[index + 1];
index += 1;
continue;
}
if (!options.version) {
options.version = arg;
continue;
}
throw new Error(`unknown argument: ${arg}`);
}
if (!options.version) {
throw new Error("usage: release-notes.mjs <version>|--unreleased [--changelog CHANGELOG.md]");
}
return options;
}

View File

@ -0,0 +1,38 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { extractReleaseNotes } from "../scripts/release-notes.mjs";
const changelog = [
"# Changelog",
"",
"## Unreleased",
"",
"### Added",
"",
"- Add grouped API helpers.",
"",
"## 0.3.0 - 2026-04-27",
"",
"### Changed",
"",
"- Improve setup.",
"",
].join("\n");
test("release notes can render unreleased draft notes", () => {
assert.equal(
extractReleaseNotes({ changelogText: changelog, version: "Unreleased" }),
["## plugin-inspector unreleased", "", "### Added", "", "- Add grouped API helpers.", ""].join("\n"),
);
});
test("release notes can render versioned changelog sections", () => {
assert.equal(
extractReleaseNotes({ changelogText: changelog, version: "0.3.0" }),
["## plugin-inspector v0.3.0", "", "### Changed", "", "- Improve setup.", ""].join("\n"),
);
});
test("release notes fail when a version section is missing", () => {
assert.throws(() => extractReleaseNotes({ changelogText: changelog, version: "9.9.9" }), /missing a 9\.9\.9/);
});