git-commit-guard 0.20.0__tar.gz → 0.20.1__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 (26) hide show
  1. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/coverage-baseline.yml +1 -1
  2. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/lint-commits.yml +1 -2
  3. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/lint-md.yml +1 -1
  4. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/lint-workflows.yml +8 -5
  5. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/test.yml +3 -1
  6. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/PKG-INFO +8 -8
  7. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/README.md +7 -7
  8. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/docs/index.html +4 -4
  9. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/src/git_commit_guard/__init__.py +10 -2
  10. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/tests/test_git_commit_guard.py +28 -0
  11. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.editorconfig +0 -0
  12. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/coverage-comment.yml +0 -0
  13. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/lint-python.yml +0 -0
  14. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.github/workflows/release.yml +0 -0
  15. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.gitignore +0 -0
  16. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.markdownlint.json +0 -0
  17. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.pre-commit-hooks.yaml +0 -0
  18. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/.python-version +0 -0
  19. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/LICENSE +0 -0
  20. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/action.yml +0 -0
  21. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/cliff.toml +0 -0
  22. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/docs/commit-guard-icon.svg +0 -0
  23. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/pyproject.toml +0 -0
  24. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/ruff.toml +0 -0
  25. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/tests/__init__.py +0 -0
  26. {git_commit_guard-0.20.0 → git_commit_guard-0.20.1}/uv.lock +0 -0
@@ -19,7 +19,7 @@ jobs:
19
19
  uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # ratchet:astral-sh/setup-uv@v7
20
20
  - name: Cache NLTK data
21
21
  # yamllint disable-line rule:line-length
22
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # ratchet:actions/cache@v5
22
+ uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
23
23
  with:
24
24
  path: ~/nltk_data
25
25
  key: nltk-averaged-perceptron-tagger-punkt
@@ -22,7 +22,6 @@ 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@7704c563540b24bb10394e373e508dc664a7f01f # v0.19.0
25
+ uses: benner/commit-guard@cab0d35c41a3f99fc5f61895f491d0ce3f5aff1c # v0.20.0
26
26
  with:
27
27
  range: origin/${{ github.base_ref }}..HEAD
28
- disable: signature
@@ -23,4 +23,4 @@ jobs:
23
23
  github_token: ${{ secrets.GITHUB_TOKEN }}
24
24
  reporter: github-pr-review
25
25
  level: info
26
- fail_on_error: true
26
+ fail_level: any
@@ -12,7 +12,7 @@ jobs:
12
12
  steps:
13
13
  - name: Checkout code
14
14
  # yamllint disable-line rule:line-length
15
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # ratchet:actions/checkout@v4
15
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
16
16
  with:
17
17
  persist-credentials: false
18
18
  - name: Run actionlint
@@ -21,6 +21,7 @@ jobs:
21
21
  with:
22
22
  github_token: ${{ github.token }}
23
23
  reporter: github-pr-review
24
+ fail_level: any
24
25
  yamlfix:
25
26
  runs-on: ubuntu-latest
26
27
  permissions:
@@ -28,7 +29,7 @@ jobs:
28
29
  steps:
29
30
  - name: Checkout code
30
31
  # yamllint disable-line rule:line-length
31
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # ratchet:actions/checkout@v4
32
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
32
33
  with:
33
34
  persist-credentials: false
34
35
  - name: Set up uv
@@ -41,10 +42,11 @@ jobs:
41
42
  env:
42
43
  REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
43
44
  run: |-
45
+ set -o pipefail
44
46
  uvx yamlfix .github/workflows/
45
47
  git diff .github/workflows/ |
46
48
  reviewdog -f=diff -name=yamlfix \
47
- -reporter=github-pr-review -fail-on-error
49
+ -reporter=github-pr-review -fail-level=any
48
50
  zizmor:
49
51
  runs-on: ubuntu-latest
50
52
  permissions:
@@ -52,7 +54,7 @@ jobs:
52
54
  steps:
53
55
  - name: Checkout code
