Skip to content

Commit 846698f

Browse files
author
Georgios Patsiaouras
committed
feat(scope): Added support for non optional scope
By using the argument --force-scope the presense of scope in the commit message is enforced, meaning that the commit should always have a scope.
1 parent 0319903 commit 846698f

File tree

7 files changed

+51
-8
lines changed

7 files changed

+51
-8
lines changed

conventional_pre_commit/format.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ def r_types(types):
2121
return "|".join(types)
2222

2323

24-
def r_scope():
24+
def r_scope(optional=True):
2525
"""Regex str for an optional (scope)."""
26-
return r"(\([\w \/:-]+\))?"
26+
if optional:
27+
return r"(\([\w \/:-]+\))?"
28+
else:
29+
return r"(\([\w \/:-]+\))"
2730

2831

2932
def r_delim():
@@ -43,15 +46,15 @@ def conventional_types(types=[]):
4346
return types
4447

4548

46-
def is_conventional(input, types=DEFAULT_TYPES):
49+
def is_conventional(input, types=DEFAULT_TYPES, optional_scope=True):
4750
"""
4851
Returns True if input matches Conventional Commits formatting
4952
https://www.conventionalcommits.org
5053
5154
Optionally provide a list of additional custom types.
5255
"""
5356
types = conventional_types(types)
54-
pattern = f"^({r_types(types)}){r_scope()}{r_delim()}{r_subject()}$"
57+
pattern = f"^({r_types(types)}){r_scope(optional_scope)}{r_delim()}{r_subject()}$"
5558
regex = re.compile(pattern, re.DOTALL)
5659

5760
return bool(regex.match(input))

conventional_pre_commit/hook.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ def main(argv=[]):
2020
)
2121
parser.add_argument("types", type=str, nargs="*", default=format.DEFAULT_TYPES, help="Optional list of types to support")
2222
parser.add_argument("input", type=str, help="A file containing a git commit message")
23+
parser.add_argument(
24+
"--force-scope", action="store_false", default=True, dest="optional_scope", help="Force commit to have scope defined."
25+
)
2326

2427
if len(argv) < 1:
2528
argv = sys.argv[1:]
@@ -44,7 +47,7 @@ def main(argv=[]):
4447
)
4548
return RESULT_FAIL
4649

47-
if format.is_conventional(message, args.types):
50+
if format.is_conventional(message, args.types, args.optional_scope):
4851
return RESULT_SUCCESS
4952
else:
5053
print(
@@ -66,7 +69,7 @@ def main(argv=[]):
6669
6770
fix: remove infinite loop
6871
69-
{Colors.YELLOW}Optionally, include a scope in parentheses after the type for more context:{Colors.RESTORE}
72+
{Colors.YELLOW}Example commit with scope in parentheses after the type for more context:{Colors.RESTORE}
7073
7174
fix(account): remove infinite loop"""
7275
)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "conventional_pre_commit"
3-
version = "2.2.0"
3+
version = "2.3.0"
44
description = "A pre-commit hook that checks commit messages for Conventional Commits formatting."
55
readme = "README.md"
66
license = { file = "LICENSE" }

tests/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ def conventional_commit_path():
1919
return get_message_path("conventional_commit")
2020

2121

22+
@pytest.fixture
23+
def conventional_commit_with_scope_path():
24+
return get_message_path("conventional_commit_with_scope")
25+
26+
2227
@pytest.fixture
2328
def custom_commit_path():
2429
return get_message_path("custom_commit")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
feat(scope): message

tests/test_format.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from conventional_pre_commit import format
66

7-
87
CUSTOM_TYPES = ["one", "two"]
98

109

@@ -23,6 +22,14 @@ def test_r_scope__optional():
2322
assert regex.match("")
2423

2524

25+
def test_r_scope__not_optional():
26+
result = format.r_scope(optional=False)
27+
regex = re.compile(result)
28+
29+
# Assert not optional anymore
30+
assert not regex.match("")
31+
32+
2633
def test_r_scope__parenthesis_required():
2734
result = format.r_scope()
2835
regex = re.compile(result)
@@ -187,6 +194,18 @@ def test_is_conventional__scope_space():
187194
assert not format.is_conventional(input)
188195

189196

197+
def test_is_conventional__scope_not_optional():
198+
input = "feat: message"
199+
200+
assert not format.is_conventional(input, optional_scope=False)
201+
202+
203+
def test_is_conventional__scope_not_optional_empty_parenthesis():
204+
input = "feat(): message"
205+
206+
assert not format.is_conventional(input, optional_scope=False)
207+
208+
190209
def test_is_conventional__missing_delimiter():
191210
input = "feat message"
192211

tests/test_hook.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,15 @@ def test_main_fail__conventional_gbk(conventional_gbk_commit_path):
9292
result = main([conventional_gbk_commit_path])
9393

9494
assert result == RESULT_FAIL
95+
96+
97+
def test_main_fail__conventional_with_scope(cmd, conventional_commit_path):
98+
result = subprocess.call((cmd, "--force-scope", conventional_commit_path))
99+
100+
assert result == RESULT_FAIL
101+
102+
103+
def test_main_success__conventional_with_scope(cmd, conventional_commit_with_scope_path):
104+
result = subprocess.call((cmd, "--force-scope", conventional_commit_with_scope_path))
105+
106+
assert result == RESULT_SUCCESS

0 commit comments

Comments
 (0)