Skip to content

feat(bump): add functionality to write the next version to stdout #1195

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
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ def __call__(
"help": "Add additional build-metadata to the version-number",
"default": None,
},
{
"name": ["--get-next"],
"action": "store_true",
"help": "Determine the next version and write to stdout",
"default": False,
},
],
},
{
Expand Down
31 changes: 27 additions & 4 deletions commitizen/commands/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
BumpTagFailedError,
DryRunExit,
ExpectedExit,
GetNextExit,
InvalidManualVersion,
NoCommitsFoundError,
NoneIncrementExit,
Expand Down Expand Up @@ -159,6 +160,7 @@ def __call__(self) -> None: # noqa: C901
manual_version = self.arguments["manual_version"]
build_metadata = self.arguments["build_metadata"]
increment_mode: str = self.arguments["increment_mode"]
get_next: bool = self.arguments["get_next"]

if manual_version:
if increment:
Expand Down Expand Up @@ -190,6 +192,9 @@ def __call__(self) -> None: # noqa: C901
"--prerelease-offset cannot be combined with MANUAL_VERSION"
)

if get_next:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not required in this PR, but I feel we could move these validations out as a separate function 🤔

raise NotAllowed("--get-next cannot be combined with MANUAL_VERSION")

if major_version_zero:
if not current_version.release[0] == 0:
raise NotAllowed(
Expand All @@ -202,6 +207,18 @@ def __call__(self) -> None: # noqa: C901
"--local-version cannot be combined with --build-metadata"
)

# If user specified changelog_to_stdout, they probably want the
# changelog to be generated as well, this is the most intuitive solution
self.changelog = self.changelog or bool(self.changelog_to_stdout)

if get_next:
if self.changelog:
raise NotAllowed(
"--changelog or --changelog-to-stdout is not allowed with --get-next"
)
# Setting dry_run to prevent any unwanted changes to the repo or files
self.dry_run = True

current_tag_version: str = bump.normalize_tag(
current_version,
tag_format=tag_format,
Expand All @@ -210,10 +227,6 @@ def __call__(self) -> None: # noqa: C901

is_initial = self.is_initial_tag(current_tag_version, is_yes)

# If user specified changelog_to_stdout, they probably want the
# changelog to be generated as well, this is the most intuitive solution
self.changelog = self.changelog or bool(self.changelog_to_stdout)

if manual_version:
try:
new_version = self.scheme(manual_version)
Expand Down Expand Up @@ -266,6 +279,16 @@ def __call__(self) -> None: # noqa: C901
current_version, new_version, bump_commit_message
)

if get_next:
if increment is None and new_tag_version == current_tag_version:
raise NoneIncrementExit(
"[NO_COMMITS_TO_BUMP]\n"
"The commits found are not eligible to be bumped"
)

out.write(str(new_version))
raise GetNextExit()

# Report found information
information = f"{message}\n" f"tag to create: {new_tag_version}\n"
if increment:
Expand Down
4 changes: 4 additions & 0 deletions commitizen/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ class DryRunExit(ExpectedExit):
pass


class GetNextExit(ExpectedExit):
pass


class NoneIncrementExit(CommitizenException):
exit_code = ExitCode.NO_INCREMENT

Expand Down
33 changes: 33 additions & 0 deletions docs/commands/bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,39 @@ You should normally not use this functionality, but if you decide to do, keep in
* Version `1.2.3+a`, and `1.2.3+b` are the same version! Tools should not use the string after `+` for version calculation. This is probably not a guarantee (example in helm) even tho it is in the spec.
* It might be problematic having the metadata in place when doing upgrades depending on what tool you use.

### `--get-next`

Provides a way to determine the next version and write it to stdout. This parameter is not compatible with `--changelog`
and `manual version`.

```bash
cz bump --get-next
```

Will output the next version, e.g. `1.2.3`. This can be useful for determining the next version based in CI for non
production environments/builds.

This behavior differs from the `--dry-run` flag. The `--dry-run` flag provides a more detailed output and can also show
the changes as they would appear in the changelog file.

The following output is the result of `cz bump --dry-run`:

```
bump: version 3.28.0 → 3.29.0
tag to create: v3.29.0
increment detected: MINOR
```

The following output is the result of `cz bump --get-next`:

```
3.29.0
```

The `--get-next` flag will raise a `NoneIncrementExit` if the found commits are not eligible for a version bump.

For information on how to suppress this exit, see [avoid raising errors](#avoid-raising-errors).

## Avoid raising errors

Some situations from commitizen raise an exit code different than 0.
Expand Down
61 changes: 61 additions & 0 deletions tests/commands/test_bump_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
DryRunExit,
ExitCode,
ExpectedExit,
GetNextExit,
InvalidManualVersion,
NoCommitsFoundError,
NoneIncrementExit,
Expand Down Expand Up @@ -1462,3 +1463,63 @@ def test_bump_command_shows_description_when_use_help_option(

out, _ = capsys.readouterr()
file_regression.check(out, extension=".txt")


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_get_next(mocker: MockFixture, capsys):
create_file_and_commit("feat: new file")

testargs = ["cz", "bump", "--yes", "--get-next"]
mocker.patch.object(sys, "argv", testargs)
with pytest.raises(GetNextExit):
cli.main()

out, _ = capsys.readouterr()
assert "0.2.0" in out

tag_exists = git.tag_exist("0.2.0")
assert tag_exists is False


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_get_next__changelog_is_not_allowed(mocker: MockFixture):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel we can combine these not_allowed test cases

create_file_and_commit("feat: new file")

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

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


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_get_next__changelog_to_stdout_is_not_allowed(mocker: MockFixture):
create_file_and_commit("feat: new file")

testargs = ["cz", "bump", "--yes", "--get-next", "--changelog-to-stdout"]
mocker.patch.object(sys, "argv", testargs)

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


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_get_next__manual_version_is_not_allowed(mocker: MockFixture):
create_file_and_commit("feat: new file")

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

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


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_bump_get_next__no_eligible_commits_raises(mocker: MockFixture):
create_file_and_commit("chore: new commit")

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

with pytest.raises(NoneIncrementExit):
cli.main()
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ usage: cz bump [-h] [--dry-run] [--files-only] [--local-version] [--changelog]
[--file-name FILE_NAME] [--prerelease-offset PRERELEASE_OFFSET]
[--version-scheme {pep440,semver,semver2}]
[--version-type {pep440,semver,semver2}]
[--build-metadata BUILD_METADATA]
[--build-metadata BUILD_METADATA] [--get-next]
[MANUAL_VERSION]

bump semantic version based on the git log
Expand Down Expand Up @@ -77,3 +77,4 @@ options:
Deprecated, use --version-scheme
--build-metadata BUILD_METADATA
Add additional build-metadata to the version-number
--get-next Determine the next version and write to stdout
Loading