Skip to content

feat: add --allow-no-commit option #723

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
Feb 7, 2025
Merged
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
6 changes: 6 additions & 0 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
@@ -371,6 +371,12 @@ def __call__(
"help": "Determine the next version and write to stdout",
"default": False,
},
{
"name": ["--allow-no-commit"],
"default": False,
"help": "bump version without eligible commits",
"action": "store_true",
},
],
},
{
11 changes: 10 additions & 1 deletion commitizen/commands/bump.py
Original file line number Diff line number Diff line change
@@ -160,6 +160,7 @@ def __call__(self) -> None: # noqa: C901
build_metadata = self.arguments["build_metadata"]
increment_mode: str = self.arguments["increment_mode"]
get_next: bool = self.arguments["get_next"]
allow_no_commit: bool | None = self.arguments["allow_no_commit"]

if manual_version:
if increment:
@@ -250,7 +251,11 @@ def __call__(self) -> None: # noqa: C901

# No commits, there is no need to create an empty tag.
# Unless we previously had a prerelease.
if not commits and not current_version.is_prerelease:
if (
not commits
and not current_version.is_prerelease
and not allow_no_commit
):
raise NoCommitsFoundError(
"[NO_COMMITS_FOUND]\nNo new commits found."
)
@@ -266,6 +271,10 @@ def __call__(self) -> None: # noqa: C901
"To avoid this error, manually specify the type of increment with `--increment`"
)

# we create an empty PATCH increment for empty tag
if increment is None and allow_no_commit:
increment = "PATCH"

