|
22 | 22 | # Regex patterns |
23 | 23 | PREFIX_RE = re.compile(r"^[a-z0-9_]+:", re.IGNORECASE) |
24 | 24 | SIGNED_OFF_RE = re.compile(r"Signed-off-by:", re.IGNORECASE) |
| 25 | +FENCED_BLOCK_RE = re.compile( |
| 26 | + r""" |
| 27 | + (```|~~~) # fence start |
| 28 | + [^\n]*\n # optional language |
| 29 | + .*? |
| 30 | + \1 # matching fence end |
| 31 | + """, |
| 32 | + re.DOTALL | re.VERBOSE, |
| 33 | +) |
| 34 | + |
| 35 | +def strip_fenced_code_blocks(text: str) -> str: |
| 36 | + """ |
| 37 | + Remove fenced code blocks (``` or ~~~) from commit message body. |
| 38 | + """ |
| 39 | + return FENCED_BLOCK_RE.sub("", text) |
25 | 40 |
|
26 | 41 |
|
27 | 42 | # ------------------------------------------------ |
@@ -109,6 +124,8 @@ def detect_bad_squash(body): |
109 | 124 | - Multiple Signed-off-by lines in body → BAD (ONLY for this function) |
110 | 125 | """ |
111 | 126 |
|
| 127 | + body = strip_fenced_code_blocks(body) |
| 128 | + |
112 | 129 | # Normalize and discard empty lines |
113 | 130 | lines = [l.strip() for l in body.splitlines() if l.strip()] |
114 | 131 |
|
@@ -138,6 +155,8 @@ def validate_commit(commit): |
138 | 155 | first_line, *rest = msg.split("\n") |
139 | 156 | body = "\n".join(rest) |
140 | 157 |
|
| 158 | + body = strip_fenced_code_blocks(body) |
| 159 | + |
141 | 160 | # Subject must start with a prefix |
142 | 161 | subject_prefix_match = PREFIX_RE.match(first_line) |
143 | 162 | if not subject_prefix_match: |
@@ -216,16 +235,15 @@ def validate_commit(commit): |
216 | 235 | # prefix, check if the subject prefix is in the expected list. If it is, allow it |
217 | 236 | # (because the corresponding file exists). Only reject if it's not in the expected list |
218 | 237 | # or if it's an umbrella prefix that doesn't match. |
219 | | - if len(non_build_prefixes) > 1 and subj_lower not in umbrella_prefixes: |
220 | | - # If subject prefix is in expected list, it's valid (the corresponding file exists) |
221 | | - if subj_lower not in expected_lower: |
| 238 | + if len(non_build_prefixes) > 1: |
| 239 | + # Only umbrella prefixes are allowed to cover multiple components |
| 240 | + if subj_lower not in umbrella_prefixes: |
222 | 241 | expected_list = sorted(expected) |
223 | 242 | expected_str = ", ".join(expected_list) |
224 | 243 | return False, ( |
225 | 244 | f"Subject prefix '{subject_prefix}' does not match files changed.\n" |
226 | 245 | f"Expected one of: {expected_str}" |
227 | 246 | ) |
228 | | - # Subject prefix is in expected list, so it's valid - no need to check further |
229 | 247 |
|
230 | 248 | # Subject prefix must be one of the expected ones |
231 | 249 | if subj_lower not in expected_lower: |
|
0 commit comments