2323import logging
2424import traceback
2525import re
26- from typing import Dict , Any , List , Optional , Callable
26+ from typing import Dict , Any , List , Optional , Callable , Union
2727from pathlib import Path
2828
2929from git_utils import git , GitHubRepo , parse_remote , post
@@ -122,6 +122,7 @@ def to_json_str(obj: Any) -> str:
122122 databaseId
123123 checkSuite {
124124 workflowRun {
125+ databaseId
125126 workflow {
126127 name
127128 }
@@ -528,37 +529,53 @@ def rerun_jenkins_ci(self) -> None:
528529 post (url , auth = ("tvm-bot" , TVM_BOT_JENKINS_TOKEN ))
529530
530531 def rerun_github_actions (self ) -> None :
531- job_ids = []
532+ workflow_ids = []
532533 for item in self .head_commit ()["statusCheckRollup" ]["contexts" ]["nodes" ]:
533- if "checkSuite" in item :
534- job_ids .append (item ["databaseId" ])
534+ if "checkSuite" in item and item ["conclusion" ] == "FAILURE" :
535+ workflow_id = item ["checkSuite" ]["workflowRun" ]["databaseId" ]
536+ workflow_ids .append (workflow_id )
535537
536- logging .info (f"Rerunning GitHub Actions jobs with IDs: { job_ids } " )
538+ workflow_ids = list (set (workflow_ids ))
539+ logging .info (f"Rerunning GitHub Actions workflows with IDs: { workflow_ids } " )
537540 actions_github = GitHubRepo (
538541 user = self .github .user , repo = self .github .repo , token = GH_ACTIONS_TOKEN
539542 )
540- for job_id in job_ids :
543+ for workflow_id in workflow_ids :
541544 if self .dry_run :
545+ logging .info (f"Dry run, not restarting workflow { workflow_id } " )
546+ else :
542547 try :
543- actions_github .post (f"actions/jobs/ { job_id } /rerun" , data = {})
548+ actions_github .post (f"actions/runs/ { workflow_id } /rerun-failed-jobs " , data = {})
544549 except RuntimeError as e :
550+ logging .exception (e )
545551 # Ignore errors about jobs that are part of the same workflow to avoid
546552 # having to figure out which jobs are in which workflows ahead of time
547553 if "The workflow run containing this job is already running" in str (e ):
548554 pass
549555 else :
550556 raise e
551- else :
552- logging .info (f"Dry run, not restarting { job_id } " )
553557
554- def comment_failure (self , msg : str , exception : Exception ):
555- if not self .dry_run :
556- exception_msg = traceback .format_exc ()
557- comment = f"{ msg } in { args .run_url } \n \n <details>\n \n ```\n { exception_msg } \n ```\n \n "
558+ def comment_failure (self , msg : str , exceptions : Union [Exception , List [Exception ]]):
559+ if not isinstance (exceptions , list ):
560+ exceptions = [exceptions ]
561+
562+ logging .info (f"Failed, commenting { exceptions } " )
563+
564+ # Extract all the traceback strings
565+ for item in exceptions :
566+ try :
567+ raise item
568+ except Exception :
569+ item .exception_msg = traceback .format_exc ()
570+
571+ comment = f"{ msg } in { args .run_url } \n \n "
572+ for exception in exceptions :
573+ comment += f"<details>\n \n ```\n { exception .exception_msg } \n ```\n \n "
558574 if hasattr (exception , "read" ):
559575 comment += f"with response\n \n ```\n { exception .read ().decode ()} \n ```\n \n "
560576 comment += "</details>"
561- pr .comment (comment )
577+
578+ pr .comment (comment )
562579 return exception
563580
564581
@@ -570,30 +587,35 @@ def check_author(pr, triggering_comment, args):
570587 return False
571588
572589
573- def check_collaborator (pr , triggering_comment , args ):
574- logging .info ("Checking collaborators" )
575- # Get the list of collaborators for the repo filtered by the comment
576- # author
590+ def search_users (name , triggering_comment , testing_json , search_fn ):
591+ logging .info (f"Checking { name } " )
577592 commment_author = triggering_comment ["user" ]["login" ]
578- if args . testing_collaborators_json :
579- collaborators = json .loads (args . testing_collaborators_json )
593+ if testing_json :
594+ matching_users = json .loads (testing_json )
580595 else :
581- collaborators = pr .search_collaborator (commment_author )
582- logging .info (f"Found collaborators: { collaborators } " )
596+ matching_users = search_fn (commment_author )
597+ logging .info (f"Found { name } : { matching_users } " )
598+ user_names = {user ["login" ] for user in matching_users }
583599
584- return len (collaborators ) > 0 and commment_author in collaborators
600+ return len (matching_users ) > 0 and commment_author in user_names
585601
586602
587- def check_mentionable_users (pr , triggering_comment , args ):
588- logging .info ("Checking mentionable users" )
589- commment_author = triggering_comment ["user" ]["login" ]
590- if args .testing_mentionable_users_json :
591- mentionable_users = json .loads (args .testing_mentionable_users_json )
592- else :
593- mentionable_users = pr .search_mentionable_users (commment_author )
594- logging .info (f"Found mentionable_users: { mentionable_users } " )
603+ def check_collaborator (pr , triggering_comment , args ):
604+ return search_users (
605+ name = "collaborators" ,
606+ triggering_comment = triggering_comment ,
607+ search_fn = pr .search_collaborator ,
608+ testing_json = args .testing_collaborators_json ,
609+ )
595610
596- return len (mentionable_users ) > 0 and commment_author in mentionable_users
611+
612+ def check_mentionable_users (pr , triggering_comment , args ):
613+ return search_users (
614+ name = "mentionable users" ,
615+ triggering_comment = triggering_comment ,
616+ search_fn = pr .search_mentionable_users ,
617+ testing_json = args .testing_mentionable_users_json ,
618+ )
597619
598620
599621AUTH_CHECKS = {
@@ -645,11 +667,19 @@ class Rerun:
645667
646668 @staticmethod
647669 def run (pr : PR ):
670+ errors = []
648671 try :
649672 pr .rerun_jenkins_ci ()
673+ except Exception as e :
674+ errors .append (e )
675+
676+ try :
650677 pr .rerun_github_actions ()
651678 except Exception as e :
652- pr .comment_failure ("Failed to re-run CI" , e )
679+ errors .append (e )
680+
681+ if len (errors ) > 0 :
682+ pr .comment_failure ("Failed to re-run CI" , errors )
653683
654684
655685if __name__ == "__main__" :
0 commit comments