"""Regression tests for empty Gitea Actions wrappers and merge validation fallback.""" from __future__ import annotations import pytest from packages.connector_kit import GiteaError, PageRequest from tests.test_gitea_connector import connector, context def _force_empty_actions_wrapper(connector_instance) -> None: original_request = connector_instance.client._request actions_runs_path = connector_instance.client._path("repos", "acme", "hub", "actions", "runs") def request(path, *args, **kwargs): if path == actions_runs_path: return {"workflow_runs": []} return original_request(path, *args, **kwargs) connector_instance.client._request = request def _add_validated_head_branch(fixture) -> None: fixture._branches.append( {"name": "codex/workflows", "commit": {"id": "e" * 40}, "protected": False} ) def test_empty_actions_wrapper_uses_green_exact_head_status_evidence() -> None: connector_instance, fixture = connector() _add_validated_head_branch(fixture) _force_empty_actions_wrapper(connector_instance) try: result = connector_instance.validation_list( context(), "hub-repository", "codex/workflows", page=PageRequest(limit=10), )["data"]["items"] assert len(result) == 1 assert result[0]["id"] == 0 assert result[0]["status"] == "completed" assert result[0]["conclusion"] == "success" assert result[0]["headSha"] == "e" * 40 finally: connector_instance.client.close() def test_merge_uses_status_linked_run_when_actions_wrapper_is_empty() -> None: connector_instance, fixture = connector() _add_validated_head_branch(fixture) _force_empty_actions_wrapper(connector_instance) try: merged = connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" )["data"] assert merged["validationRunId"] == 42 assert fixture._pulls[0]["merged"] is True finally: connector_instance.client.close() def test_merge_accepts_exact_head_managed_run_when_gitea_omits_workflow_id() -> None: connector_instance, fixture = connector() _add_validated_head_branch(fixture) fixture._action_run.pop("workflow_id") try: review = connector_instance.change_review(context(), "hub-repository", "codex/workflows")[ "data" ] assert review["readyToMerge"] is True assert review["validationRuns"][0]["id"] > 0 assert review["validationRuns"][0]["workflowId"] == "" merged = connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" )["data"] assert merged["merged"] is True assert merged["validationRunId"] > 0 assert fixture._pulls[0]["merged"] is True finally: connector_instance.client.close() def test_green_workflow_dispatch_cannot_authorize_pr_merge() -> None: connector_instance, fixture = connector() fixture._action_run["event"] = "workflow_dispatch" try: with pytest.raises(GiteaError) as captured: connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" ) assert captured.value.code == "GITEA_PR_VALIDATION_REQUIRED" assert fixture._pulls[0].get("merged") is not True finally: connector_instance.client.close() def test_green_pr_run_for_old_sha_cannot_authorize_merge() -> None: connector_instance, fixture = connector() fixture._action_run["head_sha"] = "d" * 40 try: with pytest.raises(GiteaError) as captured: connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" ) assert captured.value.code == "GITEA_PR_VALIDATION_REQUIRED" assert fixture._pulls[0].get("merged") is not True finally: connector_instance.client.close() def test_green_pr_run_with_pending_required_context_cannot_authorize_merge() -> None: connector_instance, fixture = connector() fixture._statuses[0]["status"] = "pending" try: with pytest.raises(GiteaError) as captured: connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" ) assert captured.value.code == "GITEA_PR_CHECK_PENDING" assert fixture._pulls[0].get("merged") is not True finally: connector_instance.client.close() def test_status_linked_pr_run_without_workflow_id_requires_green_full_job() -> None: connector_instance, fixture = connector() fixture._action_run.pop("workflow_id") fixture._action_job["conclusion"] = "failure" try: with pytest.raises(GiteaError) as captured: connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" ) assert captured.value.code == "GITEA_PR_VALIDATION_REQUIRED" assert fixture._pulls[0].get("merged") is not True finally: connector_instance.client.close() def test_empty_actions_wrapper_fails_closed_when_latest_status_is_pending() -> None: connector_instance, fixture = connector() _add_validated_head_branch(fixture) fixture._statuses[0]["status"] = "pending" _force_empty_actions_wrapper(connector_instance) try: validation_items = connector_instance.validation_list( context(), "hub-repository", "codex/workflows", page=PageRequest(limit=10), )["data"]["items"] assert validation_items == [] with pytest.raises(GiteaError, match="status is not successful"): connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" ) assert fixture._pulls[0].get("merged") is not True assert not any(body.get("Do") == "squash" for body in fixture.recorded_bodies) finally: connector_instance.client.close() def test_merge_reports_pending_readiness_instead_of_unsupported_capability() -> None: connector_instance, _ = connector() writer = connector_instance._writer() def reject_pending(*args, **kwargs): raise GiteaError( "GITEA_STATE_TRANSITION_DENIED", "Gitea rejected the requested state transition", ) writer.merge_pull_request = reject_pending try: with pytest.raises(GiteaError) as captured: connector_instance.pull_request_merge( context(), "hub-repository", 7, "e" * 40, "squash" ) assert captured.value.code == "GITEA_UPSTREAM_MERGE_REJECTED" assert "after eligibility verification" in str(captured.value) assert "unsupported" not in str(captured.value).casefold() finally: connector_instance.client.close()