Skip to content

Commit

Permalink
fix: properly bump versions between prereleases
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardocardoso committed Jul 27, 2023
1 parent d1c06eb commit c68a231
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 7 deletions.
52 changes: 49 additions & 3 deletions commitizen/commands/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
NoVersionSpecifiedError,
)
from commitizen.providers import get_provider
from commitizen.version_schemes import get_version_scheme, InvalidVersion
from commitizen.version_schemes import (
get_version_scheme,
InvalidVersion,
VersionProtocol,
)

logger = getLogger("commitizen")

Expand Down Expand Up @@ -215,15 +219,27 @@ def __call__(self): # noqa: C901

# Increment is removed when current and next version
# are expected to be prereleases.
if prerelease and current_version.is_prerelease:
increment = None
force_bump = False
if current_version.is_prerelease:
last_final = self.find_previous_final_version(current_version)
if last_final is not None:
commits = git.get_commits(last_final)
increment = self.find_increment(commits)
semver = last_final.increment_base(
increment=increment, force_bump=True
)
if semver != current_version.base_version:
force_bump = True
elif prerelease:
increment = None

new_version = current_version.bump(
increment,
prerelease=prerelease,
prerelease_offset=prerelease_offset,
devrelease=devrelease,
is_local_version=is_local_version,
force_bump=force_bump,
)

new_tag_version = bump.normalize_tag(
Expand Down Expand Up @@ -375,3 +391,33 @@ def _get_commit_args(self):
if self.no_verify:
commit_args.append("--no-verify")
return " ".join(commit_args)

def find_previous_final_version(
self, current_version: VersionProtocol
) -> VersionProtocol | None:
tag_format: str = self.bump_settings["tag_format"]
current = bump.normalize_tag(
current_version,
tag_format=tag_format,
scheme=self.scheme,
)

final_versions = []
for tag in git.get_tag_names():
assert tag
try:
version = self.scheme(tag)
if not version.is_prerelease or tag == current:
final_versions.append(version)
except InvalidVersion:
continue

Check warning on line 413 in commitizen/commands/bump.py

View check run for this annotation

Codecov / codecov/patch

commitizen/commands/bump.py#L412-L413

Added lines #L412 - L413 were not covered by tests

if not final_versions:
return None

final_versions = sorted(final_versions) # type: ignore [type-var]
current_index = final_versions.index(current_version)
previous_index = current_index - 1
if previous_index < 0:
return None
return final_versions[previous_index]
24 changes: 20 additions & 4 deletions commitizen/version_schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def bump(
prerelease_offset: int = 0,
devrelease: int | None = None,
is_local_version: bool = False,
force_bump: bool = False,
) -> Self:
"""
Based on the given increment, generate the next bumped version according to the version scheme
Expand Down Expand Up @@ -171,7 +172,9 @@ def generate_devrelease(self, devrelease: int | None) -> str:

return f"dev{devrelease}"

def increment_base(self, increment: str | None = None) -> str:
def increment_base(
self, increment: str | None = None, force_bump: bool = False
) -> str:
prev_release = list(self.release)
increments = [MAJOR, MINOR, PATCH]
base = dict(zip_longest(increments, prev_release, fillvalue=0))
Expand All @@ -180,7 +183,7 @@ def increment_base(self, increment: str | None = None) -> str:
# must remove its prerelease tag,
# so it doesn't matter the increment.
# Example: 1.0.0a0 with PATCH/MINOR -> 1.0.0
if not self.is_prerelease:
if not self.is_prerelease or force_bump:
if increment == MAJOR:
base[MAJOR] += 1
base[MINOR] = 0
Expand All @@ -200,6 +203,7 @@ def bump(
prerelease_offset: int = 0,
devrelease: int | None = None,
is_local_version: bool = False,
force_bump: bool = False,
) -> Self:
"""Based on the given increment a proper semver will be generated.
Expand All @@ -217,9 +221,21 @@ def bump(
local_version = self.scheme(self.local).bump(increment)
return self.scheme(f"{self.public}+{local_version}") # type: ignore
else:
base = self.increment_base(increment)
base = self.increment_base(increment, force_bump)
dev_version = self.generate_devrelease(devrelease)
pre_version = self.generate_prerelease(prerelease, offset=prerelease_offset)
release = list(self.release)
if len(release) < 3:
release += [0] * (3 - len(release))
current_semver = ".".join(str(part) for part in release)
if base == current_semver:
pre_version = self.generate_prerelease(
prerelease, offset=prerelease_offset
)
else:
base_version = cast(BaseVersion, self.scheme(base))
pre_version = base_version.generate_prerelease(
prerelease, offset=prerelease_offset
)
# TODO: post version
return self.scheme(f"{base}{pre_version}{dev_version}") # type: ignore

Expand Down
36 changes: 36 additions & 0 deletions tests/commands/test_bump_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,42 @@ def test_bump_command_prelease(mocker: MockFixture):
assert tag_exists is True


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_command_prelease_increment(mocker: MockFixture):
# FINAL RELEASE
create_file_and_commit("fix: location")

testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()
assert git.tag_exist("0.1.1")

# PRERELEASE
create_file_and_commit("fix: location")

testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

assert git.tag_exist("0.1.2a0")

create_file_and_commit("feat: location")

testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

assert git.tag_exist("0.2.0a0")

create_file_and_commit("feat!: breaking")

testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

assert git.tag_exist("1.0.0a0")


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_on_git_with_hooks_no_verify_disabled(mocker: MockFixture):
"""Bump commit without --no-verify"""
Expand Down

0 comments on commit c68a231

Please sign in to comment.