new_version = current_version.bump(
increment,
prerelease=prerelease,
36 changes: 24 additions & 12 deletions docs/commands/bump.md
Original file line number Diff line number Diff line change
@@ -52,7 +52,6 @@ Some examples of pep440:

![cz bump --help](../images/cli_help/cz_bump___help.svg)


### `--files-only`

Bumps the version in the files defined in `version_files` without creating a commit and tag on the git repository,
@@ -178,6 +177,7 @@ If `--local-version` is used, it will bump only the local version `0.1.0` and ke
If `--annotated-tag` is used, commitizen will create annotated tags. Also available via configuration, in `pyproject.toml` or `.cz.toml`.

### `--annotated-tag-message`

If `--annotated-tag-message` is used, commitizen will create annotated tags with the given message.

### `--changelog-to-stdout`
@@ -276,14 +276,14 @@ cz bump --build-metadata yourmetadata

Will create a version like `1.1.2+yourmetadata`.
This can be useful for multiple things
* Git hash in version
* Labeling the version with additional metadata.
- Git hash in version
- Labeling the version with additional metadata.

Note that Commitizen ignores everything after `+` when it bumps the version. It is therefore safe to write different build-metadata between versions.

You should normally not use this functionality, but if you decide to do, keep in mind that
* 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.
- 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`

@@ -318,6 +318,18 @@ The `--get-next` flag will raise a `NoneIncrementExit` if the found commits are

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

### `--allow-no-commit`

Allow the project version to be bumped even when there's no eligible version. This is most useful when used with `--increment {MAJOR,MINOR,PATCH}` or `[MANUL_VERSION]`

```sh
# bump a minor version even when there's only bug fixes, documentation changes or even no commits
cz bump --incremental MINOR --allow-no-commit

# bump version to 2.0.0 even when there's no breaking changes changes or even no commits
cz bump --allow-no-commit 2.0.0
```

## Avoid raising errors

Some situations from commitizen raise an exit code different than 0.
@@ -389,13 +401,13 @@ cz -nr 21 bump

These are used in:

* `cz bump`: Find previous release tag (exact match) and generate new tag.
* Find previous release tags in `cz changelog`.
* If `--incremental`: Using latest version found in the changelog, scan existing Git tags with 89\% similarity match.
* `--rev-range` is converted to Git tag names with `tag_format` before searching Git history.
* If the `scm` `version_provider` is used, it uses different regexes to find the previous version tags:
* If `tag_format` is set to `$version` (default): `VersionProtocol.parser` (allows `v` prefix)
* If `tag_format` is set: Custom regex similar to SemVer (not as lenient as PEP440 e.g. on dev-releases)
- `cz bump`: Find previous release tag (exact match) and generate new tag.
- Find previous release tags in `cz changelog`.
- If `--incremental`: Using latest version found in the changelog, scan existing Git tags with 89\% similarity match.
- `--rev-range` is converted to Git tag names with `tag_format` before searching Git history.
- If the `scm` `version_provider` is used, it uses different regexes to find the previous version tags:
- If `tag_format` is set to `$version` (default): `VersionProtocol.parser` (allows `v` prefix)
- If `tag_format` is set: Custom regex similar to SemVer (not as lenient as PEP440 e.g. on dev-releases)

Commitizen supports 2 types of formats, a simple and a more complex.

162 changes: 81 additions & 81 deletions docs/images/cli_help/cz___help.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
358 changes: 185 additions & 173 deletions docs/images/cli_help/cz_bump___help.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
190 changes: 97 additions & 93 deletions docs/images/cli_help/cz_changelog___help.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
134 changes: 69 additions & 65 deletions docs/images/cli_help/cz_check___help.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 55 additions & 55 deletions docs/images/cli_help/cz_commit___help.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 101 additions & 0 deletions tests/commands/test_bump_command.py
Original file line number Diff line number Diff line change
@@ -1543,3 +1543,104 @@ def test_bump_get_next__no_eligible_commits_raises(mocker: MockFixture):

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


def test_bump_allow_no_commit_with_no_commit(mocker, tmp_commitizen_project, capsys):
with tmp_commitizen_project.as_cwd():
# Create the first commit and bump to 1.0.0
create_file_and_commit("feat(user)!: new file")
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# Verify NoCommitsFoundError should be raised
# when there's no new commit and "--allow-no-commit" is not set
with pytest.raises(NoCommitsFoundError):
testargs = ["cz", "bump"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# bump to 1.0.1 with new commit when "--allow-no-commit" is set
testargs = ["cz", "bump", "--allow-no-commit"]
mocker.patch.object(sys, "argv", testargs)
cli.main()
out, _ = capsys.readouterr()
assert "bump: version 1.0.0 → 1.0.1" in out


def test_bump_allow_no_commit_with_no_eligible_commit(
mocker, tmp_commitizen_project, capsys
):
with tmp_commitizen_project.as_cwd():
# Create the first commit and bump to 1.0.0
create_file_and_commit("feat(user)!: new file")
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# Create a commit that is ineligible to bump
create_file_and_commit("docs(bump): add description for allow no commit")

# Verify NoneIncrementExit should be raised
# when there's no eligible bumping commit and "--allow-no-commit" is not set
with pytest.raises(NoneIncrementExit):
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# bump to 1.0.1 with ineligible commit when "--allow-no-commit" is set
testargs = ["cz", "bump", "--allow-no-commit"]
mocker.patch.object(sys, "argv", testargs)
cli.main()
out, _ = capsys.readouterr()
assert "bump: version 1.0.0 → 1.0.1" in out


def test_bump_allow_no_commit_with_increment(mocker, tmp_commitizen_project, capsys):
with tmp_commitizen_project.as_cwd():
# # Create the first commit and bump to 1.0.0
create_file_and_commit("feat(user)!: new file")
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# Verify NoCommitsFoundError should be raised
# when there's no new commit and "--allow-no-commit" is not set
with pytest.raises(NoCommitsFoundError):
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# bump to 1.1.0 with no new commit when "--allow-no-commit" is set
# and increment is specified
testargs = ["cz", "bump", "--yes", "--allow-no-commit", "--increment", "MINOR"]
mocker.patch.object(sys, "argv", testargs)
cli.main()
out, _ = capsys.readouterr()
assert "bump: version 1.0.0 → 1.1.0" in out


def test_bump_allow_no_commit_with_manual_version(
mocker, tmp_commitizen_project, capsys
):
with tmp_commitizen_project.as_cwd():
# # Create the first commit and bump to 1.0.0
create_file_and_commit("feat(user)!: new file")
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# Verify NoCommitsFoundError should be raised
# when there's no new commit and "--allow-no-commit" is not set
with pytest.raises(NoCommitsFoundError):
testargs = ["cz", "bump", "--yes"]
mocker.patch.object(sys, "argv", testargs)
cli.main()

# bump to 1.1.0 with no new commit when "--allow-no-commit" is set
# and increment is specified
testargs = ["cz", "bump", "--yes", "--allow-no-commit", "2.0.0"]
mocker.patch.object(sys, "argv", testargs)
cli.main()
out, _ = capsys.readouterr()
assert "bump: version 1.0.0 → 2.0.0" in out
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ usage: cz bump [-h] [--dry-run] [--files-only] [--local-version] [--changelog]
[--version-scheme {pep440,semver,semver2}]
[--version-type {pep440,semver,semver2}]
[--build-metadata BUILD_METADATA] [--get-next]
[--allow-no-commit]
[MANUAL_VERSION]

bump semantic version based on the git log
@@ -77,3 +78,4 @@ options:
--build-metadata BUILD_METADATA
Add additional build-metadata to the version-number
--get-next Determine the next version and write to stdout
--allow-no-commit bump version without eligible commits