Skip to content

Commit e218264

Browse files
committed
Fixed issue with tag name.
Fixes #74 current_version and tag_name now do not need to match exactly
1 parent 909a53f commit e218264

File tree

3 files changed

+31
-19
lines changed

3 files changed

+31
-19
lines changed

bumpversion/config.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,7 @@ def get_configuration(config_file: Union[str, Path, None] = None, **overrides) -
200200
config = Config(**config_dict) # type: ignore[arg-type]
201201

202202
# Get the information about the SCM
203-
tag_pattern = config.tag_name.replace("{new_version}", "*")
204-
scm_info = get_scm_info(tag_pattern)
203+
scm_info = get_scm_info(config.tag_name, config.parse)
205204
config.scm_info = scm_info
206205

207206
# Update and verify the current_version

bumpversion/scm.py

+22-11
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def assert_nondirty(cls) -> None:
8686
raise NotImplementedError()
8787

8888
@classmethod
89-
def latest_tag_info(cls, tag_pattern: str) -> SCMInfo:
89+
def latest_tag_info(cls, tag_name: str, parse_pattern: str) -> SCMInfo:
9090
"""Return information about the latest tag."""
9191
raise NotImplementedError()
9292

@@ -109,6 +109,14 @@ def get_all_tags(cls) -> List[str]:
109109
except (FileNotFoundError, PermissionError, NotADirectoryError, subprocess.CalledProcessError):
110110
return []
111111

