2121repo = Repo ("." )
2222
2323# Regex patterns
24- PREFIX_RE = re .compile (r"^([a-z0-9_]+:)\s+\S" , re .IGNORECASE )
24+ #
25+ # Allow test-specific prefixes such as:
26+ # - tests: internal:
27+ # - tests: runtime:
28+ # - tests: integration:
29+ #
30+ # These are normalized back to tests: for path-based validation.
31+ PREFIX_RE = re .compile (
32+ r"^((?:tests:\s+(?:internal|runtime|integration):)|[a-z0-9_]+:)\s+\S" ,
33+ re .IGNORECASE ,
34+ )
2535SIGNED_OFF_RE = re .compile (r"Signed-off-by:" , re .IGNORECASE )
2636FENCED_BLOCK_RE = re .compile (
2737 r"""
@@ -40,6 +50,19 @@ def strip_fenced_code_blocks(text: str) -> str:
4050 return FENCED_BLOCK_RE .sub ("" , text )
4151
4252
53+ def normalize_subject_prefix (prefix : str ) -> str :
54+ """
55+ Map accepted subject-prefix variants to the canonical prefix used by
56+ path-based validation.
57+ """
58+ lowered = prefix .lower ()
59+
60+ if lowered in ("tests: internal:" , "tests: runtime:" , "tests: integration:" ):
61+ return "tests:"
62+
63+ return lowered
64+
65+
4366# ------------------------------------------------
4467# Identify expected prefixes dynamically from file paths
4568# ------------------------------------------------
@@ -231,6 +254,7 @@ def is_version_bump(commit):
231254 return False , f"Missing prefix in commit subject: '{ first_line } '"
232255
233256 subject_prefix = subject_prefix_match .group (1 )
257+ normalized_subject_prefix = normalize_subject_prefix (subject_prefix )
234258
235259 # Run squash detection (but ignore multi-signoff errors)
236260 bad_squash , reason = detect_bad_squash (body )
@@ -281,7 +305,7 @@ def is_version_bump(commit):
281305 return True , ""
282306
283307 expected_lower = {p .lower () for p in expected }
284- subj_lower = subject_prefix . lower ()
308+ subj_lower = normalized_subject_prefix
285309
286310
287311 # ------------------------------------------------
0 commit comments