git-commit-guard 0.17.0__tar.gz → 0.18.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.
Files changed (25) hide show
  1. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.github/workflows/lint-commits.yml +1 -1
  2. git_commit_guard-0.18.0/.github/workflows/lint-workflows.yml +47 -0
  3. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/PKG-INFO +11 -11
  4. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/README.md +10 -10
  5. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/action.yml +1 -1
  6. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/docs/index.html +5 -5
  7. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/src/git_commit_guard/__init__.py +2 -2
  8. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/tests/test_git_commit_guard.py +68 -0
  9. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.editorconfig +0 -0
  10. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.github/workflows/coverage-baseline.yml +0 -0
  11. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.github/workflows/coverage-comment.yml +0 -0
  12. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.github/workflows/lint-md.yml +0 -0
  13. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.github/workflows/lint-python.yml +0 -0
  14. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.github/workflows/release.yml +0 -0
  15. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.github/workflows/test.yml +0 -0
  16. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.gitignore +0 -0
  17. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.markdownlint.json +0 -0
  18. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.pre-commit-hooks.yaml +0 -0
  19. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/.python-version +0 -0
  20. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/LICENSE +0 -0
  21. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/docs/commit-guard-icon.svg +0 -0
  22. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/pyproject.toml +0 -0
  23. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/ruff.toml +0 -0
  24. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/tests/__init__.py +0 -0
  25. {git_commit_guard-0.17.0 → git_commit_guard-0.18.0}/uv.lock +0 -0
@@ -22,7 +22,7 @@ jobs:
22
22
  key: nltk-averaged-perceptron-tagger-punkt
23
23
  - name: Lint commits
24
24
  # yamllint disable-line rule:line-length
25
- uses: benner/commit-guard@064132b8b0cf5ec26083de7193f4e78d37a615d4 # v0.15.1
25
+ uses: benner/commit-guard@d4c9fbe4a203ab32f63f66e1902d780528f781f2 # v0.17.0
26
26
  with:
27
27
  range: origin/${{ github.base_ref }}..HEAD
28
28
  disable: signature
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: Lint GitHub Actions workflows
3
+ on: # yamllint disable-line rule:truthy
4
+ pull_request:
5
+ permissions:
6
+ contents: read
7
+ jobs:
8
+ actionlint:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ pull-requests: write
12
+ steps:
13
+ - name: Checkout code
14
+ # yamllint disable-line rule:line-length
15
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # ratchet:actions/checkout@v4
16
+ with:
17
+ persist-credentials: false
18
+ - name: Run actionlint
19
+ # yamllint disable-line rule:line-length
20
+ uses: reviewdog/action-actionlint@6fb7acc99f4a1008869fa8a0f09cfca740837d9d # ratchet:reviewdog/action-actionlint@v1
21
+ with:
22
+ github_token: ${{ github.token }}
23
+ reporter: github-pr-review
24
+
25
+ zizmor:
26
+ runs-on: ubuntu-latest
27
+ permissions:
28
+ pull-requests: write
29
+ steps:
30
+ - name: Checkout code
31
+ # yamllint disable-line rule:line-length
32
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # ratchet:actions/checkout@v4
33
+ with:
34
+ persist-credentials: false
35
+ - name: Set up uv
36
+ # yamllint disable-line rule:line-length
37
+ uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # ratchet:astral-sh/setup-uv@v7
38
+ - name: Set up reviewdog
39
+ # yamllint disable-line rule:line-length
40
+ uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # ratchet:reviewdog/action-setup@v1
41
+ - name: Run zizmor
42
+ env:
43
+ REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
44
+ run: |
45
+ uvx zizmor==1.24.1 --format=sarif . |
46
+ reviewdog -f=sarif -name=zizmor \
47
+ -reporter=github-pr-review -fail-on-error
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-commit-guard
3
- Version: 0.17.0
3
+ Version: 0.18.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
@@ -94,7 +94,7 @@ commit-guard --disable body,signed-off,signature
94
94
  Available checks:
95
95
 
96
96
  * `subject` - Format matches `type(scope): description`, valid type,
97
- lowercase start, no trailing period, max 72 chars
97
+ lowercase start, no trailing `.` `!` `?` or space, max 72 chars
98
98
  * `imperative` - First word is an imperative verb (for example `add` not `added`)
99
99
  * `body` - Blank line separates subject from body, and body is non-empty
100
100
  * `signed-off` - `Signed-off-by:` trailer exists
@@ -131,8 +131,8 @@ In `.commit-guard.toml`:
131
131
  require-lowercase = false