112+
@classmethod
113+
def get_version_from_tag(cls, tag: str, tag_name: str, parse_pattern: str) -> Optional[str]:
114+
"""Return the version from a tag."""
115+
version_pattern = parse_pattern.replace("\\\\", "\\")
116+
rep = tag_name.replace("{new_version}", f"(?P<current_version>{version_pattern})")
117+
tag_regex = re.compile(rep)
118+
return match["current_version"] if (match := tag_regex.match(tag)) else None
119+
112120
@classmethod
113121
def commit_to_scm(
114122
cls,
@@ -173,7 +181,6 @@ def tag_in_scm(cls, config: "Config", context: MutableMapping, dry_run: bool = F
173181
tag_name = config.tag_name.format(**context)
174182
tag_message = config.tag_message.format(**context)
175183
existing_tags = cls.get_all_tags()
176-
177184
do_tag = not dry_run
178185

179186
if tag_name in existing_tags:
@@ -219,15 +226,15 @@ def assert_nondirty(cls) -> None:
219226
raise DirtyWorkingDirectoryError(f"Git working directory is not clean:\n\n{joined_lines}")
220227

221228
@classmethod
222-
def latest_tag_info(cls, tag_pattern: str) -> SCMInfo:
229+
def latest_tag_info(cls, tag_name: str, parse_pattern: str) -> SCMInfo:
223230
"""Return information about the latest tag."""
224231
try:
225232
# git-describe doesn't update the git-index, so we do that
226233
subprocess.run(["git", "update-index", "--refresh", "-q"], capture_output=True) # noqa: S603, S607
227234
except subprocess.CalledProcessError as e:
228235
logger.debug("Error when running git update-index: %s", e.stderr)
229236
return SCMInfo(tool=cls)
230-
237+
tag_pattern = tag_name.replace("{new_version}", "*")
231238
try:
232239
# get info about the latest tag in git
233240
git_cmd = [
@@ -260,7 +267,8 @@ def latest_tag_info(cls, tag_pattern: str) -> SCMInfo:
260267

261268
info.commit_sha = describe_out.pop().lstrip("g")
262269
info.distance_to_latest_tag = int(describe_out.pop())
263-
info.current_version = "-".join(describe_out).lstrip("v")
270+
version = cls.get_version_from_tag(describe_out[-1], tag_name, parse_pattern)
271+
info.current_version = version or "-".join(describe_out).lstrip("v")
264272

265273
return info
266274

@@ -298,10 +306,10 @@ class Mercurial(SourceCodeManager):
298306
_ALL_TAGS_COMMAND: ClassVar[List[str]] = ["hg", "log", '--rev="tag()"', '--template="{tags}\n"']
299307

300308
@classmethod
301-
def latest_tag_info(cls, tag_pattern: str) -> SCMInfo:
309+
def latest_tag_info(cls, tag_name: str, parse_pattern: str) -> SCMInfo:
302310
"""Return information about the latest tag."""
303311
current_version = None
304-
re_pattern = tag_pattern.replace("*", ".*")
312+
re_pattern = tag_name.replace("{new_version}", ".*")
305313
result = subprocess.run(
306314
["hg", "log", "-r", f"tag('re:{re_pattern}')", "--template", "{latesttag}\n"], # noqa: S603, S607
307315
text=True,
@@ -310,7 +318,10 @@ def latest_tag_info(cls, tag_pattern: str) -> SCMInfo:
310318
)
311319
result.check_returncode()
312320
if result.stdout:
313-
current_version = result.stdout.splitlines(keepends=False)[-1].lstrip("v")
321+
tag_string = result.stdout.splitlines(keepends=False)[-1]
322+
current_version = cls.get_version_from_tag(tag_string, tag_name, parse_pattern)
323+
else:
324+
logger.debug("No tags found")
314325
is_dirty = len(subprocess.check_output(["hg", "status", "-mard"])) != 0 # noqa: S603, S607
315326
return SCMInfo(tool=cls, current_version=current_version, dirty=is_dirty)
316327

@@ -356,11 +367,11 @@ def tag(cls, name: str, sign: bool = False, message: Optional[str] = None) -> No
356367
subprocess.check_output(command) # noqa: S603
357368

358369

359-
def get_scm_info(tag_pattern: str) -> SCMInfo:
370+
def get_scm_info(tag_name: str, parse_pattern: str) -> SCMInfo:
360371
"""Return a dict with the latest source code management info."""
361372
if Git.is_usable():
362-
return Git.latest_tag_info(tag_pattern)
373+
return Git.latest_tag_info(tag_name, parse_pattern)
363374
elif Mercurial.is_usable():
364-
return Mercurial.latest_tag_info(tag_pattern)
375+
return Mercurial.latest_tag_info(tag_name, parse_pattern)
365376
else:
366377
return SCMInfo()

tests/test_scm.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,25 @@ def test_git_latest_tag_info(git_repo: Path) -> None:
4343
"""Should return information about the latest tag."""
4444
readme = git_repo.joinpath("readme.md")
4545
readme.touch()
46-
46+
tag_prefix = "app/"
47+
parse_pattern = r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)"
48+
tag_name = f"{tag_prefix}{{new_version}}"
4749
with inside_dir(git_repo):
48-
assert scm.Git.latest_tag_info("v*") == scm.SCMInfo(tool=scm.Git)
50+
assert scm.Git.latest_tag_info(tag_name, parse_pattern=parse_pattern) == scm.SCMInfo(tool=scm.Git)
4951

5052
# Add a file and tag
5153
subprocess.run(["git", "add", "readme.md"])
5254
subprocess.run(["git", "commit", "-m", "first"])
53-
subprocess.run(["git", "tag", "v0.1.0"])
54-
tag_info = scm.Git.latest_tag_info("v*")
55+
subprocess.run(["git", "tag", f"{tag_prefix}0.1.0"])
56+
tag_info = scm.Git.latest_tag_info(tag_name, parse_pattern=parse_pattern)
5557
assert tag_info.commit_sha is not None
5658
assert tag_info.current_version == "0.1.0"
5759
assert tag_info.distance_to_latest_tag == 0
5860

5961
# Make it dirty
6062
git_repo.joinpath("something.md").touch()
6163
subprocess.run(["git", "add", "something.md"])
62-
tag_info = scm.Git.latest_tag_info("v*")
64+
tag_info = scm.Git.latest_tag_info(tag_name, parse_pattern=parse_pattern)
6365
assert tag_info.commit_sha is not None
6466
assert tag_info.current_version == "0.1.0"
6567
assert tag_info.distance_to_latest_tag == 0
@@ -137,7 +139,7 @@ def test_commit_and_tag_from_below_scm_root(repo: str, scm_command: str, scm_cla
137139
scm_class.tag_in_scm(config=conf, context=context)
138140

139141
# Assert
140-
tag_info = scm_class.latest_tag_info("v*")
142+
tag_info = scm_class.latest_tag_info(conf.tag_name, parse_pattern=conf.parse)
141143
if scm_command == "git":
142144
assert tag_info.commit_sha is not None
143145
assert tag_info.distance_to_latest_tag == 0

0 commit comments

Comments
 (0)