From cd957d90438c06f3ba4965c2f90b321bbceceb80 Mon Sep 17 00:00:00 2001 From: Xianpeng Shen Date: Mon, 13 Oct 2025 00:27:40 +0300 Subject: [PATCH] fix: update regex to support breaking changes --- commit_check/engine.py | 3 ++- tests/engine_test.py | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/commit_check/engine.py b/commit_check/engine.py index e4f39271..4a76e0e7 100644 --- a/commit_check/engine.py +++ b/commit_check/engine.py @@ -200,7 +200,8 @@ def _validate_subject(self, subject: str) -> ValidationResult: # Extract first word (ignore conventional commit prefixes) import re - match = re.match(r"^(?:\w+(?:\([^)]*\))?[!:]?\s*)?(\w+)", subject) + # support breaking changes (feat!:) + match = re.match(r"^(?:\w+(?:\([^)]*\))?!?:\s*)?(\w+)", subject) if not match: return ValidationResult.PASS diff --git a/tests/engine_test.py b/tests/engine_test.py index da5c62e9..f34b1159 100644 --- a/tests/engine_test.py +++ b/tests/engine_test.py @@ -778,3 +778,23 @@ def test_validate_short_subject(self): # "add" is a valid imperative word with conventional prefix result = validator.validate(context) assert result == ValidationResult.PASS + + def test_validate_with_breaking_change(self): + """Test validation with breaking change notation.""" + rule = ValidationRule(check="imperative") + validator = SubjectImperativeValidator(rule) + context = ValidationContext(stdin_text="feat!: update authentication system") + + # "update" is a valid imperative word with breaking change notation + result = validator.validate(context) + assert result == ValidationResult.PASS + + def test_validate_with_scoped_breaking_change(self): + """Test validation with scoped breaking change notation.""" + rule = ValidationRule(check="imperative") + validator = SubjectImperativeValidator(rule) + context = ValidationContext(stdin_text="fix(auth)!: resolve login bug") + + # "resolve" is a valid imperative word with scope and breaking change notation + result = validator.validate(context) + assert result == ValidationResult.PASS