commit-check 2.4.2__py3-none-any.whl → 2.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- commit_check/config.py +119 -4
- commit_check/engine.py +49 -5
- commit_check/imperatives.py +1 -0
- commit_check/rule_builder.py +6 -1
- commit_check/rules_catalog.py +2 -2
- commit_check/util.py +17 -5
- {commit_check-2.4.2.dist-info → commit_check-2.5.0.dist-info}/METADATA +157 -12
- commit_check-2.5.0.dist-info/RECORD +15 -0
- {commit_check-2.4.2.dist-info → commit_check-2.5.0.dist-info}/WHEEL +1 -1
- commit_check-2.4.2.dist-info/RECORD +0 -15
- {commit_check-2.4.2.dist-info → commit_check-2.5.0.dist-info}/entry_points.txt +0 -0
- {commit_check-2.4.2.dist-info → commit_check-2.5.0.dist-info}/licenses/LICENSE +0 -0
- {commit_check-2.4.2.dist-info → commit_check-2.5.0.dist-info}/top_level.txt +0 -0
commit_check/config.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""TOML config loader and schema for commit-check."""
|
|
2
2
|
|
|
3
|
-
from typing import Any, Dict
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
import urllib.request
|
|
6
|
+
import urllib.error
|
|
5
7
|
|
|
6
8
|
try:
|
|
7
9
|
import tomllib
|
|
@@ -20,20 +22,133 @@ DEFAULT_CONFIG_PATHS = [
|
|
|
20
22
|
]
|
|
21
23
|
|
|
22
24
|
|
|
25
|
+
def _deep_merge(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
|
|
26
|
+
"""Deep merge override into base, returning a new dict."""
|
|
27
|
+
result = dict(base)
|
|
28
|
+
for key, value in override.items():
|
|
29
|
+
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
|
30
|
+
result[key] = _deep_merge(result[key], value)
|
|
31
|
+
else:
|
|
32
|
+
result[key] = value
|
|
33
|
+
return result
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _github_shorthand_to_url(value: str) -> Optional[str]:
|
|
37
|
+
"""Convert a ``github:`` shorthand to a raw GitHub content URL.
|
|
38
|
+
|
|
39
|
+
Supported formats (modelled after Release Drafter's convention):
|
|
40
|
+
|
|
41
|
+
* ``github:owner/repo:path/to/file.toml``
|
|
42
|
+
→ ``https://raw.githubusercontent.com/owner/repo/HEAD/path/to/file.toml``
|
|
43
|
+
* ``github:owner/repo@ref:path/to/file.toml``
|
|
44
|
+
→ ``https://raw.githubusercontent.com/owner/repo/ref/path/to/file.toml``
|
|
45
|
+
|
|
46
|
+
:param value: The raw ``inherit_from`` value starting with ``github:``.
|
|
47
|
+
:returns: A resolved HTTPS URL, or ``None`` if the format is unrecognized.
|
|
48
|
+
"""
|
|
49
|
+
# Strip the "github:" prefix
|
|
50
|
+
rest = value[len("github:") :]
|
|
51
|
+
|
|
52
|
+
# The path separator between repo spec and file path is ":"
|
|
53
|
+
if ":" not in rest:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
repo_spec, file_path = rest.split(":", 1)
|
|
57
|
+
if not repo_spec or not file_path:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
# Support optional ref via "@": "owner/repo@ref"
|
|
61
|
+
if "@" in repo_spec:
|
|
62
|
+
repo_part, ref = repo_spec.split("@", 1)
|
|
63
|
+
else:
|
|
64
|
+
repo_part, ref = repo_spec, "HEAD"
|
|
65
|
+
|
|
66
|
+
if "/" not in repo_part:
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
return f"https://raw.githubusercontent.com/{repo_part}/{ref}/{file_path}"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _load_from_url(url: str) -> Dict[str, Any]:
|
|
73
|
+
"""Load TOML config from an HTTPS URL.
|
|
74
|
+
|
|
75
|
+
:param url: HTTPS URL pointing to a TOML config file.
|
|
76
|
+
:returns: Parsed config dict, or empty dict on failure.
|
|
77
|
+
:raises ValueError: If the URL does not use HTTPS.
|
|
78
|
+
"""
|
|
79
|
+
if not url.startswith("https://"):
|
|
80
|
+
return {}
|
|
81
|
+
try:
|
|
82
|
+
with urllib.request.urlopen(url, timeout=10) as response: # noqa: S310
|
|
83
|
+
data = response.read()
|
|
84
|
+
import io
|
|
85
|
+
|
|
86
|
+
return toml_load(io.BytesIO(data))
|
|
87
|
+
except (urllib.error.URLError, urllib.error.HTTPError, Exception):
|
|
88
|
+
return {}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _resolve_inherit_from(config: Dict[str, Any]) -> Dict[str, Any]:
|
|
92
|
+
"""Resolve ``inherit_from`` directive, merging parent config with local.
|
|
93
|
+
|
|
94
|
+
The ``inherit_from`` key at the top level of a config file may be:
|
|
95
|
+
|
|
96
|
+
* A ``github:owner/repo:path`` shorthand (fetches via raw.githubusercontent.com)
|
|
97
|
+
* An HTTPS URL pointing to a TOML config file
|
|
98
|
+
* A local file path
|
|
99
|
+
|
|
100
|
+
HTTP (non-TLS) URLs are rejected to prevent MITM attacks. The parent
|
|
101
|
+
config is loaded first; local settings override the parent.
|
|
102
|
+
|
|
103
|
+
:param config: Already-parsed local TOML dict (may contain ``inherit_from``).
|
|
104
|
+
:returns: Merged config with parent settings applied as base.
|
|
105
|
+
"""
|
|
106
|
+
inherit_from = config.pop("inherit_from", None)
|
|
107
|
+
if not inherit_from or not isinstance(inherit_from, str):
|
|
108
|
+
return config
|
|
109
|
+
|
|
110
|
+
parent: Dict[str, Any] = {}
|
|
111
|
+
if inherit_from.startswith("github:"):
|
|
112
|
+
url = _github_shorthand_to_url(inherit_from)
|
|
113
|
+
if url:
|
|
114
|
+
parent = _load_from_url(url)
|
|
115
|
+
elif inherit_from.startswith("https://"):
|
|
116
|
+
parent = _load_from_url(inherit_from)
|
|
117
|
+
else:
|
|
118
|
+
parent_path = Path(inherit_from)
|
|
119
|
+
if parent_path.exists():
|
|
120
|
+
try:
|
|
121
|
+
with open(parent_path, "rb") as f:
|
|
122
|
+
parent = toml_load(f)
|
|
123
|
+
except Exception:
|
|
124
|
+
parent = {}
|
|
125
|
+
|
|
126
|
+
if parent:
|
|
127
|
+
return _deep_merge(parent, config)
|
|
128
|
+
return config
|
|
129
|
+
|
|
130
|
+
|
|
23
131
|
def load_config(path_hint: str = "") -> Dict[str, Any]:
|
|
24
|
-
"""Load and validate config from TOML file.
|
|
132
|
+
"""Load and validate config from TOML file.
|
|
133
|
+
|
|
134
|
+
Supports ``inherit_from`` at the top level to merge an organization-level
|
|
135
|
+
configuration from a local file path, a ``github:`` shorthand, or an HTTPS
|
|
136
|
+
URL before applying local overrides.
|
|
137
|
+
"""
|
|
25
138
|
if path_hint:
|
|
26
139
|
p = Path(path_hint)
|
|
27
140
|
if not p.exists():
|
|
28
141
|
raise FileNotFoundError(f"Specified config file not found: {path_hint}")
|
|
29
142
|
with open(p, "rb") as f:
|
|
30
|
-
|
|
143
|
+
config = toml_load(f)
|
|
144
|
+
return _resolve_inherit_from(config)
|
|
31
145
|
|
|
32
146
|
# Check default config paths only when no specific path is provided
|
|
33
147
|
for candidate in DEFAULT_CONFIG_PATHS:
|
|
34
148
|
if candidate.exists():
|
|
35
149
|
with open(candidate, "rb") as f:
|
|
36
|
-
|
|
150
|
+
config = toml_load(f)
|
|
151
|
+
return _resolve_inherit_from(config)
|
|
37
152
|
|
|
38
153
|
# Return empty config if no default config files found
|
|
39
154
|
return {}
|
commit_check/engine.py
CHANGED
|
@@ -9,6 +9,7 @@ from dataclasses import field
|
|
|
9
9
|
from commit_check.rule_builder import ValidationRule
|
|
10
10
|
from commit_check.util import (
|
|
11
11
|
get_commit_info,
|
|
12
|
+
get_git_config_value,
|
|
12
13
|
get_branch_name,
|
|
13
14
|
has_commits,
|
|
14
15
|
git_merge_base,
|
|
@@ -59,13 +60,39 @@ class BaseValidator(ABC):
|
|
|
59
60
|
"""
|
|
60
61
|
Determine if commit validation should be skipped.
|
|
61
62
|
|
|
62
|
-
Skip if the current author is in the ignore_authors list
|
|
63
|
-
or if no stdin_text, no commit_file, and no commits exist.
|
|
63
|
+
Skip if the current author or any co-author is in the ignore_authors list
|
|
64
|
+
for commits, or if no stdin_text, no commit_file, and no commits exist.
|
|
64
65
|
"""
|
|
66
|
+
import re
|
|
67
|
+
|
|
65
68
|
ignore_authors = context.config.get("commit", {}).get("ignore_authors", [])
|
|
66
69
|
current_author = get_commit_info("an")
|
|
67
70
|
if current_author and current_author in ignore_authors:
|
|
68
71
|
return True
|
|
72
|
+
|
|
73
|
+
# Check co-authors from the commit message body
|
|
74
|
+
if ignore_authors:
|
|
75
|
+
message = ""
|
|
76
|
+
if context.stdin_text:
|
|
77
|
+
message = context.stdin_text
|
|
78
|
+
elif context.commit_file:
|
|
79
|
+
try:
|
|
80
|
+
with open(context.commit_file, "r") as f:
|
|
81
|
+
message = f.read()
|
|
82
|
+
except (OSError, IOError):
|
|
83
|
+
pass
|
|
84
|
+
else:
|
|
85
|
+
message = get_commit_info("b")
|
|
86
|
+
if message:
|
|
87
|
+
co_authors = re.findall(
|
|
88
|
+
r"^Co-authored-by:\s*([^<\n]+?)\s*(?:<|$)",
|
|
89
|
+
message,
|
|
90
|
+
re.MULTILINE,
|
|
91
|
+
)
|
|
92
|
+
for co_author in co_authors:
|
|
93
|
+
if co_author.strip() in ignore_authors:
|
|
94
|
+
return True
|
|
95
|
+
|
|
69
96
|
return (
|
|
70
97
|
context.stdin_text is None
|
|
71
98
|
and context.commit_file is None
|
|
@@ -250,15 +277,32 @@ class AuthorValidator(BaseValidator):
|
|
|
250
277
|
return self._validate_author(author_value)
|
|
251
278
|
|
|
252
279
|
def _get_author_value(self, context: ValidationContext) -> str:
|
|
253
|
-
"""Get author value based on rule type.
|
|
280
|
+
"""Get author value based on rule type.
|
|
281
|
+
|
|
282
|
+
Checks git config first (for pre-commit validation of the configured identity),
|
|
283
|
+
then falls back to the last commit's author info.
|
|
284
|
+
"""
|
|
254
285
|
if context.stdin_text:
|
|
255
286
|
return context.stdin_text.strip()
|
|
256
287
|
|
|
257
|
-
|
|
288
|
+
git_config_map = {
|
|
289
|
+
"author_name": "user.name",
|
|
290
|
+
"author_email": "user.email",
|
|
291
|
+
}
|
|
292
|
+
git_log_map = {
|
|
258
293
|
"author_name": "an",
|
|
259
294
|
"author_email": "ae",
|
|
260
295
|
}
|
|
261
|
-
|
|
296
|
+
|
|
297
|
+
# Try git config first (validates configured identity for new commits)
|
|
298
|
+
config_key = git_config_map.get(self.rule.check, "")
|
|
299
|
+
if config_key:
|
|
300
|
+
config_value = get_git_config_value(config_key)
|
|
301
|
+
if config_value:
|
|
302
|
+
return config_value
|
|
303
|
+
|
|
304
|
+
# Fall back to last commit's author info
|
|
305
|
+
format_str = git_log_map.get(self.rule.check, "")
|
|
262
306
|
return get_commit_info(format_str) if format_str else ""
|
|
263
307
|
|
|
264
308
|
def _validate_author(self, author_value: str) -> ValidationResult:
|
commit_check/imperatives.py
CHANGED
commit_check/rule_builder.py
CHANGED
|
@@ -110,11 +110,16 @@ class RuleBuilder:
|
|
|
110
110
|
allowed_types = self._get_allowed_commit_types()
|
|
111
111
|
regex = self._build_conventional_commit_regex(allowed_types)
|
|
112
112
|
|
|
113
|
+
types_str = ", ".join(allowed_types)
|
|
114
|
+
suggest = (
|
|
115
|
+
f"Use <type>(<scope>): <description>, where <type> is one of: {types_str}"
|
|
116
|
+
)
|
|
117
|
+
|
|
113
118
|
return ValidationRule(
|
|
114
119
|
check=catalog_entry.check,
|
|
115
120
|
regex=regex,
|
|
116
121
|
error=catalog_entry.error,
|
|
117
|
-
suggest=
|
|
122
|
+
suggest=suggest,
|
|
118
123
|
allowed=allowed_types,
|
|
119
124
|
)
|
|
120
125
|
|
commit_check/rules_catalog.py
CHANGED
|
@@ -29,8 +29,8 @@ COMMIT_RULES = [
|
|
|
29
29
|
RuleCatalogEntry(
|
|
30
30
|
check="subject_imperative",
|
|
31
31
|
regex=None,
|
|
32
|
-
error="Commit message should use imperative mood (e.g., '
|
|
33
|
-
suggest="
|
|
32
|
+
error="Commit message should use imperative mood (e.g., 'fix bug' not 'fixed bug', 'add feature' not 'adding feature')",
|
|
33
|
+
suggest="Change the first verb to imperative form, e.g., 'fix' instead of 'fixed'/'fixes'/'fixing'",
|
|
34
34
|
),
|
|
35
35
|
RuleCatalogEntry(
|
|
36
36
|
check="subject_max_length",
|
commit_check/util.py
CHANGED
|
@@ -36,7 +36,7 @@ def _print_failure(check: dict, regex: str, actual: str) -> None:
|
|
|
36
36
|
"""Print a standardized failure message."""
|
|
37
37
|
if not print_error_header.has_been_called:
|
|
38
38
|
print_error_header()
|
|
39
|
-
print_error_message(check["check"],
|
|
39
|
+
print_error_message(check["check"], check.get("error", ""), actual)
|
|
40
40
|
if check.get("suggest"):
|
|
41
41
|
print_suggestion(check.get("suggest"))
|
|
42
42
|
|
|
@@ -108,6 +108,19 @@ def get_commit_info(format_string: str, sha: str = "HEAD") -> str:
|
|
|
108
108
|
return output
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
def get_git_config_value(key: str) -> str:
|
|
112
|
+
"""Get a value from git config.
|
|
113
|
+
:param key: git config key, e.g., 'user.name' or 'user.email'
|
|
114
|
+
:returns: The configured value as a `str`, or empty string if not set.
|
|
115
|
+
"""
|
|
116
|
+
try:
|
|
117
|
+
commands = ["git", "config", "--get", key]
|
|
118
|
+
output = cmd_output(commands)
|
|
119
|
+
return output.strip()
|
|
120
|
+
except CalledProcessError:
|
|
121
|
+
return ""
|
|
122
|
+
|
|
123
|
+
|
|
111
124
|
def git_merge_base(target_branch: str, current_branch: str) -> int:
|
|
112
125
|
"""Check ancestors for a given commit.
|
|
113
126
|
:param target_branch: target branch
|
|
@@ -241,10 +254,9 @@ def print_error_header():
|
|
|
241
254
|
print(" ")
|
|
242
255
|
|
|
243
256
|
|
|
244
|
-
def print_error_message(check_type: str,
|
|
257
|
+
def print_error_message(check_type: str, error: str, reason: str):
|
|
245
258
|
"""Print error message.
|
|
246
259
|
:param check_type:
|
|
247
|
-
:param regex:
|
|
248
260
|
:param error:
|
|
249
261
|
:param reason:
|
|
250
262
|
|
|
@@ -255,8 +267,8 @@ def print_error_message(check_type: str, regex: str, error: str, reason: str):
|
|
|
255
267
|
end="",
|
|
256
268
|
)
|
|
257
269
|
print("")
|
|
258
|
-
|
|
259
|
-
|
|
270
|
+
if error:
|
|
271
|
+
print(error)
|
|
260
272
|
|
|
261
273
|
|
|
262
274
|
def print_suggestion(suggest: Optional[str]) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: commit-check
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
4
4
|
Summary: Check commit message formatting, branch naming, commit author, email, and more.
|
|
5
5
|
Author-email: Xianpeng Shen <xianpeng.shen@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -66,17 +66,84 @@ Commit Check
|
|
|
66
66
|
:target: https://slsa.dev
|
|
67
67
|
:alt: SLSA
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
.. |pypi-downloads| image:: https://img.shields.io/pypi/dm/commit-check?color=%232c9ccd
|
|
70
|
+
:target: https://pypi.org/project/commit-check/
|
|
71
|
+
:alt: PyPI Downloads
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
.. |python-versions| image:: https://img.shields.io/pypi/pyversions/commit-check?logo=python&logoColor=white
|
|
74
|
+
:target: https://pypi.org/project/commit-check/
|
|
75
|
+
:alt: Python Versions
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
|ci-badge| |sonar-badge| |pypi-version| |pypi-downloads| |python-versions| |commit-check-badge| |codecov-badge| |slsa-badge|
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
Overview
|
|
80
|
+
--------
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
**Commit Check** (aka **cchk**) is the most comprehensive open-source tool for enforcing Git commit standards — including commit messages, branch naming, author identity, commit signoff, and more — helping teams maintain consistency and compliance across every repository.
|
|
83
|
+
|
|
84
|
+
As a lightweight, free alternative to GitHub Enterprise `Metadata restrictions <https://docs.github.com/en/enterprise-server@3.11/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#metadata-restrictions>`_
|
|
85
|
+
and Bitbucket's paid `Yet Another Commit Checker <https://marketplace.atlassian.com/apps/1211854/yet-another-commit-checker?tab=overview&hosting=datacenter>`_ plugin, Commit Check integrates DevOps principles and Infrastructure as Code (IaC) practices for a modern workflow.
|
|
86
|
+
|
|
87
|
+
**Why Commit Check?**
|
|
88
|
+
|
|
89
|
+
.. list-table::
|
|
90
|
+
:header-rows: 1
|
|
91
|
+
:widths: 40 20 20 20
|
|
92
|
+
|
|
93
|
+
* - Feature
|
|
94
|
+
- Commit Check ✅
|
|
95
|
+
- commitlint
|
|
96
|
+
- pre-commit hooks
|
|
97
|
+
* - Conventional Commits enforcement
|
|
98
|
+
- ✅
|
|
99
|
+
- ✅
|
|
100
|
+
- ✅
|
|
101
|
+
* - Branch naming validation
|
|
102
|
+
- ✅
|
|
103
|
+
- ❌
|
|
104
|
+
- Partial
|
|
105
|
+
* - Author name / email validation
|
|
106
|
+
- ✅
|
|
107
|
+
- ❌
|
|
108
|
+
- ❌
|
|
109
|
+
* - Signoff / DCO check
|
|
110
|
+
- ✅
|
|
111
|
+
- ❌
|
|
112
|
+
- ❌
|
|
113
|
+
* - Co-author ignore list
|
|
114
|
+
- ✅
|
|
115
|
+
- ❌
|
|
116
|
+
- ❌
|
|
117
|
+
* - Organization-level config inheritance
|
|
118
|
+
- ✅
|
|
119
|
+
- ❌
|
|
120
|
+
- ❌
|
|
121
|
+
* - Zero-config defaults
|
|
122
|
+
- ✅
|
|
123
|
+
- ❌
|
|
124
|
+
- ❌
|
|
125
|
+
* - Works without Node.js
|
|
126
|
+
- ✅
|
|
127
|
+
- ❌
|
|
128
|
+
- ✅
|
|
129
|
+
* - TOML configuration
|
|
130
|
+
- ✅
|
|
131
|
+
- ❌
|
|
132
|
+
- ✅
|
|
133
|
+
* - pre-commit framework integration
|
|
134
|
+
- ✅
|
|
135
|
+
- ✅
|
|
136
|
+
- ✅
|
|
137
|
+
* - CI/CD environment variables
|
|
138
|
+
- ✅
|
|
139
|
+
- Partial
|
|
140
|
+
- ❌
|
|
141
|
+
* - SLSA Level 3 supply chain security
|
|
142
|
+
- ✅
|
|
143
|
+
- ❌
|
|
144
|
+
- ❌
|
|
145
|
+
|
|
146
|
+
What's New in v2.0.0
|
|
80
147
|
--------------------
|
|
81
148
|
|
|
82
149
|
Version 2.0.0 is a major release featuring a new configuration format, a modernized architecture, and an improved user experience.
|
|
@@ -86,6 +153,9 @@ Version 2.0.0 is a major release featuring a new configuration format, a moderni
|
|
|
86
153
|
* **TOML Configuration** — Replaces ``.commit-check.yml`` with ``cchk.toml`` or ``commit-check.toml`` for clearer, more consistent syntax.
|
|
87
154
|
* **Simplified CLI & Hooks** — Legacy pre-commit hooks and options removed to deliver a cleaner, more streamlined interface.
|
|
88
155
|
* **New Validation Engine** — Fully redesigned for greater flexibility, performance, and maintainability.
|
|
156
|
+
* **Co-author ignore support** — Bypass checks when a commit is co-authored by a bot or trusted identity in ``ignore_authors``.
|
|
157
|
+
* **Organization-level configuration** — Use ``inherit_from`` to share a base config across all repositories in your org.
|
|
158
|
+
* **Git config author validation** — ``--author-name`` and ``--author-email`` now validate the configured identity for the next commit.
|
|
89
159
|
|
|
90
160
|
For the full list of updates and improvements, visit the `What's New <https://commit-check.github.io/commit-check/what-is-new.html>`_ page.
|
|
91
161
|
|
|
@@ -108,6 +178,34 @@ Then, run ``commit-check --help`` or ``cchk --help`` (alias for ``commit-check``
|
|
|
108
178
|
For more information, see the `docs <https://commit-check.github.io/commit-check/cli_args.html>`_.
|
|
109
179
|
|
|
110
180
|
|
|
181
|
+
Quick Start
|
|
182
|
+
-----------
|
|
183
|
+
|
|
184
|
+
**1. Install and run with zero configuration:**
|
|
185
|
+
|
|
186
|
+
.. code-block:: bash
|
|
187
|
+
|
|
188
|
+
pip install commit-check
|
|
189
|
+
commit-check --message --branch
|
|
190
|
+
|
|
191
|
+
**2. Add to your pre-commit hooks** (``.pre-commit-config.yaml``):
|
|
192
|
+
|
|
193
|
+
.. code-block:: yaml
|
|
194
|
+
|
|
195
|
+
repos:
|
|
196
|
+
- repo: https://github.com/commit-check/commit-check
|
|
197
|
+
rev: v2.3.0
|
|
198
|
+
hooks:
|
|
199
|
+
- id: check-message
|
|
200
|
+
- id: check-branch
|
|
201
|
+
|
|
202
|
+
**3. Add a badge to your repository:**
|
|
203
|
+
|
|
204
|
+
.. code-block:: text
|
|
205
|
+
|
|
206
|
+
[](https://github.com/commit-check/commit-check)
|
|
207
|
+
|
|
208
|
+
|
|
111
209
|
Configuration
|
|
112
210
|
-------------
|
|
113
211
|
|
|
@@ -129,6 +227,49 @@ Use Custom Configuration File
|
|
|
129
227
|
|
|
130
228
|
To customize the behavior, create a configuration file named ``cchk.toml`` or ``commit-check.toml`` in your repository's root directory or in the ``.github`` folder, e.g., `cchk.toml <https://github.com/commit-check/commit-check/blob/main/cchk.toml>`_ or ``.github/cchk.toml``.
|
|
131
229
|
|
|
230
|
+
.. code-block:: toml
|
|
231
|
+
|
|
232
|
+
[commit]
|
|
233
|
+
# https://www.conventionalcommits.org
|
|
234
|
+
conventional_commits = true
|
|
235
|
+
subject_imperative = true
|
|
236
|
+
subject_max_length = 80
|
|
237
|
+
allow_commit_types = ["feat", "fix", "docs", "style", "refactor", "test", "chore", "ci"]
|
|
238
|
+
allow_merge_commits = true
|
|
239
|
+
allow_wip_commits = false
|
|
240
|
+
require_signed_off_by = false
|
|
241
|
+
# Bypass checks for bot/automation authors and co-authors:
|
|
242
|
+
ignore_authors = ["dependabot[bot]", "renovate[bot]", "copilot[bot]"]
|
|
243
|
+
|
|
244
|
+
[branch]
|
|
245
|
+
# https://conventional-branch.github.io/
|
|
246
|
+
conventional_branch = true
|
|
247
|
+
allow_branch_types = ["feature", "bugfix", "hotfix", "release", "chore", "feat", "fix"]
|
|
248
|
+
|
|
249
|
+
Organization-Level Configuration (inherit_from)
|
|
250
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
251
|
+
|
|
252
|
+
Share a base configuration across all repositories in your organization using ``inherit_from``:
|
|
253
|
+
|
|
254
|
+
.. code-block:: toml
|
|
255
|
+
|
|
256
|
+
# .github/cchk.toml — inherits from org-level config, then overrides locally
|
|
257
|
+
inherit_from = "github:my-org/.github:cchk.toml"
|
|
258
|
+
|
|
259
|
+
[commit]
|
|
260
|
+
subject_max_length = 72 # Local override
|
|
261
|
+
|
|
262
|
+
The ``inherit_from`` field accepts:
|
|
263
|
+
|
|
264
|
+
* A **GitHub shorthand** (recommended): ``inherit_from = "github:owner/repo:path/to/cchk.toml"``
|
|
265
|
+
* A **GitHub shorthand with ref**: ``inherit_from = "github:owner/repo@main:path/to/cchk.toml"``
|
|
266
|
+
* A **local file path** (relative or absolute): ``inherit_from = "../shared/cchk.toml"``
|
|
267
|
+
* An **HTTPS URL**: ``inherit_from = "https://example.com/cchk.toml"``
|
|
268
|
+
|
|
269
|
+
The ``github:`` shorthand fetches from ``raw.githubusercontent.com``. HTTP (non-TLS) URLs are rejected for security.
|
|
270
|
+
|
|
271
|
+
Local settings always **override** the inherited base configuration.
|
|
272
|
+
|
|
132
273
|
Use CLI Arguments or Environment Variables
|
|
133
274
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
134
275
|
|
|
@@ -164,6 +305,12 @@ For detailed usage instructions including pre-commit hooks, CLI commands, and ST
|
|
|
164
305
|
Examples
|
|
165
306
|
--------
|
|
166
307
|
|
|
308
|
+
.. image:: https://github.com/commit-check/commit-check/raw/main/docs/demo.gif
|
|
309
|
+
:alt: commit-check demo
|
|
310
|
+
:align: center
|
|
311
|
+
|
|
312
|
+
|
|
|
313
|
+
|
|
167
314
|
Check Commit Message Failed
|
|
168
315
|
|
|
169
316
|
.. code-block:: text
|
|
@@ -182,9 +329,8 @@ Check Commit Message Failed
|
|
|
182
329
|
Commit rejected.
|
|
183
330
|
|
|
184
331
|
Type message check failed ==> test commit message check
|
|
185
|
-
It doesn't match regex: ^(chore|ci|docs|feat|fix|refactor|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)|(Merge).*|(fixup!.*)
|
|
186
332
|
The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
|
|
187
|
-
Suggest: Use <type>(<scope>): <description>
|
|
333
|
+
Suggest: Use <type>(<scope>): <description>, where <type> is one of: feat, fix, docs, style, refactor, test, chore, ci
|
|
188
334
|
|
|
189
335
|
|
|
190
336
|
Check Branch Naming Failed
|
|
@@ -205,9 +351,8 @@ Check Branch Naming Failed
|
|
|
205
351
|
Commit rejected.
|
|
206
352
|
|
|
207
353
|
Type branch check failed ==> test-branch
|
|
208
|
-
It doesn't match regex: ^(feature|bugfix|hotfix|release|chore|feat|fix)\/.+|(master)|(main)|(HEAD)|(PR-.+)
|
|
209
354
|
The branch should follow Conventional Branch. See https://conventional-branch.github.io/
|
|
210
|
-
Suggest: Use <type>/<description> with allowed types or ignore_authors in config branch section to bypass
|
|
355
|
+
Suggest: Use <type>/<description> with allowed types or add branch name to allow_branch_names in config, or use ignore_authors in config branch section to bypass
|
|
211
356
|
|
|
212
357
|
More examples see `example documentation <https://commit-check.github.io/commit-check/example.html>`_.
|
|
213
358
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
commit_check/__init__.py,sha256=6bUw-6fUjCN5qAxe6i4mUztQiAHpjOhyPHsegW1tbBc,1297
|
|
2
|
+
commit_check/config.py,sha256=sBC88kUizxna-X8n20pRayvkExbO7wEElz_9MCdycgM,5049
|
|
3
|
+
commit_check/config_merger.py,sha256=QwOLi3-pm-1w77aMiBeJzJLKoERDJlzH4IfTyNa421I,9427
|
|
4
|
+
commit_check/engine.py,sha256=Va6zf-UntD0PX6vTh-mk3s6YzW20qCklB2f97YqxaBc,20864
|
|
5
|
+
commit_check/imperatives.py,sha256=INIMI2PAzQaaM4qfaLAEkSrnuMZtuzSZtpad0D6DkKA,3844
|
|
6
|
+
commit_check/main.py,sha256=Ozm-ZJcIo-sjuXA7NZtEQCxP9PzKsKN9yP0_puIBs8Y,12094
|
|
7
|
+
commit_check/rule_builder.py,sha256=yvaxGW3ED6upunvtse8qEcIENySWHG8tW_ZaC8cCN2k,9354
|
|
8
|
+
commit_check/rules_catalog.py,sha256=l7qvrAK71Q9J0Wv8AeLve7aHYzKTaqh_pWS0ILJ2fxE,4366
|
|
9
|
+
commit_check/util.py,sha256=6m3Jij4DzRGZRCy9Q4sUo1QqZLZgiiM4da11rjt6Ebs,8843
|
|
10
|
+
commit_check-2.5.0.dist-info/licenses/LICENSE,sha256=VAJ9TE1ov8aUKmeoBRYqciMs0CXag1TeDCoLhwbeQmA,1095
|
|
11
|
+
commit_check-2.5.0.dist-info/METADATA,sha256=_l8rMFEFUecAApi1H9DqN0kw3dRKpscyQbMyfqdOD1g,14840
|
|
12
|
+
commit_check-2.5.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
13
|
+
commit_check-2.5.0.dist-info/entry_points.txt,sha256=YMrkFGeub-3-IanV1d9qnopXVaRQM7MA9foXKW9iZ88,86
|
|
14
|
+
commit_check-2.5.0.dist-info/top_level.txt,sha256=Wf46u-ooHBMJNHbhfrBNQw3wC5_m8wt-o_Lfbc4QpRg,13
|
|
15
|
+
commit_check-2.5.0.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
commit_check/__init__.py,sha256=6bUw-6fUjCN5qAxe6i4mUztQiAHpjOhyPHsegW1tbBc,1297
|
|
2
|
-
commit_check/config.py,sha256=88zOLW6W2DHQjglxfSR3LQhCXgw-QcfEg118-OaWxIg,1031
|
|
3
|
-
commit_check/config_merger.py,sha256=QwOLi3-pm-1w77aMiBeJzJLKoERDJlzH4IfTyNa421I,9427
|
|
4
|
-
commit_check/engine.py,sha256=O9H39JgqrzWclfVTZYf-tJP8lAhHzGfV7j-CIxAsXWA,19348
|
|
5
|
-
commit_check/imperatives.py,sha256=dNLeGUaSjfWtKNcFnmMWWmzcfX5J2sTCWZcOmEKlbm4,3829
|
|
6
|
-
commit_check/main.py,sha256=Ozm-ZJcIo-sjuXA7NZtEQCxP9PzKsKN9yP0_puIBs8Y,12094
|
|
7
|
-
commit_check/rule_builder.py,sha256=0UqMQxDiPNgqEjmRTYnyHimCA7vZRZqgqdm7ughp3DY,9205
|
|
8
|
-
commit_check/rules_catalog.py,sha256=FSRsdecwfUteEp3J8lnfehLu4j6owZlWfDzPa1ar1Fg,4288
|
|
9
|
-
commit_check/util.py,sha256=4c9cxbBR3ZBSmYGNmzj87XWWr0zsCV8tmg1Z1yZ3iBI,8501
|
|
10
|
-
commit_check-2.4.2.dist-info/licenses/LICENSE,sha256=VAJ9TE1ov8aUKmeoBRYqciMs0CXag1TeDCoLhwbeQmA,1095
|
|
11
|
-
commit_check-2.4.2.dist-info/METADATA,sha256=h7-PAMqvqWCSMgSCvaz8aCRlom8fp2bs4feYStJhoAY,10724
|
|
12
|
-
commit_check-2.4.2.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
|
|
13
|
-
commit_check-2.4.2.dist-info/entry_points.txt,sha256=YMrkFGeub-3-IanV1d9qnopXVaRQM7MA9foXKW9iZ88,86
|
|
14
|
-
commit_check-2.4.2.dist-info/top_level.txt,sha256=Wf46u-ooHBMJNHbhfrBNQw3wC5_m8wt-o_Lfbc4QpRg,13
|
|
15
|
-
commit_check-2.4.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|