132
132
  ```
133
133
 
134
- By default trailing `.` is forbidden. To change the set of forbidden trailing
135
- characters (any character is valid, including space):
134
+ By default `.`, `!`, `?`, and space are forbidden as trailing characters.
135
+ To change the set (any character is valid):
136
136
 
137
137
  ```bash
138
138
  commit-guard --no-trailing-chars ".,"
@@ -246,7 +246,7 @@ COMMIT_GUARD_GIT_TIMEOUT=30 commit-guard --range origin/main..HEAD
246
246
  In GitHub Actions, set it at the step or job level:
247
247
 
248
248
  ```yaml
249
- - uses: benner/commit-guard@v0.17.0
249
+ - uses: benner/commit-guard@v0.18.0
250
250
  env:
251
251
  COMMIT_GUARD_GIT_TIMEOUT: 30
252
252
  with:
@@ -330,7 +330,7 @@ steps:
330
330
  - uses: actions/checkout@v4
331
331
  with:
332
332
  fetch-depth: 0
333
- - uses: benner/commit-guard@v0.17.0
333
+ - uses: benner/commit-guard@v0.18.0
334
334
  ```
335
335
 
336
336
  Check all commits in a pull request:
@@ -346,7 +346,7 @@ jobs:
346
346
  - uses: actions/checkout@v4
347
347
  with:
348
348
  fetch-depth: 0
349
- - uses: benner/commit-guard@v0.17.0
349
+ - uses: benner/commit-guard@v0.18.0
350
350
  with:
351
351
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
352
352
  ```
@@ -354,7 +354,7 @@ jobs:
354
354
  Check a specific commit SHA (mirrors the positional CLI argument):
355
355
 
356
356
  ```yaml
357
- - uses: benner/commit-guard@v0.17.0
357
+ - uses: benner/commit-guard@v0.18.0
358
358
  with:
359
359
  rev: ${{ github.sha }}
360
360
  ```
@@ -372,7 +372,7 @@ jobs:
372
372
  - uses: actions/checkout@v4
373
373
  with:
374
374
  fetch-depth: 0
375
- - uses: benner/commit-guard@v0.17.0
375
+ - uses: benner/commit-guard@v0.18.0
376
376
  with:
377
377
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
378
378
  disable: signed-off,signature
@@ -391,7 +391,7 @@ jobs:
391
391
  When `output-file` is set the action exposes the path as an output:
392
392
 
393
393
  ```yaml
394
- - uses: benner/commit-guard@v0.17.0
394
+ - uses: benner/commit-guard@v0.18.0
395
395
  id: cg
396
396
  with:
397
397
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
@@ -407,7 +407,7 @@ Add to your `.pre-commit-config.yaml`:
407
407
  ---
408
408
  repos:
409
409
  - repo: https://github.com/benner/commit-guard
410
- rev: v0.17.0
410
+ rev: v0.18.0
411
411
  hooks:
412
412
  - id: commit-guard
413
413
  - id: commit-guard-signature
@@ -73,7 +73,7 @@ commit-guard --disable body,signed-off,signature
73
73
  Available checks:
74
74
 
75
75
  * `subject` - Format matches `type(scope): description`, valid type,
76
- lowercase start, no trailing period, max 72 chars
76
+ lowercase start, no trailing `.` `!` `?` or space, max 72 chars
77
77
  * `imperative` - First word is an imperative verb (for example `add` not `added`)
78
78
  * `body` - Blank line separates subject from body, and body is non-empty
79
79
  * `signed-off` - `Signed-off-by:` trailer exists
@@ -110,8 +110,8 @@ In `.commit-guard.toml`:
110
110
  require-lowercase = false
111
111
  ```
112
112
 
113
- By default trailing `.` is forbidden. To change the set of forbidden trailing
114
- characters (any character is valid, including space):
113
+ By default `.`, `!`, `?`, and space are forbidden as trailing characters.
114
+ To change the set (any character is valid):
115
115
 
116
116
  ```bash
117
117
  commit-guard --no-trailing-chars ".,"
@@ -225,7 +225,7 @@ COMMIT_GUARD_GIT_TIMEOUT=30 commit-guard --range origin/main..HEAD
225
225
  In GitHub Actions, set it at the step or job level:
226
226
 
227
227
  ```yaml
228
- - uses: benner/commit-guard@v0.17.0
228
+ - uses: benner/commit-guard@v0.18.0
229
229
  env:
230
230
  COMMIT_GUARD_GIT_TIMEOUT: 30
231
231
  with:
@@ -309,7 +309,7 @@ steps:
309
309
  - uses: actions/checkout@v4
310
310
  with:
311
311
  fetch-depth: 0
312
- - uses: benner/commit-guard@v0.17.0
312
+ - uses: benner/commit-guard@v0.18.0
313
313
  ```
314
314
 
