Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Bump: support manual version #591

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@
"default": False,
"help": "retry commit if it fails the 1st time",
},
{
"name": "manual_version",
"type": str,
"nargs": "?",
"help": "bump to the given version (e.g: 1.5.3)",
"metavar": "MANUAL_VERSION",
},
],
},
{
Expand Down
95 changes: 60 additions & 35 deletions commitizen/commands/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import List, Optional

import questionary
from packaging.version import Version
from packaging.version import InvalidVersion, Version

from commitizen import bump, cmd, factory, git, out
from commitizen.commands.changelog import Changelog
Expand All @@ -12,10 +12,12 @@
BumpTagFailedError,
DryRunExit,
ExpectedExit,
InvalidManualVersion,
NoCommitsFoundError,
NoneIncrementExit,
NoPatternMapError,
NotAGitProjectError,
NotAllowed,
NoVersionSpecifiedError,
)

Expand Down Expand Up @@ -102,10 +104,26 @@ def __call__(self): # noqa: C901
dry_run: bool = self.arguments["dry_run"]
is_yes: bool = self.arguments["yes"]
increment: Optional[str] = self.arguments["increment"]
prerelease: str = self.arguments["prerelease"]
prerelease: Optional[str] = self.arguments["prerelease"]
devrelease: Optional[int] = self.arguments["devrelease"]
is_files_only: Optional[bool] = self.arguments["files_only"]
is_local_version: Optional[bool] = self.arguments["local_version"]
manual_version = self.arguments["manual_version"]

if manual_version:
if increment:
raise NotAllowed("--increment cannot be combined with MANUAL_VERSION")

if prerelease:
raise NotAllowed("--prerelease cannot be combined with MANUAL_VERSION")

if devrelease is not None:
raise NotAllowed("--devrelease cannot be combined with MANUAL_VERSION")

if is_local_version:
raise NotAllowed(
"--local-version cannot be combined with MANUAL_VERSION"
)

current_tag_version: str = bump.normalize_tag(
current_version, tag_format=tag_format
Expand All @@ -127,46 +145,53 @@ def __call__(self): # noqa: C901
if not commits and not current_version_instance.is_prerelease:
raise NoCommitsFoundError("[NO_COMMITS_FOUND]\n" "No new commits found.")

if increment is None:
increment = self.find_increment(commits)

# It may happen that there are commits, but they are not elegible
# for an increment, this generates a problem when using prerelease (#281)
if (
prerelease
and increment is None
and not current_version_instance.is_prerelease
):
raise NoCommitsFoundError(
"[NO_COMMITS_FOUND]\n"
"No commits found to generate a pre-release.\n"
"To avoid this error, manually specify the type of increment with `--increment`"
)

# Increment is removed when current and next version
# are expected to be prereleases.
if prerelease and current_version_instance.is_prerelease:
increment = None
if manual_version:
try:
new_version = Version(manual_version)
except InvalidVersion as exc:
raise InvalidManualVersion(
"[INVALID_MANUAL_VERSION]\n"
f"Invalid manual version: '{manual_version}'"
) from exc
else:
if increment is None:
increment = self.find_increment(commits)

# It may happen that there are commits, but they are not eligible
# for an increment, this generates a problem when using prerelease (#281)
if (
prerelease
and increment is None
and not current_version_instance.is_prerelease
):
raise NoCommitsFoundError(
"[NO_COMMITS_FOUND]\n"
"No commits found to generate a pre-release.\n"
"To avoid this error, manually specify the type of increment with `--increment`"
)

new_version = bump.generate_version(
current_version,
increment,
prerelease=prerelease,
devrelease=devrelease,
is_local_version=is_local_version,
)
# Increment is removed when current and next version
# are expected to be prereleases.
if prerelease and current_version_instance.is_prerelease:
increment = None

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

new_tag_version = bump.normalize_tag(new_version, tag_format=tag_format)
message = bump.create_commit_message(
current_version, new_version, bump_commit_message
)

# Report found information
information = (
f"{message}\n"
f"tag to create: {new_tag_version}\n"
f"increment detected: {increment}\n"
)
information = f"{message}\n" f"tag to create: {new_tag_version}\n"
if increment:
information += f"increment detected: {increment}\n"

if self.changelog_to_stdout:
# When the changelog goes to stdout, we want to send
Expand All @@ -179,7 +204,7 @@ def __call__(self): # noqa: C901
if increment is None and new_tag_version == current_tag_version:
raise NoneIncrementExit(
"[NO_COMMITS_TO_BUMP]\n"
"The commits found are not elegible to be bumped"
"The commits found are not eligible to be bumped"
)

if self.changelog:
Expand Down
5 changes: 5 additions & 0 deletions commitizen/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ExitCode(enum.IntEnum):
NO_INCREMENT = 21
UNRECOGNIZED_CHARACTERSET_ENCODING = 22
GIT_COMMAND_ERROR = 23
INVALID_MANUAL_VERSION = 24


class CommitizenException(Exception):
Expand Down Expand Up @@ -158,3 +159,7 @@ class CharacterSetDecodeError(CommitizenException):

class GitCommandError(CommitizenException):
exit_code = ExitCode.GIT_COMMAND_ERROR


class InvalidManualVersion(CommitizenException):
exit_code = ExitCode.INVALID_MANUAL_VERSION
14 changes: 9 additions & 5 deletions docs/bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,13 @@ Some examples:
$ cz bump --help
usage: cz bump [-h] [--dry-run] [--files-only] [--local-version] [--changelog]
[--no-verify] [--yes] [--tag-format TAG_FORMAT]
[--bump-message BUMP_MESSAGE] [--increment {MAJOR,MINOR,PATCH}]
[--prerelease {alpha,beta,rc}] [--devrelease {DEV}]
[--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}]
[--devrelease DEVRELEASE] [--increment {MAJOR,MINOR,PATCH}]
[--check-consistency] [--annotated-tag] [--gpg-sign]
[--changelog-to-stdout] [--retry]
[--changelog-to-stdout] [--retry] [MANUAL_VERSION]

