Skip to content
141 changes: 126 additions & 15 deletions tests/tools/private/release/changelog_news_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,9 @@ def test_update_changelog_with_news(self):

[unreleased]: https://github.com/bazel-contrib/rules_python/releases/tag/unreleased

{#unreleased-removed}
### Removed
* Nothing removed.

{#unreleased-changed}
### Changed
* Nothing changed.

{#unreleased-fixed}
### Fixed
* Nothing fixed.

{#unreleased-added}
### Added
* Nothing added.
Unreleased changes are tracked as individual files in the [news/](./news)
directory, or view the [latest generated
changelog](https://rules-python.readthedocs.io/en/latest/changelog.html).

{#v2-0-2}
## [2.0.2] - 2026-05-14
Expand Down Expand Up @@ -408,6 +396,129 @@ def test_update_changelog_empty_news(self):
self.assertNotIn("{#v3-0-0-fixed}", new_content)
self.assertNotIn("{#v3-0-0-added}", new_content)

def test_update_changelog_selective_news_files(self):
# Arrange
changelog = """# Changelog

{#unreleased}
## Unreleased

[unreleased]: https://github.com/bazel-contrib/rules_python/releases/tag/unreleased

{#v2-0-2}
## [2.0.2] - 2026-05-14

[2.0.2]: https://github.com/bazel-contrib/rules_python/releases/tag/2.0.2
"""
changelog_path = self.tmpdir / "CHANGELOG.md"
changelog_path.write_text(changelog)

news_dir = self.tmpdir / "news"
news_dir.mkdir()

# Create news files
(news_dir / "123.fixed.md").write_text("Fix A")
(news_dir / "456.fixed.md").write_text("Fix B")

# Act: Only process 123.fixed.md
changelog_news.update_changelog(
"2.0.3",
"2026-06-16",
changelog_path=changelog_path,
news_dir=news_dir,
news_files=[news_dir / "123.fixed.md"],
)

# Assert
# 1. Only 123.fixed.md should be deleted
self.assertFalse((news_dir / "123.fixed.md").exists())
self.assertTrue((news_dir / "456.fixed.md").exists())

new_content = changelog_path.read_text()

# 2. Only Fix A should be in the changelog
self.assertIn("Fix A", new_content)
self.assertNotIn("Fix B", new_content)

def test_update_changelog_insertion_point(self):
# Arrange
changelog = """# Changelog

{#unreleased}
## Unreleased

[unreleased]: https://github.com/bazel-contrib/rules_python/releases/tag/unreleased

{#v2-2-0}
## [2.2.0] - 2026-06-30

[2.2.0]: https://github.com/bazel-contrib/rules_python/releases/tag/2.2.0

{#v2-0-0}
## [2.0.0] - 2026-04-09

[2.0.0]: https://github.com/bazel-contrib/rules_python/releases/tag/2.0.0
"""
changelog_path = self.tmpdir / "CHANGELOG.md"
changelog_path.write_text(changelog)

news_dir = self.tmpdir / "news"
news_dir.mkdir()
(news_dir / "123.fixed.md").write_text("Fix in 2.1.0")

# Act: Insert 2.1.0
changelog_news.update_changelog(
"2.1.0",
"2026-06-17",
changelog_path=changelog_path,
news_dir=news_dir,
)

# Assert
new_content = changelog_path.read_text()

# Verify 2.1.0 is inserted BEFORE 2.0.0 but AFTER 2.2.0
idx_2_2_0 = new_content.index("{#v2-2-0}")
idx_2_1_0 = new_content.index("{#v2-1-0}")
idx_2_0_0 = new_content.index("{#v2-0-0}")

self.assertTrue(idx_2_2_0 < idx_2_1_0 < idx_2_0_0)
self.assertIn("Fix in 2.1.0", new_content)

def test_update_changelog_insertion_point_too_small(self):
# Arrange
changelog = """# Changelog

{#unreleased}
## Unreleased

[unreleased]: https://github.com/bazel-contrib/rules_python/releases/tag/unreleased

{#v2-0-0}
## [2.0.0] - 2026-04-09

[2.0.0]: https://github.com/bazel-contrib/rules_python/releases/tag/2.0.0
"""
changelog_path = self.tmpdir / "CHANGELOG.md"
changelog_path.write_text(changelog)

news_dir = self.tmpdir / "news"
news_dir.mkdir()
(news_dir / "123.fixed.md").write_text("Fix in 1.0.0")

# Act & Assert
with self.assertRaises(ValueError) as ctx:
changelog_news.update_changelog(
"1.0.0",
"2026-01-01",
changelog_path=changelog_path,
news_dir=news_dir,
)
self.assertIn(
"Could not find a version in CHANGELOG.md smaller than 1.0.0",
str(ctx.exception),
)
Comment thread
rickeylev marked this conversation as resolved.


if __name__ == "__main__":
unittest.main()
83 changes: 83 additions & 0 deletions tests/tools/private/release/git_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,88 @@ def test_fetch_all_options(self):
)


class GitGetModifiedFilesTest(unittest.TestCase):
def setUp(self):
self.git = Git(".")
self.patcher = patch.object(self.git, "_run_git")
self.mock_run_git = self.patcher.start()
self.addCleanup(self.patcher.stop)

def test_get_modified_files(self):
self.mock_run_git.return_value = "file1.txt\nfile2.py\n\n"
files = self.git.get_modified_files("HEAD")
self.mock_run_git.assert_called_once_with(
"show", "--name-only", "--format=", "HEAD"
)
self.assertEqual(files, ["file1.txt", "file2.py"])

def test_get_modified_files_empty(self):
self.mock_run_git.return_value = ""
files = self.git.get_modified_files("HEAD")
self.assertEqual(files, [])


class GitDiffTest(unittest.TestCase):
def setUp(self):
self.git = Git(".")
self.patcher = patch.object(self.git, "_run_git")
self.mock_run_git = self.patcher.start()
self.addCleanup(self.patcher.stop)

def test_diff_has_changes(self):
self.mock_run_git.return_value = "some diff output"
output = self.git.diff()
self.mock_run_git.assert_called_once_with("diff")
self.assertEqual(output, "some diff output")

def test_diff_empty(self):
self.mock_run_git.return_value = ""
output = self.git.diff()
self.mock_run_git.assert_called_once_with("diff")
self.assertEqual(output, "")


class GitApplyTest(unittest.TestCase):
def setUp(self):
self.git = Git(".")
self.patcher = patch.object(self.git, "_run_git")
self.mock_run_git = self.patcher.start()
self.addCleanup(self.patcher.stop)

def test_apply(self):
self.git.apply("patch.patch")
self.mock_run_git.assert_called_once_with(
"apply", "patch.patch", capture_output=False
)


class GitApplyCheckTest(unittest.TestCase):
def setUp(self):
self.git = Git(".")
self.patcher = patch.object(self.git, "_run_git")
self.mock_run_git = self.patcher.start()
self.addCleanup(self.patcher.stop)

def test_apply_check_clean(self):
self.mock_run_git.return_value = ""
result = self.git.apply_check("patch.patch")
self.mock_run_git.assert_called_once_with(
"apply", "--check", "patch.patch", capture_output=False
)
self.assertTrue(result)

def test_apply_check_conflict(self):
import subprocess

self.mock_run_git.side_effect = subprocess.CalledProcessError(
1, ["git", "apply", "--check", "patch.patch"]
)
result = self.git.apply_check("patch.patch")
self.mock_run_git.assert_called_once_with(
"apply", "--check", "patch.patch", capture_output=False
)
self.assertFalse(result)


if __name__ == "__main__":
unittest.main()
18 changes: 15 additions & 3 deletions tests/tools/private/release/prepare_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ def test_prepare_success_existing_issue(self, mock_replace, mock_changelog):
self.assertEqual(result, 0)
self.mock_gh.get_release_tracking_issue.assert_called_once_with("2.0.0")
self.mock_gh.create_tracking_issue.assert_not_called()
self.mock_gh.create_pr.assert_called_once_with("2.0.0", 123)
self.mock_gh.create_pr.assert_called_once_with(
title="Prepare release v2.0.0",
body="Work towards #123",
base="main",
)
self.mock_git.add_modified_and_deleted.assert_called_once()

@patch("tools.private.release.prepare.changelog_news")
Expand Down Expand Up @@ -67,7 +71,11 @@ def test_prepare_success_create_issue(self, mock_replace, mock_changelog):
self.mock_gh.create_tracking_issue.assert_called_once_with(
"2.0.0", "dummy template content"
)
self.mock_gh.create_pr.assert_called_once_with("2.0.0", 123)
self.mock_gh.create_pr.assert_called_once_with(
title="Prepare release v2.0.0",
body="Work towards #123",
base="main",
)
self.mock_git.add_modified_and_deleted.assert_called_once()

@patch("tools.private.release.prepare.changelog_news")
Expand Down Expand Up @@ -172,7 +180,11 @@ def test_prepare_create_pr_when_none_associated(self, mock_replace, mock_changel
"origin", "prepare-2.0.0", set_upstream=True, force=True
)
self.mock_gh.get_open_pr.assert_called_once_with("prepare-2.0.0")
self.mock_gh.create_pr.assert_called_once_with("2.0.0", 123)
self.mock_gh.create_pr.assert_called_once_with(
title="Prepare release v2.0.0",
body="Work towards #123",
base="main",
)
self.mock_gh.update_issue_body.assert_called_once()
call_args = self.mock_gh.update_issue_body.call_args[0]
self.assertIn("pr=#789", call_args[1])
Expand Down
Loading