Skip to content

Commit 4cea29d

Browse files
authored
Merge pull request #10632 from Joe-Downs/pr/commit-checker-messages
git-commit-checks: comment on PR with error(s)
2 parents e04fbe0 + 4b0ce7e commit 4cea29d

File tree

2 files changed

+82
-27
lines changed

2 files changed

+82
-27
lines changed

.github/workflows/git-commit-checks.py

Lines changed: 76 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
variables that are available in the Github Action environment. Specifically:
99
1010
* GITHUB_WORKSPACE: directory where the git clone is located
11-
* GITHUB_SHA: the git commit SHA of the artificial Github PR test merge commit
1211
* GITHUB_BASE_REF: the git ref for the base branch
12+
* GITHUB_HEAD_REF: the git commit ref of the head branch
1313
* GITHUB_TOKEN: token authorizing Github API usage
1414
* GITHUB_REPOSITORY: "org/repo" name of the Github repository of this PR
1515
* GITHUB_REF: string that includes this Github PR number
16+
* GITHUB_RUN_ID: unique ID for each workflow run
17+
* GITHUB_SERVER_URL: the URL of the GitHub server
1618
17-
This script tests each git commit between (and not including) GITHUB_SHA and
19+
This script tests each git commit between (and not including) GITHUB_HEAD_REF and
1820
GITHUB_BASE_REF multiple ways:
1921
2022
1. Ensure that the committer and author do not match any bad patterns (e.g.,
@@ -53,19 +55,25 @@
5355
NACP = "bot:notacherrypick"
5456

5557
GITHUB_WORKSPACE = os.environ.get('GITHUB_WORKSPACE')
56-
GITHUB_SHA = os.environ.get('GITHUB_SHA')
5758
GITHUB_BASE_REF = os.environ.get('GITHUB_BASE_REF')
59+
GITHUB_HEAD_REF = os.environ.get('GITHUB_HEAD_REF')
5860
GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN')
5961
GITHUB_REPOSITORY = os.environ.get('GITHUB_REPOSITORY')
6062
GITHUB_REF = os.environ.get('GITHUB_REF')
63+
GITHUB_RUN_ID = os.environ.get('GITHUB_RUN_ID')
64+
GITHUB_SERVER_URL = os.environ.get('GITHUB_SERVER_URL')
65+
PR_NUM = os.environ.get('PR_NUM')
6166

6267
# Sanity check
6368
if (GITHUB_WORKSPACE is None or
64-
GITHUB_SHA is None or
6569
GITHUB_BASE_REF is None or
70+
GITHUB_HEAD_REF is None or
6671
GITHUB_TOKEN is None or
6772
GITHUB_REPOSITORY is None or
68-
GITHUB_REF is None):
73+
GITHUB_REF is None or
74+
GITHUB_RUN_ID is None or
75+
GITHUB_SERVER_URL is None or
76+
PR_NUM is None):
6977
print("Error: this script is designed to run as a Github Action")
7078
exit(1)
7179

@@ -85,6 +93,50 @@ def make_commit_message(repo, hash):
8593

8694
#----------------------------------------------------------------------------
8795