positional arguments:
MANUAL_VERSION bump to the given version (e.g: 1.5.3)

options:
-h, --help show this help message and exit
Expand All @@ -78,14 +81,15 @@ options:
when working with CI
--prerelease {alpha,beta,rc}, -pr {alpha,beta,rc}
choose type of prerelease
--devrelease {DEV} specify dev release
--devrelease DEVRELEASE, -d DEVRELEASE
specify non-negative integer for dev. release
--increment {MAJOR,MINOR,PATCH}
manually specify the desired increment
--check-consistency, -cc
check consistency among versions defined in commitizen
configuration and version_files
--gpg-sign, -s create a signed tag instead of lightweight one or annotated tag
--annotated-tag, -at create annotated tag instead of lightweight one
--gpg-sign, -s sign tag instead of lightweight one
--changelog-to-stdout
Output changelog to the stdout
--retry retry commit if it fails the 1st time
Expand Down
66 changes: 66 additions & 0 deletions tests/commands/test_bump_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
DryRunExit,
ExitCode,
ExpectedExit,
InvalidManualVersion,
NoCommitsFoundError,
NoneIncrementExit,
NoPatternMapError,
NotAGitProjectError,
NotAllowed,
NoVersionSpecifiedError,
)
from tests.utils import create_file_and_commit
Expand Down Expand Up @@ -614,3 +616,67 @@ def test_bump_changelog_command_commits_untracked_changelog_and_version_files(
commit_file_names = git.get_filenames_in_commit()
assert "CHANGELOG.md" in commit_file_names
assert version_filepath in commit_file_names


@pytest.mark.parametrize(
"testargs",
[
["cz", "bump", "--local-version", "1.2.3"],
["cz", "bump", "--prerelease", "rc", "1.2.3"],
["cz", "bump", "--devrelease", "0", "1.2.3"],
["cz", "bump", "--devrelease", "1", "1.2.3"],
["cz", "bump", "--increment", "PATCH", "1.2.3"],
],
)
def test_bump_invalid_manual_args_raises_exception(mocker, testargs):
mocker.patch.object(sys, "argv", testargs)

with pytest.raises(NotAllowed):
cli.main()


@pytest.mark.usefixtures("tmp_commitizen_project")
@pytest.mark.parametrize(
"manual_version",
[
"noversion",
"1.2..3",
],
)
def test_bump_invalid_manual_version_raises_exception(mocker, manual_version):
create_file_and_commit("feat: new file")

testargs = ["cz", "bump", "--yes", manual_version]
mocker.patch.object(sys, "argv", testargs)

with pytest.raises(InvalidManualVersion) as excinfo:
cli.main()

expected_error_message = (
"[INVALID_MANUAL_VERSION]\n" f"Invalid manual version: '{manual_version}'"
)
assert expected_error_message in str(excinfo.value)


@pytest.mark.usefixtures("tmp_commitizen_project")
@pytest.mark.parametrize(
"manual_version",
[
"0.0.1",
"0.1.0rc2",
"0.1.0.dev2",
"0.1.0+1.0.0",
"0.1.0rc2.dev2+1.0.0",
"0.1.1",
"0.2.0",
"1.0.0",
],
)
def test_bump_manual_version(mocker, manual_version):
create_file_and_commit("feat: new file")

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