@@ -4110,6 +4110,109 @@ def test_a_missing_pygithub_warns(self):
41104110 unittest .main ()
41114111
41124112
4113+ class TestPrAuthorChecksEveryCommit (unittest .TestCase ):
4114+ """The author checks read every PR commit's author, not only the tip."""
4115+
4116+ def setUp (self ):
4117+ main .API_AUTHORS .clear ()
4118+ self .addCleanup (main .API_AUTHORS .clear )
4119+
4120+ def _run (self , commits , authors , resolves = True , message = False ):
4121+ commands : list [list [str ]] = []
4122+
4123+ def run (command , ** _kwargs ):
4124+ commands .append (command )
4125+ if command [:2 ] == ["git" , "rev-parse" ]:
4126+ return MagicMock (returncode = 0 if resolves else 1 , stdout = "" )
4127+ if command [:2 ] == ["git" , "fetch" ]:
4128+ return MagicMock (returncode = 1 , stdout = "" )
4129+ if "--message" in command :
4130+ return MagicMock (
4131+ returncode = 0 , stdout = json_output (make_check ("message" ))
4132+ )
4133+ check = command [3 ].lstrip ("-" ).replace ("-" , "_" )
4134+ sha = command [- 1 ]
4135+ status = "fail" if "noreply" in authors [sha ][1 ] else "pass"
4136+ return MagicMock (
4137+ returncode = 0 ,
4138+ stdout = json_output (make_check (check , status = status , value = sha )),
4139+ )
4140+
4141+ with (
4142+ patch ("main.MESSAGE_ENABLED" , message ),
4143+ patch ("main.BRANCH_ENABLED" , False ),
4144+ patch ("main.AUTHOR_NAME_ENABLED" , False ),
4145+ patch ("main.AUTHOR_EMAIL_ENABLED" , True ),
4146+ patch .dict (os .environ , {"GITHUB_EVENT_NAME" : "pull_request" }),
4147+ patch ("main.get_pr_commit_messages" , return_value = commits ) as listed ,
4148+ patch ("main._local_author" , side_effect = lambda sha : authors .get (sha )),
4149+ patch ("main.get_pr_head_sha" , return_value = commits [- 1 ][0 ]),
4150+ patch ("main.subprocess.run" , side_effect = run ),
4151+ patch ("sys.stdout" , io .StringIO ()),
4152+ ):
4153+ rc , results = main .run_commit_check ()
4154+ self .listed_calls = listed .call_count
4155+ return rc , results , commands
4156+
4157+ def test_the_commits_are_listed_once_for_messages_and_authors (self ):
4158+ commits = [("a1" , "feat: one" )]
4159+ _rc , results , _commands = self ._run (
4160+ commits , {"a1" : ("Dev" , "dev@example.org" )}, message = True
4161+ )
4162+ self .assertEqual (self .listed_calls , 1 )
4163+ self .assertEqual ([s .label for s in results ], ["Commit 1/1" , "Author email" ])
4164+
4165+ def test_a_commit_whose_author_cannot_be_read_is_passed_over (self ):
4166+ commits = [("a1" , "feat: one" ), ("b2" , "feat: two" )]
4167+ _rc , results , _commands = self ._run (commits , {"b2" : ("Dev" , "dev@example.org" )})
4168+ self .assertEqual ([(s .label , s .sha ) for s in results ], [("Author email" , "b2" )])
4169+
4170+ def test_an_earlier_commit_by_another_author_is_checked (self ):
4171+ """FreeBSD atf forbids noreply emails; the tip alone hid this one."""
4172+ commits = [("a1" , "feat: one" ), ("b2" , "feat: two" )]
4173+ authors = {
4174+ "a1" : ("Dev" , "dev@users.noreply.github.com" ),
4175+ "b2" : ("Dev" , "dev@example.org" ),
4176+ }
4177+ rc , results , commands = self ._run (commits , authors )
4178+ self .assertEqual (rc , 1 )
4179+ self .assertEqual (
4180+ [(s .label , s .sha , s .status ) for s in results ],
4181+ [("Author email" , "a1" , "fail" ), ("Author email" , "b2" , "pass" )],
4182+ )
4183+ self .assertIn (
4184+ ["commit-check" , "--format" , "json" , "--author-email" , "--rev" , "a1" ],
4185+ commands ,
4186+ )
4187+
4188+ def test_one_author_is_checked_once_on_the_newest_commit (self ):
4189+ commits = [("a1" , "feat: one" ), ("b2" , "feat: two" ), ("c3" , "feat: three" )]
4190+ same = ("Dev" , "dev@example.org" )
4191+ rc , results , _commands = self ._run (
4192+ commits , dict .fromkeys (("a1" , "b2" , "c3" ), same )
4193+ )
4194+ self .assertEqual (rc , 0 )
4195+ self .assertEqual ([(s .label , s .sha ) for s in results ], [("Author email" , "c3" )])
4196+
4197+ def test_an_api_listed_author_is_used (self ):
4198+ main .API_AUTHORS ["a1" ] = ("Dev" , "dev@users.noreply.github.com" )
4199+ _rc , results , _ = self ._run (
4200+ [("a1" , "feat: one" )], {"a1" : ("Dev" , "dev@users.noreply.github.com" )}
4201+ )
4202+ self .assertEqual ([(s .sha , s .status ) for s in results ], [("a1" , "fail" )])
4203+
4204+ def test_a_commit_that_cannot_be_had_falls_back_to_the_tip (self ):
4205+ """Neither in the clone nor fetchable: the tip path decides (here: skip)."""
4206+ commits = [("a1" , "feat: one" )]
4207+ _rc , results , commands = self ._run (
4208+ commits , {"a1" : ("Dev" , "dev@example.org" )}, resolves = False
4209+ )
4210+ self .assertEqual (
4211+ [(s .label , s .status ) for s in results ], [("Author email" , "skip" )]
4212+ )
4213+ self .assertFalse ([c for c in commands if c [0 ] == "commit-check" ], commands )
4214+
4215+
41134216class TestBooleanInputs (unittest .TestCase ):
41144217 """A boolean input is true or false; anything else fails the step."""
41154218
0 commit comments