返回 CodeWhale
test_check_coauthor_trailers.py
根目录 / scripts / test_check_coauthor_trailers.py
1 #!/usr/bin/env python3
2 """Regression tests for scripts/check-coauthor-trailers.py."""
3
4 from __future__ import annotations
5
6 import importlib.util
7 import sys
8 import unittest
9 from pathlib import Path
10
11 ROOT = Path(__file__).resolve().parents[1]
12 SCRIPT = ROOT / "scripts" / "check-coauthor-trailers.py"
13 AUTHOR_MAP = ROOT / ".github" / "AUTHOR_MAP"
14 FIXTURES = Path(__file__).resolve().parent / "fixtures" / "coauthor-trailers"
15
16 SPEC = importlib.util.spec_from_file_location("check_coauthor_trailers", SCRIPT)
17 assert SPEC and SPEC.loader
18 mod = importlib.util.module_from_spec(SPEC)
19 sys.modules[SPEC.name] = mod
20 SPEC.loader.exec_module(mod)
21
22
23 def commit(subject: str, body: str, *, harvested: bool = False) -> mod.Commit:
24 if harvested and "Harvested from PR" not in body:
25 body = f"{body}\n\nHarvested from PR #1 by @contributor"
26 return mod.Commit(
27 sha="deadbeef" * 5,
28 parents="",
29 author_name="Maintainer",
30 author_email="1+maintainer@users.noreply.github.com",
31 subject=subject,
32 body=body,
33 )
34
35
36 class CheckCoauthorTrailersTests(unittest.TestCase):
37 @classmethod
38 def setUpClass(cls) -> None:
39 cls.aliases = mod.load_author_map(AUTHOR_MAP)
40
41 def test_rejects_cursor_trailer_on_non_harvested_commit(self) -> None:
42 body = (FIXTURES / "cursor-non-harvested.txt").read_text(encoding="utf-8")
43 errors = mod.validate([commit("direct change", body)], self.aliases, False)
44 self.assertTrue(errors)
45 self.assertIn("cursoragent@cursor.com", errors[0])
46
47 def test_rejects_cursor_trailer_on_harvested_commit(self) -> None:
48 body = (FIXTURES / "cursor-harvested.txt").read_text(encoding="utf-8")
49 errors = mod.validate([commit("harvested change", body, harvested=True)], self.aliases, False)
50 self.assertTrue(errors)
51
52 def test_allows_human_canonical_trailer(self) -> None:
53 body = (FIXTURES / "human-canonical.txt").read_text(encoding="utf-8")
54 errors = mod.validate([commit("human credit", body)], self.aliases, False)
55 self.assertEqual(errors, [])
56
57 def test_allows_merge_commit_with_bot_trailer(self) -> None:
58 merge = mod.Commit(
59 sha="cafebabe" * 5,
60 parents="aaa bbb",
61 author_name="Maintainer",
62 author_email="1+maintainer@users.noreply.github.com",
63 subject="Merge branch",
64 body="Co-authored-by: Cursor <cursoragent@cursor.com>",
65 )
66 errors = mod.validate([merge], self.aliases, False)
67 self.assertEqual(errors, [])
68
69 def test_allows_only_the_exact_immutable_automation_trailer(self) -> None:
70 legacy = mod.Commit(
71 sha="9a74825cd182a62465943bcbbcbcf591d1ce99ee",
72 parents="parent",
73 author_name="Maintainer",
74 author_email="1+maintainer@users.noreply.github.com",
75 subject="legacy automation commit",
76 body="Co-authored-by: CodeWhale Agent <codewhale-agent@hmbown.local>",
77 )
78 errors = mod.validate([legacy], self.aliases, False)
79 self.assertEqual(errors, [])
80
81 other_commit = mod.Commit(
82 sha="deadbeef" * 5,
83 parents=legacy.parents,
84 author_name=legacy.author_name,
85 author_email=legacy.author_email,
86 subject=legacy.subject,
87 body=legacy.body,
88 )
89 errors = mod.validate([other_commit], self.aliases, False)
90 self.assertTrue(errors)
91 self.assertIn("codewhale-agent@hmbown.local", errors[0])
92
93 def test_legacy_exception_does_not_hide_another_bad_trailer(self) -> None:
94 legacy_with_extra = mod.Commit(
95 sha="9a74825cd182a62465943bcbbcbcf591d1ce99ee",
96 parents="parent",
97 author_name="Maintainer",
98 author_email="1+maintainer@users.noreply.github.com",
99 subject="legacy automation commit",
100 body=(
101 "Co-authored-by: CodeWhale Agent <codewhale-agent@hmbown.local>\n"
102 "Co-authored-by: Unknown Person <unknown@example.com>"
103 ),
104 )
105 errors = mod.validate([legacy_with_extra], self.aliases, False)
106 self.assertEqual(len(errors), 1)
107 self.assertIn("unknown@example.com", errors[0])
108
109 def test_preserved_hunter_credit_resolves_only_for_exact_commit(self) -> None:
110 preserved = mod.Commit(
111 sha="5087269606fc8847487b0a8b51ef6adffa8eb2ca",
112 parents="parent",
113 author_name="Hunter B",
114 author_email="hmbown@gmail.com",
115 subject="docs(public): refresh v0.9.1 product truth",
116 body=(
117 "Harvested from PR #4508 by @Hmbown.\n\n"
118 "Co-authored-by: Hunter Bown <hmbown@gmail.com>"
119 ),
120 )
121 errors = mod.validate([preserved], self.aliases, True)
122 self.assertEqual(errors, [])
123
124 rewritten = mod.Commit(
125 sha="deadbeef" * 5,
126 parents=preserved.parents,
127 author_name=preserved.author_name,
128 author_email=preserved.author_email,
129 subject=preserved.subject,
130 body=preserved.body,
131 )
132 errors = mod.validate([rewritten], self.aliases, True)
133 self.assertTrue(errors)
134 self.assertTrue(any("not GitHub-mappable" in error for error in errors))
135
136 def test_preserved_web_credit_resolves_without_rewriting_commit(self) -> None:
137 preserved = mod.Commit(
138 sha="e37df06caeb3064b2bb9263c1c98a903738f3a0a",
139 parents="parent",
140 author_name="Hunter B",
141 author_email="hmbown@gmail.com",
142 subject="docs(web): make the homepage product first",
143 body="Co-authored-by: Hunter Bown <hmbown@gmail.com>",
144 )
145 errors = mod.validate([preserved], self.aliases, True)
146 self.assertEqual(errors, [])
147
148 def test_preserved_fleitz_credit_resolves_only_for_exact_commit(self) -> None:
149 preserved = mod.Commit(
150 sha="6d0ebc881a8bd2469c45b25f2a606fa63681e112",
151 parents="parent",
152 author_name="Fred Leitz",
153 author_email="fred.leitz@gmail.com",
154 subject="fix(shell): default no-cwd shell commands to context.workspace",
155 body="Co-authored-by: fleitz <fleitzo@gmail.com>",
156 )
157 errors = mod.validate([preserved], self.aliases, True)
158 self.assertEqual(errors, [])
159
160 changed_identity = mod.Commit(
161 sha=preserved.sha,
162 parents=preserved.parents,
163 author_name=preserved.author_name,
164 author_email=preserved.author_email,
165 subject=preserved.subject,
166 body="Co-authored-by: fleitz <different@example.com>",
167 )
168 errors = mod.validate([changed_identity], self.aliases, True)
169 self.assertTrue(errors)
170 self.assertTrue(any("different@example.com" in error for error in errors))
171
172 def test_preserved_telecom_harvest_author_resolves_only_for_exact_commit(self) -> None:
173 preserved = mod.Commit(
174 sha="338138eb546bcf8917b27395325f59af0d2e4f52",
175 parents="parent",
176 author_name="Hunter B",
177 author_email="hmbown@gmail.com",
178 subject="feat(provider): add TelecomJS live catalog",
179 body=(
180 "Harvested from PR #4370 by @baendlorel.\n\n"
181 "Co-authored-by: baendlorel "
182 "<50111870+baendlorel@users.noreply.github.com>"
183 ),
184 )
185 errors = mod.validate([preserved], self.aliases, True)
186 self.assertEqual(errors, [])
187
188 rewritten = mod.Commit(
189 sha="deadbeef" * 5,
190 parents=preserved.parents,
191 author_name=preserved.author_name,
192 author_email=preserved.author_email,
193 subject=preserved.subject,
194 body=preserved.body,
195 )
196 errors = mod.validate([rewritten], self.aliases, True)
197 self.assertTrue(errors)
198 self.assertTrue(any("not canonical" in error for error in errors))
199
200
201 if __name__ == "__main__":
202 raise SystemExit(unittest.main())
203
203 lines PYTHON