diff --git a/src/core/changelog.ts b/src/core/changelog.ts index c90e473..07f8831 100644 --- a/src/core/changelog.ts +++ b/src/core/changelog.ts @@ -43,9 +43,10 @@ export async function generateChangelogEntry(options: { } = options; // Build compare URL - const compareUrl = previousVersion - ? `https://github.com/${owner}/${repo}/compare/${packageName}@${previousVersion}...${packageName}@${version}` - : undefined; + const compareUrl = + previousVersion && previousVersion !== version + ? `https://github.com/${owner}/${repo}/compare/${packageName}@${previousVersion}...${packageName}@${version}` + : undefined; const commitAuthors = await resolveCommitAuthors(commits, githubClient); const templateGroups = buildTemplateGroups({ @@ -92,6 +93,13 @@ export async function updateChangelog(options: { githubClient, } = options; + if (previousVersion === version) { + logger.verbose( + `Skipping changelog update for ${workspacePackage.name}: version unchanged (${version})`, + ); + return; + } + const changelogPath = join(workspacePackage.path, "CHANGELOG.md"); const changelogRelativePath = relative( diff --git a/src/workflows/prepare.ts b/src/workflows/prepare.ts index f831fe6..22dc42c 100644 --- a/src/workflows/prepare.ts +++ b/src/workflows/prepare.ts @@ -183,6 +183,13 @@ export async function prepareWorkflow( const changelogPromises = allUpdates .map((update) => { return (async () => { + if (update.currentVersion === update.newVersion) { + logger.verbose( + `Skipping changelog for ${update.package.name}: version unchanged (${update.newVersion})`, + ); + return; + } + let pkgCommits = groupedPackageCommits.get(update.package.name) || []; let globalCommits = globalCommitsPerPackage.get(update.package.name) || []; let previousVersionForChangelog: string | undefined = diff --git a/test/core/changelog.test.ts b/test/core/changelog.test.ts index 4c5bcff..e586552 100644 --- a/test/core/changelog.test.ts +++ b/test/core/changelog.test.ts @@ -1,4 +1,4 @@ -import { readFile } from "node:fs/promises"; +import { readFile, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { generateChangelogEntry, parseChangelog, updateChangelog } from "#core/changelog"; @@ -508,4 +508,44 @@ describe("updateChangelog", () => { expect(content).toContain("add feature A"); expect(content).toContain("add feature B"); }); + + it("should not rewrite the changelog when version is unchanged", async () => { + const testdirPath = await testdir({}); + const context = createChangelogTestContext(testdirPath); + + const existingChangelog = dedent` + # @ucdjs/test + + ## 0.1.0 (2025-01-15) + + ### Features + + * initial release + `; + + await writeFile(join(testdirPath, "CHANGELOG.md"), `${existingChangelog}\n`, "utf-8"); + + mockExec.mockResolvedValueOnce({ stdout: existingChangelog, stderr: "", exitCode: 0 }); + + await updateChangelog({ + normalizedOptions: context.normalizedOptions, + workspacePackage: context.workspacePackage, + version: "0.1.0", + previousVersion: "0.1.0", + commits: [ + createCommit({ + type: "feat", + message: "feat: this should not be written", + hash: "def456", + shortHash: "def456", + }), + ], + date: "2025-01-16", + githubClient: context.githubClient, + }); + + const content = await readFile(join(testdirPath, "CHANGELOG.md"), "utf-8"); + + expect(content).toBe(`${existingChangelog}\n`); + }); });