|
5 | 5 | #
|
6 | 6 | # For more info visit https://github.com/pulp/plugin_template
|
7 | 7 |
|
| 8 | +import os |
8 | 9 | import re
|
| 10 | +import subprocess |
9 | 11 | import sys
|
| 12 | +import tomllib |
10 | 13 | from pathlib import Path
|
11 |
| -import subprocess |
12 |
| -import os |
13 |
| -import warnings |
| 14 | + |
14 | 15 | from github import Github
|
15 | 16 |
|
16 |
| -CHANGELOG_EXTS = [".feature", ".bugfix", ".doc", ".removal", ".misc", ".deprecation"] |
| 17 | +with open("pyproject.toml", "rb") as fp: |
| 18 | + PYPROJECT_TOML = tomllib.load(fp) |
17 | 19 | KEYWORDS = ["fixes", "closes"]
|
| 20 | +BLOCKING_REGEX = [ |
| 21 | + r"^DRAFT", |
| 22 | + r"^WIP", |
| 23 | + r"^NOMERGE", |
| 24 | + r"^DO\s*NOT\s*MERGE", |
| 25 | + r"^EXPERIMENT", |
| 26 | + r"^FIXUP", |
| 27 | + r"Apply suggestions from code review", |
| 28 | +] |
| 29 | +try: |
| 30 | + CHANGELOG_EXTS = [ |
| 31 | + f".{item['directory']}" for item in PYPROJECT_TOML["tool"]["towncrier"]["type"] |
| 32 | + ] |
| 33 | +except KeyError: |
| 34 | + CHANGELOG_EXTS = [".feature", ".bugfix", ".doc", ".removal", ".misc"] |
| 35 | +NOISSUE_MARKER = "[noissue]" |
18 | 36 |
|
19 | 37 | sha = sys.argv[1]
|
20 | 38 | message = subprocess.check_output(["git", "log", "--format=%B", "-n 1", sha]).decode("utf-8")
|
21 | 39 |
|
| 40 | +if NOISSUE_MARKER in message: |
| 41 | + sys.exit(f"Do not add '{NOISSUE_MARKER}' in the commit message.") |
| 42 | + |
| 43 | +if any((re.match(pattern, message, re.IGNORECASE) for pattern in BLOCKING_REGEX)): |
| 44 | + sys.exit("This PR is not ready for consumption.") |
| 45 | + |
22 | 46 | g = Github(os.environ.get("GITHUB_TOKEN"))
|
23 | 47 | repo = g.get_repo("pulp/pulpcore")
|
24 | 48 |
|
25 | 49 |
|
26 |
| -def __check_status(issue): |
| 50 | +def check_status(issue): |
27 | 51 | gi = repo.get_issue(int(issue))
|
28 | 52 | if gi.pull_request:
|
29 | 53 | sys.exit(f"Error: issue #{issue} is a pull request.")
|
30 |
| - if gi.closed_at and "cherry picked from commit" not in message: |
31 |
| - warnings.warn( |
32 |
| - "When backporting, use the -x flag to append a line that says " |
33 |
| - "'(cherry picked from commit ...)' to the original commit message." |
34 |
| - ) |
| 54 | + if gi.closed_at: |
35 | 55 | sys.exit(f"Error: issue #{issue} is closed.")
|
36 | 56 |
|
37 | 57 |
|
38 |
| -def __check_changelog(issue): |
| 58 | +def check_changelog(issue): |
39 | 59 | matches = list(Path("CHANGES").rglob(f"{issue}.*"))
|
40 | 60 |
|
41 | 61 | if len(matches) < 1:
|
42 | 62 | sys.exit(f"Could not find changelog entry in CHANGES/ for {issue}.")
|
43 | 63 | for match in matches:
|
44 | 64 | if match.suffix not in CHANGELOG_EXTS:
|
45 | 65 | sys.exit(f"Invalid extension for changelog entry '{match}'.")
|
46 |
| - if match.suffix == ".feature" and "cherry picked from commit" in message: |
47 |
| - sys.exit(f"Can not backport '{match}' as it is a feature.") |
48 | 66 |
|
49 | 67 |
|
50 | 68 | print("Checking commit message for {sha}.".format(sha=sha[0:7]))
|
51 | 69 |
|
52 | 70 | # validate the issue attached to the commit
|
53 |
| -regex = r"(?:{keywords})[\s:]+#(\d+)".format(keywords=("|").join(KEYWORDS)) |
54 |
| -pattern = re.compile(regex, re.IGNORECASE) |
55 |
| - |
56 |
| -issues = pattern.findall(message) |
| 71 | +issue_regex = r"(?:{keywords})[\s:]+#(\d+)".format(keywords=("|").join(KEYWORDS)) |
| 72 | +issues = re.findall(issue_regex, message, re.IGNORECASE) |
| 73 | +cherry_pick_regex = r"^\s*\(cherry picked from commit [0-9a-f]*\)\s*$" |
| 74 | +cherry_pick = re.search(cherry_pick_regex, message, re.MULTILINE) |
57 | 75 |
|
58 | 76 | if issues:
|
59 |
| - for issue in pattern.findall(message): |
60 |
| - __check_status(issue) |
61 |
| - __check_changelog(issue) |
| 77 | + for issue in issues: |
| 78 | + if not cherry_pick: |
| 79 | + check_status(issue) |
| 80 | + check_changelog(issue) |
62 | 81 |
|
63 | 82 | print("Commit message for {sha} passed.".format(sha=sha[0:7]))
|
0 commit comments