Repository: compilerla/conventional-pre-commit

Issue:
Shouldn't we do a case-insensitive check for commit type?
This tool classify one of your commit https://github.com/compilerla/conventional-pre-commit/commit/5f9c312d9978fbcee1da97154ba385834eeda799 as False. This is due to Capitalization of first word in "Refactor". I think  we should do case-insensitive check for commit type.

Discussion:
@thekaveman: Thanks for the question @rsh-raj. The commit you mention https://github.com/compilerla/conventional-pre-commit/commit/5f9c312d9978fbcee1da97154ba385834eeda799 is a merge commit made on GitHub, so the tool never ran on this commit. 

We are happy to review a PR with tests if you see a bug that should be fixed!@jonathanraesch: The [specification](https://www.conventionalcommits.org/en/v1.0.0/#specification) states that 
> 15. The units of information that make up Conventional Commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.

But this tool only allows lowercase commit types. This is clearly a bug.
@jonathanraesch: #135 should fix this. I could not find any case-sensitive units other than types and scopes.@thekaveman: Fixed in #135.

Thank you @rsh-raj for the original report and @jonathanraesch for the PR/fix!

* PyPI: https://pypi.org/project/conventional-pre-commit/4.2.0/
* GitHub: https://github.com/compilerla/conventional-pre-commit/releases/tag/v4.2.0

Solution patch:
diff --git a/conventional_pre_commit/format.py b/conventional_pre_commit/format.py
index e4023a2..f19f0af 100644
--- a/conventional_pre_commit/format.py
+++ b/conventional_pre_commit/format.py
@@ -121,7 +121,7 @@ class ConventionalCommit(Commit):
     @property
     def r_types(self):
         """Regex str for valid types."""
-        return self._r_or(self.types)
+        return f"(?i:{self._r_or(self.types)})"
 
     @property
     def r_scope(self):
@@ -130,7 +130,7 @@ class ConventionalCommit(Commit):
             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*(?:{scopes})(?:\s*(?:{delimiters_pattern})\s*(?:{scopes}))*\s*\)"
+            scope_pattern = rf"\(\s*(?:(?i:{scopes}))(?:\s*(?:{delimiters_pattern})\s*(?:(?i:{scopes})))*\s*\)"
 
             if self.scope_optional:
                 return f"(?:{scope_pattern})?"


Test patch:
diff --git a/tests/test_format.py b/tests/test_format.py
index a46005b..97e207d 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -459,6 +459,20 @@ def test_r_scope__scopes(conventional_commit_scope_required):
     assert not regex.match("(api; client)")
 
 
+def test_r_scope__scopes_uppercase(conventional_commit_scope_required):
+    conventional_commit_scope_required.scopes = ["api", "client"]
+    regex = re.compile(conventional_commit_scope_required.r_scope)
+
+    assert regex.match("(API)")
+    assert regex.match("(CLIENT)")
+    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)")
+
+
 def test_r_delim(conventional_commit):
     regex = re.compile(conventional_commit.r_delim)
 
@@ -565,6 +579,13 @@ def test_is_valid__default_type(conventional_commit, type):
     assert conventional_commit.is_valid(input)
 
 
+@pytest.mark.parametrize("type", ConventionalCommit.DEFAULT_TYPES)
+def test_is_valid__default_type_uppercase(conventional_commit, type):
+    input = f"{type.upper()}: message"
+
+    assert conventional_commit.is_valid(input)
+
+
 @pytest.mark.parametrize("type", ConventionalCommit.CONVENTIONAL_TYPES)
 def test_is_valid__conventional_type(conventional_commit, type):
     input = f"{type}: message"
@@ -572,6 +593,13 @@ def test_is_valid__conventional_type(conventional_commit, type):
     assert conventional_commit.is_valid(input)
 
 
+@pytest.mark.parametrize("type", ConventionalCommit.CONVENTIONAL_TYPES)
+def test_is_valid__conventional_type_uppercase(conventional_commit, type):
+    input = f"{type.upper()}: message"
+
+    assert conventional_commit.is_valid(input)
+
+
 @pytest.mark.parametrize("type", CUSTOM_TYPES)
 def test_is_valid__custom_type(type):
     input = f"{type}: message"
@@ -588,6 +616,14 @@ def test_is_valid__conventional_custom_type(type):
     assert conventional_commits.is_valid(input)
 
 
+@pytest.mark.parametrize("type", ConventionalCommit.CONVENTIONAL_TYPES)
+def test_is_valid__conventional_custom_type_uppercase(type):
+    input = f"{type.upper()}: message"
+    conventional_commits = ConventionalCommit(types=CUSTOM_TYPES)
+
+    assert conventional_commits.is_valid(input)
+
+
 def test_is_valid__breaking_change(conventional_commit):
     input = "fix!: message"