DEVX-58: Fix publish idempotency when release already exists #96

Merged
emil merged 1 commits from DEVX-58-fix-publish-idempotency into master 2026-06-25 23:32:29 +00:00
2 changed files with 39 additions and 0 deletions
+3
View File
@@ -298,6 +298,9 @@ def main(
try:
tea.create_release(repo, tag=tag, title=tag, body=release_body)
except TeaCLIError as e:
if "already" in str(e).lower() and "release" in str(e).lower():
click.echo(_("Gitea release {tag} already exists — skipping creation.", tag=tag))
return
raise click.ClickException(_("Release creation failed: {error}", error=str(e))) from None
click.echo(
+36
View File
@@ -388,6 +388,42 @@ class TestMain:
result = runner.invoke(main, ["v1.0.0", "owner/repo"])
assert result.exit_code == 0
@patch.dict("os.environ", {"REPO_TOKEN": "gitea-tok"})
@patch("devx.ci.publish.generate_release_notes", return_value="Release notes")
@patch("devx.ci.publish.TeaCLI")
@patch("devx.ci.publish.publish_to_pypi")
@patch("devx.ci.publish.build_package")
def test_create_release_already_exists_is_idempotent(
self, mock_build: MagicMock, mock_publish: MagicMock, mock_tea_cls: MagicMock, mock_notes: MagicMock
) -> None:
"""If create_release fails with 'already exists', treat as success."""
mock_tea = MagicMock()
mock_tea.list_releases.side_effect = TeaCLIError("api error")
mock_tea.create_release.side_effect = TeaCLIError("there is already a release for this tag")
mock_tea_cls.return_value = mock_tea
runner = CliRunner()
result = runner.invoke(main, ["v1.0.0", "owner/repo"])
assert result.exit_code == 0
assert "already exists" in result.output
@patch.dict("os.environ", {"REPO_TOKEN": "gitea-tok"})
@patch("devx.ci.publish.generate_release_notes", return_value="Release notes")
@patch("devx.ci.publish.TeaCLI")
@patch("devx.ci.publish.publish_to_pypi")
@patch("devx.ci.publish.build_package")
def test_create_release_other_error_raises(
self, mock_build: MagicMock, mock_publish: MagicMock, mock_tea_cls: MagicMock, mock_notes: MagicMock
) -> None:
"""If create_release fails with a non-'already exists' error, raise."""
mock_tea = MagicMock()
mock_tea.list_releases.side_effect = TeaCLIError("api error")
mock_tea.create_release.side_effect = TeaCLIError("network error")
mock_tea_cls.return_value = mock_tea
runner = CliRunner()
result = runner.invoke(main, ["v1.0.0", "owner/repo"])
assert result.exit_code != 0
assert "Release creation failed" in result.output
class TestFromTag:
def test_get_latest_tag_success(self) -> None: