Skip to content

Commit 7898b11

Browse files
authored
fix(cmd-version): forces tag timestamp to be same time as release commit (python-semantic-release#1117)
1 parent ba85532 commit 7898b11

File tree

2 files changed

+51
-20
lines changed

2 files changed

+51
-20
lines changed

src/semantic_release/cli/commands/version.py

+1
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ def version( # noqa: C901
653653
project.git_tag(
654654
tag_name=new_version.as_tag(),
655655
message=new_version.as_tag(),
656+
isotimestamp=commit_date.isoformat(),
656657
noop=opts.noop,
657658
)
658659

src/semantic_release/gitproject.py

+50-20
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
from contextlib import nullcontext
6+
from datetime import datetime
67
from logging import getLogger
78
from pathlib import Path
89
from typing import TYPE_CHECKING
@@ -48,23 +49,36 @@ def logger(self) -> Logger:
4849
return self._logger
4950

5051
def _get_custom_environment(
51-
self, repo: Repo
52+
self,
53+
repo: Repo,
54+
custom_vars: dict[str, str] | None = None,
5255
) -> nullcontext[None] | _GeneratorContextManager[None]:
5356
"""
5457
git.custom_environment is a context manager but
5558
is not reentrant, so once we have "used" it
5659
we need to throw it away and re-create it in
5760
order to use it again
5861
"""
62+
author_vars = (
63+
{
64+
"GIT_AUTHOR_NAME": self._commit_author.name,
65+
"GIT_AUTHOR_EMAIL": self._commit_author.email,
66+
"GIT_COMMITTER_NAME": self._commit_author.name,
67+
"GIT_COMMITTER_EMAIL": self._commit_author.email,
68+
}
69+
if self._commit_author
70+
else {}
71+
)
72+
73+
custom_env_vars = {
74+
**author_vars,
75+
**(custom_vars or {}),
76+
}
77+
5978
return (
6079
nullcontext()
61-
if not self._commit_author
62-
else repo.git.custom_environment(
63-
GIT_AUTHOR_NAME=self._commit_author.name,
64-
GIT_AUTHOR_EMAIL=self._commit_author.email,
65-
GIT_COMMITTER_NAME=self._commit_author.name,
66-
GIT_COMMITTER_EMAIL=self._commit_author.email,
67-
)
80+
if not custom_env_vars
81+
else repo.git.custom_environment(**custom_env_vars)
6882
)
6983

7084
def is_dirty(self) -> bool:
@@ -182,19 +196,32 @@ def git_commit(
182196
self.logger.exception(str(err))
183197
raise GitCommitError("Failed to commit changes") from err
184198

185-
def git_tag(self, tag_name: str, message: str, noop: bool = False) -> None:
199+
def git_tag(
200+
self, tag_name: str, message: str, isotimestamp: str, noop: bool = False
201+
) -> None:
202+
try:
203+
datetime.fromisoformat(isotimestamp)
204+
except ValueError as err:
205+
raise ValueError("Invalid timestamp format") from err
206+
186207
if noop:
187-
command = (
188-
f"""\
189-
GIT_AUTHOR_NAME={self._commit_author.name} \\
190-
GIT_AUTHOR_EMAIL={self._commit_author.email} \\
191-
GIT_COMMITTER_NAME={self._commit_author.name} \\
192-
GIT_COMMITTER_EMAIL={self._commit_author.email} \\
193-
"""
194-
if self._commit_author
195-
else ""
208+
command = str.join(
209+
" ",
210+
[
211+
f"GIT_COMMITTER_DATE={isotimestamp}",
212+
*(
213+
[
214+
f"GIT_AUTHOR_NAME={self._commit_author.name}",
215+
f"GIT_AUTHOR_EMAIL={self._commit_author.email}",
216+
f"GIT_COMMITTER_NAME={self._commit_author.name}",
217+
f"GIT_COMMITTER_EMAIL={self._commit_author.email}",
218+
]
219+
if self._commit_author
220+
else [""]
221+
),
222+
f"git tag -a {tag_name} -m '{message}'",
223+
],
196224
)
197-
command += f"git tag -a {tag_name} -m '{message}'"
198225

199226
noop_report(
200227
indented(
@@ -206,7 +233,10 @@ def git_tag(self, tag_name: str, message: str, noop: bool = False) -> None:
206233
)
207234
return
208235

209-
with Repo(str(self.project_root)) as repo, self._get_custom_environment(repo):
236+
with Repo(str(self.project_root)) as repo, self._get_custom_environment(
237+
repo,
238+
{"GIT_COMMITTER_DATE": isotimestamp},
239+
):
210240
try:
211241
repo.git.tag("-a", tag_name, m=message)
212242
except GitCommandError as err:

0 commit comments

Comments
 (0)