Skip to content

Commit 096da69

Browse files
test(conftest): make GPG-signing fixture work on Windows
Two changes to the `tmp_commitizen_project_with_gpg` fixture and its helper so that the GPG-related bump tests run reliably on Windows hosts where `Gpg4win` and `Git for Windows` ship separate gpg binaries and keyrings: * `_get_gpg_keyid` now parses `gpg --with-colons` output instead of relying on a regex over the human-friendly layout. The regex required LF line endings, which gpg does not produce on Windows (CRLF), so it always returned `None` and the fixture asserted out. * The fixture pins `git config gpg.program` to the same gpg binary it used to create the test key (resolved via `shutil.which`). Otherwise `git commit -S` invokes the gpg shipped with Git for Windows, which has a different keyring and reports `gpg: skipped <fingerprint>: No secret key`. Behaviour on Linux / macOS is unchanged because `shutil.which` and `--with-colons` work identically there. The codespell ignore list is extended with `fpr` so the gpg colon output prefix used in the parser does not trip the spelling check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4d99415 commit 096da69

2 files changed

Lines changed: 26 additions & 8 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ ignore_missing_imports = true
268268
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
269269
skip = '.git*,*.svg,*.lock'
270270
check-hidden = true
271-
ignore-words-list = 'asend'
271+
ignore-words-list = 'asend,fpr'
272272

273273
[tool.poe]
274274
executor.type = "uv"

tests/conftest.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
import os
4-
import re
4+
import shutil
55
import subprocess
66
import sys
77
import tempfile
@@ -123,12 +123,22 @@ def _initial(
123123

124124

125125
def _get_gpg_keyid(signer_mail):
126-
_new_key = cmd.run(["gpg", "--list-secret-keys", signer_mail])
127-
_m = re.search(
128-
r"[a-zA-Z0-9 \[\]-_]*\n[ ]*([0-9A-Za-z]*)\n[\na-zA-Z0-9 \[\]-_<>@]*",
129-
_new_key.out,
130-
)
131-
return _m.group(1) if _m else None
126+
"""Return the primary fingerprint of the first secret key matching ``signer_mail``.
127+
128+
Uses the stable ``--with-colons`` machine-readable format so we don't rely
129+
on ``gpg``'s human-friendly layout, which differs between platforms (notably
130+
CRLF on Windows).
131+
"""
132+
_new_key = cmd.run(["gpg", "--with-colons", "--list-secret-keys", signer_mail])
133+
in_sec = False
134+
for line in _new_key.out.splitlines():
135+
if line.startswith("sec:"):
136+
in_sec = True
137+
elif in_sec and line.startswith("fpr:"):
138+
fields = line.split(":")
139+
# Field index 9 holds the fingerprint per gpg(1) DETAILS.
140+
return fields[9] if len(fields) > 9 and fields[9] else None
141+
return None
132142

133143

134144
@pytest.fixture
@@ -140,6 +150,12 @@ def tmp_commitizen_project_with_gpg(tmp_commitizen_project):
140150
if os.name != "nt":
141151
os.environ["GNUPGHOME"] = gpg_home.name # tempdir = temp keyring
142152

153+
# Resolve the absolute path to the gpg binary used by this fixture so that
154+
# git invokes the same one (and therefore the same keyring). This matters
155+
# on Windows where Git for Windows ships its own gpg binary that has a
156+
# different keyring than a system-wide GnuPG/Gpg4win install.
157+
gpg_binary = shutil.which("gpg")
158+
143159
try:
144160
# create a key (a keyring will be generated within GPUPGHOME)
145161
subprocess.run(
@@ -161,6 +177,8 @@ def tmp_commitizen_project_with_gpg(tmp_commitizen_project):
161177
# configure git to use gpg signing
162178
cmd.run(["git", "config", "commit.gpgsign", "true"])
163179
cmd.run(["git", "config", "user.signingkey", key_id])
180+
if gpg_binary:
181+
cmd.run(["git", "config", "gpg.program", gpg_binary])
164182

165183
yield tmp_commitizen_project
166184
finally:

0 commit comments

Comments
 (0)