Skip to content

feat: add custom regex back via message_pattern config option - #427

Merged
shenxianpeng merged 3 commits into
mainfrom
feature/support-custom-message-pattern
Jun 13, 2026
Merged

feat: add custom regex back via message_pattern config option#427
shenxianpeng merged 3 commits into
mainfrom
feature/support-custom-message-pattern

Conversation

@shenxianpeng

@shenxianpeng shenxianpeng commented Jun 13, 2026

Copy link
Copy Markdown
Member

Summary

Add message_pattern to the [commit] config section — a custom regex that replaces the auto-generated Conventional Commits regex when set. Only available via TOML config and env var (CCHK_MESSAGE_PATTERN). No CLI flag — regex belongs in config files, not command lines.

Closes #426.

Motivation

Many organizations have custom commit message policies beyond Conventional Commits:

  • JIRA smart commits: PROJ-123: Fix login bug
  • GitHub issue references: Fix login #123
  • Any other organization-specific format

Usage

TOML config

[commit]
message_pattern = "^PROJ-\\d+: .+"

Environment variable

export CCHK_MESSAGE_PATTERN="^PROJ-\d+: .+"
commit-check --message

When message_pattern is set (non-empty), it takes precedence over conventional_commits. If empty/unset, behavior is unchanged.

Summary by CodeRabbit

  • New Features

    • Introduced custom regex pattern support for commit message validation, allowing rules to override standard conventional commits validation when configured with a non-empty pattern.
  • Documentation

    • Updated configuration documentation to describe the custom message pattern option and its precedence over conventional commits validation.
    • Added migration guide section detailing how to implement custom regex patterns for commit messages.

@shenxianpeng
shenxianpeng requested a review from a team as a code owner June 13, 2026 04:41
@netlify

netlify Bot commented Jun 13, 2026

Copy link
Copy Markdown

Deploy Preview for commit-check ready!

Name Link
🔨 Latest commit 371bd51
🔍 Latest deploy log https://app.netlify.com/projects/commit-check/deploys/6a2ce7f209ae8e00081f664f
😎 Deploy Preview https://deploy-preview-427--commit-check.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added documentation Improvements or additions to documentation enhancement New feature or request labels Jun 13, 2026
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a commit.message_pattern configuration option that allows custom regex validation of commit messages. When set to a non-empty pattern, it fully overrides the auto-generated Conventional Commits regex. The feature includes environment variable wiring, rule-builder precedence logic, comprehensive tests, and updated documentation.

Changes

Custom Regex Message Pattern Feature

Layer / File(s) Summary
Configuration defaults and environment wiring
commit_check/config_merger.py
Default config initializes commit.message_pattern to empty string; environment variable CCHK_MESSAGE_PATTERN is mapped to the config path.
Rule builder override implementation
commit_check/rule_builder.py
_build_conventional_commit_rule checks commit.message_pattern early in the method flow, returning a ValidationRule with the custom regex immediately when non-empty, before conventional commits logic.
Configuration and rule builder unit tests
tests/config_merger_test.py, tests/rule_builder_test.py
Tests verify environment variable parsing, that message_pattern takes precedence, overrides even when conventional_commits is disabled, and falls back to auto-generated regex when empty.
End-to-end validation tests
tests/engine_test.py
Integration tests exercise custom regex patterns (JIRA-style and GitHub-style issue keys) and edge cases (empty subject and message) with expected validator outcomes.
Configuration and migration documentation
docs/configuration.rst, docs/migration.rst
TOML example, environment variable mapping table, option reference table, and migration guide section explain commit.message_pattern behavior and precedence.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • commit-check/commit-check#383: Both PRs modify commit_check/rule_builder.py's _build_conventional_commit_rule to change how the conventional commit message validation rule is constructed.
  • commit-check/commit-check#357: This PR extends the ConfigMerger environment variable wiring infrastructure introduced in the retrieved PR.

Suggested labels

minor

Poem

A rabbit hops through commit schemes,
With custom patterns, not just dreams—
JIRA keys and issues bright,
Message matching set just right! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding support for custom regex patterns via a new message_pattern configuration option.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #426: it restores custom regex validation for commit messages in 2.x, allows configuration via TOML and environment variables, and takes precedence over conventional commits.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the message_pattern feature: configuration, rule building logic, documentation, and comprehensive tests for the new functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/support-custom-message-pattern

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.93%. Comparing base (185d570) to head (371bd51).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #427      +/-   ##
==========================================
+ Coverage   95.92%   95.93%   +0.01%     
==========================================
  Files          10       10              
  Lines        1152     1155       +3     
==========================================
+ Hits         1105     1108       +3     
  Misses         47       47              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
docs/configuration.rst (1)

388-392: 💤 Low value

Documentation is clear but could refine the "mutually exclusive" phrasing.

The description states:

This is mutually exclusive with conventional_commits — if message_pattern is non-empty it takes precedence.

"Mutually exclusive" typically means both cannot be set simultaneously, but here they can both be set—message_pattern simply takes precedence. Consider rewording for precision:

When set to a non-empty value, message_pattern takes precedence over the conventional_commits auto-generated regex.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/configuration.rst` around lines 388 - 392, Update the phrasing
explaining the relationship between message_pattern and conventional_commits:
replace "This is mutually exclusive with ``conventional_commits`` — if
``message_pattern`` is non-empty it takes precedence." with a clearer statement
such as "When set to a non-empty value, ``message_pattern`` takes precedence
over the ``conventional_commits`` auto-generated regex." Ensure this change
references the same option names (``message_pattern`` and
``conventional_commits``) so readers understand precedence rather than mutual
exclusivity.
commit_check/rule_builder.py (2)

161-161: 💤 Low value

Consider including the pattern in the suggestion message.

The hardcoded suggestion "Commit message does not match the required pattern" doesn't tell users what pattern is expected. Including the actual regex would make debugging easier.

💡 Proposed enhancement
-        suggest="Commit message does not match the required pattern",
+        suggest=f"Commit message does not match the required pattern: {custom_pattern}",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@commit_check/rule_builder.py` at line 161, Update the suggestion text so it
includes the actual regex pattern used for validation instead of the generic
message; locate the assignment to suggest (the `suggest="Commit message does not
match the required pattern"` entry) in rule_builder.py and interpolate/format
the rule's regex (the variable used for the commit message check, e.g., the
pattern/regex variable that the rule uses) into that string so users see the
exact pattern expected.

155-162: ⚡ Quick win

Consider validating the custom regex pattern at configuration time.

Currently, an invalid regex in message_pattern will fail at runtime when CommitMessageValidator calls re.match(). Validating the pattern here would provide earlier, clearer feedback.

🛡️ Proposed validation logic
 custom_pattern = self.commit_config.get("message_pattern", "")
 if custom_pattern:
+    # Validate regex syntax early
+    try:
+        import re
+        re.compile(custom_pattern)
+    except re.error as e:
+        raise ValueError(f"Invalid message_pattern regex: {e}")
     return ValidationRule(
         check=catalog_entry.check,
         regex=custom_pattern,
         error=catalog_entry.error,
         suggest="Commit message does not match the required pattern",
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@commit_check/rule_builder.py` around lines 155 - 162, The custom regex in
commit_config["message_pattern"] should be validated when building the
ValidationRule to fail fast: in the block that creates ValidationRule
(referencing commit_config, ValidationRule and catalog_entry) try to compile the
pattern with re.compile() and catch re.error; if compilation fails raise or
propagate a clear configuration error (or log and skip rule) so
CommitMessageValidator's later re.match() cannot encounter an invalid pattern at
runtime; optionally store the compiled pattern in the ValidationRule so
validators reuse the precompiled regex.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@commit_check/rule_builder.py`:
- Line 161: Update the suggestion text so it includes the actual regex pattern
used for validation instead of the generic message; locate the assignment to
suggest (the `suggest="Commit message does not match the required pattern"`
entry) in rule_builder.py and interpolate/format the rule's regex (the variable
used for the commit message check, e.g., the pattern/regex variable that the
rule uses) into that string so users see the exact pattern expected.
- Around line 155-162: The custom regex in commit_config["message_pattern"]
should be validated when building the ValidationRule to fail fast: in the block
that creates ValidationRule (referencing commit_config, ValidationRule and
catalog_entry) try to compile the pattern with re.compile() and catch re.error;
if compilation fails raise or propagate a clear configuration error (or log and
skip rule) so CommitMessageValidator's later re.match() cannot encounter an
invalid pattern at runtime; optionally store the compiled pattern in the
ValidationRule so validators reuse the precompiled regex.

In `@docs/configuration.rst`:
- Around line 388-392: Update the phrasing explaining the relationship between
message_pattern and conventional_commits: replace "This is mutually exclusive
with ``conventional_commits`` — if ``message_pattern`` is non-empty it takes
precedence." with a clearer statement such as "When set to a non-empty value,
``message_pattern`` takes precedence over the ``conventional_commits``
auto-generated regex." Ensure this change references the same option names
(``message_pattern`` and ``conventional_commits``) so readers understand
precedence rather than mutual exclusivity.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 61e206ae-b488-408d-8872-a84c37c28a93

📥 Commits

Reviewing files that changed from the base of the PR and between 185d570 and 3098376.

