Simplify getChangelogEntry (#632)

This commit is contained in:
Bjorn Lu
2026-05-27 15:41:11 +00:00
committed by GitHub
parent 031358f743
commit 1d54b9e660
6 changed files with 61 additions and 390 deletions
+9 -16
View File
@@ -12,8 +12,7 @@ exports[`version > creates a draft PR when prDraft is "create" 1`] = `
### Minor Changes
- Awesome feature
",
- Awesome feature",
"draft": true,
"head": "changeset-release/some-branch",
"owner": "changesets",
@@ -35,19 +34,17 @@ exports[`version > creates simple PR 1`] = `
### Minor Changes
- Awesome feature
- Awesome feature
### Patch Changes
- Updated dependencies
- changesets-dev-simple-project-pkg-b@1.1.0
- Updated dependencies
- changesets-dev-simple-project-pkg-b@1.1.0
## changesets-dev-simple-project-pkg-b@1.1.0
### Minor Changes
- Awesome feature
",
- Awesome feature",
"draft": false,
"head": "changeset-release/some-branch",
"owner": "changesets",
@@ -111,8 +108,7 @@ exports[`version > doesn't include ignored package that got a dependency update
### Minor Changes
- Awesome feature
",
- Awesome feature",
"draft": false,
"head": "changeset-release/some-branch",
"owner": "changesets",
@@ -134,8 +130,7 @@ exports[`version > only includes bumped packages in the PR body 1`] = `
### Minor Changes
- Awesome feature
",
- Awesome feature",
"draft": false,
"head": "changeset-release/some-branch",
"owner": "changesets",
@@ -187,8 +182,7 @@ exports[`version > updates an existing PR via GraphQL and converts it to draft w
### Minor Changes
- Awesome feature
",
- Awesome feature",
"pullRequestId": "PR_kwDOA",
"title": "Version Packages",
},
@@ -228,8 +222,7 @@ exports[`version > updates an existing PR via GraphQL without converting it to d
### Minor Changes
- Awesome feature
",
- Awesome feature",
"pullRequestId": "PR_kwDOA",
"title": "Version Packages",
},
+6 -8
View File
@@ -23,23 +23,21 @@ exports[`it sorts the things right 1`] = `
exports[`it works 1`] = `
"### Major Changes
- [2164a779](https://github.com/keystonejs/keystone-5/commit/2164a779):
- [2164a779](https://github.com/keystonejs/keystone-5/commit/2164a779):
- Replace jade with pug because Jade was renamed to Pug, and \`jade\` package is outdated
- Replace jade with pug because Jade was renamed to Pug, and \`jade\` package is outdated
### Patch Changes
- [81dc0be5](https://github.com/keystonejs/keystone-5/commit/81dc0be5):
- [81dc0be5](https://github.com/keystonejs/keystone-5/commit/81dc0be5):
- Update dependencies
"
- Update dependencies"
`;
exports[`it works 2`] = `
"### Patch Changes
- [19fe6c1b](https://github.com/keystonejs/keystone-5/commit/19fe6c1b):
- [19fe6c1b](https://github.com/keystonejs/keystone-5/commit/19fe6c1b):
Move frontmatter in docs into comments
"
Move frontmatter in docs into comments"
`;
+40 -42
View File
@@ -1,11 +1,5 @@
import fs from "node:fs/promises";
import { getPackages, type Package } from "@manypkg/get-packages";
import type { Root } from "mdast";
// @ts-ignore
import mdastToString from "mdast-util-to-string";
import remarkParse from "remark-parse";
import remarkStringify from "remark-stringify";
import unified from "unified";
export const BumpLevels = {
dep: 0,
@@ -37,51 +31,55 @@ export async function getChangedPackages(
}
export function getChangelogEntry(changelog: string, version: string) {
let ast = unified().use(remarkParse).parse(changelog) as Root;
let highestLevel: number = BumpLevels.dep;
let nodes = ast.children;
let headingStartInfo:
| {
index: number;
depth: number;
}
| undefined;
let headingStartInfo: { index: number; depth: number } | undefined;
let endIndex: number | undefined;
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
if (node.type === "heading") {
let stringified: string = mdastToString(node);
let match = stringified.toLowerCase().match(/(major|minor|patch)/);
if (match !== null) {
let level = BumpLevels[match[0] as "major" | "minor" | "patch"];
highestLevel = Math.max(level, highestLevel);
}
if (headingStartInfo === undefined && stringified === version) {
headingStartInfo = {
index: i,
depth: node.depth,
};
// Iterate through each headings and code blocks (for skipping its contents)
const regex = /^(#{1,6})\s(.*)$|^(`{3,})/gm;
let match: RegExpExecArray | null;
while ((match = regex.exec(changelog)) != null) {
// Skip over code blocks so we don't match any headings inside of them
if (match[3]) {
const endOfCodeBlockRegex = new RegExp(`^${match[3]}`, "gm");
endOfCodeBlockRegex.lastIndex = regex.lastIndex;
const endMatch = endOfCodeBlockRegex.exec(changelog);
if (endMatch) {
// Start next search for headings after the end of the code block
regex.lastIndex = endOfCodeBlockRegex.lastIndex;
continue;
}
if (
endIndex === undefined &&
headingStartInfo !== undefined &&
headingStartInfo.depth === node.depth
) {
endIndex = i;
} else {
// Can't find end of code block, probably malformed
break;
}
}
const headingDepth = match[1].length;
const headingText = match[2].trim();
// Search for the highest bump level in the entire changelog
const levelMatch = /(major|minor|patch)/.exec(headingText.toLowerCase());
if (levelMatch != null) {
const level = BumpLevels[levelMatch[0] as "major" | "minor" | "patch"];
highestLevel = Math.max(level, highestLevel);
}
// Search for heading of the entry
if (headingText === version) {
headingStartInfo = { index: regex.lastIndex, depth: headingDepth };
continue;
}
// If we've found the entry heading, search for the closing heading with the same depth
if (headingStartInfo && headingDepth === headingStartInfo.depth) {
endIndex = match.index;
break;
}
}
if (headingStartInfo) {
ast.children = ast.children.slice(headingStartInfo.index + 1, endIndex);
}
return {
content: unified().use(remarkStringify).stringify(ast),
highestLevel: highestLevel,
content: changelog.slice(headingStartInfo?.index, endIndex).trim(),
highestLevel,
};
}