From e7f8e4ac66de081a794a1b331282ce89c6a55f31 Mon Sep 17 00:00:00 2001 From: emil Date: Sun, 21 Jun 2026 17:53:18 +0000 Subject: [PATCH] GRM-35: fix: strip git-cliff header from CHANGELOG.md updates The update_changelog function now strips the git-cliff header before inserting into CHANGELOG.md, preventing duplicate headers. Closes GRM-35 --- CHANGELOG.md | 4 ---- scripts/release.py | 11 ++++++++--- tests/unit/test_cli.py | 2 +- tests/unit/test_release.py | 24 ++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de519ff..0db0757 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,6 @@ All notable changes to this project will be documented in this file. -# Changelog - -All notable changes to this project will be documented in this file. - ## [0.2.0] - 2026-06-21 ### Features diff --git a/scripts/release.py b/scripts/release.py index 019b1bc..9d4faa8 100644 --- a/scripts/release.py +++ b/scripts/release.py @@ -138,10 +138,15 @@ def update_init_version(new_version: str) -> None: def update_changelog(changelog: str) -> None: """Prepend the new changelog section to CHANGELOG.md. - If the file doesn't exist, create it with the changelog as the sole content. - If it exists, insert the new version section after the header (before the - first existing version section). + The changelog from git-cliff may include a header (e.g., "# Changelog"). + This function strips everything before the first ``## [`` version section + before inserting, to avoid duplicating the header. """ + # Strip git-cliff header — keep only from the first version section + section_match = re.search(r"^## \[", changelog, flags=re.MULTILINE) + if section_match: + changelog = changelog[section_match.start() :] + try: with open(CHANGELOG_FILE) as f: existing = f.read() diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index fc45759..2c6e80f 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -12,7 +12,7 @@ class TestCLI: runner = CliRunner() result = runner.invoke(cli, ["--version"]) assert result.exit_code == 0 - assert "0.1.0" in result.output + assert "0.2.0" in result.output @patch("gitea_runner_manager.cli.RunnerManager") def test_install(self, mock_manager_class: MagicMock) -> None: diff --git a/tests/unit/test_release.py b/tests/unit/test_release.py index 58e2656..8860ba4 100644 --- a/tests/unit/test_release.py +++ b/tests/unit/test_release.py @@ -186,6 +186,30 @@ class TestUpdateChangelog: assert "Some intro text" in content assert "## [0.2.0]" in content + def test_strips_git_cliff_header(self, tmp_path, monkeypatch) -> None: + """git-cliff output includes a header — should be stripped before inserting.""" + changelog_file = tmp_path / "CHANGELOG.md" + changelog_file.write_text("# Changelog\n\n## [0.1.0] - 2026-06-20\n\n### Features\n- old thing\n") + monkeypatch.setattr("scripts.release.CHANGELOG_FILE", str(changelog_file)) + # Simulate git-cliff output with header + cliff_output = "# Changelog\n\nAll notable changes...\n\n## [0.2.0] - 2026-06-21\n\n### Features\n- new thing" + update_changelog(cliff_output) + content = changelog_file.read_text() + # Header should appear only once (from the existing file) + assert content.count("# Changelog") == 1 + assert "## [0.2.0]" in content + assert "new thing" in content + + def test_strips_header_when_creating_new_file(self, tmp_path, monkeypatch) -> None: + """When creating a new file, strip the git-cliff header.""" + changelog_file = tmp_path / "CHANGELOG.md" + monkeypatch.setattr("scripts.release.CHANGELOG_FILE", str(changelog_file)) + cliff_output = "# Changelog\n\nAll notable changes...\n\n## [0.2.0] - 2026-06-21\n\n### Features\n- new thing" + update_changelog(cliff_output) + content = changelog_file.read_text() + assert "# Changelog" not in content + assert "## [0.2.0]" in content + class TestCommitReleaseChanges: @patch("scripts.release.run_cmd")