315
315
  Check all commits in a pull request:
@@ -325,7 +325,7 @@ jobs:
325
325
  - uses: actions/checkout@v4
326
326
  with:
327
327
  fetch-depth: 0
328
- - uses: benner/commit-guard@v0.17.0
328
+ - uses: benner/commit-guard@v0.18.0
329
329
  with:
330
330
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
331
331
  ```
@@ -333,7 +333,7 @@ jobs:
333
333
  Check a specific commit SHA (mirrors the positional CLI argument):
334
334
 
335
335
  ```yaml
336
- - uses: benner/commit-guard@v0.17.0
336
+ - uses: benner/commit-guard@v0.18.0
337
337
  with:
338
338
  rev: ${{ github.sha }}
339
339
  ```
@@ -351,7 +351,7 @@ jobs:
351
351
  - uses: actions/checkout@v4
352
352
  with:
353
353
  fetch-depth: 0
354
- - uses: benner/commit-guard@v0.17.0
354
+ - uses: benner/commit-guard@v0.18.0
355
355
  with:
356
356
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
357
357
  disable: signed-off,signature
@@ -370,7 +370,7 @@ jobs:
370
370
  When `output-file` is set the action exposes the path as an output:
371
371
 
372
372
  ```yaml
373
- - uses: benner/commit-guard@v0.17.0
373
+ - uses: benner/commit-guard@v0.18.0
374
374
  id: cg
375
375
  with:
376
376
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
@@ -386,7 +386,7 @@ Add to your `.pre-commit-config.yaml`:
386
386
  ---
387
387
  repos:
388
388
  - repo: https://github.com/benner/commit-guard
389
- rev: v0.17.0
389
+ rev: v0.18.0
390
390
  hooks:
391
391
  - id: commit-guard
392
392
  - id: commit-guard-signature
@@ -39,7 +39,7 @@ inputs:
39
39
  required: false
40
40
  default: 'false'
41
41
  no-trailing-chars:
42
- description: Forbidden trailing characters, comma-separated (default '.')
42
+ description: Forbidden trailing characters, comma-separated (default '.', '!', '?', ' ')
43
43
  required: false
44
44
  allow-empty:
45
45
  description: Exit 0 when --range yields no commits
@@ -355,7 +355,7 @@ $ echo "fix(auth): add token refresh" | commit-guard</code></pre>
355
355
  <td><code>subject</code></td>
356
356
  <td>
357
357
  <a href="https://www.conventionalcommits.org/" target="_blank" rel="noopener">Conventional Commits</a>
358
- format: valid type, lowercase start, no trailing period,
358
+ format: valid type, lowercase start, no trailing <code>.</code> <code>!</code> <code>?</code> or space,
359
359
  max length (default 72). All limits are configurable. Use
360
360
  <code>!</code> before the colon for breaking changes:
361
361
  <code>feat!: remove endpoint</code>
@@ -479,13 +479,13 @@ require-trailers = ["Closes", "Reviewed-by"]</code></pre>
479
479
  - uses: actions/checkout@v4
480
480
  with:
481
481
  fetch-depth: 0
482
- - uses: benner/commit-guard@v0.17.0
482
+ - uses: benner/commit-guard@v0.18.0
483
483
  with:
484
484
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
485
485
  disable: signed-off,signature</code></pre>
486
486
 
487
487
  <p>Check a specific commit SHA:</p>
488
- <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.17.0
488
+ <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.18.0
489
489
  with:
490
490
  rev: ${{ github.sha }}</code></pre>
491
491
 
@@ -504,7 +504,7 @@ require-trailers = ["Closes", "Reviewed-by"]</code></pre>
504
504
  When <code>output-file</code> is set the action exposes the path as
505
505
  a step output, making JSONL results available to subsequent steps:
506
506
  </p>
507
- <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.17.0
507
+ <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.18.0
508
508
  id: cg
509
509
  with:
510
510
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
@@ -517,7 +517,7 @@ require-trailers = ["Closes", "Reviewed-by"]</code></pre>
517
517
  <p>Add to <code>.pre-commit-config.yaml</code>:</p>
518
518
  <pre><code class="language-yaml">repos:
519
519
  - repo: https://github.com/benner/commit-guard
520
- rev: v0.17.0
520
+ rev: v0.18.0
521
521
  hooks:
522
522
  - id: commit-guard
523
523
  - id: commit-guard-signature</code></pre>
