git-commit-guard 0.10.0__tar.gz → 0.12.0__tar.gz
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.
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.github/workflows/release.yml +19 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/PKG-INFO +65 -6
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/README.md +64 -5
- git_commit_guard-0.12.0/action.yml +85 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/src/git_commit_guard/__init__.py +23 -1
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/tests/test_git_commit_guard.py +107 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.github/workflows/lint-commits.yml +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.github/workflows/lint-md.yml +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.github/workflows/lint-python.yml +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.github/workflows/test.yml +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.gitignore +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.pre-commit-hooks.yaml +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/.python-version +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/LICENSE +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/pyproject.toml +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/ruff.toml +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/tests/__init__.py +0 -0
- {git_commit_guard-0.10.0 → git_commit_guard-0.12.0}/uv.lock +0 -0
|
@@ -6,6 +6,7 @@ on: # yamllint disable-line rule:truthy
|
|
|
6
6
|
- 'v*'
|
|
7
7
|
permissions:
|
|
8
8
|
contents: write
|
|
9
|
+
id-token: write
|
|
9
10
|
jobs:
|
|
10
11
|
release:
|
|
11
12
|
runs-on: ubuntu-latest
|
|
@@ -16,6 +17,19 @@ jobs:
|
|
|
16
17
|
with:
|
|
17
18
|
persist-credentials: false
|
|
18
19
|
fetch-depth: 0
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
# yamllint disable-line rule:line-length
|
|
22
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
23
|
+
- name: Set up uv
|
|
24
|
+
# yamllint disable-line rule:line-length
|
|
25
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
26
|
+
with:
|
|
27
|
+
enable-cache: false
|
|
28
|
+
- name: Build package
|
|
29
|
+
run: uv build
|
|
30
|
+
- name: Publish to PyPI
|
|
31
|
+
# yamllint disable-line rule:line-length
|
|
32
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
19
33
|
- name: Generate release notes
|
|
20
34
|
id: git-cliff
|
|
21
35
|
# yamllint disable-line rule:line-length
|
|
@@ -31,3 +45,8 @@ jobs:
|
|
|
31
45
|
gh release create "$TAG" \
|
|
32
46
|
--title "$TAG" \
|
|
33
47
|
--notes-file "$NOTES_FILE"
|
|
48
|
+
- name: Upload dist to GitHub Release
|
|
49
|
+
env:
|
|
50
|
+
GH_TOKEN: ${{ github.token }}
|
|
51
|
+
TAG: ${{ github.ref_name }}
|
|
52
|
+
run: gh release upload "$TAG" dist/*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-commit-guard
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Opinionated conventional commit message linter with imperative mood detection
|
|
5
5
|
Project-URL: Homepage, https://github.com/benner/commit-guard
|
|
6
6
|
Project-URL: Repository, https://github.com/benner/commit-guard
|
|
@@ -110,6 +110,13 @@ The default maximum subject line length is 72 characters. Override with
|
|
|
110
110
|
commit-guard --max-subject-length 100
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
By default there is no minimum description length. Enforce one with
|
|
114
|
+
`--min-description-length`:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
commit-guard --min-description-length 10
|
|
118
|
+
```
|
|
119
|
+
|
|
113
120
|
### Type validation
|
|
114
121
|
|
|
115
122
|
By default the standard conventional commit types are accepted. Use `--types`
|
|
@@ -143,9 +150,9 @@ commit-guard --scopes auth,api --require-scope
|
|
|
143
150
|
### Configuration file
|
|
144
151
|
|
|
145
152
|
Place `.commit-guard.toml` in your project root (or any parent directory) to
|
|
146
|
-
set defaults for `enable`, `disable`, `scopes`, `require-scope`, `types`,
|
|
147
|
-
`max-subject-length`. commit-guard searches
|
|
148
|
-
and uses the first file found.
|
|
153
|
+
set defaults for `enable`, `disable`, `scopes`, `require-scope`, `types`,
|
|
154
|
+
`max-subject-length`, and `min-description-length`. commit-guard searches
|
|
155
|
+
upward from the working directory and uses the first file found.
|
|
149
156
|
|
|
150
157
|
```toml
|
|
151
158
|
# .commit-guard.toml
|
|
@@ -154,6 +161,7 @@ scopes = ["auth", "api", "db"]
|
|
|
154
161
|
require-scope = true
|
|
155
162
|
types = ["feat", "fix", "chore", "wip"]
|
|
156
163
|
max-subject-length = 100
|
|
164
|
+
min-description-length = 10
|
|
157
165
|
```
|
|
158
166
|
|
|
159
167
|
```toml
|
|
@@ -162,8 +170,8 @@ enable = ["subject", "imperative"]
|
|
|
162
170
|
```
|
|
163
171
|
|
|
164
172
|
CLI flags (`--enable`, `--disable`, `--scopes`, `--require-scope`, `--types`,
|
|
165
|
-
`--max-subject-length`) take full precedence and
|
|
166
|
-
provided.
|
|
173
|
+
`--max-subject-length`, `--min-description-length`) take full precedence and
|
|
174
|
+
ignore config file values when provided.
|
|
167
175
|
|
|
168
176
|
### Checking a range of commits
|
|
169
177
|
|
|
@@ -194,6 +202,57 @@ misconfigured range specs in CI. Use `--allow-empty` to exit 0 instead:
|
|
|
194
202
|
commit-guard --range origin/main..HEAD --allow-empty
|
|
195
203
|
```
|
|
196
204
|
|
|
205
|
+
### GitHub Actions
|
|
206
|
+
|
|
207
|
+
```yaml
|
|
208
|
+
steps:
|
|
209
|
+
- uses: actions/checkout@v4
|
|
210
|
+
with:
|
|
211
|
+
fetch-depth: 0
|
|
212
|
+
- uses: benner/commit-guard@vX.Y.Z
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Check all commits in a pull request:
|
|
216
|
+
|
|
217
|
+
```yaml
|
|
218
|
+
jobs:
|
|
219
|
+
lint-commits:
|
|
220
|
+
runs-on: ubuntu-latest
|
|
221
|
+
env:
|
|
222
|
+
PR_BASE: ${{ github.event.pull_request.base.sha }}
|
|
223
|
+
PR_HEAD: ${{ github.event.pull_request.head.sha }}
|
|
224
|
+
steps:
|
|
225
|
+
- uses: actions/checkout@v4
|
|
226
|
+
with:
|
|
227
|
+
fetch-depth: 0
|
|
228
|
+
- uses: benner/commit-guard@vX.Y.Z
|
|
229
|
+
with:
|
|
230
|
+
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
All inputs are optional and mirror the CLI flags:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
jobs:
|
|
237
|
+
lint-commits:
|
|
238
|
+
runs-on: ubuntu-latest
|
|
239
|
+
env:
|
|
240
|
+
PR_BASE: ${{ github.event.pull_request.base.sha }}
|
|
241
|
+
PR_HEAD: ${{ github.event.pull_request.head.sha }}
|
|
242
|
+
steps:
|
|
243
|
+
- uses: actions/checkout@v4
|
|
244
|
+
with:
|
|
245
|
+
fetch-depth: 0
|
|
246
|
+
- uses: benner/commit-guard@vX.Y.Z
|
|
247
|
+
with:
|
|
248
|
+
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
249
|
+
disable: signed-off,signature
|
|
250
|
+
scopes: auth,api,db
|
|
251
|
+
require-scope: 'true'
|
|
252
|
+
max-subject-length: '100'
|
|
253
|
+
min-description-length: '10'
|
|
254
|
+
```
|
|
255
|
+
|
|
197
256
|
### pre-commit
|
|
198
257
|
|
|
199
258
|
Add to your `.pre-commit-config.yaml`:
|
|
@@ -89,6 +89,13 @@ The default maximum subject line length is 72 characters. Override with
|
|
|
89
89
|
commit-guard --max-subject-length 100
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
By default there is no minimum description length. Enforce one with
|
|
93
|
+
`--min-description-length`:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
commit-guard --min-description-length 10
|
|
97
|
+
```
|
|
98
|
+
|
|
92
99
|
### Type validation
|
|
93
100
|
|
|
94
101
|
By default the standard conventional commit types are accepted. Use `--types`
|
|
@@ -122,9 +129,9 @@ commit-guard --scopes auth,api --require-scope
|
|
|
122
129
|
### Configuration file
|
|
123
130
|
|
|
124
131
|
Place `.commit-guard.toml` in your project root (or any parent directory) to
|
|
125
|
-
set defaults for `enable`, `disable`, `scopes`, `require-scope`, `types`,
|
|
126
|
-
`max-subject-length`. commit-guard searches
|
|
127
|
-
and uses the first file found.
|
|
132
|
+
set defaults for `enable`, `disable`, `scopes`, `require-scope`, `types`,
|
|
133
|
+
`max-subject-length`, and `min-description-length`. commit-guard searches
|
|
134
|
+
upward from the working directory and uses the first file found.
|
|
128
135
|
|
|
129
136
|
```toml
|
|
130
137
|
# .commit-guard.toml
|
|
@@ -133,6 +140,7 @@ scopes = ["auth", "api", "db"]
|
|
|
133
140
|
require-scope = true
|
|
134
141
|
types = ["feat", "fix", "chore", "wip"]
|
|
135
142
|
max-subject-length = 100
|
|
143
|
+
min-description-length = 10
|
|
136
144
|
```
|
|
137
145
|
|
|
138
146
|
```toml
|
|
@@ -141,8 +149,8 @@ enable = ["subject", "imperative"]
|
|
|
141
149
|
```
|
|
142
150
|
|
|
143
151
|
CLI flags (`--enable`, `--disable`, `--scopes`, `--require-scope`, `--types`,
|
|
144
|
-
`--max-subject-length`) take full precedence and
|
|
145
|
-
provided.
|
|
152
|
+
`--max-subject-length`, `--min-description-length`) take full precedence and
|
|
153
|
+
ignore config file values when provided.
|
|
146
154
|
|
|
147
155
|
### Checking a range of commits
|
|
148
156
|
|
|
@@ -173,6 +181,57 @@ misconfigured range specs in CI. Use `--allow-empty` to exit 0 instead:
|
|
|
173
181
|
commit-guard --range origin/main..HEAD --allow-empty
|
|
174
182
|
```
|
|
175
183
|
|
|
184
|
+
### GitHub Actions
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
steps:
|
|
188
|
+
- uses: actions/checkout@v4
|
|
189
|
+
with:
|
|
190
|
+
fetch-depth: 0
|
|
191
|
+
- uses: benner/commit-guard@vX.Y.Z
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Check all commits in a pull request:
|
|
195
|
+
|
|
196
|
+
```yaml
|
|
197
|
+
jobs:
|
|
198
|
+
lint-commits:
|
|
199
|
+
runs-on: ubuntu-latest
|
|
200
|
+
env:
|
|
201
|
+
PR_BASE: ${{ github.event.pull_request.base.sha }}
|
|
202
|
+
PR_HEAD: ${{ github.event.pull_request.head.sha }}
|
|
203
|
+
steps:
|
|
204
|
+
- uses: actions/checkout@v4
|
|
205
|
+
with:
|
|
206
|
+
fetch-depth: 0
|
|
207
|
+
- uses: benner/commit-guard@vX.Y.Z
|
|
208
|
+
with:
|
|
209
|
+
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
All inputs are optional and mirror the CLI flags:
|
|
213
|
+
|
|
214
|
+
```yaml
|
|
215
|
+
jobs:
|
|
216
|
+
lint-commits:
|
|
217
|
+
runs-on: ubuntu-latest
|
|
218
|
+
env:
|
|
219
|
+
PR_BASE: ${{ github.event.pull_request.base.sha }}
|
|
220
|
+
PR_HEAD: ${{ github.event.pull_request.head.sha }}
|
|
221
|
+
steps:
|
|
222
|
+
- uses: actions/checkout@v4
|
|
223
|
+
with:
|
|
224
|
+
fetch-depth: 0
|
|
225
|
+
- uses: benner/commit-guard@vX.Y.Z
|
|
226
|
+
with:
|
|
227
|
+
range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
|
|
228
|
+
disable: signed-off,signature
|
|
229
|
+
scopes: auth,api,db
|
|
230
|
+
require-scope: 'true'
|
|
231
|
+
max-subject-length: '100'
|
|
232
|
+
min-description-length: '10'
|
|
233
|
+
```
|
|
234
|
+
|
|
176
235
|
### pre-commit
|
|
177
236
|
|
|
178
237
|
Add to your `.pre-commit-config.yaml`:
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit-guard
|
|
3
|
+
description: Conventional commit message linter with imperative mood detection
|
|
4
|
+
author: Nerijus Bendžiūnas
|
|
5
|
+
branding:
|
|
6
|
+
icon: shield
|
|
7
|
+
color: green
|
|
8
|
+
inputs:
|
|
9
|
+
rev:
|
|
10
|
+
description: Commit SHA to check (defaults to HEAD)
|
|
11
|
+
required: false
|
|
12
|
+
range:
|
|
13
|
+
description: Revision range to check (e.g. abc123..HEAD)
|
|
14
|
+
required: false
|
|
15
|
+
enable:
|
|
16
|
+
description: Comma-separated checks to enable
|
|
17
|
+
required: false
|
|
18
|
+
disable:
|
|
19
|
+
description: Comma-separated checks to disable
|
|
20
|
+
required: false
|
|
21
|
+
scopes:
|
|
22
|
+
description: Comma-separated list of allowed scopes
|
|
23
|
+
required: false
|
|
24
|
+
require-scope:
|
|
25
|
+
description: Require a scope in the subject line
|
|
26
|
+
required: false
|
|
27
|
+
default: 'false'
|
|
28
|
+
types:
|
|
29
|
+
description: Comma-separated list of allowed types (replaces defaults)
|
|
30
|
+
required: false
|
|
31
|
+
max-subject-length:
|
|
32
|
+
description: Maximum subject line length (default 72)
|
|
33
|
+
required: false
|
|
34
|
+
min-description-length:
|
|
35
|
+
description: Minimum description length in characters (default 0, off)
|
|
36
|
+
required: false
|
|
37
|
+
allow-empty:
|
|
38
|
+
description: Exit 0 when --range yields no commits
|
|
39
|
+
required: false
|
|
40
|
+
default: 'false'
|
|
41
|
+
include-merges:
|
|
42
|
+
description: Include merge commits when checking a range
|
|
43
|
+
required: false
|
|
44
|
+
default: 'false'
|
|
45
|
+
runs:
|
|
46
|
+
using: composite
|
|
47
|
+
steps:
|
|
48
|
+
- name: Set up uv
|
|
49
|
+
# yamllint disable-line rule:line-length
|
|
50
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
51
|
+
with:
|
|
52
|
+
enable-cache: false
|
|
53
|
+
- name: Install commit-guard
|
|
54
|
+
run: uv tool install git-commit-guard
|
|
55
|
+
shell: bash
|
|
56
|
+
- name: Run commit-guard
|
|
57
|
+
env:
|
|
58
|
+
CG_REV: ${{ inputs.rev }}
|
|
59
|
+
CG_RANGE: ${{ inputs.range }}
|
|
60
|
+
CG_ENABLE: ${{ inputs.enable }}
|
|
61
|
+
CG_DISABLE: ${{ inputs.disable }}
|
|
62
|
+
CG_SCOPES: ${{ inputs.scopes }}
|
|
63
|
+
CG_REQUIRE_SCOPE: ${{ inputs.require-scope }}
|
|
64
|
+
CG_TYPES: ${{ inputs.types }}
|
|
65
|
+
CG_MAX_SUBJECT_LENGTH: ${{ inputs.max-subject-length }}
|
|
66
|
+
CG_MIN_DESCRIPTION_LENGTH: ${{ inputs.min-description-length }}
|
|
67
|
+
CG_ALLOW_EMPTY: ${{ inputs.allow-empty }}
|
|
68
|
+
CG_INCLUDE_MERGES: ${{ inputs.include-merges }}
|
|
69
|
+
run: |
|
|
70
|
+
ARGS=()
|
|
71
|
+
[[ -n "$CG_REV" ]] && ARGS+=("$CG_REV")
|
|
72
|
+
[[ -n "$CG_RANGE" ]] && ARGS+=(--range "$CG_RANGE")
|
|
73
|
+
[[ -n "$CG_ENABLE" ]] && ARGS+=(--enable "$CG_ENABLE")
|
|
74
|
+
[[ -n "$CG_DISABLE" ]] && ARGS+=(--disable "$CG_DISABLE")
|
|
75
|
+
[[ -n "$CG_SCOPES" ]] && ARGS+=(--scopes "$CG_SCOPES")
|
|
76
|
+
[[ "$CG_REQUIRE_SCOPE" == "true" ]] && ARGS+=(--require-scope)
|
|
77
|
+
[[ -n "$CG_TYPES" ]] && ARGS+=(--types "$CG_TYPES")
|
|
78
|
+
[[ -n "$CG_MAX_SUBJECT_LENGTH" ]] && \
|
|
79
|
+
ARGS+=(--max-subject-length "$CG_MAX_SUBJECT_LENGTH")
|
|
80
|
+
[[ -n "$CG_MIN_DESCRIPTION_LENGTH" ]] && \
|
|
81
|
+
ARGS+=(--min-description-length "$CG_MIN_DESCRIPTION_LENGTH")
|
|
82
|
+
[[ "$CG_ALLOW_EMPTY" == "true" ]] && ARGS+=(--allow-empty)
|
|
83
|
+
[[ "$CG_INCLUDE_MERGES" == "true" ]] && ARGS+=(--include-merges)
|
|
84
|
+
commit-guard "${ARGS[@]}"
|
|
85
|
+
shell: bash
|
|
@@ -120,12 +120,13 @@ def _strip_comments(message):
|
|
|
120
120
|
)
|
|
121
121
|
|
|
122
122
|
|
|
123
|
-
def check_subject( # noqa: PLR0913 Too many arguments in function definition (
|
|
123
|
+
def check_subject( # noqa: PLR0913 Too many arguments in function definition (7 > 5)
|
|
124
124
|
line,
|
|
125
125
|
result,
|
|
126
126
|
allowed_scopes=frozenset(),
|
|
127
127
|
allowed_types=TYPES,
|
|
128
128
|
max_subject_length=MAX_SUBJECT_LEN,
|
|
129
|
+
min_description_length=0,
|
|
129
130
|
*,
|
|
130
131
|
require_scope=False,
|
|
131
132
|
):
|
|
@@ -150,6 +151,8 @@ def check_subject( # noqa: PLR0913 Too many arguments in function definition (6
|
|
|
150
151
|
result.error("description must not end with period")
|
|
151
152
|
if len(line) > max_subject_length:
|
|
152
153
|
result.error(f"subject too long: {len(line)} > {max_subject_length}")
|
|
154
|
+
if min_description_length > 0 and len(desc) < min_description_length:
|
|
155
|
+
result.error(f"description too short: {len(desc)} < {min_description_length}")
|
|
153
156
|
return desc
|
|
154
157
|
|
|
155
158
|
|
|
@@ -250,6 +253,7 @@ class Args:
|
|
|
250
253
|
require_scope: bool
|
|
251
254
|
allowed_types: frozenset
|
|
252
255
|
max_subject_length: int
|
|
256
|
+
min_description_length: int
|
|
253
257
|
rev_range: str | None
|
|
254
258
|
allow_empty: bool
|
|
255
259
|
include_merges: bool
|
|
@@ -279,6 +283,14 @@ def _resolve_max_subject_length(args, config):
|
|
|
279
283
|
return MAX_SUBJECT_LEN
|
|
280
284
|
|
|
281
285
|
|
|
286
|
+
def _resolve_min_description_length(args, config):
|
|
287
|
+
if args.min_description_length is not None:
|
|
288
|
+
return args.min_description_length
|
|
289
|
+
if "min-description-length" in config:
|
|
290
|
+
return config["min-description-length"]
|
|
291
|
+
return 0
|
|
292
|
+
|
|
293
|
+
|
|
282
294
|
def _resolve_types(args, config):
|
|
283
295
|
if args.types:
|
|
284
296
|
return frozenset(t.strip() for t in args.types.split(","))
|
|
@@ -350,6 +362,13 @@ def _parse_args():
|
|
|
350
362
|
metavar="N",
|
|
351
363
|
help=f"maximum subject line length (default: {MAX_SUBJECT_LEN})",
|
|
352
364
|
)
|
|
365
|
+
parser.add_argument(
|
|
366
|
+
"--min-description-length",
|
|
367
|
+
type=int,
|
|
368
|
+
default=None,
|
|
369
|
+
metavar="N",
|
|
370
|
+
help="minimum description length in characters (default: 0, off)",
|
|
371
|
+
)
|
|
353
372
|
parser.add_argument(
|
|
354
373
|
"--range",
|
|
355
374
|
dest="rev_range",
|
|
@@ -374,6 +393,7 @@ def _parse_args():
|
|
|
374
393
|
allowed_scopes, require_scope = _resolve_scopes(args, config)
|
|
375
394
|
allowed_types = _resolve_types(args, config)
|
|
376
395
|
max_subject_length = _resolve_max_subject_length(args, config)
|
|
396
|
+
min_description_length = _resolve_min_description_length(args, config)
|
|
377
397
|
|
|
378
398
|
if args.allow_empty and not args.rev_range:
|
|
379
399
|
parser.error("--allow-empty requires --range")
|
|
@@ -406,6 +426,7 @@ def _parse_args():
|
|
|
406
426
|
require_scope=require_scope,
|
|
407
427
|
allowed_types=allowed_types,
|
|
408
428
|
max_subject_length=max_subject_length,
|
|
429
|
+
min_description_length=min_description_length,
|
|
409
430
|
rev_range=args.rev_range,
|
|
410
431
|
allow_empty=args.allow_empty,
|
|
411
432
|
include_merges=args.include_merges,
|
|
@@ -432,6 +453,7 @@ def _run_checks(args, rev, message, result):
|
|
|
432
453
|
args.allowed_scopes,
|
|
433
454
|
args.allowed_types,
|
|
434
455
|
args.max_subject_length,
|
|
456
|
+
args.min_description_length,
|
|
435
457
|
require_scope=args.require_scope,
|
|
436
458
|
)
|
|
437
459
|
if Check.IMPERATIVE in args.enabled:
|
|
@@ -17,6 +17,7 @@ from git_commit_guard import (
|
|
|
17
17
|
_parse_config_checks,
|
|
18
18
|
_report,
|
|
19
19
|
_resolve_max_subject_length,
|
|
20
|
+
_resolve_min_description_length,
|
|
20
21
|
_resolve_types,
|
|
21
22
|
_strip_comments,
|
|
22
23
|
check_body,
|
|
@@ -161,6 +162,22 @@ class TestCheckSubject:
|
|
|
161
162
|
check_subject("fix: ok", r, max_subject_length=10)
|
|
162
163
|
assert r.ok
|
|
163
164
|
|
|
165
|
+
def test_min_description_length_zero_disables_check(self):
|
|
166
|
+
r = Result()
|
|
167
|
+
check_subject("fix: add x", r, min_description_length=0)
|
|
168
|
+
assert r.ok
|
|
169
|
+
|
|
170
|
+
def test_min_description_length_enforced(self):
|
|
171
|
+
r = Result()
|
|
172
|
+
check_subject("fix: add x", r, min_description_length=6)
|
|
173
|
+
assert not r.ok
|
|
174
|
+
assert any("description too short" in m for _, m in r.errors)
|
|
175
|
+
|
|
176
|
+
def test_min_description_length_exact_passes(self):
|
|
177
|
+
r = Result()
|
|
178
|
+
check_subject("fix: hello", r, min_description_length=5)
|
|
179
|
+
assert r.ok
|
|
180
|
+
|
|
164
181
|
def test_custom_type_passes(self):
|
|
165
182
|
r = Result()
|
|
166
183
|
check_subject("wip: add thing", r, allowed_types=frozenset(["wip"]))
|
|
@@ -455,6 +472,32 @@ class TestResolveMaxSubjectLength:
|
|
|
455
472
|
assert result == 50 # noqa: PLR2004 Magic value used in comparison, consider replacing 50 with a constant variable
|
|
456
473
|
|
|
457
474
|
|
|
475
|
+
class TestResolveMinDescriptionLength:
|
|
476
|
+
def test_defaults_to_zero(self):
|
|
477
|
+
result = _resolve_min_description_length(
|
|
478
|
+
Namespace(min_description_length=None), {}
|
|
479
|
+
)
|
|
480
|
+
assert result == 0
|
|
481
|
+
|
|
482
|
+
def test_cli_flag_overrides_default(self):
|
|
483
|
+
result = _resolve_min_description_length(
|
|
484
|
+
Namespace(min_description_length=10), {}
|
|
485
|
+
)
|
|
486
|
+
assert result == 10 # noqa: PLR2004 Magic value used in comparison, consider replacing 10 with a constant variable
|
|
487
|
+
|
|
488
|
+
def test_config_overrides_default(self):
|
|
489
|
+
result = _resolve_min_description_length(
|
|
490
|
+
Namespace(min_description_length=None), {"min-description-length": 8}
|
|
491
|
+
)
|
|
492
|
+
assert result == 8 # noqa: PLR2004 Magic value used in comparison, consider replacing 8 with a constant variable
|
|
493
|
+
|
|
494
|
+
def test_cli_overrides_config(self):
|
|
495
|
+
result = _resolve_min_description_length(
|
|
496
|
+
Namespace(min_description_length=10), {"min-description-length": 8}
|
|
497
|
+
)
|
|
498
|
+
assert result == 10 # noqa: PLR2004 Magic value used in comparison, consider replacing 10 with a constant variable
|
|
499
|
+
|
|
500
|
+
|
|
458
501
|
class TestResolveTypes:
|
|
459
502
|
def test_defaults_when_no_config_or_flag(self):
|
|
460
503
|
assert _resolve_types(Namespace(types=None), {}) == TYPES
|
|
@@ -812,6 +855,70 @@ class TestMain:
|
|
|
812
855
|
):
|
|
813
856
|
assert main() == 0
|
|
814
857
|
|
|
858
|
+
def test_min_description_length_flag_passes(self, tmp_path):
|
|
859
|
+
f = tmp_path / "msg"
|
|
860
|
+
f.write_text("fix: add thing\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
861
|
+
argv = [
|
|
862
|
+
"cg",
|
|
863
|
+
"--message-file",
|
|
864
|
+
str(f),
|
|
865
|
+
"--disable",
|
|
866
|
+
"signature",
|
|
867
|
+
"--min-description-length",
|
|
868
|
+
"5",
|
|
869
|
+
]
|
|
870
|
+
with patch("sys.argv", argv):
|
|
871
|
+
assert main() == 0
|
|
872
|
+
|
|
873
|
+
def test_min_description_length_flag_fails(self, tmp_path):
|
|
874
|
+
f = tmp_path / "msg"
|
|
875
|
+
f.write_text("fix: add x\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
876
|
+
argv = [
|
|
877
|
+
"cg",
|
|
878
|
+
"--message-file",
|
|
879
|
+
str(f),
|
|
880
|
+
"--disable",
|
|
881
|
+
"signature,imperative",
|
|
882
|
+
"--min-description-length",
|
|
883
|
+
"6",
|
|
884
|
+
]
|
|
885
|
+
with patch("sys.argv", argv):
|
|
886
|
+
assert main() == 1
|
|
887
|
+
|
|
888
|
+
def test_min_description_length_from_config(self, tmp_path):
|
|
889
|
+
f = tmp_path / "msg"
|
|
890
|
+
f.write_text("fix: add x\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
891
|
+
argv = ["cg", "--message-file", str(f), "--disable", "signature,imperative"]
|
|
892
|
+
with (
|
|
893
|
+
patch("sys.argv", argv),
|
|
894
|
+
patch(
|
|
895
|
+
"git_commit_guard._load_config",
|
|
896
|
+
return_value={"min-description-length": 6},
|
|
897
|
+
),
|
|
898
|
+
):
|
|
899
|
+
assert main() == 1
|
|
900
|
+
|
|
901
|
+
def test_min_description_length_cli_overrides_config(self, tmp_path):
|
|
902
|
+
f = tmp_path / "msg"
|
|
903
|
+
f.write_text("fix: add x\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
904
|
+
argv = [
|
|
905
|
+
"cg",
|
|
906
|
+
"--message-file",
|
|
907
|
+
str(f),
|
|
908
|
+
"--disable",
|
|
909
|
+
"signature,imperative",
|
|
910
|
+
"--min-description-length",
|
|
911
|
+
"3",
|
|
912
|
+
]
|
|
913
|
+
with (
|
|
914
|
+
patch("sys.argv", argv),
|
|
915
|
+
patch(
|
|
916
|
+
"git_commit_guard._load_config",
|
|
917
|
+
return_value={"min-description-length": 6},
|
|
918
|
+
),
|
|
919
|
+
):
|
|
920
|
+
assert main() == 0
|
|
921
|
+
|
|
815
922
|
def test_types_cli_overrides_config(self, tmp_path):
|
|
816
923
|
f = tmp_path / "msg"
|
|
817
924
|
f.write_text("wip: add thing\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|