From 437cd901ecbdd1021745a1d5b35166e636446646 Mon Sep 17 00:00:00 2001 From: Juan Alberto Regalado Galvan <00jarg@gmail.com> Date: Sat, 24 Oct 2026 22:18:28 -0300 Subject: [PATCH 1/6] feat: Add BREAKING CHANGE parsing logic --- conventional_pre_commit/format.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py index 6b664a8..8227272 100644 --- a/conventional_pre_commit/format.py +++ b/conventional_pre_commit/format.py @@ -156,7 +156,7 @@ def r_subject(self): @property def r_body(self): """Regex str for the body, with multiline support.""" - return r"(?P\r?\n(?P^$\r?\n)?.+)?" + return r"(?P\r?\n(?P^$\r?\n)?(?P(?i:BREAKING[ -]CHANGE: ))?.+)?" @property def regex(self): @@ -201,6 +201,16 @@ def errors(self, commit_msg: str = "") -> List[str]: return [g for g, v in groups.items() if not v] + def _valid_body(self, match: re.Match) -> bool: + if not match.group("body"): # no extra body + return True + if match.group("multi") and match.group("sep"): # a multiline body with proper separator + if match.group("break"): + return match.group("break").isupper() + else: + return True + return False + def is_valid(self, commit_msg: str = "") -> bool: """ Returns True if commit_msg matches Conventional Commits formatting. @@ -220,14 +230,7 @@ def is_valid(self, commit_msg: str = "") -> bool: self.scope_optional or match.group("scope"), match.group("delim"), match.group("subject"), - any( - [ - # no extra body; OR - not match.group("body"), - # a multiline body with proper separator - match.group("multi") and match.group("sep"), - ] - ), + self._valid_body(match) ] ) From d7f64142b7cde973b93d2b1435967b940fafa4e7 Mon Sep 17 00:00:00 2001 From: Juan Alberto Regalado Galvan <00jarg@gmail.com> Date: Sat, 24 Oct 2026 22:19:07 -0300 Subject: [PATCH 2/6] test(format): Add breaking change tests --- tests/test_format.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_format.py b/tests/test_format.py index 30dbd2d..be6a9f8 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -768,6 +768,24 @@ def test_is_valid__missing_delimiter(conventional_commit): """, False, ), + ( + "feat(scope): subject\n" + "\n" + "Breaking change: description\n", + False, + ), + ( + "feat(scope): subject\n" + "\n" + "BREAKING CHANGE: description\n", + True, + ), + ( + "feat(scope): subject\n" + "\n" + "BREAKING-CHANGE: description\n", + True, + ), ], ) def test_is_conventional(input, expected_result): From 0cbdd17cbb655c6c609b975aa55b264e685efa4e Mon Sep 17 00:00:00 2001 From: Juan Alberto Regalado Galvan <00jarg@gmail.com> Date: Sat, 24 Oct 2026 23:09:51 -0300 Subject: [PATCH 3/6] refactor: consitent naming --- conventional_pre_commit/format.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py index 8227272..67ab7ba 100644 --- a/conventional_pre_commit/format.py +++ b/conventional_pre_commit/format.py @@ -201,7 +201,7 @@ def errors(self, commit_msg: str = "") -> List[str]: return [g for g, v in groups.items() if not v] - def _valid_body(self, match: re.Match) -> bool: + def _is_valid_body(self, match: re.Match) -> bool: if not match.group("body"): # no extra body return True if match.group("multi") and match.group("sep"): # a multiline body with proper separator @@ -230,7 +230,7 @@ def is_valid(self, commit_msg: str = "") -> bool: self.scope_optional or match.group("scope"), match.group("delim"), match.group("subject"), - self._valid_body(match) + self._is_valid_body(match) ] ) From 48474e462f3a5247be00dd12f961812a45c49e7a Mon Sep 17 00:00:00 2001 From: Juan Alberto Regalado Galvan <00jarg@gmail.com> Date: Sat, 24 Oct 2026 23:10:12 -0300 Subject: [PATCH 4/6] docs: Add missing docstring --- conventional_pre_commit/format.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py index 67ab7ba..fa44bde 100644 --- a/conventional_pre_commit/format.py +++ b/conventional_pre_commit/format.py @@ -202,6 +202,9 @@ def errors(self, commit_msg: str = "") -> List[str]: return [g for g, v in groups.items() if not v] def _is_valid_body(self, match: re.Match) -> bool: + """ + Returns True if the body follows Conventional Commits formatting. + """ if not match.group("body"): # no extra body return True if match.group("multi") and match.group("sep"): # a multiline body with proper separator From b32b481bd35efc925253aa23084a00670dcb6ffe Mon Sep 17 00:00:00 2001 From: Juan Alberto Regalado Galvan <00jarg@gmail.com> Date: Sat, 24 Oct 2026 23:52:18 -0300 Subject: [PATCH 5/6] style: Add trailing comma --- conventional_pre_commit/format.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py index fa44bde..4a856a4 100644 --- a/conventional_pre_commit/format.py +++ b/conventional_pre_commit/format.py @@ -233,7 +233,7 @@ def is_valid(self, commit_msg: str = "") -> bool: self.scope_optional or match.group("scope"), match.group("delim"), match.group("subject"), - self._is_valid_body(match) + self._is_valid_body(match), ] ) From 37d10c1252bbbdc12cd4c48964457a7f5d164e3c Mon Sep 17 00:00:00 2001 From: Juan Alberto Regalado Galvan <00jarg@gmail.com> Date: Sun, 25 Oct 2026 11:49:22 -0300 Subject: [PATCH 6/6] style: format --- tests/test_format.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/test_format.py b/tests/test_format.py index be6a9f8..6817180 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -769,21 +769,15 @@ def test_is_valid__missing_delimiter(conventional_commit): False, ), ( - "feat(scope): subject\n" - "\n" - "Breaking change: description\n", + "feat(scope): subject\n\nBreaking change: description\n", False, ), ( - "feat(scope): subject\n" - "\n" - "BREAKING CHANGE: description\n", + "feat(scope): subject\n\nBREAKING CHANGE: description\n", True, ), ( - "feat(scope): subject\n" - "\n" - "BREAKING-CHANGE: description\n", + "feat(scope): subject\n\nBREAKING-CHANGE: description\n", True, ), ],