git-commit-guard 0.8.0__tar.gz → 0.9.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.9.0/.github/workflows/lint-python.yml +24 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/PKG-INFO +34 -8
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/README.md +33 -7
- git_commit_guard-0.9.0/ruff.toml +13 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/src/git_commit_guard/__init__.py +53 -6
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/tests/test_git_commit_guard.py +193 -3
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/.github/workflows/lint-commits.yml +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/.github/workflows/lint-md.yml +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/.github/workflows/test.yml +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/.gitignore +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/.pre-commit-hooks.yaml +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/.python-version +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/LICENSE +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/.gitignore +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/class_index.html +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/coverage_html_cb_dd2e7eb5.js +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/favicon_32_cb_c827f16f.png +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/function_index.html +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/index.html +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/keybd_closed_cb_900cfef5.png +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/status.json +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/style_cb_9ff733b0.css +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/z_262b75d81d1cf686___init___py.html +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/pyproject.toml +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/tests/__init__.py +0 -0
- {git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/uv.lock +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Lint Python
|
|
3
|
+
on: # yamllint disable-line rule:truthy
|
|
4
|
+
pull_request:
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
jobs:
|
|
8
|
+
lint-python:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
checks: write
|
|
12
|
+
pull-requests: write
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout code
|
|
15
|
+
# yamllint disable-line rule:line-length
|
|
16
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
17
|
+
with:
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
- name: Run ruff
|
|
20
|
+
# yamllint disable-line rule:line-length
|
|
21
|
+
uses: benner/action-ruff@b36eb590165f0ea36700bb92de15235c121f24f0 # v0.1.0
|
|
22
|
+
with:
|
|
23
|
+
fail_level: error
|
|
24
|
+
reporter: github-pr-review
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: git-commit-guard
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.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
|
|
@@ -101,6 +101,28 @@ Available checks:
|
|
|
101
101
|
* `signed-off` - `Signed-off-by:` trailer exists
|
|
102
102
|
* `signature` - Verify GPG or SSH signature
|
|
103
103
|
|
|
104
|
+
### Subject length
|
|
105
|
+
|
|
106
|
+
The default maximum subject line length is 72 characters. Override with
|
|
107
|
+
`--max-subject-length`:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
commit-guard --max-subject-length 100
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Type validation
|
|
114
|
+
|
|
115
|
+
By default the standard conventional commit types are accepted. Use `--types`
|
|
116
|
+
to replace the allowed set entirely:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# restrict to a subset
|
|
120
|
+
commit-guard --types feat,fix,chore
|
|
121
|
+
|
|
122
|
+
# add a project-specific type
|
|
123
|
+
commit-guard --types feat,fix,docs,style,refactor,perf,test,build,ci,chore,revert,wip
|
|
124
|
+
```
|
|
125
|
+
|
|
104
126
|
### Scope validation
|
|
105
127
|
|
|
106
128
|
By default any scope is accepted and scope is optional. Use `--scopes` to
|
|
@@ -121,15 +143,17 @@ commit-guard --scopes auth,api --require-scope
|
|
|
121
143
|
### Configuration file
|
|
122
144
|
|
|
123
145
|
Place `.commit-guard.toml` in your project root (or any parent directory) to
|
|
124
|
-
set defaults for `enable`, `disable`, `scopes`,
|
|
125
|
-
commit-guard searches upward from the working directory
|
|
126
|
-
found.
|
|
146
|
+
set defaults for `enable`, `disable`, `scopes`, `require-scope`, `types`, and
|
|
147
|
+
`max-subject-length`. commit-guard searches upward from the working directory
|
|
148
|
+
and uses the first file found.
|
|
127
149
|
|
|
128
150
|
```toml
|
|
129
151
|
# .commit-guard.toml
|
|
130
152
|
disable = ["signature", "body"]
|
|
131
153
|
scopes = ["auth", "api", "db"]
|
|
132
154
|
require-scope = true
|
|
155
|
+
types = ["feat", "fix", "chore", "wip"]
|
|
156
|
+
max-subject-length = 100
|
|
133
157
|
```
|
|
134
158
|
|
|
135
159
|
```toml
|
|
@@ -137,8 +161,9 @@ require-scope = true
|
|
|
137
161
|
enable = ["subject", "imperative"]
|
|
138
162
|
```
|
|
139
163
|
|
|
140
|
-
CLI flags (`--enable`, `--disable`, `--scopes`, `--require-scope
|
|
141
|
-
precedence and ignore config file values when
|
|
164
|
+
CLI flags (`--enable`, `--disable`, `--scopes`, `--require-scope`, `--types`,
|
|
165
|
+
`--max-subject-length`) take full precedence and ignore config file values when
|
|
166
|
+
provided.
|
|
142
167
|
|
|
143
168
|
### Checking a range of commits
|
|
144
169
|
|
|
@@ -206,8 +231,9 @@ body
|
|
|
206
231
|
trailers
|
|
207
232
|
```
|
|
208
233
|
|
|
209
|
-
|
|
210
|
-
`build`, `ci`, `chore`, `revert`.
|
|
234
|
+
Default types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`,
|
|
235
|
+
`build`, `ci`, `chore`, `revert`. Override with `--types` or the `types` config
|
|
236
|
+
key.
|
|
211
237
|
|
|
212
238
|
Scope is optional. Mark breaking changes with `!` before
|
|
213
239
|
the colon.
|
|
@@ -80,6 +80,28 @@ Available checks:
|
|
|
80
80
|
* `signed-off` - `Signed-off-by:` trailer exists
|
|
81
81
|
* `signature` - Verify GPG or SSH signature
|
|
82
82
|
|
|
83
|
+
### Subject length
|
|
84
|
+
|
|
85
|
+
The default maximum subject line length is 72 characters. Override with
|
|
86
|
+
`--max-subject-length`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
commit-guard --max-subject-length 100
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Type validation
|
|
93
|
+
|
|
94
|
+
By default the standard conventional commit types are accepted. Use `--types`
|
|
95
|
+
to replace the allowed set entirely:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# restrict to a subset
|
|
99
|
+
commit-guard --types feat,fix,chore
|
|
100
|
+
|
|
101
|
+
# add a project-specific type
|
|
102
|
+
commit-guard --types feat,fix,docs,style,refactor,perf,test,build,ci,chore,revert,wip
|
|
103
|
+
```
|
|
104
|
+
|
|
83
105
|
### Scope validation
|
|
84
106
|
|
|
85
107
|
By default any scope is accepted and scope is optional. Use `--scopes` to
|
|
@@ -100,15 +122,17 @@ commit-guard --scopes auth,api --require-scope
|
|
|
100
122
|
### Configuration file
|
|
101
123
|
|
|
102
124
|
Place `.commit-guard.toml` in your project root (or any parent directory) to
|
|
103
|
-
set defaults for `enable`, `disable`, `scopes`,
|
|
104
|
-
commit-guard searches upward from the working directory
|
|
105
|
-
found.
|
|
125
|
+
set defaults for `enable`, `disable`, `scopes`, `require-scope`, `types`, and
|
|
126
|
+
`max-subject-length`. commit-guard searches upward from the working directory
|
|
127
|
+
and uses the first file found.
|
|
106
128
|
|
|
107
129
|
```toml
|
|
108
130
|
# .commit-guard.toml
|
|
109
131
|
disable = ["signature", "body"]
|
|
110
132
|
scopes = ["auth", "api", "db"]
|
|
111
133
|
require-scope = true
|
|
134
|
+
types = ["feat", "fix", "chore", "wip"]
|
|
135
|
+
max-subject-length = 100
|
|
112
136
|
```
|
|
113
137
|
|
|
114
138
|
```toml
|
|
@@ -116,8 +140,9 @@ require-scope = true
|
|
|
116
140
|
enable = ["subject", "imperative"]
|
|
117
141
|
```
|
|
118
142
|
|
|
119
|
-
CLI flags (`--enable`, `--disable`, `--scopes`, `--require-scope
|
|
120
|
-
precedence and ignore config file values when
|
|
143
|
+
CLI flags (`--enable`, `--disable`, `--scopes`, `--require-scope`, `--types`,
|
|
144
|
+
`--max-subject-length`) take full precedence and ignore config file values when
|
|
145
|
+
provided.
|
|
121
146
|
|
|
122
147
|
### Checking a range of commits
|
|
123
148
|
|
|
@@ -185,8 +210,9 @@ body
|
|
|
185
210
|
trailers
|
|
186
211
|
```
|
|
187
212
|
|
|
188
|
-
|
|
189
|
-
`build`, `ci`, `chore`, `revert`.
|
|
213
|
+
Default types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`,
|
|
214
|
+
`build`, `ci`, `chore`, `revert`. Override with `--types` or the `types` config
|
|
215
|
+
key.
|
|
190
216
|
|
|
191
217
|
Scope is optional. Mark breaking changes with `!` before
|
|
192
218
|
the colon.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
target-version = "py312"
|
|
2
|
+
|
|
3
|
+
[lint]
|
|
4
|
+
select = ["ALL"]
|
|
5
|
+
ignore = [
|
|
6
|
+
"ANN", # flake8-annotations (ANN)
|
|
7
|
+
"COM812", # missing-trailing-comma
|
|
8
|
+
"D", # pydocstyle (D)
|
|
9
|
+
"RET504", # Unnecessary assignment to X before `return` statement
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[lint.per-file-ignores]
|
|
13
|
+
"tests/**" = ["S101"] # assert is expected in tests
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import subprocess
|
|
3
3
|
import sys
|
|
4
|
+
import tomllib
|
|
4
5
|
from argparse import ArgumentParser
|
|
5
6
|
from dataclasses import dataclass, field
|
|
6
7
|
from enum import StrEnum
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
9
10
|
import nltk
|
|
10
|
-
import tomllib
|
|
11
11
|
from nltk.corpus import wordnet
|
|
12
12
|
|
|
13
13
|
TYPES = frozenset(
|
|
@@ -120,13 +120,21 @@ def _strip_comments(message):
|
|
|
120
120
|
)
|
|
121
121
|
|
|
122
122
|
|
|
123
|
-
def check_subject(
|
|
123
|
+
def check_subject( # noqa: PLR0913 Too many arguments in function definition (6 > 5)
|
|
124
|
+
line,
|
|
125
|
+
result,
|
|
126
|
+
allowed_scopes=frozenset(),
|
|
127
|
+
allowed_types=TYPES,
|
|
128
|
+
max_subject_length=MAX_SUBJECT_LEN,
|
|
129
|
+
*,
|
|
130
|
+
require_scope=False,
|
|
131
|
+
):
|
|
124
132
|
m = SUBJECT_RE.match(line)
|
|
125
133
|
if not m:
|
|
126
134
|
result.error(f"subject does not match 'type(scope): description': {line}")
|
|
127
135
|
return None
|
|
128
136
|
|
|
129
|
-
if m.group("type") not in
|
|
137
|
+
if m.group("type") not in allowed_types:
|
|
130
138
|
result.error(f"unknown type: {m.group('type')}")
|
|
131
139
|
|
|
132
140
|
scope = m.group("scope")
|
|
@@ -140,8 +148,8 @@ def check_subject(line, result, allowed_scopes=frozenset(), *, require_scope=Fal
|
|
|
140
148
|
result.error("description must not start with uppercase")
|
|
141
149
|
if desc.endswith("."):
|
|
142
150
|
result.error("description must not end with period")
|
|
143
|
-
if len(line) >
|
|
144
|
-
result.error(f"subject too long: {len(line)} > {
|
|
151
|
+
if len(line) > max_subject_length:
|
|
152
|
+
result.error(f"subject too long: {len(line)} > {max_subject_length}")
|
|
145
153
|
return desc
|
|
146
154
|
|
|
147
155
|
|
|
@@ -223,6 +231,8 @@ class Args:
|
|
|
223
231
|
enabled: frozenset
|
|
224
232
|
allowed_scopes: frozenset
|
|
225
233
|
require_scope: bool
|
|
234
|
+
allowed_types: frozenset
|
|
235
|
+
max_subject_length: int
|
|
226
236
|
|
|
227
237
|
|
|
228
238
|
def _resolve_enabled(args, config, parser):
|
|
@@ -241,6 +251,22 @@ def _resolve_enabled(args, config, parser):
|
|
|
241
251
|
return enabled
|
|
242
252
|
|
|
243
253
|
|
|
254
|
+
def _resolve_max_subject_length(args, config):
|
|
255
|
+
if args.max_subject_length is not None:
|
|
256
|
+
return args.max_subject_length
|
|
257
|
+
if "max-subject-length" in config:
|
|
258
|
+
return config["max-subject-length"]
|
|
259
|
+
return MAX_SUBJECT_LEN
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _resolve_types(args, config):
|
|
263
|
+
if args.types:
|
|
264
|
+
return frozenset(t.strip() for t in args.types.split(","))
|
|
265
|
+
if config.get("types"):
|
|
266
|
+
return frozenset(config["types"])
|
|
267
|
+
return TYPES
|
|
268
|
+
|
|
269
|
+
|
|
244
270
|
def _resolve_scopes(args, config):
|
|
245
271
|
if args.scopes:
|
|
246
272
|
allowed_scopes = frozenset(s.strip() for s in args.scopes.split(","))
|
|
@@ -292,10 +318,24 @@ def _parse_args():
|
|
|
292
318
|
default=False,
|
|
293
319
|
help="require a scope in the subject line",
|
|
294
320
|
)
|
|
321
|
+
parser.add_argument(
|
|
322
|
+
"--types",
|
|
323
|
+
metavar="TYPE[,TYPE,...]",
|
|
324
|
+
help="allowed commit types (replaces defaults when set)",
|
|
325
|
+
)
|
|
326
|
+
parser.add_argument(
|
|
327
|
+
"--max-subject-length",
|
|
328
|
+
type=int,
|
|
329
|
+
default=None,
|
|
330
|
+
metavar="N",
|
|
331
|
+
help=f"maximum subject line length (default: {MAX_SUBJECT_LEN})",
|
|
332
|
+
)
|
|
295
333
|
args = parser.parse_args()
|
|
296
334
|
config = _load_config()
|
|
297
335
|
enabled = _resolve_enabled(args, config, parser)
|
|
298
336
|
allowed_scopes, require_scope = _resolve_scopes(args, config)
|
|
337
|
+
allowed_types = _resolve_types(args, config)
|
|
338
|
+
max_subject_length = _resolve_max_subject_length(args, config)
|
|
299
339
|
|
|
300
340
|
if args.message_file:
|
|
301
341
|
rev = None
|
|
@@ -316,6 +356,8 @@ def _parse_args():
|
|
|
316
356
|
enabled=enabled,
|
|
317
357
|
allowed_scopes=allowed_scopes,
|
|
318
358
|
require_scope=require_scope,
|
|
359
|
+
allowed_types=allowed_types,
|
|
360
|
+
max_subject_length=max_subject_length,
|
|
319
361
|
)
|
|
320
362
|
|
|
321
363
|
|
|
@@ -341,7 +383,12 @@ def main():
|
|
|
341
383
|
desc = None
|
|
342
384
|
if Check.SUBJECT in args.enabled:
|
|
343
385
|
desc = check_subject(
|
|
344
|
-
lines[0],
|
|
386
|
+
lines[0],
|
|
387
|
+
result,
|
|
388
|
+
args.allowed_scopes,
|
|
389
|
+
args.allowed_types,
|
|
390
|
+
args.max_subject_length,
|
|
391
|
+
require_scope=args.require_scope,
|
|
345
392
|
)
|
|
346
393
|
if Check.IMPERATIVE in args.enabled:
|
|
347
394
|
if desc is None:
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import subprocess
|
|
2
|
-
from argparse import ArgumentParser
|
|
2
|
+
from argparse import ArgumentParser, Namespace
|
|
3
3
|
from unittest.mock import MagicMock, patch
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
|
+
|
|
6
7
|
from git_commit_guard import (
|
|
8
|
+
MAX_SUBJECT_LEN,
|
|
9
|
+
TYPES,
|
|
7
10
|
Result,
|
|
8
11
|
_download_if_missing,
|
|
9
12
|
_ensure_nltk_data,
|
|
@@ -12,6 +15,8 @@ from git_commit_guard import (
|
|
|
12
15
|
_parse_checks,
|
|
13
16
|
_parse_config_checks,
|
|
14
17
|
_report,
|
|
18
|
+
_resolve_max_subject_length,
|
|
19
|
+
_resolve_types,
|
|
15
20
|
_strip_comments,
|
|
16
21
|
check_body,
|
|
17
22
|
check_imperative,
|
|
@@ -21,8 +26,6 @@ from git_commit_guard import (
|
|
|
21
26
|
main,
|
|
22
27
|
)
|
|
23
28
|
|
|
24
|
-
# ruff: noqa: S101 # Use of `assert` detected
|
|
25
|
-
|
|
26
29
|
|
|
27
30
|
@pytest.fixture(scope="session", autouse=True)
|
|
28
31
|
def nltk_data():
|
|
@@ -147,6 +150,26 @@ class TestCheckSubject:
|
|
|
147
150
|
check_subject("fix(anything): add token", r, allowed_scopes=frozenset())
|
|
148
151
|
assert r.ok
|
|
149
152
|
|
|
153
|
+
def test_custom_max_length_enforced(self):
|
|
154
|
+
r = Result()
|
|
155
|
+
check_subject("fix: add thing", r, max_subject_length=10)
|
|
156
|
+
assert not r.ok
|
|
157
|
+
|
|
158
|
+
def test_custom_max_length_passes(self):
|
|
159
|
+
r = Result()
|
|
160
|
+
check_subject("fix: ok", r, max_subject_length=10)
|
|
161
|
+
assert r.ok
|
|
162
|
+
|
|
163
|
+
def test_custom_type_passes(self):
|
|
164
|
+
r = Result()
|
|
165
|
+
check_subject("wip: add thing", r, allowed_types=frozenset(["wip"]))
|
|
166
|
+
assert r.ok
|
|
167
|
+
|
|
168
|
+
def test_type_not_in_custom_list_fails(self):
|
|
169
|
+
r = Result()
|
|
170
|
+
check_subject("feat: add thing", r, allowed_types=frozenset(["wip"]))
|
|
171
|
+
assert not r.ok
|
|
172
|
+
|
|
150
173
|
@pytest.mark.parametrize(
|
|
151
174
|
"type_",
|
|
152
175
|
[
|
|
@@ -409,6 +432,45 @@ class TestParseConfigChecks:
|
|
|
409
432
|
_parse_config_checks({"disable": ["bogus"]}, "disable")
|
|
410
433
|
|
|
411
434
|
|
|
435
|
+
class TestResolveMaxSubjectLength:
|
|
436
|
+
def test_defaults_when_no_config_or_flag(self):
|
|
437
|
+
result = _resolve_max_subject_length(Namespace(max_subject_length=None), {})
|
|
438
|
+
assert result == MAX_SUBJECT_LEN
|
|
439
|
+
|
|
440
|
+
def test_cli_flag_overrides_default(self):
|
|
441
|
+
result = _resolve_max_subject_length(Namespace(max_subject_length=50), {})
|
|
442
|
+
assert result == 50 # noqa: PLR2004 Magic value used in comparison, consider replacing 50 with a constant variable
|
|
443
|
+
|
|
444
|
+
def test_config_overrides_default(self):
|
|
445
|
+
result = _resolve_max_subject_length(
|
|
446
|
+
Namespace(max_subject_length=None), {"max-subject-length": 60}
|
|
447
|
+
)
|
|
448
|
+
assert result == 60 # noqa: PLR2004 Magic value used in comparison, consider replacing 60 with a constant variable
|
|
449
|
+
|
|
450
|
+
def test_cli_overrides_config(self):
|
|
451
|
+
result = _resolve_max_subject_length(
|
|
452
|
+
Namespace(max_subject_length=50), {"max-subject-length": 60}
|
|
453
|
+
)
|
|
454
|
+
assert result == 50 # noqa: PLR2004 Magic value used in comparison, consider replacing 50 with a constant variable
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
class TestResolveTypes:
|
|
458
|
+
def test_defaults_when_no_config_or_flag(self):
|
|
459
|
+
assert _resolve_types(Namespace(types=None), {}) == TYPES
|
|
460
|
+
|
|
461
|
+
def test_cli_flag_replaces_defaults(self):
|
|
462
|
+
result = _resolve_types(Namespace(types="wip,deploy"), {})
|
|
463
|
+
assert result == frozenset({"wip", "deploy"})
|
|
464
|
+
|
|
465
|
+
def test_config_replaces_defaults(self):
|
|
466
|
+
result = _resolve_types(Namespace(types=None), {"types": ["wip", "deploy"]})
|
|
467
|
+
assert result == frozenset({"wip", "deploy"})
|
|
468
|
+
|
|
469
|
+
def test_cli_overrides_config(self):
|
|
470
|
+
result = _resolve_types(Namespace(types="wip"), {"types": ["deploy"]})
|
|
471
|
+
assert result == frozenset({"wip"})
|
|
472
|
+
|
|
473
|
+
|
|
412
474
|
class TestParseChecks:
|
|
413
475
|
def test_invalid_check_name(self):
|
|
414
476
|
parser = ArgumentParser()
|
|
@@ -641,3 +703,131 @@ class TestMain:
|
|
|
641
703
|
),
|
|
642
704
|
):
|
|
643
705
|
assert main() == 0
|
|
706
|
+
|
|
707
|
+
def test_types_flag_valid(self, tmp_path):
|
|
708
|
+
f = tmp_path / "msg"
|
|
709
|
+
f.write_text("wip: add thing\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
710
|
+
argv = [
|
|
711
|
+
"cg",
|
|
712
|
+
"--message-file",
|
|
713
|
+
str(f),
|
|
714
|
+
"--disable",
|
|
715
|
+
"signature",
|
|
716
|
+
"--types",
|
|
717
|
+
"wip,feat,fix",
|
|
718
|
+
]
|
|
719
|
+
with patch("sys.argv", argv):
|
|
720
|
+
assert main() == 0
|
|
721
|
+
|
|
722
|
+
def test_types_flag_invalid(self, tmp_path):
|
|
723
|
+
f = tmp_path / "msg"
|
|
724
|
+
f.write_text("chore: add thing\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
725
|
+
argv = [
|
|
726
|
+
"cg",
|
|
727
|
+
"--message-file",
|
|
728
|
+
str(f),
|
|
729
|
+
"--disable",
|
|
730
|
+
"signature",
|
|
731
|
+
"--types",
|
|
732
|
+
"feat,fix",
|
|
733
|
+
]
|
|
734
|
+
with patch("sys.argv", argv):
|
|
735
|
+
assert main() == 1
|
|
736
|
+
|
|
737
|
+
def test_types_from_config(self, tmp_path):
|
|
738
|
+
f = tmp_path / "msg"
|
|
739
|
+
f.write_text("wip: add thing\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
740
|
+
argv = ["cg", "--message-file", str(f), "--disable", "signature"]
|
|
741
|
+
with (
|
|
742
|
+
patch("sys.argv", argv),
|
|
743
|
+
patch(
|
|
744
|
+
"git_commit_guard._load_config",
|
|
745
|
+
return_value={"types": ["wip", "feat"]},
|
|
746
|
+
),
|
|
747
|
+
):
|
|
748
|
+
assert main() == 0
|
|
749
|
+
|
|
750
|
+
def test_max_subject_length_flag_passes(self, tmp_path):
|
|
751
|
+
f = tmp_path / "msg"
|
|
752
|
+
f.write_text("fix: ok\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
753
|
+
argv = [
|
|
754
|
+
"cg",
|
|
755
|
+
"--message-file",
|
|
756
|
+
str(f),
|
|
757
|
+
"--disable",
|
|
758
|
+
"signature",
|
|
759
|
+
"--max-subject-length",
|
|
760
|
+
"10",
|
|
761
|
+
]
|
|
762
|
+
with patch("sys.argv", argv):
|
|
763
|
+
assert main() == 0
|
|
764
|
+
|
|
765
|
+
def test_max_subject_length_flag_fails(self, tmp_path):
|
|
766
|
+
f = tmp_path / "msg"
|
|
767
|
+
f.write_text(_VALID_MSG)
|
|
768
|
+
argv = [
|
|
769
|
+
"cg",
|
|
770
|
+
"--message-file",
|
|
771
|
+
str(f),
|
|
772
|
+
"--disable",
|
|
773
|
+
"signature",
|
|
774
|
+
"--max-subject-length",
|
|
775
|
+
"5",
|
|
776
|
+
]
|
|
777
|
+
with patch("sys.argv", argv):
|
|
778
|
+
assert main() == 1
|
|
779
|
+
|
|
780
|
+
def test_max_subject_length_from_config(self, tmp_path):
|
|
781
|
+
f = tmp_path / "msg"
|
|
782
|
+
f.write_text(_VALID_MSG)
|
|
783
|
+
argv = ["cg", "--message-file", str(f), "--disable", "signature"]
|
|
784
|
+
with (
|
|
785
|
+
patch("sys.argv", argv),
|
|
786
|
+
patch(
|
|
787
|
+
"git_commit_guard._load_config",
|
|
788
|
+
return_value={"max-subject-length": 5},
|
|
789
|
+
),
|
|
790
|
+
):
|
|
791
|
+
assert main() == 1
|
|
792
|
+
|
|
793
|
+
def test_max_subject_length_cli_overrides_config(self, tmp_path):
|
|
794
|
+
f = tmp_path / "msg"
|
|
795
|
+
f.write_text(_VALID_MSG)
|
|
796
|
+
argv = [
|
|
797
|
+
"cg",
|
|
798
|
+
"--message-file",
|
|
799
|
+
str(f),
|
|
800
|
+
"--disable",
|
|
801
|
+
"signature",
|
|
802
|
+
"--max-subject-length",
|
|
803
|
+
"100",
|
|
804
|
+
]
|
|
805
|
+
with (
|
|
806
|
+
patch("sys.argv", argv),
|
|
807
|
+
patch(
|
|
808
|
+
"git_commit_guard._load_config",
|
|
809
|
+
return_value={"max-subject-length": 5},
|
|
810
|
+
),
|
|
811
|
+
):
|
|
812
|
+
assert main() == 0
|
|
813
|
+
|
|
814
|
+
def test_types_cli_overrides_config(self, tmp_path):
|
|
815
|
+
f = tmp_path / "msg"
|
|
816
|
+
f.write_text("wip: add thing\n\nbody\n\nSigned-off-by: A User <a@b.com>")
|
|
817
|
+
argv = [
|
|
818
|
+
"cg",
|
|
819
|
+
"--message-file",
|
|
820
|
+
str(f),
|
|
821
|
+
"--disable",
|
|
822
|
+
"signature",
|
|
823
|
+
"--types",
|
|
824
|
+
"wip",
|
|
825
|
+
]
|
|
826
|
+
with (
|
|
827
|
+
patch("sys.argv", argv),
|
|
828
|
+
patch(
|
|
829
|
+
"git_commit_guard._load_config",
|
|
830
|
+
return_value={"types": ["deploy"]},
|
|
831
|
+
),
|
|
832
|
+
):
|
|
833
|
+
assert main() == 0
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{git_commit_guard-0.8.0 → git_commit_guard-0.9.0}/htmlcov/z_262b75d81d1cf686___init___py.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|