import datetime import io import json import os import tempfile import unittest from werkrevisor import protection ARGS = ["https://git.example.org/mi/werkator", "main", "--contexts", "werkator,ai-review/gate", "--approvers", "ai-reviewer,mi"] class FakeProtectionClient: def __init__(self, existing=None): self.existing = existing self.saved = [] def get_protection(self, branch): return self.existing def save_protection(self, branch, fields, exists): self.saved.append((branch, fields, exists)) def run(client, *extra): out = io.StringIO() cwd = os.getcwd() with tempfile.TemporaryDirectory() as tmp: os.chdir(tmp) try: code = protection.main(ARGS + list(extra), {}, out, client, lambda: datetime.datetime(2026, 10, 6, 9, 0, 0)) files = {name: json.load(open(name)) for name in os.listdir(tmp)} finally: os.chdir(cwd) return code, out.getvalue(), files class BranchProtectionTest(unittest.TestCase): def test_existing_rule_is_saved_first_and_its_contexts_stay(self): existing = {"rule_name": "main", "enable_status_check": True, "status_check_contexts": ["werkator", "lint"], "required_approvals": 0} client = FakeProtectionClient(existing) code, out, files = run(client) self.assertEqual(code, 0) self.assertEqual(files, {"branch-protection-mi-werkator-main-20261006-090000.json": existing}) branch, fields, exists = client.saved[0] self.assertEqual((branch, exists), ("main", True)) self.assertEqual(fields["status_check_contexts"], ["werkator", "lint", "ai-review/gate"]) self.assertEqual((fields["required_approvals"], fields["approvals_whitelist_username"]), (1, ["ai-reviewer", "mi"])) self.assertNotIn("block_admin_merge_override", fields) self.assertIn('required_approvals: 0 -> 1', out) def test_missing_rule_is_created(self): client = FakeProtectionClient(None) run(client, "--block-admin-override") branch, fields, exists = client.saved[0] self.assertEqual((fields["rule_name"], exists, fields["block_admin_merge_override"]), ("main", False, True)) def test_dry_run_and_unchanged_rule_write_nothing(self): client = FakeProtectionClient({"status_check_contexts": []}) code, out, files = run(client, "--dry-run") self.assertEqual((code, client.saved, files), (0, [], {})) self.assertIn("dry run: nothing written", out) done = protection.wanted({"status_check_contexts": ["werkator", "ai-review/gate"]}, "main", ["werkator", "ai-review/gate"], ["ai-reviewer", "mi"], False) client = FakeProtectionClient(done) code, out, files = run(client) self.assertEqual((client.saved, files, out), ([], {}, "branch protection is already as wanted\n")) if __name__ == "__main__": unittest.main()