Skip to content

Commit cd6d19f

Browse files
authored
[ci][tvmbot] Fix authorization filtering (#12310)
There was a level of unwrapping missing in the check for who is allowed to trigger re-runs causing it to always fail. This also uses a different actions API endpoint to re-run only failed GitHub jobs. This also fixes the text fixtures to match the GitHub API response, also tested live in driazati#34. Co-authored-by: driazati <driazati@users.noreply.github.com>
1 parent 22ba659 commit cd6d19f

File tree

2 files changed

+66
-36
lines changed

2 files changed

+66
-36
lines changed

tests/python/ci/test_tvmbot.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def test_tvmbot(tmpdir_factory, number, filename, expected, comment, user, detai
164164
"login": user,
165165
},
166166
}
167-
collaborators = ["abc"]
167+
allowed_users = [{"login": "abc"}]
168168

169169
proc = subprocess.run(
170170
[
@@ -177,9 +177,9 @@ def test_tvmbot(tmpdir_factory, number, filename, expected, comment, user, detai
177177
"--testing-pr-json",
178178
json.dumps(test_data),
179179
"--testing-collaborators-json",
180-
json.dumps(collaborators),
180+
json.dumps(allowed_users),
181181
"--testing-mentionable-users-json",
182-
json.dumps(collaborators),
182+
json.dumps(allowed_users),
183183
"--trigger-comment-json",
184184
json.dumps(comment),
185185
],

tests/scripts/github_tvmbot.py

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import logging
2424
import traceback
2525
import re
26-
from typing import Dict, Any, List, Optional, Callable
26+
from typing import Dict, Any, List, Optional, Callable, Union
2727
from pathlib import Path
2828

2929
from 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

599621
AUTH_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

655685
if __name__ == "__main__":

0 commit comments

Comments
 (0)