Refactor release helper into actions package and add RPM changelog support

- Move the monolithic pkgmgr/actions/release.py implementation into the
  pkgmgr.actions.release package, splitting concerns into versioning,
  git_ops and files helpers.
- Extend the release orchestration to update Fedora/RPM %changelog
  entries via update_spec_changelog(), reusing the same effective
  release message as for CHANGELOG.md and debian/changelog.
- Wire the new update_spec_changelog() helper into _release_impl() so
  every release keeps project, Debian and RPM metadata in sync.
- Add unit tests for update_spec_changelog() and for the updated release
  orchestration behaviour in preview and real modes.
- Remove the deprecated pkgmgr/actions/release.py module.

See ChatGPT discussion: https://chatgpt.com/share/6938368e-0940-800f-92d3-f2ccfddab794
This commit is contained in:
Kevin Veen-Birkenbach
2025-12-09 15:47:37 +01:00
parent 80329b85fb
commit ab52d37467
5 changed files with 201 additions and 763 deletions

View File

@@ -13,6 +13,7 @@ from pkgmgr.actions.release.files import (
update_spec_version,
update_changelog,
update_debian_changelog,
update_spec_changelog,
)
@@ -310,5 +311,94 @@ class TestUpdateDebianChangelog(unittest.TestCase):
self.assertEqual(content, original)
class TestUpdateSpecChangelog(unittest.TestCase):
def test_update_spec_changelog_inserts_stanza_after_changelog_marker(self) -> None:
original = textwrap.dedent(
"""
Name: package-manager
Version: 0.1.0
Release: 5%{?dist}
%description
Some description.
%changelog
* Mon Jan 01 2024 Old Maintainer <old@example.com> - 0.1.0-1
- Old entry
"""
).strip() + "\n"
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, "package-manager.spec")
with open(path, "w", encoding="utf-8") as f:
f.write(original)
with patch.dict(
os.environ,
{
"DEBFULLNAME": "Test Maintainer",
"DEBEMAIL": "test@example.com",
},
clear=False,
):
update_spec_changelog(
spec_path=path,
package_name="package-manager",
new_version="1.2.3",
message="Fedora changelog entry",
preview=False,
)
with open(path, "r", encoding="utf-8") as f:
content = f.read()
# Neue Stanza muss nach %changelog stehen
self.assertIn("%changelog", content)
self.assertIn("Fedora changelog entry", content)
self.assertIn("Test Maintainer <test@example.com>", content)
# Alte Einträge müssen erhalten bleiben
self.assertIn("Old Maintainer <old@example.com>", content)
def test_update_spec_changelog_preview_does_not_write(self) -> None:
original = textwrap.dedent(
"""
Name: package-manager
Version: 0.1.0
Release: 5%{?dist}
%changelog
* Mon Jan 01 2024 Old Maintainer <old@example.com> - 0.1.0-1
- Old entry
"""
).strip() + "\n"
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, "package-manager.spec")
with open(path, "w", encoding="utf-8") as f:
f.write(original)
with patch.dict(
os.environ,
{
"DEBFULLNAME": "Test Maintainer",
"DEBEMAIL": "test@example.com",
},
clear=False,
):
update_spec_changelog(
spec_path=path,
package_name="package-manager",
new_version="1.2.3",
message="Fedora changelog entry",
preview=True,
)
with open(path, "r", encoding="utf-8") as f:
content = f.read()
# Im Preview-Modus darf nichts verändert werden
self.assertEqual(content, original)
if __name__ == "__main__":
unittest.main()

View File

@@ -19,6 +19,7 @@ class TestReleaseOrchestration(unittest.TestCase):
patch("pkgmgr.actions.release.update_pkgbuild_version") as mock_update_pkgbuild, \
patch("pkgmgr.actions.release.update_spec_version") as mock_update_spec, \
patch("pkgmgr.actions.release.update_debian_changelog") as mock_update_debian_changelog, \
patch("pkgmgr.actions.release.update_spec_changelog") as mock_update_spec_changelog, \
patch("pkgmgr.actions.release.run_git_command") as mock_run_git_command, \
patch("pkgmgr.actions.release.sync_branch_with_remote") as mock_sync_branch, \
patch("pkgmgr.actions.release.update_latest_tag") as mock_update_latest_tag:
@@ -48,7 +49,7 @@ class TestReleaseOrchestration(unittest.TestCase):
self.assertEqual(args[1], "1.2.4")
self.assertEqual(kwargs.get("preview"), False)
# changelog update
# changelog update (Projekt)
mock_update_changelog.assert_called_once()
args, kwargs = mock_update_changelog.call_args
self.assertEqual(args[0], "CHANGELOG.md")
@@ -72,6 +73,13 @@ class TestReleaseOrchestration(unittest.TestCase):
False,
)
# Fedora / RPM %changelog helper
mock_update_spec_changelog.assert_called_once()
self.assertEqual(
mock_update_spec_changelog.call_args[1].get("preview"),
False,
)
# Git operations
mock_get_current_branch.assert_called_once()
self.assertEqual(mock_get_current_branch.return_value, "develop")
@@ -96,6 +104,7 @@ class TestReleaseOrchestration(unittest.TestCase):
patch("pkgmgr.actions.release.update_pkgbuild_version") as mock_update_pkgbuild, \
patch("pkgmgr.actions.release.update_spec_version") as mock_update_spec, \
patch("pkgmgr.actions.release.update_debian_changelog") as mock_update_debian_changelog, \
patch("pkgmgr.actions.release.update_spec_changelog") as mock_update_spec_changelog, \
patch("pkgmgr.actions.release.run_git_command") as mock_run_git_command, \
patch("pkgmgr.actions.release.sync_branch_with_remote") as mock_sync_branch, \
patch("pkgmgr.actions.release.update_latest_tag") as mock_update_latest_tag:
@@ -129,6 +138,10 @@ class TestReleaseOrchestration(unittest.TestCase):
mock_update_debian_changelog.assert_called_once()
self.assertTrue(mock_update_debian_changelog.call_args[1].get("preview"))
# Fedora / RPM spec changelog helper in preview mode
mock_update_spec_changelog.assert_called_once()
self.assertTrue(mock_update_spec_changelog.call_args[1].get("preview"))
# In preview mode no real git commands must be executed
mock_run_git_command.assert_not_called()