54
56
  # yamllint disable-line rule:line-length
55
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # ratchet:actions/checkout@v4
57
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
56
58
  with:
57
59
  persist-credentials: false
58
60
  - name: Set up uv
@@ -65,6 +67,7 @@ jobs:
65
67
  env:
66
68
  REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
67
69
  run: |-
70
+ set -o pipefail
68
71
  uvx zizmor==1.24.1 --format=sarif . |
69
72
  reviewdog -f=sarif -name=zizmor \
70
- -reporter=github-pr-review -fail-on-error
73
+ -reporter=github-pr-review -fail-level=any
@@ -27,9 +27,11 @@ jobs:
27
27
  tests/ --cov=git_commit_guard --cov-report=term-missing \
28
28
  --cov-report=xml
29
29
  - name: Save coverage artifact
30
+ env:
31
+ PR_NUMBER: ${{ github.event.number }}
30
32
  run: |
31
33
  mkdir -p ./pr
32
- echo ${{ github.event.number }} > ./pr/NR
34
+ echo "$PR_NUMBER" > ./pr/NR
33
35
  cp coverage.xml ./pr/
34
36
  - name: Upload PR artifact
35
37
  # yamllint disable-line rule:line-length
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-commit-guard
3
- Version: 0.20.0
3
+ Version: 0.20.1
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
@@ -296,7 +296,7 @@ COMMIT_GUARD_GIT_TIMEOUT=30 commit-guard --range origin/main..HEAD
296
296
  In GitHub Actions, set it at the step or job level:
297
297
 
298
298
  ```yaml
299
- - uses: benner/commit-guard@v0.19.0
299
+ - uses: benner/commit-guard@v0.20.1
300
300
  env:
301
301
  COMMIT_GUARD_GIT_TIMEOUT: 30
302
302
  with:
@@ -380,7 +380,7 @@ steps:
380
380
  - uses: actions/checkout@v4
381
381
  with:
382
382
  fetch-depth: 0
383
- - uses: benner/commit-guard@v0.19.0
383
+ - uses: benner/commit-guard@v0.20.1
384
384
  ```
385
385
 
386
386
  Check all commits in a pull request:
@@ -396,7 +396,7 @@ jobs:
396
396
  - uses: actions/checkout@v4
397
397
  with:
398
398
  fetch-depth: 0
399
- - uses: benner/commit-guard@v0.19.0
399
+ - uses: benner/commit-guard@v0.20.1
400
400
  with:
401
401
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
402
402
  ```
@@ -404,7 +404,7 @@ jobs:
404
404
  Check a specific commit SHA (mirrors the positional CLI argument):
405
405
 
406
406
  ```yaml
407
- - uses: benner/commit-guard@v0.19.0
407
+ - uses: benner/commit-guard@v0.20.1
408
408
  with:
409
409
  rev: ${{ github.sha }}
410
410
  ```
@@ -422,7 +422,7 @@ jobs:
422
422
  - uses: actions/checkout@v4
423
423
  with:
424
424
  fetch-depth: 0
425
- - uses: benner/commit-guard@v0.19.0
425
+ - uses: benner/commit-guard@v0.20.1
426
426
  with:
427
427
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
428
428
  disable: signed-off,signature
@@ -442,7 +442,7 @@ jobs:
442
442
  When `output-file` is set the action exposes the path as an output:
443
443
 
444
444
  ```yaml
445
- - uses: benner/commit-guard@v0.19.0
445
+ - uses: benner/commit-guard@v0.20.1
446
446
  id: cg
447
447
  with:
448
448
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
@@ -458,7 +458,7 @@ Add to your `.pre-commit-config.yaml`:
458
458
  ---
459
459
  repos:
460
460
  - repo: https://github.com/benner/commit-guard
461
- rev: v0.19.0
461
+ rev: v0.20.1
462
462
  hooks:
463
463
  - id: commit-guard
464
464
  - id: commit-guard-signature
