import unittest from tests.fakes import BOT, HEAD, pr_ref from tests.test_hints_hold_merge import hint_run from tests.test_line_comments import app_gitea from werkrevisor import cli, report from werkrevisor.config import GateConfig GATE = GateConfig(human_reviewers=("alice",), automerge=True) def resolve_all(gitea): for comments in gitea.line_comments.values(): for c in comments: c["resolver"] = {"login": "claude-code"} def release(gitea): return cli.release_held_merge(GATE, pr_ref(), gitea, BOT) class ReleaseHeldMergeTest(unittest.TestCase): def test_the_last_resolved_line_comment_releases_the_merge(self): """Scenario#135.01""" gitea = app_gitea() gitea.requested = ["alice"] hint_run(gitea) self.assertIn(report.HELD_MARKER, gitea.comments[0]["body"]) resolve_all(gitea) note = release(gitea) self.assertEqual(len(gitea.scheduled_merges), 1) self.assertEqual(gitea.withdrawn, ["alice"]) self.assertEqual(note, "merge scheduled for when the checks succeed; review request of alice withdrawn") self.assertIn(cli.release_marker(HEAD), gitea.created_comments[-1]) self.assertIn(f"every line comment for `{HEAD}` is resolved", gitea.created_comments[-1]) def test_a_release_happens_once_per_head(self): gitea = app_gitea() hint_run(gitea) resolve_all(gitea) release(gitea) comments = len(gitea.created_comments) self.assertEqual(release(gitea), "") self.assertEqual((len(gitea.scheduled_merges), len(gitea.created_comments)), (1, comments)) def test_an_open_line_comment_still_holds_the_merge(self): """Scenario#135.02""" gitea = app_gitea() gitea.requested = ["alice"] hint_run(gitea) self.assertEqual(release(gitea), "") self.assertEqual((gitea.scheduled_merges, gitea.withdrawn), ([], [])) def test_no_release_without_the_approval_of_werkrevisor_for_the_head(self): """Scenario#135.03""" gitea = app_gitea() hint_run(gitea) resolve_all(gitea) gitea.reviews = [{**r, "dismissed": True} for r in gitea.reviews] self.assertEqual(release(gitea), "") self.assertEqual(gitea.scheduled_merges, []) def test_a_hint_only_in_the_result_comment_is_not_released(self): """Scenario#135.03""" gitea = app_gitea() hint_run(gitea, start=0) self.assertNotIn(report.HELD_MARKER, gitea.comments[0]["body"]) self.assertEqual(release(gitea), "") self.assertEqual(gitea.scheduled_merges, []) def test_a_merge_that_was_never_held_is_not_scheduled(self): gitea = app_gitea() hint_run(gitea, automerge=False) resolve_all(gitea) self.assertEqual(release(gitea), "") self.assertEqual(gitea.scheduled_merges, []) def test_a_new_head_waits_for_its_own_review(self): gitea = app_gitea() hint_run(gitea) resolve_all(gitea) gitea.heads = ["e" * 40] self.assertEqual(release(gitea), "") self.assertEqual(gitea.scheduled_merges, []) def test_a_restart_with_open_line_comments_marks_its_comment_as_held(self): gitea = app_gitea() hint_run(gitea, start=0) # The restart releases the hint in the result comment; a line comment of an earlier head still holds. gitea.reviews.append({"id": 7, "state": "COMMENT", "commit_id": "c" * 40, "user": {"login": BOT}}) gitea.line_comments[7] = [{"id": 77, "user": {"login": BOT}, "path": "app.py", "position": 2, "resolver": None, "body": "**[low] Naming** (werkrevisor)", "html_url": "x"}] hint_run(gitea, start=0) self.assertIn(report.HELD_MARKER, gitea.created_comments[-1]) resolve_all(gitea) self.assertIn("merge scheduled", release(gitea)) def test_a_failed_scheduling_is_tried_again_by_the_next_run(self): gitea = app_gitea() hint_run(gitea) resolve_all(gitea) gitea.schedule_merge_refusals = [500] comments = len(gitea.created_comments) self.assertIn("merge not scheduled", release(gitea)) self.assertEqual(len(gitea.created_comments), comments) self.assertIn("merge scheduled", release(gitea)) def test_a_failed_withdrawal_is_tried_again_by_the_next_run(self): gitea = app_gitea() gitea.requested = ["alice"] hint_run(gitea) resolve_all(gitea) gitea.fail_review_request = True comments = len(gitea.created_comments) self.assertIn("review request of alice not withdrawn", release(gitea)) self.assertEqual(len(gitea.created_comments), comments) gitea.fail_review_request = False self.assertEqual(release(gitea), "merge already scheduled; review request of alice withdrawn") self.assertIn(cli.release_marker(HEAD), gitea.created_comments[-1]) def test_a_failed_cancel_leaves_the_release_to_a_new_review(self): from werkrevisor.gitea import GiteaError gitea = app_gitea() def refuse(number): raise GiteaError("DELETE merge failed with HTTP 403", 403) gitea.cancel_scheduled_merge = refuse outcome, gitea = hint_run(gitea) self.assertEqual(outcome.result.exit_code, 10) self.assertNotIn(report.HELD_MARKER, gitea.comments[0]["body"]) resolve_all(gitea) self.assertEqual(release(gitea), "") def test_a_hold_after_a_release_of_the_same_head_is_released_again(self): gitea = app_gitea() hint_run(gitea) resolve_all(gitea) release(gitea) for comments in gitea.line_comments.values(): comments[0]["resolver"] = None hint_run(gitea) self.assertEqual(gitea.scheduled_merges, []) self.assertIn(report.HELD_MARKER, gitea.created_comments[-1]) resolve_all(gitea) self.assertIn("merge scheduled", release(gitea)) self.assertEqual(len(gitea.scheduled_merges), 1) if __name__ == "__main__": unittest.main()