📒 Files selected for processing (7)
  • commit_check/config_merger.py
  • commit_check/main.py
  • commit_check/rule_builder.py
  • docs/configuration.rst
  • docs/migration.rst
  • tests/engine_test.py
  • tests/rule_builder_test.py

@shenxianpeng
shenxianpeng force-pushed the feature/support-custom-message-pattern branch from 3098376 to 72d4bd9 Compare June 13, 2026 04:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/configuration.rst (1)

217-282: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add message_pattern to the configuration mapping table.

The mapping table documents how each option corresponds across TOML config, environment variables, and CLI arguments. The message_pattern option is missing from this table, even though it supports all three configuration methods (verified in commit_check/config_merger.py). Users need to know about CCHK_MESSAGE_PATTERN and --message-pattern.

📝 Suggested addition

Insert after the conventional_commits row (around line 225):

   * - ``conventional_commits = true``
     - ``CCHK_CONVENTIONAL_COMMITS=true``
     - ``--conventional-commits=true``
+  * - ``message_pattern = "^PROJ-\\d+: .+"``
+    - ``CCHK_MESSAGE_PATTERN=^PROJ-\\d+: .+``
+    - ``--message-pattern=^PROJ-\\d+: .+``
   * - ``subject_capitalized = false``
     - ``CCHK_SUBJECT_CAPITALIZED=false``
     - ``--subject-capitalized=false``
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/configuration.rst` around lines 217 - 282, The docs table is missing the
message_pattern option mapping; add a new row for the TOML key message_pattern
and its env/CLI forms by inserting a table row after the conventional_commits
entry that shows ``message_pattern = "<pattern>"`` under TOML,
``CCHK_MESSAGE_PATTERN=<pattern>`` under Environment Variable, and
``--message-pattern=<pattern>`` under CLI Argument so users see the mapping for
message_pattern, CCHK_MESSAGE_PATTERN, and --message-pattern.
🧹 Nitpick comments (1)
tests/rule_builder_test.py (1)

242-242: 💤 Low value

Consider extracting the duplicated "Bad format" literal.

The literal "Bad format" appears 4 times across the three new tests (lines 242, 248, 263, 284). Extracting it to a module-level constant would reduce duplication.

♻️ Suggested refactor
+# Test constants
+_TEST_ERROR_MSG = "Bad format"
+
 class TestValidationRule:
     `@pytest.mark.benchmark`
     def test_validation_rule_to_dict_with_ignored(self):

Then replace each usage:

         catalog_entry = RuleCatalogEntry(
-            check="message", regex="", error="Bad format", suggest="Use JIRA format"
+            check="message", regex="", error=_TEST_ERROR_MSG, suggest="Use JIRA format"
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/rule_builder_test.py` at line 242, Extract the duplicated literal "Bad
format" into a module-level constant (e.g., BAD_FORMAT_ERROR) at the top of
tests/rule_builder_test.py and replace all occurrences of the string in the new
tests with that constant; update the three tests that currently use "Bad format"
(the four usages noted in the diff) to reference BAD_FORMAT_ERROR so the message
is defined once and reused.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/configuration.rst`:
- Around line 217-282: The docs table is missing the message_pattern option
mapping; add a new row for the TOML key message_pattern and its env/CLI forms by
inserting a table row after the conventional_commits entry that shows
``message_pattern = "<pattern>"`` under TOML, ``CCHK_MESSAGE_PATTERN=<pattern>``
under Environment Variable, and ``--message-pattern=<pattern>`` under CLI
Argument so users see the mapping for message_pattern, CCHK_MESSAGE_PATTERN, and
--message-pattern.

---

Nitpick comments:
In `@tests/rule_builder_test.py`:
- Line 242: Extract the duplicated literal "Bad format" into a module-level
constant (e.g., BAD_FORMAT_ERROR) at the top of tests/rule_builder_test.py and
replace all occurrences of the string in the new tests with that constant;
update the three tests that currently use "Bad format" (the four usages noted in
the diff) to reference BAD_FORMAT_ERROR so the message is defined once and
reused.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 44122a8b-c4f3-49c6-a263-75b26d31bbd9

📥 Commits

Reviewing files that changed from the base of the PR and between 3098376 and 72d4bd9.

📒 Files selected for processing (7)
  • commit_check/config_merger.py
  • commit_check/main.py
  • commit_check/rule_builder.py
  • docs/configuration.rst
  • docs/migration.rst
  • tests/engine_test.py
  • tests/rule_builder_test.py
✅ Files skipped from review due to trivial changes (1)
  • docs/migration.rst
🚧 Files skipped from review as they are similar to previous changes (4)
  • commit_check/config_merger.py
  • commit_check/rule_builder.py
  • commit_check/main.py
  • tests/engine_test.py

Add `message_pattern` to the `[commit]` config section — a custom
regex that replaces the auto-generated Conventional Commits regex
when set.  Only available via TOML and env var (CCHK_MESSAGE_PATTERN),
not as a CLI flag, since regex belongs in config files not command
lines.

Closes #426
@shenxianpeng
shenxianpeng force-pushed the feature/support-custom-message-pattern branch from 72d4bd9 to 5b41b42 Compare June 13, 2026 04:49
@codspeed-hq

codspeed-hq Bot commented Jun 13, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 302 untouched benchmarks
🆕 7 new benchmarks
⏩ 108 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_commit_message_validator_custom_pattern_github_issue N/A 804 µs N/A
🆕 test_commit_message_validator_custom_pattern_jira N/A 804.9 µs N/A
🆕 test_message_pattern_empty_falls_back N/A 138.6 µs N/A
🆕 test_message_pattern_overrides_conventional_commits N/A 123.4 µs N/A
🆕 test_message_pattern_takes_precedence N/A 125.2 µs N/A
🆕 test_commit_message_validator_empty_message_passes N/A 965.1 µs N/A
🆕 test_validate_empty_subject_passes N/A 926.6 µs N/A

Comparing feature/support-custom-message-pattern (371bd51) with main (185d570)

Open in CodSpeed

Footnotes

  1. 108 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@shenxianpeng shenxianpeng removed the documentation Improvements or additions to documentation label Jun 13, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jun 13, 2026
@shenxianpeng shenxianpeng removed the documentation Improvements or additions to documentation label Jun 13, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jun 13, 2026
@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@commit_check/rule_builder.py`:
- Around line 155-156: The code currently calls
self.commit_config.get("message_pattern", "").strip() which crashes if
message_pattern is not a string; change it to first retrieve the raw value
(e.g., raw = self.commit_config.get("message_pattern", None)), check
isinstance(raw, str) and only then call strip() (assign custom_pattern =
raw.strip()), otherwise set custom_pattern = "" (or otherwise fallback safely)
so non-string TOML values don't raise in rule_builder.py; update any downstream
uses that assume custom_pattern is a string accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7fd1833c-eb55-401b-ab0b-fc7f0a34c096

