@@ -4195,6 +4195,109 @@ def test_a_missing_pygithub_warns(self):
41954195 unittest .main ()
41964196
41974197
4198+ class TestPrAuthorChecksEveryCommit (unittest .TestCase ):
4199+ """The author checks read every PR commit's author, not only the tip."""
4200+
4201+ def setUp (self ):
4202+ main .API_AUTHORS .clear ()
4203+ self .addCleanup (main .API_AUTHORS .clear )
4204+
4205+ def _run (self , commits , authors , resolves = True , message = False ):
4206+ commands : list [list [str ]] = []
4207+
4208+ def run (command , ** _kwargs ):
4209+ commands .append (command )
4210+ if command [:2 ] == ["git" , "rev-parse" ]:
4211+ return MagicMock (returncode = 0 if resolves else 1 , stdout = "" )
4212+ if command [:2 ] == ["git" , "fetch" ]:
4213+ return MagicMock (returncode = 1 , stdout = "" )
4214+ if "--message" in command :
4215+ return MagicMock (
4216+ returncode = 0 , stdout = json_output (make_check ("message" ))
4217+ )
4218+ check = command [3 ].lstrip ("-" ).replace ("-" , "_" )
4219+ sha = command [- 1 ]
4220+ status = "fail" if "noreply" in authors [sha ][1 ] else "pass"
4221+ return MagicMock (
4222+ returncode = 0 ,
4223+ stdout = json_output (make_check (check , status = status , value = sha )),
4224+ )
4225+
4226+ with (
4227+ patch ("main.MESSAGE_ENABLED" , message ),
4228+ patch ("main.BRANCH_ENABLED" , False ),
4229+ patch ("main.AUTHOR_NAME_ENABLED" , False ),
4230+ patch ("main.AUTHOR_EMAIL_ENABLED" , True ),
4231+ patch .dict (os .environ , {"GITHUB_EVENT_NAME" : "pull_request" }),
4232+ patch ("main.get_pr_commit_messages" , return_value = commits ) as listed ,
4233+ patch ("main._local_author" , side_effect = lambda sha : authors .get (sha )),
4234+ patch ("main.get_pr_head_sha" , return_value = commits [- 1 ][0 ]),
4235+ patch ("main.subprocess.run" , side_effect = run ),
4236+ patch ("sys.stdout" , io .StringIO ()),
4237+ ):
4238+ rc , results = main .run_commit_check ()
4239+ self .listed_calls = listed .call_count
4240+ return rc , results , commands
4241+
4242+ def test_the_commits_are_listed_once_for_messages_and_authors (self ):
4243+ commits = [("a1" , "feat: one" )]
4244+ _rc , results , _commands = self ._run (
4245+ commits , {"a1" : ("Dev" , "dev@example.org" )}, message = True
4246+ )
4247+ self .assertEqual (self .listed_calls , 1 )
4248+ self .assertEqual ([s .label for s in results ], ["Commit 1/1" , "Author email" ])
4249+
4250+ def test_a_commit_whose_author_cannot_be_read_is_passed_over (self ):
4251+ commits = [("a1" , "feat: one" ), ("b2" , "feat: two" )]
4252+ _rc , results , _commands = self ._run (commits , {"b2" : ("Dev" , "dev@example.org" )})
4253+ self .assertEqual ([(s .label , s .sha ) for s in results ], [("Author email" , "b2" )])
4254+
4255+ def test_an_earlier_commit_by_another_author_is_checked (self ):
4256+ """FreeBSD atf forbids noreply emails; the tip alone hid this one."""
4257+ commits = [("a1" , "feat: one" ), ("b2" , "feat: two" )]
4258+ authors = {
4259+ "a1" : ("Dev" , "dev@users.noreply.github.com" ),
4260+ "b2" : ("Dev" , "dev@example.org" ),
4261+ }
4262+ rc , results , commands = self ._run (commits , authors )
4263+ self .assertEqual (rc , 1 )
4264+ self .assertEqual (
4265+ [(s .label , s .sha , s .status ) for s in results ],
4266+ [("Author email" , "a1" , "fail" ), ("Author email" , "b2" , "pass" )],
4267+ )
4268+ self .assertIn (
4269+ ["commit-check" , "--format" , "json" , "--author-email" , "--rev" , "a1" ],
4270+ commands ,
4271+ )
4272+
4273+ def test_one_author_is_checked_once_on_the_newest_commit (self ):
4274+ commits = [("a1" , "feat: one" ), ("b2" , "feat: two" ), ("c3" , "feat: three" )]
4275+ same = ("Dev" , "dev@example.org" )
4276+ rc , results , _commands = self ._run (
4277+ commits , dict .fromkeys (("a1" , "b2" , "c3" ), same )
4278+ )
4279+ self .assertEqual (rc , 0 )
4280+ self .assertEqual ([(s .label , s .sha ) for s in results ], [("Author email" , "c3" )])
4281+
4282+ def test_an_api_listed_author_is_used (self ):
4283+ main .API_AUTHORS ["a1" ] = ("Dev" , "dev@users.noreply.github.com" )
4284+ _rc , results , _ = self ._run (
4285+ [("a1" , "feat: one" )], {"a1" : ("Dev" , "dev@users.noreply.github.com" )}
4286+ )
4287+ self .assertEqual ([(s .sha , s .status ) for s in results ], [("a1" , "fail" )])
4288+
4289+ def test_a_commit_that_cannot_be_had_falls_back_to_the_tip (self ):
4290+ """Neither in the clone nor fetchable: the tip path decides (here: skip)."""
4291+ commits = [("a1" , "feat: one" )]
4292+ _rc , results , commands = self ._run (
4293+ commits , {"a1" : ("Dev" , "dev@example.org" )}, resolves = False
4294+ )
4295+ self .assertEqual (
4296+ [(s .label , s .status ) for s in results ], [("Author email" , "skip" )]
4297+ )
4298+ self .assertFalse ([c for c in commands if c [0 ] == "commit-check" ], commands )
4299+
4300+
41984301class TestBooleanInputs (unittest .TestCase ):
41994302 """A boolean input is true or false; anything else fails the step."""
42004303
0 commit comments