diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 6084c8c15..9e2ae81b1 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -330,7 +330,11 @@ def __call__(self) -> None: changelog_cmd = Changelog( self.config, - {**changelog_args, "file_name": self.file_name}, # type: ignore[typeddict-item] + { + **changelog_args, # type: ignore[typeddict-item] + "file_name": self.file_name, + "allow_no_commit": bool(self.arguments["allow_no_commit"]), + }, ) changelog_cmd() changelog_file_name = changelog_cmd.file_name diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 5093ed9f2..8cef5d39f 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -43,6 +43,7 @@ class ChangelogArgs(TypedDict, total=False): extras: dict[str, Any] export_template: str during_version_bump: bool | None + allow_no_commit: bool | None # Internal-only when invoked by bump. class Changelog: @@ -124,6 +125,8 @@ def __init__(self, config: BaseConfig, arguments: ChangelogArgs) -> None: self.export_template_to = arguments.get("export_template") self.during_version_bump: bool = arguments.get("during_version_bump") or False + # Internal flag used when changelog is invoked from `cz bump --allow-no-commit`. + self.allow_no_commit: bool = bool(arguments.get("allow_no_commit")) def _find_incremental_rev(self, latest_version: str, tags: Iterable[GitTag]) -> str: """Try to find the 'start_rev'. @@ -255,8 +258,10 @@ def __call__(self) -> None: changelog_meta.unreleased_end = latest_full_release_info.index + 1 commits = git.get_commits(start=start_rev, end=end_rev, args="--topo-order") - if not commits and ( - self.current_version is None or not self.current_version.is_prerelease + if ( + not self.allow_no_commit + and not commits + and (self.current_version is None or not self.current_version.is_prerelease) ): raise NoCommitsFoundError("No commits found") diff --git a/docs/commands/bump.md b/docs/commands/bump.md index cbd6d5452..06510dfef 100644 --- a/docs/commands/bump.md +++ b/docs/commands/bump.md @@ -473,6 +473,11 @@ cz bump --allow-no-commit 2.0.0 cz bump --allow-no-commit 2.0.0 ``` +!!! note "Behavior with changelog updates" + When `update_changelog_on_bump = true` (or `--changelog` is used), `cz bump --allow-no-commit` also generates a changelog entry even if there are no commits in the selected range. + + This makes the new release visible in the changelog while still showing that no commit-based changes were included. + ### `--tag-format` `tag_format` and [version_scheme][version_scheme] are combined to make Git tag names from versions. diff --git a/docs/commands/changelog.md b/docs/commands/changelog.md index da40eb6fb..2c36c0429 100644 --- a/docs/commands/changelog.md +++ b/docs/commands/changelog.md @@ -2,6 +2,8 @@ Generates a changelog following the committing rules established. +When changelog generation is triggered by `cz bump --allow-no-commit` (with `--changelog` or `update_changelog_on_bump = true`), Commitizen still creates a release entry even when no commits are found in the selected revision range. + !!! tip To create the changelog automatically on bump, add the setting [update_changelog_on_bump](../config/bump.md#update_changelog_on_bump) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 94b40e94e..86acff466 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -1540,3 +1540,18 @@ def test_changelog_merge_preserves_header( out = changelog_path.read_text() file_regression.check(out, extension=".md") + + +@pytest.mark.freeze_time("2025-01-01") +def test_bump_allow_no_commit_issue( + tmp_commitizen_project_initial, + util: UtilFixture, +) -> None: + """Issue #1866: bump command called changelog command with allow_no_commit=True, but changelog command raised NoCommitsFoundError""" + tmp_commitizen_project_initial( + version="1.0.0", config_extra="update_changelog_on_bump = true\n" + ) + util.run_cli("bump", "--yes", "--allow-no-commit", "--prerelease", "beta") + util.run_cli( + "bump", "--allow-no-commit", "--prerelease", "rc" + ) # Should not fail when changelog generation runs with no new commits