📥 Commits

Reviewing files that changed from the base of the PR and between 72d4bd9 and 371bd51.

📒 Files selected for processing (7)
  • commit_check/config_merger.py
  • commit_check/rule_builder.py
  • docs/configuration.rst
  • docs/migration.rst
  • tests/config_merger_test.py
  • tests/engine_test.py
  • tests/rule_builder_test.py
✅ Files skipped from review due to trivial changes (1)
  • docs/migration.rst
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/configuration.rst

Comment on lines +155 to +156
custom_pattern = self.commit_config.get("message_pattern", "").strip()
if custom_pattern:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard message_pattern type before calling .strip() to avoid runtime crash.

On Line 155, self.commit_config.get("message_pattern", "").strip() will raise if TOML provides a non-string value (e.g., number/list), causing rule building to fail instead of falling back safely.

Suggested fix
-        custom_pattern = self.commit_config.get("message_pattern", "").strip()
+        raw_pattern = self.commit_config.get("message_pattern", "")
+        custom_pattern = raw_pattern.strip() if isinstance(raw_pattern, str) else ""
         if custom_pattern:
             return ValidationRule(
                 check=catalog_entry.check,
                 regex=custom_pattern,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@commit_check/rule_builder.py` around lines 155 - 156, The code currently
calls self.commit_config.get("message_pattern", "").strip() which crashes if
message_pattern is not a string; change it to first retrieve the raw value
(e.g., raw = self.commit_config.get("message_pattern", None)), check
isinstance(raw, str) and only then call strip() (assign custom_pattern =
raw.strip()), otherwise set custom_pattern = "" (or otherwise fallback safely)
so non-string TOML values don't raise in rule_builder.py; update any downstream
uses that assume custom_pattern is a string accordingly.

@shenxianpeng shenxianpeng removed the documentation Improvements or additions to documentation label Jun 13, 2026
@shenxianpeng
shenxianpeng merged commit 6fb72d3 into main Jun 13, 2026
35 checks passed
@shenxianpeng
shenxianpeng deleted the feature/support-custom-message-pattern branch June 13, 2026 05:23
@shenxianpeng shenxianpeng changed the title feat: support custom regex via message_pattern config option feat: add custom regex back via message_pattern config option Jun 13, 2026
@shenxianpeng shenxianpeng changed the title feat: add custom regex back via message_pattern config option feat: add custom regex back via message_pattern config option Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support validation commit messages against regex in 2.x

1 participant