@@ -153,7 +153,7 @@ def check_subject( # noqa: PLR0913 Too many arguments in function definition (9
153
153
  allowed_types=TYPES,
154
154
  max_subject_length=MAX_SUBJECT_LEN,
155
155
  min_description_length=0,
156
- no_trailing_chars=frozenset("."),
156
+ no_trailing_chars=frozenset({".", "!", "?", " "}),
157
157
  *,
158
158
  require_scope=False,
159
159
  require_lowercase=True,
@@ -362,7 +362,7 @@ def _resolve_no_trailing_chars(args, config):
362
362
  return frozenset(c for c in args.no_trailing_chars.split(",") if c)
363
363
  if "no-trailing-chars" in config:
364
364
  return frozenset(config["no-trailing-chars"])
365
- return frozenset(".")
365
+ return frozenset({".", "!", "?", " "})
366
366
 
367
367
 
368
368
  def _resolve_required_trailers(args, config):
@@ -22,6 +22,8 @@ from git_commit_guard import (
22
22
  _report_text,
23
23
  _resolve_max_subject_length,
24
24
  _resolve_min_description_length,
25
+ _resolve_no_trailing_chars,
26
+ _resolve_require_lowercase,
25
27
  _resolve_required_trailers,
26
28
  _resolve_types,
27
29
  _strip_comments,
@@ -454,6 +456,19 @@ class TestCheckImperative:
454
456
  check_imperative("", r)
455
457
  assert r.ok
456
458
 
459
+ def test_pos_fallback_unknown_word_fails(self):
460
+ r = Result()
461
+ with (
462
+ patch("git_commit_guard.wordnet.morphy", return_value=None),
463
+ patch(
464
+ "git_commit_guard.nltk.pos_tag",
465
+ return_value=[("to", "TO"), ("xyzzy", "NN")],
466
+ ),
467
+ ):
468
+ check_imperative("xyzzy something", r)
469
+ assert not r.ok
470
+ assert "POS=NN" in r.errors[0][2]
471
+
457
472
 
458
473
  class TestDownloadIfMissing:
459
474
  def test_skips_download_when_present(self):
@@ -617,6 +632,38 @@ class TestResolveMinDescriptionLength:
617
632
  assert result == 10
618
633
 
619
634
 
635
+ class TestResolveRequireLowercase:
636
+ def test_cli_flag_overrides_default(self):
637
+ assert (
638
+ _resolve_require_lowercase(Namespace(require_lowercase=False), {}) is False
639
+ )
640
+
641
+ def test_config_overrides_default(self):
642
+ result = _resolve_require_lowercase(
643
+ Namespace(require_lowercase=None), {"require-lowercase": False}
644
+ )
645
+ assert result is False
646
+
647
+ def test_default_is_true(self):
648
+ assert _resolve_require_lowercase(Namespace(require_lowercase=None), {}) is True
649
+
650
+
651
+ class TestResolveNoTrailingChars:
652
+ def test_cli_flag_overrides_default(self):
653
+ result = _resolve_no_trailing_chars(Namespace(no_trailing_chars=".,!"), {})
654
+ assert result == frozenset({".", "!"})
655
+
656
+ def test_config_overrides_default(self):
657
+ result = _resolve_no_trailing_chars(
658
+ Namespace(no_trailing_chars=None), {"no-trailing-chars": [".", "!"]}
659
+ )
660
+ assert result == frozenset({".", "!"})
661
+
662
+ def test_default_includes_common_punctuation_and_space(self):
663
+ result = _resolve_no_trailing_chars(Namespace(no_trailing_chars=None), {})
664
+ assert result == frozenset({".", "!", "?", " "})
665
+
666
+
620
667
  class TestGitTimeout:
621
668
  def test_default(self, monkeypatch):
622
669
  monkeypatch.delenv("COMMIT_GUARD_GIT_TIMEOUT", raising=False)
@@ -1458,6 +1505,27 @@ class TestOutputJsonl:
1458
1505
  assert data["sha"] == rev
1459
1506
  assert data["ok"] is True
1460
1507
 
1508
+ def test_range_failing_commit_returns_nonzero(self, capsys):
1509
+ with (
1510
+ patch(
1511
+ "sys.argv",
1512
+ [
1513
+ "cg",
1514
+ "--range",
1515
+ "HEAD~1..HEAD",
1516
+ "--disable",
1517
+ "signature,imperative",
1518
+ "--output",
1519
+ "jsonl",
1520
+ ],
1521
+ ),
1522
+ patch("git_commit_guard._get_range_revs", return_value=["aaa"]),
1523
+ patch("git_commit_guard._get_message", return_value="bad message"),
1524
+ ):
1525
+ assert main() == 1
1526
+ data = json.loads(capsys.readouterr().out)
1527
+ assert data["ok"] is False
1528
+
1461
1529
 
1462
1530
  class TestOutputFile:
1463
1531
  def test_single_commit_writes_jsonl_to_file(self, tmp_path, capsys):