@@ -275,7 +275,7 @@ COMMIT_GUARD_GIT_TIMEOUT=30 commit-guard --range origin/main..HEAD
275
275
  In GitHub Actions, set it at the step or job level:
276
276
 
277
277
  ```yaml
278
- - uses: benner/commit-guard@v0.19.0
278
+ - uses: benner/commit-guard@v0.20.1
279
279
  env:
280
280
  COMMIT_GUARD_GIT_TIMEOUT: 30
281
281
  with:
@@ -359,7 +359,7 @@ steps:
359
359
  - uses: actions/checkout@v4
360
360
  with:
361
361
  fetch-depth: 0
362
- - uses: benner/commit-guard@v0.19.0
362
+ - uses: benner/commit-guard@v0.20.1
363
363
  ```
364
364
 
365
365
  Check all commits in a pull request:
@@ -375,7 +375,7 @@ jobs:
375
375
  - uses: actions/checkout@v4
376
376
  with:
377
377
  fetch-depth: 0
378
- - uses: benner/commit-guard@v0.19.0
378
+ - uses: benner/commit-guard@v0.20.1
379
379
  with:
380
380
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
381
381
  ```
@@ -383,7 +383,7 @@ jobs:
383
383
  Check a specific commit SHA (mirrors the positional CLI argument):
384
384
 
385
385
  ```yaml
386
- - uses: benner/commit-guard@v0.19.0
386
+ - uses: benner/commit-guard@v0.20.1
387
387
  with:
388
388
  rev: ${{ github.sha }}
389
389
  ```
@@ -401,7 +401,7 @@ jobs:
401
401
  - uses: actions/checkout@v4
402
402
  with:
403
403
  fetch-depth: 0
404
- - uses: benner/commit-guard@v0.19.0
404
+ - uses: benner/commit-guard@v0.20.1
405
405
  with:
406
406
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
407
407
  disable: signed-off,signature
@@ -421,7 +421,7 @@ jobs:
421
421
  When `output-file` is set the action exposes the path as an output:
422
422
 
423
423
  ```yaml
424
- - uses: benner/commit-guard@v0.19.0
424
+ - uses: benner/commit-guard@v0.20.1
425
425
  id: cg
426
426
  with:
427
427
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
@@ -437,7 +437,7 @@ Add to your `.pre-commit-config.yaml`:
437
437
  ---
438
438
  repos:
439
439
  - repo: https://github.com/benner/commit-guard
440
- rev: v0.19.0
440
+ rev: v0.20.1
441
441
  hooks:
442
442
  - id: commit-guard
443
443
  - id: commit-guard-signature
@@ -538,13 +538,13 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
538
538
  - uses: actions/checkout@v4
539
539
  with:
540
540
  fetch-depth: 0
541
- - uses: benner/commit-guard@v0.19.0
541
+ - uses: benner/commit-guard@v0.20.1
542
542
  with:
543
543
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
544
544
  disable: signed-off,signature</code></pre>
545
545
 
546
546
  <p>Check a specific commit SHA:</p>
547
- <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.19.0
547
+ <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.20.1
548
548
  with:
549
549
  rev: ${{ github.sha }}</code></pre>
550
550
 
@@ -563,7 +563,7 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
563
563
  When <code>output-file</code> is set the action exposes the path as
564
564
  a step output, making JSONL results available to subsequent steps:
565
565
  </p>
566
- <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.19.0
566
+ <pre><code class="language-yaml"> - uses: benner/commit-guard@v0.20.1
567
567
  id: cg
568
568
  with:
569
569
  range: ${{ env.PR_BASE }}..${{ env.PR_HEAD }}
@@ -576,7 +576,7 @@ require-subject-pattern = "[A-Z]+-[0-9]+"</code></pre>
576
576
  <p>Add to <code>.pre-commit-config.yaml</code>:</p>
577
577
  <pre><code class="language-yaml">repos:
578
578
  - repo: https://github.com/benner/commit-guard
579
- rev: v0.19.0
579
+ rev: v0.20.1
580
580
  hooks:
581
581
  - id: commit-guard
