From 10d1e31dd07ba9cb77aa4029278193beed0d1115 Mon Sep 17 00:00:00 2001 From: ddluke Date: Wed, 8 Oct 2025 07:17:36 +0200 Subject: [PATCH 1/2] fix: scope now allows usage of dots --- conventional_pre_commit/format.py | 6 +++--- tests/conftest.py | 5 +++++ tests/messages/conventional_commit_with_dots | 1 + tests/test_format.py | 3 +++ tests/test_hook.py | 6 ++++++ 5 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 tests/messages/conventional_commit_with_dots diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py index f19f0af..414ace9 100644 --- a/conventional_pre_commit/format.py +++ b/conventional_pre_commit/format.py @@ -128,7 +128,7 @@ def r_scope(self): """Regex str for an optional (scope).""" if self.scopes: scopes = self._r_or(self.scopes) - escaped_delimiters = list(map(re.escape, [":", ",", "-", "/"])) # type: ignore + escaped_delimiters = list(map(re.escape, [":", ",", "-", "/", "."])) # type: ignore delimiters_pattern = self._r_or(escaped_delimiters) scope_pattern = rf"\(\s*(?:(?i:{scopes}))(?:\s*(?:{delimiters_pattern})\s*(?:(?i:{scopes})))*\s*\)" @@ -138,9 +138,9 @@ def r_scope(self): return scope_pattern if self.scope_optional: - return r"(\([\w \/:,-]+\))?" + return r"(\([\w \/:,-\.]+\))?" else: - return r"(\([\w \/:,-]+\))" + return r"(\([\w \/:,-\.]+\))" @property def r_delim(self): diff --git a/tests/conftest.py b/tests/conftest.py index bab7488..76bb46f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -34,6 +34,11 @@ def conventional_utf8_commit_path(): return get_message_path("conventional_commit_utf-8") +@pytest.fixture +def conventional_commit_with_dots_path(): + return get_message_path("conventional_commit_with_dots") + + @pytest.fixture def conventional_gbk_commit_path(): return get_message_path("conventional_commit_gbk") diff --git a/tests/messages/conventional_commit_with_dots b/tests/messages/conventional_commit_with_dots new file mode 100644 index 0000000..7fefad4 --- /dev/null +++ b/tests/messages/conventional_commit_with_dots @@ -0,0 +1 @@ +feat(customer.registration): adds support for oauth2 diff --git a/tests/test_format.py b/tests/test_format.py index 97e207d..310d5ec 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -443,6 +443,7 @@ def test_r_scope__special_chars(conventional_commit_scope_required): assert regex.match("(some thing)") assert regex.match("(some:thing)") assert regex.match("(some,thing)") + assert regex.match("(some.thing)") def test_r_scope__scopes(conventional_commit_scope_required): @@ -455,6 +456,7 @@ def test_r_scope__scopes(conventional_commit_scope_required): assert regex.match("(api: client)") assert regex.match("(api/client)") assert regex.match("(api-client)") + assert regex.match("(api.client)") assert not regex.match("(test)") assert not regex.match("(api; client)") @@ -469,6 +471,7 @@ def test_r_scope__scopes_uppercase(conventional_commit_scope_required): assert regex.match("(API: CLIENT)") assert regex.match("(API/CLIENT)") assert regex.match("(API-CLIENT)") + assert regex.match("(API.CLIENT)") assert not regex.match("(TEST)") assert not regex.match("(API; CLIENT)") diff --git a/tests/test_hook.py b/tests/test_hook.py index c3a3d28..695b4c3 100644 --- a/tests/test_hook.py +++ b/tests/test_hook.py @@ -54,6 +54,12 @@ def test_main_success__conventional_utf8(conventional_utf8_commit_path): assert result == RESULT_SUCCESS +def test_main_success__conventional_commit_with_dots_path(conventional_commit_with_dots_path): + result = main([conventional_commit_with_dots_path]) + + assert result == RESULT_SUCCESS + + def test_main_fail__conventional_gbk(conventional_gbk_commit_path): result = main([conventional_gbk_commit_path]) From b12adac2cec28e98737c74242dd8f728d82cd9ce Mon Sep 17 00:00:00 2001 From: ddluke Date: Thu, 9 Oct 2025 14:11:58 +0200 Subject: [PATCH 2/2] refactor: only specify scope delimiters once --- conventional_pre_commit/format.py | 7 ++++--- tests/test_format.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py index 414ace9..bb56001 100644 --- a/conventional_pre_commit/format.py +++ b/conventional_pre_commit/format.py @@ -126,9 +126,9 @@ def r_types(self): @property def r_scope(self): """Regex str for an optional (scope).""" + escaped_delimiters = list(map(re.escape, [":", ",", "-", "/", "."])) # type: ignore if self.scopes: scopes = self._r_or(self.scopes) - escaped_delimiters = list(map(re.escape, [":", ",", "-", "/", "."])) # type: ignore delimiters_pattern = self._r_or(escaped_delimiters) scope_pattern = rf"\(\s*(?:(?i:{scopes}))(?:\s*(?:{delimiters_pattern})\s*(?:(?i:{scopes})))*\s*\)" @@ -137,10 +137,11 @@ def r_scope(self): else: return scope_pattern + joined_delimiters = "".join(escaped_delimiters) if self.scope_optional: - return r"(\([\w \/:,-\.]+\))?" + return rf"(\([\w {joined_delimiters}]+\))?" else: - return r"(\([\w \/:,-\.]+\))" + return rf"(\([\w {joined_delimiters}]+\))" @property def r_delim(self): diff --git a/tests/test_format.py b/tests/test_format.py index 310d5ec..9bb8502 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -560,6 +560,16 @@ def test_match_multiline(conventional_commit): assert match.group("body").strip() == "body copy" +def test_match_dots(conventional_commit): + match = conventional_commit.match("""feat(foo.bar): hello world""") + assert isinstance(match, re.Match) + assert match.group("type") == "feat" + assert match.group("scope") == "(foo.bar)" + assert match.group("delim") == ":" + assert match.group("subject").strip() == "hello world" + assert match.group("body").strip() == "" + + def test_match_invalid_type(conventional_commit): match = conventional_commit.match( """invalid(scope): subject line