@@ -95,53 +95,63 @@ def extract_checksum_from_tag(repo: Path, tag: str) -> str | None:
9595
9696
9797def 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 \n Git-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 \n Git-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 \n Git-EVTag-v0-SHA512: { in_csum } \n "
145+ if compat
146+ else f"\n \n Git-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
147157def 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