Skip to content

Commit 1ebd47f

Browse files
committed
Change the sign_tree_checksum() impl to create the tag and append to it
This is the same flow as upstream git-evtag. Added support for `-m` and `-F` too. As per cgwalters/git-evtag#9
1 parent 0c23b05 commit 1ebd47f

File tree

2 files changed

+118
-56
lines changed

2 files changed

+118
-56
lines changed

README.md

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,41 @@ git evtag --rev COMMIT
3434
# message of the tag 'TAG' against the one calculated
3535
git evtag --verify TAG
3636

37-
# Add the EVTag checksum to the tag 'TAG'. Preserves the message of the
38-
# original tag 'TAG', creates a new tag 'TAG' with the previous message
39-
# and the EVTag checksum appended to it
37+
# Create a signed and annotated tag 'TAG' from HEAD and append the EVTag
38+
checksum to it. Opens EDITOR for the tag message
4039
git evtag --sign TAG
4140

41+
# Create a signed and annotated tag 'TAG' from HEAD and append the EVTag
42+
# checksum to it. Uses 'Tag Message' as the tag message
43+
git evtag --sign TAG -m "Tag Message"
44+
45+
# Create a signed and annotated tag 'TAG' from HEAD and append the EVTag
46+
# checksum to it. Uses the message from the file 'FILE' as the tag
47+
# message
48+
git evtag --sign TAG -F FILE
49+
4250
# Produces 'Git-EVTag-v0-SHA512' prefixed output
4351
git evtag --compat
4452
git evtag --compat --sign TAG
4553
```
4654

4755
```sh
4856
$ git evtag -h
49-
usage: git-evtag [-h] [--rev REV] [--repo REPO] [--verify VERIFY] [--sign SIGN] [--compat]
57+
usage: git-evtag [-h] [--rev REV] [--repo REPO] [--verify VERIFY] [--sign SIGN] [--compat] [-m TAG_MESSAGE | -F TAG_MESSAGE_FILE]
5058

5159
EVTag checksum of a git repository
5260

