GRM-35: fix: release push permission and notify_failure label IDs
Fix two issues found during release workflow testing. Closes GRM-35
This commit is contained in:
@@ -51,15 +51,17 @@ def main(repo: str, run_id: str, workflow: str, commit: str) -> None:
|
||||
)
|
||||
|
||||
try:
|
||||
issue = client.create_issue(title=title, body=body, labels=["bug"])
|
||||
# Look up label IDs by name (Gitea API expects integer IDs, not strings)
|
||||
label_ids: list[int] = []
|
||||
for label in client.list_labels():
|
||||
if label.get("name") == "bug":
|
||||
label_ids.append(int(label["id"]))
|
||||
break
|
||||
issue = client.create_issue(title=title, body=body, labels=label_ids if label_ids else None)
|
||||
except APIError as e:
|
||||
# If labels don't exist, retry without labels
|
||||
if e.status == 404:
|
||||
issue = client.create_issue(title=title, body=body)
|
||||
else:
|
||||
raise click.ClickException(
|
||||
_("Failed to create issue: HTTP {status} — {message}", status=e.status, message=e.message)
|
||||
) from None
|
||||
raise click.ClickException(
|
||||
_("Failed to create issue: HTTP {status} — {message}", status=e.status, message=e.message)
|
||||
) from None
|
||||
|
||||
click.echo(
|
||||
_(
|
||||
|
||||
@@ -105,8 +105,12 @@ class GiteaClient:
|
||||
return None
|
||||
return self.create_label(name, color, description)
|
||||
|
||||
def create_issue(self, title: str, body: str = "", labels: list[str] | None = None) -> dict[str, Any]:
|
||||
"""Create a new issue in the repository."""
|
||||
def create_issue(self, title: str, body: str = "", labels: list[int] | None = None) -> dict[str, Any]:
|
||||
"""Create a new issue in the repository.
|
||||
|
||||
Args:
|
||||
labels: List of label IDs (integers, not names).
|
||||
"""
|
||||
payload: dict[str, Any] = {"title": title, "body": body}
|
||||
if labels:
|
||||
payload["labels"] = labels
|
||||
|
||||
@@ -275,12 +275,12 @@ class TestGiteaClient:
|
||||
client = GiteaClient("https://git.example.com", "tok", "owner", "repo")
|
||||
client._session.request = MagicMock(return_value=_mock_response({"id": 42, "title": "bug"}))
|
||||
|
||||
result = client.create_issue(title="bug", body="description", labels=["bug"])
|
||||
result = client.create_issue(title="bug", body="description", labels=[1])
|
||||
assert result["id"] == 42
|
||||
client._session.request.assert_called_once_with(
|
||||
"POST",
|
||||
"https://git.example.com/repos/owner/repo/issues",
|
||||
json={"title": "bug", "body": "description", "labels": ["bug"]},
|
||||
json={"title": "bug", "body": "description", "labels": [1]},
|
||||
timeout=DEFAULT_TIMEOUT,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Unit tests for scripts/notify_failure.py."""
|
||||
|
||||
import http
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from click.testing import CliRunner
|
||||
@@ -14,6 +13,7 @@ class TestNotifyFailure:
|
||||
@patch("scripts.notify_failure.GiteaClient")
|
||||
def test_creates_issue_with_labels(self, mock_client_cls: MagicMock) -> None:
|
||||
mock_client = MagicMock()
|
||||
mock_client.list_labels.return_value = [{"id": 5, "name": "bug"}]
|
||||
mock_client.create_issue.return_value = {"id": 42}
|
||||
mock_client_cls.return_value = mock_client
|
||||
|
||||
@@ -35,17 +35,15 @@ class TestNotifyFailure:
|
||||
assert "issue #42" in result.output
|
||||
mock_client.create_issue.assert_called_once()
|
||||
call_kwargs = mock_client.create_issue.call_args
|
||||
assert "release" in call_kwargs.kwargs["title"]
|
||||
assert call_kwargs.kwargs["labels"] == ["bug"]
|
||||
assert call_kwargs.kwargs["labels"] == [5]
|
||||
|
||||
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
|
||||
@patch("scripts.notify_failure.GiteaClient")
|
||||
def test_creates_issue_without_labels_on_404(self, mock_client_cls: MagicMock) -> None:
|
||||
def test_creates_issue_without_bug_label(self, mock_client_cls: MagicMock) -> None:
|
||||
"""When 'bug' label doesn't exist, create issue without labels."""
|
||||
mock_client = MagicMock()
|
||||
mock_client.create_issue.side_effect = [
|
||||
APIError(http.HTTPStatus.NOT_FOUND, "label not found"),
|
||||
{"id": 43},
|
||||
]
|
||||
mock_client.list_labels.return_value = [{"id": 1, "name": "enhancement"}]
|
||||
mock_client.create_issue.return_value = {"id": 43}
|
||||
mock_client_cls.return_value = mock_client
|
||||
|
||||
runner = CliRunner()
|
||||
@@ -64,16 +62,16 @@ class TestNotifyFailure:
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "issue #43" in result.output
|
||||
assert mock_client.create_issue.call_count == 2
|
||||
# Second call should not have labels
|
||||
second_call = mock_client.create_issue.call_args_list[1]
|
||||
assert "labels" not in second_call.kwargs or second_call.kwargs.get("labels") is None
|
||||
mock_client.create_issue.assert_called_once()
|
||||
call_kwargs = mock_client.create_issue.call_args
|
||||
assert call_kwargs.kwargs.get("labels") is None
|
||||
|
||||
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
|
||||
@patch("scripts.notify_failure.GiteaClient")
|
||||
def test_api_error_raises(self, mock_client_cls: MagicMock) -> None:
|
||||
mock_client = MagicMock()
|
||||
mock_client.create_issue.side_effect = APIError(http.HTTPStatus.FORBIDDEN, "forbidden")
|
||||
mock_client.list_labels.return_value = []
|
||||
mock_client.create_issue.side_effect = APIError(403, "forbidden")
|
||||
mock_client_cls.return_value = mock_client
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
Reference in New Issue
Block a user