Skip to content

Commit f0e28cb

Browse files
IamXanderMongoDB Bot
authored and
MongoDB Bot
committed
SERVER-101443 Get PR title/description feedback on push (#32907)
GitOrigin-RevId: 8488bf74340cf02347d551f9bc3ecbcec51f2391
1 parent 71bf33a commit f0e28cb

File tree

3 files changed

+152
-24
lines changed

3 files changed

+152
-24
lines changed

Diff for: buildscripts/tests/test_validate_commit_message.py

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
"""Unit tests for the evergreen_task_timeout script."""
22

33
import unittest
4+
from unittest.mock import patch
45

56
from git import Commit, Repo
67

7-
from buildscripts.validate_commit_message import is_valid_commit
8+
from buildscripts.validate_commit_message import (
9+
get_non_merge_queue_squashed_commits,
10+
is_valid_commit,
11+
)
812

913

1014
class ValidateCommitMessageTest(unittest.TestCase):
@@ -68,3 +72,28 @@ def test_invalid(self):
6872
]
6973

7074
self.assertTrue(all(not is_valid_commit(message) for message in messages))
75+
76+
@patch("requests.post")
77+
def test_squashed_commit(self, mock_request):
78+
class FakeResponse:
79+
def json(self):
80+
return {
81+
"data": {
82+
"repository": {
83+
"pullRequest": {
84+
"viewerMergeHeadlineText": "SERVER-1234 Add a ton of great support (#32823)",
85+
"viewerMergeBodyText": "This PR adds back support for a lot of things\nMany great things!",
86+
}
87+
}
88+
}
89+
}
90+
91+
mock_request.return_value = FakeResponse()
92+
commits = get_non_merge_queue_squashed_commits(
93+
github_org="fun_org", github_repo="fun_repo", pr_number=1024, github_token="fun_token"
94+
)
95+
self.assertEqual(len(commits), 1)
96+
self.assertEqual(
97+
commits[0].message,
98+
"SERVER-1234 Add a ton of great support (#32823)\nThis PR adds back support for a lot of things\nMany great things!",
99+
)

Diff for: buildscripts/validate_commit_message.py

+106-22
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import re
3333
import subprocess
3434