96+
"""
97+
Iterate through the BAD results, collect the error messages, and send a nicely
98+
formatted comment to the PR.
99+
100+
For the structure of the results dictionary, see comment for print_results()
101+
below.
102+
103+
"""
104+
def comment_on_pr(pr, results, repo):
105+
# If there are no BAD results, just return without posting a comment to the
106+
# GitHub PR.
107+
if len(results[BAD]) == 0:
108+
return
109+
110+
comment = "Hello! The Git Commit Checker CI bot found a few problems with this PR:"
111+
for hash, entry in results[BAD].items():
112+
comment += f"\n\n**{hash[:8]}: {make_commit_message(repo, hash)}**"
113+
for check_name, message in entry.items():
114+
if message is not None:
115+
comment += f"\n * *{check_name}: {message}*"
116+
comment_footer = "\n\nPlease fix these problems and, if necessary, force-push new commits back up to the PR branch. Thanks!"
117+
118+
# GitHub says that 65536 characters is the limit of comment messages, so
119+
# check if our comment is over that limit. If it is, truncate it to fit, and
120+
# add a message explaining with a link to the full error list.
121+
comment_char_limit = 65536
122+
if len(comment + comment_footer) >= comment_char_limit:
123+
run_url = f"{GITHUB_SERVER_URL}/{GITHUB_REPOSITORY}/actions/runs/{GITHUB_RUN_ID}?check_suite_focus=true"
124+
truncation_message = f"\n\n**Additional errors could not be shown...\n[Please click here for a full list of errors.]({run_url})**"
125+
# Cut the comment down so we can get the comment itself, and the new
126+
# message in.
127+
comment = comment[:(comment_char_limit - len(comment_footer + truncation_message))]
128+
# In case a newline gets split in half, remove the leftover '\' (if
129+
# there is one). (This is purely an aesthetics choice).
130+
comment = comment.rstrip("\\")
131+
comment += truncation_message
132+
133+
comment += comment_footer
134+
pr.create_issue_comment(comment)
135+
136+
return
137+
138+
#----------------------------------------------------------------------------
139+
88140
"""
89141
The results dictionary is in the following format:
90142
@@ -242,15 +294,15 @@ def _is_entirely_submodule_updates(repo, commit):
242294
#----------------------------------------------------------------------------
243295

244296
def check_all_commits(config, repo):
245-
# Get a list of commits that we'll be examining. Use the progromatic form
246-
# of "git log GITHUB_BASE_REF..GITHUB_SHA" (i.e., "git log ^GITHUB_BASE_REF
247-
# GITHUB_SHA") to do the heavy lifting to find that set of commits.
297+
# Get a list of commits that we'll be examining. Use the programmatic form
298+
# of "git log GITHUB_BASE_REF..GITHUB_HEAD_REF" (i.e., "git log
299+
# ^GITHUB_BASE_REF GITHUB_HEAD_REF") to do the heavy lifting to find that
300+
# set of commits. Because we're using pull_request_target, GITHUB_BASE_REF
301+
# is already checked out. GITHUB_HEAD_REF has never been checked out, so we
302+
# specify "origin/{GITHUB_HEAD_REF}".
248303
git_cli = git.cmd.Git(GITHUB_WORKSPACE)
249-
hashes = git_cli.log(f"--pretty=format:%h", f"origin/{GITHUB_BASE_REF}..{GITHUB_SHA}").splitlines()
250-
251-
# The first entry in the list will be the artificial Github merge commit for
252-
# this PR. We don't want to examine this commit.
253-
del hashes[0]
304+
hashes = git_cli.log(f"--pretty=format:%h",
305+
f"{GITHUB_BASE_REF}..origin/{GITHUB_HEAD_REF}").splitlines()
254306

255307
#------------------------------------------------------------------------
256308

@@ -292,15 +344,7 @@ def check_all_commits(config, repo):
292344
If "bot:notacherrypick" is in the PR description, then disable the
293345
cherry-pick message requirement.
294346
"""
295-
def check_github_pr_description(config):
296-
g = Github(GITHUB_TOKEN)
297-
repo = g.get_repo(GITHUB_REPOSITORY)
298-
299-
# Extract the PR number from GITHUB_REF
300-
match = re.search("/(\d+)/", GITHUB_REF)
301-
pr_num = int(match.group(1))
302-
pr = repo.get_pull(pr_num)
303-
347+
def check_github_pr_description(config, pr):
304348
if pr.body and NACP in pr.body:
305349
config['cherry pick required'] = False
306350

@@ -334,11 +378,17 @@ def load_config():
334378

335379
def main():
336380
config = load_config()
337-
check_github_pr_description(config)
338381

339-
repo = git.Repo(GITHUB_WORKSPACE)
340-
results, hashes = check_all_commits(config, repo)
341-
print_results(results, repo, hashes)
382+
g = Github(GITHUB_TOKEN)
383+
github_repo = g.get_repo(GITHUB_REPOSITORY)
384+
pr_num = int(PR_NUM)
385+
pr = github_repo.get_pull(pr_num)
386+
check_github_pr_description(config, pr)
387+
388+
local_repo = git.Repo(GITHUB_WORKSPACE)
389+
results, hashes = check_all_commits(config, local_repo)
390+
print_results(results, local_repo, hashes)
391+
comment_on_pr(pr, results, local_repo)
342392

343393
if len(results[BAD]) == 0:
344394
print("\nTest passed: everything was good!")

.github/workflows/git-commit-checks.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
name: GitHub Action CI
22

3+
# We're using pull_request_target here instead of just pull_request so that the
4+
# action runs in the context of the base of the pull request, rather than in the
5+
# context of the merge commit. For more detail about the differences, see:
6+
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
37
on:
4-
pull_request:
8+
pull_request_target:
59
# We don't need this to be run on all types of PR behavior
610
# See https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request
711
types:
@@ -32,3 +36,4 @@ jobs:
3236
run: $GITHUB_WORKSPACE/.github/workflows/git-commit-checks.py
3337
env:
3438
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
PR_NUM: ${{ github.event.number }}

0 commit comments

Comments
 (0)