summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim OLeary <jim.oleary@gmail.com>2020-04-29 19:00:37 +0100
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-05-05 21:07:44 +0000
commit0684c1761e399146a3a1760162d017d747bc3d3e (patch)
tree67ef028fb2a1f34ff334d129251e48888fad9a22
parent8602f5f7b69d2ae71ed7a50acfc779ac57eba107 (diff)
downloadmongo-0684c1761e399146a3a1760162d017d747bc3d3e.tar.gz
SERVER-45949 Update validate commit message client to work with new patch description standard
(cherry picked from commit 09b9e9316877084501db453d08510345465a6770)
-rw-r--r--buildscripts/tests/test_validate_commit_message.py58
-rwxr-xr-xbuildscripts/validate_commit_message.py78
2 files changed, 109 insertions, 27 deletions
diff --git a/buildscripts/tests/test_validate_commit_message.py b/buildscripts/tests/test_validate_commit_message.py
index 1cfd37a1d0c..0539776fd71 100644
--- a/buildscripts/tests/test_validate_commit_message.py
+++ b/buildscripts/tests/test_validate_commit_message.py
@@ -1,5 +1,5 @@
"""Unit tests for the evergreen_task_timeout script."""
-
+import itertools
import unittest
from mock import MagicMock, patch
@@ -8,11 +8,11 @@ from buildscripts.validate_commit_message import main, STATUS_OK, STATUS_ERROR,
# pylint: disable=missing-docstring,no-self-use
INVALID_MESSAGES = [
- [""], # You must provide a message
- ["RevertEVG-1"], # revert and ticket must be formatted
- ["revert EVG-1"], # revert must be capitalized
- ["This is not a valid message"], # message must be valid
- ["Fix lint plus extras is not a valid message"], # Fix lint is strict
+ "", # You must provide a message
+ "RevertEVG-1", # revert and ticket must be formatted
+ "revert EVG-1", # revert must be capitalized
+ "This is not a valid message", # message must be valid
+ "Fix Lint", # Fix lint is strict in terms of caps
]
NS = "buildscripts.validate_commit_message"
@@ -23,33 +23,49 @@ def ns(relative_name): # pylint: disable=invalid-name
return NS + "." + relative_name
+def interleave_new_format(older):
+ """Create a new list containing a new and old format copy of each string."""
+ newer = [
+ f"Commit Queue Merge: '{old}' into 'mongodb/mongo:SERVER-45949-validate-message-format'"
+ for old in older
+ ]
+ return list(itertools.chain(*zip(older, newer)))
+
+
class ValidateCommitMessageTest(unittest.TestCase):
def test_valid(self):
messages = [
- ["Fix lint"],
- ["EVG-1"], # Test valid projects with various number lengths
- ["SERVER-20"],
- ["WT-300"],
- ["SERVER-44338"],
- ["Revert EVG-5"],
- ["Revert SERVER-60"],
- ["Revert WT-700"],
- ["Revert 'SERVER-8000"],
- ['Revert "SERVER-90000'],
- ["Import wiredtiger: 58115abb6fbb3c1cc7bfd087d41a47347bce9a69 from branch mongodb-4.4"],
- ["Import tools: 58115abb6fbb3c1cc7bfd087d41a47347bce9a69 from branch mongodb-4.4"]
+ "Fix lint",
+ "EVG-1", # Test valid projects with various number lengths
+ "SERVER-20",
+ "WT-300",
+ "SERVER-44338",
+ "Revert EVG-5",
+ "Revert SERVER-60",
+ "Revert WT-700",
+ "Revert 'SERVER-8000",
+ 'Revert "SERVER-90000',
+ "Import wiredtiger: 58115abb6fbb3c1cc7bfd087d41a47347bce9a69 from branch mongodb-4.4",
+ "Import tools: 58115abb6fbb3c1cc7bfd087d41a47347bce9a69 from branch mongodb-4.4"
]
- self.assertTrue(all(main(message) == STATUS_OK for message in messages))
+ self.assertTrue(
+ all(main([message]) == STATUS_OK for message in interleave_new_format(messages)))
def test_private(self):
self.assertEqual(main(["XYZ-1"]), STATUS_ERROR)
def test_catch_all(self):
- self.assertTrue(all(main(message) == STATUS_ERROR for message in INVALID_MESSAGES))
+ self.assertTrue(
+ all(
+ main([message]) == STATUS_ERROR
+ for message in interleave_new_format(INVALID_MESSAGES)))
def test_ignore_warnings(self):
- self.assertTrue(all(main(["-i"] + message) == STATUS_OK for message in INVALID_MESSAGES))
+ self.assertTrue(
+ all(
+ main(["-i"] + [message]) == STATUS_OK
+ for message in interleave_new_format(INVALID_MESSAGES)))
def test_last_git_commit_success(self):
with patch(
diff --git a/buildscripts/validate_commit_message.py b/buildscripts/validate_commit_message.py
index 03283b9d940..e9e186dd25c 100755
--- a/buildscripts/validate_commit_message.py
+++ b/buildscripts/validate_commit_message.py
@@ -33,12 +33,26 @@ import re
import subprocess
import sys
-VALID_PATTERNS = [
- re.compile(r"^Fix lint$"), # Allow "Fix lint" as the sole commit summary
- re.compile(r'^(Revert ["\']?)?(EVG|SERVER|WT)-[0-9]+'), # These are public tickets
- re.compile(r'^Import (wiredtiger|tools):'), # These are public tickets
-]
-PRIVATE_PATTERNS = [re.compile(r"^[A-Z]+-[0-9]+")]
+COMMON_PUBLIC_PATTERN = r'''
+ ((?P<revert>Revert)\s+[\"\']?)? # Revert (optional)
+ ((?P<ticket>(?:EVG|SERVER|WT)-[0-9]+)[\"\']?\s*) # ticket identifier
+ (?P<body>(?:(?!\(cherry\spicked\sfrom).)*)? # To also capture the body
+ (?P<backport>\(cherry\spicked\sfrom.*)? # back port (optional)
+ '''
+"""Common Public pattern format."""
+
+COMMON_LINT_PATTERN = r'(?P<lint>Fix\slint)'
+"""Common Lint pattern format."""
+
+COMMON_IMPORT_PATTERN = r'(?P<imported>Import\s(wiredtiger|tools):\s.*)'
+"""Common Import pattern format."""
+
+COMMON_PRIVATE_PATTERN = r'''
+ ((?P<revert>Revert)\s+[\"\']?)? # Revert (optional)
+ ((?P<ticket>[A-Z]+-[0-9]+)[\"\']?\s*) # ticket identifier
+ (?P<body>(?:(?!('\s(into\s'(([^/]+))/(([^:]+)):(([^']+))'))).)*)? # To also capture the body
+'''
+"""Common Private pattern format."""
STATUS_OK = 0
STATUS_ERROR = 1
@@ -46,6 +60,58 @@ STATUS_ERROR = 1
GIT_SHOW_COMMAND = ["git", "show", "-1", "-s", "--format=%s"]
+def new_patch_description(pattern: str) -> str:
+ """
+ Wrap the pattern to conform to the new commit queue patch description format.
+
+ Add the commit queue prefix and suffix to the pattern. The format looks like:
+
+ Commit Queue Merge: '<commit message>' into '<owner>/<repo>:<branch>'
+
+ :param pattern: The pattern to wrap.
+ :return: A pattern to match the new format for the patch description.
+ """
+ return (r"""^((?P<commitqueue>Commit\sQueue\sMerge:)\s')"""
+ f'{pattern}'
+ # r"""('\s(?P<into>into\s'((?P<owner>[^/]+))/((?P<repo>[^:]+)):((?P<branch>[^']+))'))"""
+ )
+
+
+def old_patch_description(pattern: str) -> str:
+ """
+ Wrap the pattern to conform to the new commit queue patch description format.
+
+ Just add a start anchor. The format looks like:
+
+ <commit message>
+
+ :param pattern: The pattern to wrap.
+ :return: A pattern to match the old format for the patch description.
+ """
+ return r'^' f'{pattern}'
+
+
+# NOTE: re.VERBOSE is for visibility / debugging. As such significant white space must be
+# escaped (e.g ' ' to \s).
+VALID_PATTERNS = [
+ re.compile(new_patch_description(COMMON_PUBLIC_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+ re.compile(old_patch_description(COMMON_PUBLIC_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+ re.compile(new_patch_description(COMMON_LINT_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+ re.compile(old_patch_description(COMMON_LINT_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+ re.compile(new_patch_description(COMMON_IMPORT_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+ re.compile(old_patch_description(COMMON_IMPORT_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+]
+"""valid public patterns."""
+
+PRIVATE_PATTERNS = [
+ re.compile(
+ new_patch_description(COMMON_PRIVATE_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+ re.compile(
+ old_patch_description(COMMON_PRIVATE_PATTERN), re.MULTILINE | re.DOTALL | re.VERBOSE),
+]
+"""private patterns."""
+
+
def main(argv=None):
"""Execute Main function to validate commit messages."""
parser = argparse.ArgumentParser(