GRM-27: fix: CI workflows for rootless runner compatibility
Post-merge Vikunja update / vikunja (push) Failing after 5s
CI / quality (push) Successful in 1m3s
CI / molecule-tests (0) (push) Failing after 3m35s
CI / molecule-tests (1) (push) Failing after 5m53s
CI / molecule-tests (2) (push) Failing after 5m59s

This commit was merged in pull request #6.
This commit is contained in:
2026-06-20 17:01:55 +00:00
parent ea18793963
commit 0fadb7c504
7 changed files with 125 additions and 17 deletions
+81 -8
View File
@@ -9,7 +9,7 @@ from click.testing import CliRunner
from gitea_runner_manager.config import CONVENTIONAL_RE, TASK_ID_RE
from gitea_runner_manager.exceptions import APIError
from scripts.auto_merge import extract_task_id, main, validate_pr_title
from scripts.auto_merge import extract_task_id, has_ready_to_merge_label, main, validate_pr_title
class TestRegexes:
@@ -53,40 +53,111 @@ class TestValidatePrTitle:
assert "conventional" in str(exc.value)
class TestHasReadyToMergeLabel:
def test_label_present(self) -> None:
client = MagicMock()
client.get_pr_labels.return_value = [{"name": "bug"}, {"name": "ready-to-merge"}]
assert has_ready_to_merge_label(client, "5") is True
def test_label_absent(self) -> None:
client = MagicMock()
client.get_pr_labels.return_value = [{"name": "bug"}]
assert has_ready_to_merge_label(client, "5") is False
def test_no_labels(self) -> None:
client = MagicMock()
client.get_pr_labels.return_value = []
assert has_ready_to_merge_label(client, "5") is False
class TestMain:
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
@patch("scripts.auto_merge.GiteaClient")
def test_successful_flow(self, mock_client_cls: MagicMock) -> None:
def test_successful_flow_with_label_arg(self, mock_client_cls: MagicMock) -> None:
mock_client = MagicMock()
mock_client_cls.return_value = mock_client
runner = CliRunner()
result = runner.invoke(
main,
["GRM-19-fix-bug", "fix: resolve timeout", "owner/repo", "7", "ready-to-merge"],
)
assert result.exit_code == 0
assert "squash-merged" in result.output
mock_client.merge_pr.assert_called_once_with("7", "GRM-19: fix: resolve timeout")
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
@patch("scripts.auto_merge.GiteaClient")
def test_successful_flow_label_fallback(self, mock_client_cls: MagicMock) -> None:
"""Label not passed via arg, but PR has ready-to-merge via API."""
mock_client = MagicMock()
mock_client.get_pr_labels.return_value = [{"name": "ready-to-merge"}]
mock_client_cls.return_value = mock_client
runner = CliRunner()
result = runner.invoke(
main,
["GRM-19-fix-bug", "fix: resolve timeout", "owner/repo", "7"],
)
assert result.exit_code == 0
assert "squash-merged" in result.output
mock_client_cls.assert_called_once()
mock_client.merge_pr.assert_called_once_with("7", "GRM-19: fix: resolve timeout")
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
@patch("scripts.auto_merge.GiteaClient")
def test_wrong_label_skips_merge(self, mock_client_cls: MagicMock) -> None:
"""Label is not ready-to-merge and PR doesn't have it via API either."""
mock_client = MagicMock()
mock_client.get_pr_labels.return_value = [{"name": "bug"}]
mock_client_cls.return_value = mock_client
runner = CliRunner()
result = runner.invoke(
main,
["GRM-19-fix-bug", "fix: resolve timeout", "owner/repo", "7", "bug"],
)
assert result.exit_code == 0
assert "skipping" in result.output
mock_client.merge_pr.assert_not_called()
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
@patch("scripts.auto_merge.GiteaClient")
def test_empty_label_falls_back_to_api(self, mock_client_cls: MagicMock) -> None:
"""Gitea Actions doesn't populate label name, but API shows ready-to-merge."""
mock_client = MagicMock()
mock_client.get_pr_labels.return_value = [{"name": "ready-to-merge"}]
mock_client_cls.return_value = mock_client
runner = CliRunner()
result = runner.invoke(
main,
["GRM-19-fix-bug", "fix: resolve timeout", "owner/repo", "7", ""],
)
assert result.exit_code == 0
assert "squash-merged" in result.output
@patch.dict("os.environ", {"REPO_TOKEN": ""}, clear=True)
def test_missing_token_exits(self) -> None:
runner = CliRunner()
result = runner.invoke(main, ["branch", "title", "repo", "1"])
result = runner.invoke(main, ["branch", "title", "owner/repo", "1"])
assert result.exit_code == 1
assert "REPO_TOKEN" in result.output
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
def test_missing_task_id_exits(self) -> None:
@patch("scripts.auto_merge.GiteaClient")
def test_missing_task_id_exits(self, mock_client_cls: MagicMock) -> None:
mock_client = MagicMock()
mock_client.get_pr_labels.return_value = [{"name": "ready-to-merge"}]
mock_client_cls.return_value = mock_client
runner = CliRunner()
result = runner.invoke(main, ["feature-no-id", "fix: bug", "repo", "1"])
result = runner.invoke(main, ["feature-no-id", "fix: bug", "owner/repo", "1"])
assert result.exit_code == 1
assert "task ID" in result.output
@patch.dict("os.environ", {"REPO_TOKEN": "tok"})
def test_invalid_pr_title_exits(self) -> None:
@patch("scripts.auto_merge.GiteaClient")
def test_invalid_pr_title_exits(self, mock_client_cls: MagicMock) -> None:
mock_client = MagicMock()
mock_client.get_pr_labels.return_value = [{"name": "ready-to-merge"}]
mock_client_cls.return_value = mock_client
runner = CliRunner()
result = runner.invoke(main, ["GRM-19-fix", "random title", "repo", "1"])
result = runner.invoke(main, ["GRM-19-fix", "random title", "owner/repo", "1"])
assert result.exit_code == 1
assert "conventional" in result.output
@@ -94,6 +165,7 @@ class TestMain:
@patch("scripts.auto_merge.GiteaClient")
def test_merge_pr_failure_raises_click(self, mock_client_cls: MagicMock) -> None:
mock_client = MagicMock()
mock_client.get_pr_labels.return_value = [{"name": "ready-to-merge"}]
mock_client.merge_pr.side_effect = APIError(http.HTTPStatus.INTERNAL_SERVER_ERROR, "server error")
mock_client_cls.return_value = mock_client
runner = CliRunner()
@@ -105,6 +177,7 @@ class TestMain:
@patch("scripts.auto_merge.GiteaClient")
def test_merge_pr_json_parse_failure(self, mock_client_cls: MagicMock) -> None:
mock_client = MagicMock()
mock_client.get_pr_labels.return_value = [{"name": "ready-to-merge"}]
mock_client.merge_pr.side_effect = APIError(http.HTTPStatus.BAD_GATEWAY, "bad gateway")
mock_client_cls.return_value = mock_client
runner = CliRunner()