Skip to content
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
Copy link
Contributor

Choose a reason for hiding this comment

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

Is self.dry_run used anywhere?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

dry_run and self.dry_run are different objects here.

I have tested in my local environment. The assignment is redundant and the if dry_run: path is never hit if get_next is True because GetNextExit() is raised earlier.


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