5361
options:
54-
-h, --help show this help message and exit
55-
--rev REV Git revision (default: HEAD)
56-
--repo REPO Path to the git repository (default: PWD)
57-
--verify VERIFY Verify the EVTag checksum of the input tag
58-
--sign SIGN Sign the input tag with the EVTag checksum
59-
--compat Produce 'Git-EVTag-v0-SHA512' prefixed output
62+
-h, --help show this help message and exit
63+
--rev REV Git revision (default: HEAD)
64+
--repo REPO Path to the git repository (default: PWD)
65+
--verify VERIFY Verify the EVTag checksum of the input tag
66+
--sign SIGN Create a signed and annotated tag and append the EVTag checksum
67+
--compat Produce 'Git-EVTag-v0-SHA512' prefixed output
68+
-m, --tag-message TAG_MESSAGE
69+
Use the input message as the tag message
70+
-F, --tag-message-file TAG_MESSAGE_FILE
71+
Use the message from the input file as the tag message
6072
```
6173

6274
### Development

git_evtag_py.py

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -95,53 +95,63 @@ def extract_checksum_from_tag(repo: Path, tag: str) -> str | None:
9595

9696

9797
def sign_tree_checksum(
98-
repo: Path, tag: str, in_csum: str, compat: bool = False
98+
repo: Path,
99+
tag: str,
100+
in_csum: str,
101+
compat: bool = False,
102+
tag_msg: str | None = None,
103+
tag_msg_file: Path | None = None,
99104
) -> None:
100-
commit = subprocess.check_output(
101-
["git", "rev-parse", f"{tag}^{{}}"],
102-
text=True,
105+
ret = subprocess.run(
106+
["git", "rev-parse", f"refs/tags/{tag}"],
107+
check=False,
103108
cwd=repo,
104109
env=GIT_ENV,
105-
).strip()
110+
stdout=subprocess.DEVNULL,
111+
stderr=subprocess.DEVNULL,
112+
)
113+
if ret.returncode == 0:
114+
raise RuntimeError(f"Tag '{tag}' already exists")
106115

107-
tag_msg = subprocess.check_output(
108-
["git", "for-each-ref", f"refs/tags/{tag}", "--format=%(contents)"],
116+
commit = subprocess.check_output(
117+
["git", "rev-parse", "HEAD"],
109118
text=True,
110119
cwd=repo,
111120
env=GIT_ENV,
112-
)
113-
114-
pattern = (
115-
r"(?:\n?Git-EVTag-Py-v0-SHA512: .*\n?|"
116-
r"\n?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----\n?)"
117-
)
118-
119-
if compat:
120-
pattern = pattern[:-1] + r"|\n?Git-EVTag-v0-SHA512: .*\n?)"
121-
122-
cleaned_msg = re.sub(pattern, "", tag_msg, flags=re.DOTALL)
123-
124-
editor = os.environ.get("EDITOR", "vi")
125-
with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".tmp") as tmp:
126-
tmp.write(cleaned_msg)
127-
tmp.flush()
128-
subprocess.run([editor, tmp.name], check=True)
129-
tmp.seek(0)
130-
edited_msg = tmp.read()
121+
).strip()
131122

132-
if compat:
133-
footer = f"\n\nGit-EVTag-v0-SHA512: {in_csum}\n"
123+
if tag_msg:
124+
message = tag_msg
125+
elif tag_msg_file:
126+
message = Path(tag_msg_file).read_text()
134127
else:
135-
footer = f"\n\nGit-EVTag-Py-v0-SHA512: {in_csum}\n"
128+
editor = os.environ.get("EDITOR", "vi")
129+
with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".tmp") as tmp:
130+
tmp.write("")
131+
tmp.flush()
132+
subprocess.run([editor, tmp.name], check=True)
133+
tmp.seek(0)
134+
message = tmp.read()
135+
os.unlink(tmp.name)
136136

137-
final_msg = edited_msg.rstrip() + footer
137+
pattern = (
138+
r"\n?Git-EVTag-v0-SHA512: .*\n?"
139+
if compat
140+
else r"\n?Git-EVTag-Py-v0-SHA512: .*\n?"
141+
)
142+
cleaned_msg = re.sub(pattern, "", message, flags=re.DOTALL).rstrip()
143+
footer = (
144+
f"\n\nGit-EVTag-v0-SHA512: {in_csum}\n"
145+
if compat
146+
else f"\n\nGit-EVTag-Py-v0-SHA512: {in_csum}\n"
147+
)
148+
final_msg = cleaned_msg + footer
138149

139150
subprocess.run(
140-
["git", "tag", tag, commit, "-f", "-m", final_msg],
151+
["git", "tag", "-a", "-s", tag, commit, "-m", final_msg],
141152
check=True,
142153
cwd=repo,
143154
)
144-
os.unlink(tmp.name)
145155

146156

147157
def is_tag_signature_valid(repo: Path, tag: str) -> bool:
@@ -364,6 +374,14 @@ def validate_args(args: argparse.Namespace) -> bool:
364374
if args.rev and (args.verify or args.sign):
365375
logging.error("'--rev' cannot be used with '--verify' or '--sign'")
366376
return False
377+
if (args.tag_message or args.tag_message_file) and not args.sign:
378+
logging.error(
379+
"'--tag-message' and '--tag-message-file' can only be used with '--sign'"
380+
)
381+
return False
382+
if args.tag_message_file and not args.tag_message_file.exists():
383+
logging.error("The tag message file does not exist '%s'", args.tag_message_file)
384+
return False
367385
return True
368386

369387

@@ -374,12 +392,27 @@ def parse_args() -> argparse.Namespace:
374392
"--repo", default=".", help="Path to the git repository (default: PWD)"
375393
)
376394
parser.add_argument("--verify", help="Verify the EVTag checksum of the input tag")
377-
parser.add_argument("--sign", help="Sign the input tag with the EVTag checksum")
395+
parser.add_argument(
396+
"--sign",
397+
help=(
398+
"Create a signed and annotated tag from HEAD and append the EVTag checksum"
399+
),
400+
)
378401
parser.add_argument(
379402
"--compat",
380403
action="store_true",
381404
help="Produce 'Git-EVTag-v0-SHA512' prefixed output",
382405
)
406+
tag_msg = parser.add_mutually_exclusive_group()
407+
tag_msg.add_argument(
408+
"-m", "--tag-message", help="Use the input message as the tag message"
409+
)
410+
tag_msg.add_argument(
411+
"-F",
412+
"--tag-message-file",
413+
type=Path,
414+
help="Use the message from the input file as the tag message",
415+
)
383416
return parser.parse_args()
384417

385418

@@ -400,13 +433,13 @@ def main() -> int:
400433
resolved_commit = ensure_git_rev("HEAD", repo)
401434
if args.rev:
402435
resolved_commit = ensure_git_rev(args.rev, repo)
403-
if args.verify or args.sign:
404-
in_tag = args.verify or args.sign
405-
resolved_commit = ensure_git_rev(in_tag, repo)
406-
if not in_tag:
407-
logging.error("Failed to get the input tag")
408-
return 1
436+
if args.sign or args.verify:
437+
in_tag = args.sign or args.verify
438+
if (args.verify or args.sign) and not in_tag:
439+
logging.error("Failed to get the input tag")
440+
return 1
409441
if args.verify and in_tag:
442+
resolved_commit = ensure_git_rev(in_tag, repo)
410443
tag_evtag_csum = extract_checksum_from_tag(repo, in_tag)
411444
if not tag_evtag_csum:
412445
logging.error(
@@ -415,15 +448,19 @@ def main() -> int:
415448
in_tag,
416449
)
417450
return 1
418-
if not resolved_commit:
451+
if not (args.sign or resolved_commit):
419452
logging.error("Failed to calculate the resolved commit from the input")
420453
return 1
421454

422-
checksum = ChecksumProcessor()
423-
ensure_submodules_init(repo)
424-
processor = GitProcessor(repo, checksum)
425-
with GitBatchProcessor(repo) as batch_proc:
426-
processor.checksum_repo(batch_proc, resolved_commit, repo)
455+
if resolved_commit:
456+
checksum = ChecksumProcessor()
457+
ensure_submodules_init(repo)
458+
processor = GitProcessor(repo, checksum)
459+
with GitBatchProcessor(repo) as batch_proc:
460+
processor.checksum_repo(batch_proc, resolved_commit, repo)
461+
else:
462+
logging.error("Failed to calculate the resolved commit from the input")
463+
return 1
427464

428465
calc_evtag_csum = checksum.get_digest()
429466

@@ -433,7 +470,20 @@ def main() -> int:
433470
else:
434471
print(f"Git-EVTag-Py-v0-SHA512: {calc_evtag_csum}") # noqa: T201
435472
elif args.sign and in_tag:
436-
sign_tree_checksum(repo, in_tag, calc_evtag_csum, args.compat)
473+
if args.tag_message:
474+
sign_tree_checksum(
475+
repo, in_tag, calc_evtag_csum, args.compat, tag_msg=args.tag_message
476+
)
477+
elif args.tag_message_file:
478+
sign_tree_checksum(
479+
repo,
480+
in_tag,
481+
calc_evtag_csum,
482+
args.compat,
483+
tag_msg_file=args.tag_message_file,
484+
)
485+
else:
486+
sign_tree_checksum(repo, in_tag, calc_evtag_csum, args.compat)
437487
elif (
438488
args.verify
439489
and in_tag

0 commit comments

Comments
 (0)