Skip to content

Commit 8f1b0a5

Browse files
committed
feat(format): added scopes argument to specify valid scopes
Closes: #101
1 parent d2f40e2 commit 8f1b0a5

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

conventional_pre_commit/format.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import re
2+
from typing import List, Optional
23

34
CONVENTIONAL_TYPES = ["feat", "fix"]
45
DEFAULT_TYPES = [
@@ -26,11 +27,23 @@ def r_types(types):
2627
return "|".join(types)
2728

2829

29-
def r_scope(optional=True):
30+
def r_scope(optional=True, scopes: Optional[List[str]] = None):
3031
"""Regex str for an optional (scope)."""
32+
3133
if optional:
34+
if scopes:
35+
scopes_str = r_types(scopes)
36+
# delims_str = r_types([":", ",", "-"])
37+
escaped_delimiters = list(map(re.escape, [":", ","])) # type: ignore
38+
delimiters_pattern = r_types(escaped_delimiters)
39+
return rf"\(\s*(?:{scopes_str})(?:\s*(?:{delimiters_pattern})\s*(?:{scopes_str}))*\s*\)"
3240
return r"(\([\w \/:,-]+\))?"
3341
else:
42+
if scopes:
43+
scopes_str = r_types(scopes)
44+
escaped_delimiters = list(map(re.escape, [":", ","])) # type: ignore
45+
delimiters_pattern = r_types(escaped_delimiters)
46+
return rf"\(\s*(?:{scopes_str})(?:\s*(?:{delimiters_pattern})\s*(?:{scopes_str}))*\s*\)"
3447
return r"(\([\w \/:,-]+\))"
3548

3649

@@ -79,7 +92,7 @@ def conventional_types(types=[]):
7992
return types
8093

8194

82-
def is_conventional(input, types=DEFAULT_TYPES, optional_scope=True):
95+
def is_conventional(input, types=DEFAULT_TYPES, optional_scope=True, scopes: Optional[list[str]] = None):
8396
"""
8497
Returns True if input matches Conventional Commits formatting
8598
https://www.conventionalcommits.org
@@ -89,7 +102,7 @@ def is_conventional(input, types=DEFAULT_TYPES, optional_scope=True):
89102
input = strip_verbose_diff(input)
90103
input = strip_comments(input)
91104
types = conventional_types(types)
92-
pattern = f"^({r_types(types)}){r_scope(optional_scope)}{r_delim()}{r_subject()}{r_body()}"
105+
pattern = f"^({r_types(types)}){r_scope(optional_scope, scopes=scopes)}{r_delim()}{r_subject()}{r_body()}"
93106
regex = re.compile(pattern, re.MULTILINE)
94107

95108
result = regex.match(input)

conventional_pre_commit/hook.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def main(argv=[]):
2828
action="store_true",
2929
help="Force commit to strictly follow Conventional Commits formatting. Disallows fixup! style commits.",
3030
)
31+
parser.add_argument("scopes", type=str, nargs="*", default=None, help="Optional list of scopes to support")
3132

3233
if len(argv) < 1:
3334
argv = sys.argv[1:]
@@ -56,7 +57,7 @@ def main(argv=[]):
5657
if format.has_autosquash_prefix(message):
5758
return RESULT_SUCCESS
5859

59-
if format.is_conventional(message, args.types, args.optional_scope):
60+
if format.is_conventional(message, args.types, args.optional_scope, args.scopes):
6061
return RESULT_SUCCESS
6162
else:
6263
print(

tests/test_format.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ def test_r_scope__special_chars():
6464
assert regex.match("(some,thing)")
6565

6666

67+
def test_r_scope__scopes():
68+
scopes_input = ["api", "client"]
69+
result = format.r_scope(scopes=scopes_input)
70+
regex = re.compile(result)
71+
assert regex.match("(api)")
72+
assert regex.match("(client)")
73+
assert regex.match("(api, client)")
74+
assert regex.match("(api: client)")
75+
assert not regex.match("(test)")
76+
assert not regex.match("(api; client)")
77+
78+
6779
def test_r_delim():
6880
result = format.r_delim()
6981
regex = re.compile(result)

0 commit comments

Comments
 (0)