35+
import requests
3536
import structlog
3637
import typer
3738
from git import Commit, Repo
@@ -65,7 +66,10 @@ def is_valid_commit(commit: Commit) -> bool:
6566
# 4. Revert "Import wiredtiger
6667
if not VALID_SUMMARY.match(commit.summary):
6768
LOGGER.error(
68-
"Commit did not contain a valid summary",
69+
f"""Commit did not contain a valid summary.
70+
Please update the PR title and description to match the following regular expressions {VALID_SUMMARY}.
71+
If you are seeing this on a PR, after changing the title/description you will need to rerun this check before being able to submit your PR.
72+
The decision to add this check was made in SERVER-101443, please feel free to leave comments/feedback on that ticket.""",
6973
commit_hexsha=commit.hexsha,
7074
commit_summary=commit.summary,
7175
)
@@ -77,7 +81,10 @@ def is_valid_commit(commit: Commit) -> bool:
7781
for banned_string in BANNED_STRINGS:
7882
if "".join(banned_string.split()) in stripped_message:
7983
LOGGER.error(
80-
"Commit contains banned string (ignoring whitespace)",
84+
"""Commit contains banned string (ignoring whitespace).
85+
Please update the PR title and description to not contain the following banned string.
86+
If you are seeing this on a PR, after changing the title/description you will need to rerun this check before being able to submit your PR.
87+
The decision to add this check was made in SERVER-101443, please feel free to leave comments/feedback on that ticket.""",
8188
banned_string=banned_string,
8289
commit_hexsha=commit.hexsha,
8390
commit_message=commit.message,
@@ -87,16 +94,98 @@ def is_valid_commit(commit: Commit) -> bool:
8794
return True
8895

8996

97+
def get_non_merge_queue_squashed_commits(
98+
github_org: str,
99+
github_repo: str,
100+
pr_number: int,
101+
github_token: str,
102+
) -> list[Commit]:
103+
assert github_org
104+
assert github_repo
105+
assert pr_number >= 0
106+
assert github_token
107+
108+
pr_merge_info_query = {
109+
"query": f"""{{
110+
repository(owner: "{github_org}", name: "{github_repo}") {{
111+
pullRequest(number: {pr_number}) {{
112+
viewerMergeHeadlineText(mergeType: SQUASH)
113+
viewerMergeBodyText(mergeType: SQUASH)
114+
}}
115+
}}
116+
}}"""
117+
}
118+
headers = {"Authorization": f"token {github_token}"}
119+
120+
LOGGER.info("Sending request", request=pr_merge_info_query)
121+
req = requests.post(
122+
url="https://api.github.com/graphql",
123+
json=pr_merge_info_query,
124+
headers=headers,
125+
timeout=60, # 60s
126+
)
127+
resp = req.json()
128+
# Response will look like
129+
# {'data': {'repository': {'pullRequest':
130+
# {
131+
# 'viewerMergeHeadlineText': 'SERVER-1234 Add a ton of great support (#32823)',
132+
# 'viewerMergeBodyText': 'This PR adds back support for a lot of things\nMany great things!'
133+
# }}}}
134+
LOGGER.info("Squashed content", content=resp)
135+
pr_info = resp["data"]["repository"]["pullRequest"]
136+
fake_repo = Repo()
137+
return [
138+
Commit(
139+
repo=fake_repo,
140+
binsha=b"00000000000000000000",
141+
message="\n".join([pr_info["viewerMergeHeadlineText"], pr_info["viewerMergeBodyText"]]),
142+
)
143+
]
144+
145+
146+
def get_merge_queue_commits(branch_name: str) -> list[Commit]:
147+
assert branch_name
148+
149+
diff_commits = subprocess.run(
150+
["git", "log", '--pretty=format:"%H"', f"{branch_name}...HEAD"],
151+
check=True,
152+
capture_output=True,
153+
text=True,
154+
)
155+
# Comes back like "hash1"\n"hash2"\n...
156+
commit_hashs: list[str] = diff_commits.stdout.replace('"', "").splitlines()
157+
LOGGER.info("Diff commit hashes", commit_hashs=commit_hashs)
158+
repo = Repo(repo_root)
159+
160+
return [repo.commit(commit_hash) for commit_hash in commit_hashs]
161+
162+
90163
def main(
164+
github_org: Annotated[
165+
str,
166+
typer.Option(envvar="GITHUB_ORG", help="Name of the github organization (e.g. 10gen)"),
167+
] = "",
168+
github_repo: Annotated[
169+
str,
170+
typer.Option(envvar="GITHUB_REPO", help="Name of the repo (e.g. mongo)"),
171+
] = "",
91172
branch_name: Annotated[
92173
str,
93174
typer.Option(envvar="BRANCH_NAME", help="Name of the branch to compare against HEAD"),
94-
],
95-
is_commit_queue: Annotated[
175+
] = "",
176+
pr_number: Annotated[
177+
int,
178+
typer.Option(envvar="PR_NUMBER", help="PR Number to compare with"),
179+
] = -1,
180+
github_token: Annotated[
181+
str,
182+
typer.Option(envvar="GITHUB_TOKEN", help="Github token with pr read access"),
183+
] = "",
184+
requester: Annotated[
96185
str,
97186
typer.Option(
98-
envvar="IS_COMMIT_QUEUE",
99-
help="If this is being run in the commit/merge queue. Set to anything to be considered part of the commit/merge queue.",
187+
envvar="REQUESTER",
188+
help="What is requested this task. Defined https://docs.devprod.prod.corp.mongodb.com/evergreen/Project-Configuration/Project-Configuration-Files#expansions.",
100189
),
101190
] = "",
102191
):
@@ -106,23 +195,18 @@ def main(
106195
It validates the latest message when no arguments are provided.
107196
"""
108197

109-
if not is_commit_queue:
110-
LOGGER.info("Exiting early since this is not running in the commit/merge queue")
111-
raise typer.Exit(code=STATUS_OK)
112-
113-
diff_commits = subprocess.run(
114-
["git", "log", '--pretty=format:"%H"', f"{branch_name}...HEAD"],
115-
check=True,
116-
capture_output=True,
117-
text=True,
118-
)
119-
# Comes back like "hash1"\n"hash2"\n...
120-
commit_hashs: list[str] = diff_commits.stdout.replace('"', "").splitlines()
121-
LOGGER.info("Diff commit hashes", commit_hashs=commit_hashs)
122-
repo = Repo(repo_root)
198+
commits: list[Commit] = []
199+
if requester == "github_merge_queue":
200+
commits = get_merge_queue_commits(branch_name)
201+
elif requester == "github_pr":
202+
commits = get_non_merge_queue_squashed_commits(
203+
github_org, github_repo, pr_number, github_token
204+
)
205+
else:
206+
LOGGER.error("Running with an invalid requester", requester=requester)
207+
raise typer.Exit(code=STATUS_ERROR)
123208

124-
for commit_hash in commit_hashs:
125-
commit = repo.commit(commit_hash)
209+
for commit in commits:
126210
if not is_valid_commit(commit):
127211
LOGGER.error("Found an invalid commit", commit=commit)
128212
raise typer.Exit(code=STATUS_ERROR)

Diff for: etc/evergreen_yml_components/tasks/misc_tasks.yml

+16-1
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,7 @@ tasks:
15161516
docker_password: ${dockerhub_password}
15171517

15181518
- name: validate_commit_message
1519+
allowed_requesters: ["github_merge_queue", "github_pr"]
15191520
tags:
15201521
[
15211522
"assigned_to_jira_team_devprod_correctness",
@@ -1532,10 +1533,20 @@ tasks:
15321533
- func: "upload pip requirements"
15331534
- func: "configure evergreen api credentials"
15341535
- func: "f_expansions_write"
1536+
- command: github.generate_token
1537+
params:
1538+
owner: ${github_org}
1539+
repo: ${github_repo}
1540+
expansion_name: github_token
1541+
permissions:
1542+
pull_requests: read
1543+
metadata: read
15351544
- command: subprocess.exec
15361545
type: test
15371546
params:
15381547
binary: bash
1548+
include_expansions_in_env:
1549+
- github_token
15391550
args:
15401551
- "./src/evergreen/run_python_script_with_report.sh"
15411552
- "validate_commit_message"
@@ -1545,8 +1556,12 @@ tasks:
15451556
JIRA_AUTH_ACCESS_TOKEN_SECRET: ${jira_auth_access_token_secret}
15461557
JIRA_AUTH_CONSUMER_KEY: ${jira_auth_consumer_key}
15471558
JIRA_AUTH_KEY_CERT: ${jira_auth_key_cert}
1548-
IS_COMMIT_QUEUE: ${is_commit_queue}
1559+
REQUESTER: ${requester}
15491560
BRANCH_NAME: ${branch_name}
1561+
PR_NUMBER: ${github_pr_number}
1562+
GITHUB_ORG: ${github_org}
1563+
GITHUB_REPO: ${github_repo}
1564+
GITHUB_TOKEN: ${github_token}
15501565

15511566
- name: version_burn_in_gen
15521567
run_on: ubuntu2004-medium

0 commit comments

Comments
 (0)