Skip to content

Commit ab08cdc

Browse files
zamjEvergreen Agent
authored andcommitted
SERVER-55279: Commit queue message validation got tricked by merging multiple commits
1 parent 987dfec commit ab08cdc

File tree

5 files changed

+64
-51
lines changed

5 files changed

+64
-51
lines changed

buildscripts/tests/test_validate_commit_message.py

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""Unit tests for the evergreen_task_timeout script."""
22
import itertools
33
import unittest
4+
from typing import List
45
from mock import MagicMock, patch
56

6-
from buildscripts.validate_commit_message import main, STATUS_OK, STATUS_ERROR, GIT_SHOW_COMMAND
7+
import evergreen
8+
9+
from buildscripts.validate_commit_message import main, STATUS_OK, STATUS_ERROR
710

811
# pylint: disable=missing-docstring,no-self-use
912

@@ -23,6 +26,18 @@ def ns(relative_name): # pylint: disable=invalid-name
2326
return NS + "." + relative_name
2427

2528

29+
def create_mock_evg_client(code_change_messages: List[str]) -> MagicMock:
30+
mock_code_change = MagicMock()
31+
mock_code_change.commit_messages = code_change_messages
32+
33+
mock_patch = MagicMock()
34+
mock_patch.module_code_changes = [mock_code_change]
35+
36+
mock_evg_client = MagicMock()
37+
mock_evg_client.patch_by_id.return_value = mock_patch
38+
return mock_evg_client
39+
40+
2641
def interleave_new_format(older):
2742
"""Create a new list containing a new and old format copy of each string."""
2843
newer = [
@@ -33,7 +48,8 @@ def interleave_new_format(older):
3348

3449

3550
class ValidateCommitMessageTest(unittest.TestCase):
36-
def test_valid(self):
51+
@patch.object(evergreen.RetryingEvergreenApi, "get_api")
52+
def test_valid_commits(self, get_api_mock):
3753
messages = [
3854
"Fix lint",
3955
"EVG-1", # Test valid projects with various number lengths
@@ -48,22 +64,28 @@ def test_valid(self):
4864
"Import wiredtiger: 58115abb6fbb3c1cc7bfd087d41a47347bce9a69 from branch mongodb-4.4",
4965
"Import tools: 58115abb6fbb3c1cc7bfd087d41a47347bce9a69 from branch mongodb-4.4"
5066
]
67+
api_mock = create_mock_evg_client(interleave_new_format(messages))
68+
69+
get_api_mock.return_value = api_mock
70+
self.assertTrue(main(["fake_version"]) == STATUS_OK)
5171

52-
self.assertTrue(
53-
all(main([message]) == STATUS_OK for message in interleave_new_format(messages)))
72+
@patch.object(evergreen.RetryingEvergreenApi, "get_api")
73+
def test_private(self, get_api_mock):
74+
messages = ["XYZ-1"]
75+
api_mock = create_mock_evg_client(interleave_new_format(messages))
5476

55-
def test_private(self):
56-
self.assertEqual(main(["XYZ-1"]), STATUS_ERROR)
77+
get_api_mock.return_value = api_mock
78+
self.assertTrue(main(["fake_version"]) == STATUS_ERROR)
5779

58-
def test_catch_all(self):
59-
self.assertTrue(
60-
all(
61-
main([message]) == STATUS_ERROR
62-
for message in interleave_new_format(INVALID_MESSAGES)))
80+
@patch.object(evergreen.RetryingEvergreenApi, "get_api")
81+
def test_private_with_public(self, get_api_mock):
82+
messages = [
83+
"Fix lint",
84+
"EVG-1", # Test valid projects with various number lengths
85+
"SERVER-20",
86+
"XYZ-1"
87+
]
88+
api_mock = create_mock_evg_client(interleave_new_format(messages))
6389

64-
def test_last_git_commit_success(self):
65-
with patch(
66-
ns("subprocess.check_output"),
67-
return_value=bytearray('SERVER-1111 this is a test', 'utf-8')) as check_output_mock:
68-
self.assertEqual(main([]), 0)
69-
check_output_mock.assert_called_with(GIT_SHOW_COMMAND)
90+
get_api_mock.return_value = api_mock
91+
self.assertTrue(main(["fake_version"]) == STATUS_ERROR)

buildscripts/validate_commit_message.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@
2828
#
2929
"""Validate that the commit message is ok."""
3030
import argparse
31-
import os
3231
import re
33-
import subprocess
3432
import sys
3533
import logging
34+
from evergreen import RetryingEvergreenApi
3635

36+
EVG_CONFIG_FILE = "./.evergreen.yml"
3737
LOGGER = logging.getLogger(__name__)
3838

3939
COMMON_PUBLIC_PATTERN = r'''
@@ -121,29 +121,28 @@ def main(argv=None):
121121
usage="Validate the commit message. "
122122
"It validates the latest message when no arguments are provided.")
123123
parser.add_argument(
124-
"message",
125-
metavar="commit message",
126-
nargs="*",
127-
help="The commit message to validate",
124+
"version_id",
125+
metavar="version id",
126+
help="The id of the version to validate",
128127
)
129128
args = parser.parse_args(argv)
130-
131-
if not args.message:
132-
print('Validating last git commit message')
133-
result = subprocess.check_output(GIT_SHOW_COMMAND)
134-
message = result.decode('utf-8')
135-
else:
136-
message = " ".join(args.message)
137-
138-
if any(valid_pattern.match(message) for valid_pattern in VALID_PATTERNS):
139-
return STATUS_OK
140-
else:
141-
if any(private_pattern.match(message) for private_pattern in PRIVATE_PATTERNS):
142-
error_type = "Found a reference to a private project"
143-
else:
144-
error_type = "Found a commit without a ticket"
145-
LOGGER.error(f"{error_type}\n{message}") # pylint: disable=logging-fstring-interpolation
146-
return STATUS_ERROR
129+
evg_api = RetryingEvergreenApi.get_api(config_file=EVG_CONFIG_FILE)
130+
131+
code_changes = evg_api.patch_by_id(args.version_id).module_code_changes
132+
133+
for change in code_changes:
134+
for message in change.commit_messages:
135+
if any(valid_pattern.match(message) for valid_pattern in VALID_PATTERNS):
136+
continue
137+
elif any(private_pattern.match(message) for private_pattern in PRIVATE_PATTERNS):
138+
error_type = "Found a reference to a private project"
139+
else:
140+
error_type = "Found a commit without a ticket"
141+
if error_type:
142+
LOGGER.error(f"{error_type}\n{message}") # pylint: disable=logging-fstring-interpolation
143+
return STATUS_ERROR
144+
145+
return STATUS_OK
147146

148147

149148
if __name__ == "__main__":

etc/evergreen.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6910,6 +6910,7 @@ tasks:
69106910
- *kill_processes
69116911
- *cleanup_environment
69126912
- func: "set up venv"
6913+
- func: "configure evergreen api credentials"
69136914
- command: subprocess.exec
69146915
type: test
69156916
params:

etc/pip/components/resmoke.req

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
curatorbin == 1.2.1
22
PyKMIP == 0.4.0 # It's now 0.8.0. We're far enough back to have API conflicts.
3-
evergreen.py == 3.1.0
3+
evergreen.py == 3.2.0
44
jinja2
55
MarkupSafe == 1.1.0 # See SERVER-57036, this is a transitive dependency of jinja2
66
mock

evergreen/commit_message_validate.sh

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,6 @@ cd src
66
set -o verbose
77
set -o errexit
88
if [ "${is_commit_queue}" = "true" ]; then
9-
# Since `commit_message` is an evergreen expansion, we need a way to ensure we
10-
# properly deal with any special characters that could cause issues (like "). To
11-
# do this, we will write it out to a file, then read that file into a variable.
12-
cat > commit_message.txt << END_OF_COMMIT_MSG
13-
${commit_message}
14-
END_OF_COMMIT_MSG
15-
16-
commit_message_content=$(cat commit_message.txt)
17-
189
activate_venv
19-
$python buildscripts/validate_commit_message.py "$commit_message_content"
10+
$python buildscripts/validate_commit_message.py ${version_id}
2011
fi

0 commit comments

Comments
 (0)