fix(changelog): preserved released sections during auto-fix
Restored the released coding-agent changelog sections that the previous pre-publish fix run flattened into Unreleased. The local checkout only had tags through v15.5.15, so fix-changelogs compared against an old tag and promoted entire newly-added release sections. - Kept newly-added release-section hunks out of collectPromotableAddedItemLines so the fixer still promotes individual new items added under an existing released section, but does not rewrite whole release blocks. - Added regression coverage for the release-section case. - Restored the coding-agent changelog history and kept only the #2582 entry under Unreleased. Fixes #2582
This commit is contained in:
+1037
-466
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,27 @@ describe("collectPromotableAddedItemLines", () => {
|
||||
|
||||
expect(lines.get("packages/example/CHANGELOG.md")).toEqual(new Set([12, 33]));
|
||||
});
|
||||
|
||||
it("does not promote items from newly added release sections", () => {
|
||||
const diff = [
|
||||
"diff --git a/packages/example/CHANGELOG.md b/packages/example/CHANGELOG.md",
|
||||
"--- a/packages/example/CHANGELOG.md",
|
||||
"+++ b/packages/example/CHANGELOG.md",
|
||||
"@@ -1,0 +1,8 @@",
|
||||
"+# Changelog",
|
||||
"+",
|
||||
"+## [1.0.0] - 2026-01-01",
|
||||
"+",
|
||||
"+### Fixed",
|
||||
"+",
|
||||
"+- Released fix.",
|
||||
"+- Another released fix.",
|
||||
].join("\n");
|
||||
|
||||
const lines = collectPromotableAddedItemLines(diff);
|
||||
|
||||
expect(lines.get("packages/example/CHANGELOG.md")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("fixChangelogContent", () => {
|
||||
|
||||
@@ -425,6 +425,10 @@ export function fixChangelogContent(
|
||||
function hunkKey(hunk: HunkRef): string {
|
||||
return `${hunk.path}\0${hunk.index}`;
|
||||
}
|
||||
function isAddedReleaseHeadingLine(line: string): boolean {
|
||||
return line.startsWith("+## [");
|
||||
}
|
||||
|
||||
|
||||
function itemKey(pathName: string, text: string): string {
|
||||
return `${pathName}\0${normalizeItemText(text)}`;
|
||||
@@ -433,11 +437,11 @@ function itemKey(pathName: string, text: string): string {
|
||||
export function collectPromotableAddedItemLines(diffText: string): Map<string, Set<number>> {
|
||||
const candidates: AddedItemCandidate[] = [];
|
||||
const removals: RemovedItemOccurrence[] = [];
|
||||
const addedReleaseHeadingHunks = new Set<string>();
|
||||
let currentPath = "";
|
||||
let oldLine = 0;
|
||||
let newLine = 0;
|
||||
let hunkIndex = -1;
|
||||
|
||||
for (const rawLine of diffText.replace(/\r\n/g, "\n").split("\n")) {
|
||||
if (rawLine.startsWith("+++ b/")) {
|
||||
currentPath = rawLine.slice("+++ b/".length);
|
||||
@@ -464,6 +468,10 @@ export function collectPromotableAddedItemLines(diffText: string): Map<string, S
|
||||
const text = rawLine.slice(1);
|
||||
const hunk = { path: currentPath, index: hunkIndex };
|
||||
if (marker === "+") {
|
||||
const hunkKeyValue = hunkKey(hunk);
|
||||
if (isAddedReleaseHeadingLine(rawLine)) {
|
||||
addedReleaseHeadingHunks.add(hunkKeyValue);
|
||||
}
|
||||
if (isListItemLine(text)) {
|
||||
candidates.push({
|
||||
path: currentPath,
|
||||
@@ -525,8 +533,8 @@ export function collectPromotableAddedItemLines(diffText: string): Map<string, S
|
||||
|
||||
const linesByPath = new Map<string, Set<number>>();
|
||||
for (const candidate of candidates) {
|
||||
if (candidate.pairedWithRemoval) continue;
|
||||
const key = hunkKey(candidate.hunk);
|
||||
if (candidate.pairedWithRemoval || addedReleaseHeadingHunks.has(key)) continue;
|
||||
const unpairedRemovalCount = unpairedRemovalCountByHunk.get(key) ?? 0;
|
||||
if (unpairedRemovalCount > 0) {
|
||||
unpairedRemovalCountByHunk.set(key, unpairedRemovalCount - 1);
|
||||
|
||||
Reference in New Issue
Block a user