582
582
  - id: commit-guard-signature</code></pre>
@@ -78,7 +78,10 @@ def _load_config(start=None):
78
78
  config_path = directory / ".commit-guard.toml"
79
79
  if config_path.exists():
80
80
  with config_path.open("rb") as f:
81
- return tomllib.load(f)
81
+ try:
82
+ return tomllib.load(f)
83
+ except tomllib.TOMLDecodeError as e:
84
+ sys.exit(f"{config_path}: {e}")
82
85
  return {}
83
86
 
84
87
 
@@ -411,6 +414,11 @@ def check_signature(rev, result):
411
414
  result.info("signature type: SSH", check=Check.SIGNATURE)
412
415
  return
413
416
  result.error("commit is not signed (GPG/SSH)", check=Check.SIGNATURE)
417
+ except subprocess.TimeoutExpired:
418
+ result.error(
419
+ "git operation timed out — cannot verify signature",
420
+ check=Check.SIGNATURE,
421
+ )
414
422
  except (urllib.error.URLError, TimeoutError):
415
423
  result.error(
416
424
  "GitHub API unreachable — cannot verify signature",
@@ -698,7 +706,7 @@ def _parse_args(): # noqa: PLR0915 Too many statements (59 > 50)
698
706
  message = ""
699
707
  elif args.message_file:
700
708
  rev = None
701
- message = _strip_comments(args.message_file.read_text().strip())
709
+ message = _strip_comments(args.message_file.read_text(encoding="utf-8").strip())
702
710
  elif args.rev:
703
711
  rev = args.rev
704
712
  message = _strip_comments(_get_message(rev))
@@ -833,6 +833,16 @@ class TestCheckSignature:
833
833
  assert not r.ok
834
834
  assert any("API unreachable" in msg for _, _, msg in r.errors)
835
835
 
836
+ def test_subprocess_timeout_fails_gracefully(self):
837
+ r = Result()
838
+ with patch(
839
+ "git_commit_guard._get_author_email",
840
+ side_effect=subprocess.TimeoutExpired(cmd="git", timeout=10),
841
+ ):
842
+ check_signature("abc123", r)
843
+ assert not r.ok
844
+ assert any("git operation timed out" in msg for _, _, msg in r.errors)
845
+
836
846
  def test_commits_api_resolves_username(self):
837
847
  r = Result()
838
848
  with (
@@ -1007,6 +1017,12 @@ class TestLoadConfig:
1007
1017
  (subdir / ".commit-guard.toml").write_text('disable = ["signature"]\n')
1008
1018
  assert _load_config(subdir) == {"disable": ["signature"]}
1009
1019
 
1020
+ def test_malformed_toml_exits_with_path(self, tmp_path):
1021
+ config_path = tmp_path / ".commit-guard.toml"
1022
+ config_path.write_text("disable = [unclosed\n")
1023
+ with pytest.raises(SystemExit, match=re.escape(str(config_path))):
1024
+ _load_config(tmp_path)
1025
+
1010
1026
 
1011
1027
  class TestParseConfigChecks:
1012
1028
  def test_disable_list(self):
@@ -1244,6 +1260,18 @@ class TestMain:
1244
1260
  assert main() == 0
1245
1261
  assert "all checks passed" in capsys.readouterr().out
1246
1262
 
1263
+ def test_from_message_file_utf8_non_ascii(self, tmp_path):
1264
+ f = tmp_path / "msg"
1265
+ f.write_bytes(
1266
+ "fix: handle non-ascii\n\nbody\n\n"
1267
+ "Signed-off-by: Nerijus Bendžiūnas <a@b.com>".encode()
1268
+ )
1269
+ with patch(
1270
+ "sys.argv",
1271
+ ["cg", "--message-file", str(f), "--disable", "signature"],
1272
+ ):
1273
+ assert main() == 0
1274
+
1247
1275
  def test_from_stdin(self):
1248
1276
  stdin = MagicMock()
1249
1277
  stdin.isatty.return_value = False