GRM-59: fix: post-merge workflow failures (4 jobs)
This commit is contained in:
@@ -54,8 +54,9 @@ jobs:
|
||||
env:
|
||||
PYTHONPATH: .:src
|
||||
run: |
|
||||
git log -1 --format=%B > /tmp/commit-msg.txt
|
||||
python3 scripts/ci/validate_commit_msg.py /tmp/commit-msg.txt --branch master
|
||||
git log -1 --format=%B > commit-msg.txt
|
||||
python3 scripts/ci/validate_commit_msg.py commit-msg.txt --branch master
|
||||
rm -f commit-msg.txt
|
||||
|
||||
release:
|
||||
needs: [detect-type]
|
||||
|
||||
+14
-10
@@ -64,11 +64,11 @@ def extract_conventional_msg(commit_msg: str) -> str:
|
||||
return re.sub(r"^GRM-\d+[:\s]\s*", "", first_line)
|
||||
|
||||
|
||||
def resolve_task_id(client: VikunjaClient, task_id: str) -> int:
|
||||
def resolve_task_id(client: VikunjaClient, task_id: str) -> int | None:
|
||||
"""Resolve GRM-N identifier to Vikunja numeric task ID.
|
||||
|
||||
Paginates through the project's tasks to handle projects with more
|
||||
than 50 tasks.
|
||||
than 50 tasks. Returns None if the task is not found.
|
||||
"""
|
||||
page = 1
|
||||
while True:
|
||||
@@ -81,13 +81,7 @@ def resolve_task_id(client: VikunjaClient, task_id: str) -> int:
|
||||
if len(tasks) < DEFAULT_PER_PAGE:
|
||||
break
|
||||
page += 1
|
||||
raise click.ClickException(
|
||||
_(
|
||||
"Could not find Vikunja task for {task_id} in project {project_id}.",
|
||||
task_id=task_id,
|
||||
project_id=VIKUNJA_PROJECT_ID,
|
||||
)
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def build_comment(task_id: str, conv_msg: str, commit_sha: str) -> str:
|
||||
@@ -162,7 +156,17 @@ def main(commit_msg: str | None, commit_sha: str, from_git: bool, git_sha: str)
|
||||
client = VikunjaClient(VIKUNJA_API_URL, token)
|
||||
vikunja_task_id = 0
|
||||
try:
|
||||
vikunja_task_id = resolve_task_id(client, task_id)
|
||||
vikunja_task_id = resolve_task_id(client, task_id) or 0
|
||||
if not vikunja_task_id:
|
||||
click.echo(
|
||||
_(
|
||||
"Warning: Could not find Vikunja task {task_id} in project {project_id}. "
|
||||
"The merge succeeded — please update the Vikunja task manually.",
|
||||
task_id=task_id,
|
||||
project_id=VIKUNJA_PROJECT_ID,
|
||||
)
|
||||
)
|
||||
return
|
||||
conv_msg = extract_conventional_msg(commit_msg)
|
||||
sha = commit_sha or "unknown"
|
||||
html = build_comment(task_id, conv_msg, sha)
|
||||
|
||||
@@ -50,6 +50,7 @@ def _ensure_label_via_tea(tea: TeaCLI, repo: str, name: str, color: str, descrip
|
||||
"""Create a label via tea if it doesn't already exist.
|
||||
|
||||
Returns True if created, False if it already existed.
|
||||
Falls back to GiteaClient if tea is not installed or fails.
|
||||
"""
|
||||
try:
|
||||
existing = tea.list_labels(repo)
|
||||
@@ -57,8 +58,8 @@ def _ensure_label_via_tea(tea: TeaCLI, repo: str, name: str, color: str, descrip
|
||||
return False
|
||||
tea.create_label(repo, name=name, color=color, description=description)
|
||||
return True
|
||||
except TeaCLIError:
|
||||
# Fall back to GiteaClient if tea fails
|
||||
except (TeaCLIError, FileNotFoundError):
|
||||
# Fall back to GiteaClient if tea is not installed or fails
|
||||
return _ensure_label_via_client(name, color, description)
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ DEFAULT_PER_PAGE = 50
|
||||
|
||||
BRANCH_PROTECTION_CONFIG: dict[str, object] = {
|
||||
"branch_name": "master",
|
||||
"enable_push": False,
|
||||
"enable_push": True,
|
||||
"enable_push_whitelist": True,
|
||||
"push_whitelist_usernames": ["emil"],
|
||||
"enable_status_check": True,
|
||||
"status_check_contexts": [
|
||||
"CI / quality (pull_request)",
|
||||
|
||||
@@ -46,7 +46,9 @@ class TestConfigConstants:
|
||||
|
||||
def test_branch_protection_config(self) -> None:
|
||||
assert BRANCH_PROTECTION_CONFIG["branch_name"] == "master"
|
||||
assert BRANCH_PROTECTION_CONFIG["enable_push"] is False
|
||||
assert BRANCH_PROTECTION_CONFIG["enable_push"] is True
|
||||
assert BRANCH_PROTECTION_CONFIG["enable_push_whitelist"] is True
|
||||
assert "emil" in BRANCH_PROTECTION_CONFIG["push_whitelist_usernames"]
|
||||
assert BRANCH_PROTECTION_CONFIG["required_approvals"] == 0
|
||||
contexts = BRANCH_PROTECTION_CONFIG["status_check_contexts"]
|
||||
assert isinstance(contexts, list)
|
||||
|
||||
@@ -62,6 +62,15 @@ class TestEnsureLabelViaTea:
|
||||
assert result is True
|
||||
mock_fallback.assert_called_once_with("ready-to-merge", "2ecc71", "desc")
|
||||
|
||||
def test_tea_not_installed_falls_back_to_client(self) -> None:
|
||||
"""When tea CLI is not installed (FileNotFoundError), fall back to GiteaClient."""
|
||||
mock_tea = MagicMock()
|
||||
mock_tea.list_labels.side_effect = FileNotFoundError("[Errno 2] No such file or directory: 'tea'")
|
||||
with patch("scripts.configure_repo._ensure_label_via_client", return_value=True) as mock_fallback:
|
||||
result = _ensure_label_via_tea(mock_tea, "owner/repo", "ready-to-merge", "2ecc71", "desc")
|
||||
assert result is True
|
||||
mock_fallback.assert_called_once_with("ready-to-merge", "2ecc71", "desc")
|
||||
|
||||
|
||||
class TestEnsureLabelViaClient:
|
||||
@patch.dict("os.environ", {"REPO_TOKEN": "tok"}, clear=True)
|
||||
|
||||
@@ -58,12 +58,10 @@ class TestResolveTaskId:
|
||||
assert resolve_task_id(mock_client, "GRM-19") == 42
|
||||
mock_client.list_project_tasks.assert_called_once()
|
||||
|
||||
def test_not_found_raises(self) -> None:
|
||||
def test_not_found_returns_none(self) -> None:
|
||||
mock_client = MagicMock()
|
||||
mock_client.list_project_tasks.return_value = []
|
||||
with pytest.raises(click.ClickException) as exc:
|
||||
resolve_task_id(mock_client, "GRM-99")
|
||||
assert "Could not find" in str(exc.value)
|
||||
assert resolve_task_id(mock_client, "GRM-99") is None
|
||||
|
||||
def test_found_on_second_page(self) -> None:
|
||||
"""Task is on page 2 when project has more than 50 tasks."""
|
||||
@@ -79,9 +77,7 @@ class TestResolveTaskId:
|
||||
mock_client = MagicMock()
|
||||
page1 = [{"id": i, "identifier": f"GRM-{i}"} for i in range(10)]
|
||||
mock_client.list_project_tasks.return_value = page1
|
||||
with pytest.raises(click.ClickException) as exc:
|
||||
resolve_task_id(mock_client, "GRM-99")
|
||||
assert "Could not find" in str(exc.value)
|
||||
assert resolve_task_id(mock_client, "GRM-99") is None
|
||||
assert mock_client.list_project_tasks.call_count == 1
|
||||
|
||||
def test_http_error_propagates(self) -> None:
|
||||
@@ -168,14 +164,16 @@ class TestMain:
|
||||
|
||||
@patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"})
|
||||
@patch("scripts.ci.post_merge.VikunjaClient")
|
||||
def test_resolve_failure_propagates(self, mock_client_cls: MagicMock) -> None:
|
||||
def test_resolve_failure_warns(self, mock_client_cls: MagicMock) -> None:
|
||||
"""Missing Vikunja task should warn, not fail — the merge already succeeded."""
|
||||
mock_client = MagicMock()
|
||||
mock_client.list_project_tasks.return_value = []
|
||||
mock_client_cls.return_value = mock_client
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["GRM-20: fix: bug"])
|
||||
assert result.exit_code == 1
|
||||
assert result.exit_code == 0
|
||||
assert "Could not find" in result.output
|
||||
assert "Warning" in result.output
|
||||
|
||||
@patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"})
|
||||
@patch("scripts.ci.post_merge.VikunjaClient")
|
||||
|
||||
Reference in New Issue
Block a user