From 3449f6dfb7378a82e630aa474b994ee91d9e7eaa Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Mon, 14 Sep 2026 05:56:01 +0800 Subject: [PATCH 1/4] fix(changelog): allow --no-incremental to override changelog_incremental config The "Bump version" workflow's release-notes step runs `cz changelog --dry-run "${NEW_VERSION}"`, passing the new version as a positional rev_range. Since pyproject.toml sets `changelog_incremental = true` (#2074), this combination now always raises "--incremental cannot be combined with a rev_range", failing every release. There was previously no way to override a config-enabled `changelog_incremental` back to false from the CLI, since `--incremental` was a plain store_true flag defaulting to False. - Change `--incremental` to use argparse.BooleanOptionalAction (default None), adding a `--no-incremental` flag. - CLI flag now takes precedence over the `changelog_incremental` config setting; falls back to config only when neither flag is passed. Note: `.github/workflows/bumpversion.yml` still needs to be updated to pass `--no-incremental` in its release-notes step, but that change requires the `workflow` OAuth scope and is left for a follow-up/maintainer to apply. `cz bump`'s internal changelog call already hardcodes incremental=True, so it is unaffected by this change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- commitizen/cli.py | 8 +++++--- commitizen/commands/changelog.py | 15 +++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 3ee03d99ce..8c261d5e95 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -413,11 +413,13 @@ def __call__( }, { "name": "--incremental", - "action": "store_true", - "default": False, + "action": argparse.BooleanOptionalAction, + "default": None, "help": ( "Generate changelog from the last created version, " - "useful if the changelog has been manually modified." + "useful if the changelog has been manually modified. " + "Use `--no-incremental` to override a `changelog_incremental` " + "setting enabled in the configuration." ), }, { diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 7dbc28ac54..be2ba9c367 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -32,7 +32,7 @@ class ChangelogArgs(TypedDict, total=False): current_version: str dry_run: bool file_name: str | None - incremental: bool + incremental: bool | None merge_prerelease: bool rev_range: str start_rev: str @@ -78,9 +78,16 @@ def __init__(self, config: BaseConfig, arguments: ChangelogArgs) -> None: self.changelog_format = get_changelog_format(self.config, self.file_name) - self.incremental = bool( - arguments.get("incremental") - or self.config.settings.get("changelog_incremental") + # `--incremental`/`--no-incremental` on the CLI always takes precedence over + # the `changelog_incremental` setting. When neither flag is passed, the + # argument is `None` and we fall back to the config value. This lets a + # one-off invocation (e.g. `cz changelog `) opt out of an + # incremental default enabled in the configuration. + incremental_arg = arguments.get("incremental") + self.incremental = ( + incremental_arg + if incremental_arg is not None + else bool(self.config.settings.get("changelog_incremental")) ) self.dry_run = bool(arguments.get("dry_run")) From 285e782114601ef0e858f9700f33621851141280 Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Mon, 14 Sep 2026 06:05:57 +0800 Subject: [PATCH 2/4] ci: pass --no-incremental to release changelog dry-run Complements the previous commit: now that the changelog command respects an explicit --no-incremental override, update the release workflow's one-off dry-run step to use it, fixing the actual pipeline failure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/bumpversion.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index aab3b0ab4a..0fc1bb129b 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -58,7 +58,7 @@ jobs: env: NEW_VERSION: ${{ steps.bump-version.outputs.new_version }} run: | - cz changelog --dry-run "${NEW_VERSION}" > .changelog.md + cz changelog --no-incremental --dry-run "${NEW_VERSION}" > .changelog.md - name: Release if: steps.bump-version.outputs.bumped == 'true' env: From 554d1282bae2f19418085ca6721146133d947a59 Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Mon, 14 Sep 2026 06:10:24 +0800 Subject: [PATCH 3/4] test(changelog): regenerate help snapshots for --no-incremental flag Update the CLI help golden files (all supported Python versions) and docs/commands/changelog.md to reflect the new --no-incremental option added in a previous commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/commands/changelog.md | 10 ++++++++++ ...iption_when_use_help_option_py_3_10_changelog_.txt | 11 ++++++++--- ...iption_when_use_help_option_py_3_11_changelog_.txt | 11 ++++++++--- ...iption_when_use_help_option_py_3_12_changelog_.txt | 11 ++++++++--- ...iption_when_use_help_option_py_3_13_changelog_.txt | 11 ++++++++--- ...iption_when_use_help_option_py_3_14_changelog_.txt | 11 ++++++++--- 6 files changed, 50 insertions(+), 15 deletions(-) diff --git a/docs/commands/changelog.md b/docs/commands/changelog.md index 8b7a7a4d48..8db83826c1 100644 --- a/docs/commands/changelog.md +++ b/docs/commands/changelog.md @@ -115,6 +115,16 @@ This flag can be set in the configuration file with the key `changelog_increment changelog_incremental = true ``` +Pass `--no-incremental` on the command line to disable incremental generation +for a single run, even when `changelog_incremental = true` is set in the +configuration. This is useful, for example, when generating a one-off +changelog for a specific `rev_range`, since `--incremental` cannot be combined +with a `rev_range`. + +```bash +cz changelog --no-incremental "v1.0.0..v1.1.0" +``` + ### `--start-rev` Start from a given git rev to generate the changelog. Commits before that rev will not be considered. This is especially useful for long-running projects adopting conventional commits, where old commit messages might fail to be parsed for changelog generation. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_changelog_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_changelog_.txt index 2d1135af74..7bea3466bb 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_changelog_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_changelog_.txt @@ -1,6 +1,7 @@ usage: cz changelog [-h] [--dry-run] [--file-name FILE_NAME] - [--unreleased-version UNRELEASED_VERSION] [--incremental] - [--start-rev START_REV] [--merge-prerelease] + [--unreleased-version UNRELEASED_VERSION] + [--incremental | --no-incremental] [--start-rev START_REV] + [--merge-prerelease] [--version-scheme {pep440,semver,semver2}] [--export-template EXPORT_TEMPLATE] [--template TEMPLATE] [--extra EXTRA] [--tag-format TAG_FORMAT] @@ -20,8 +21,12 @@ options: --unreleased-version UNRELEASED_VERSION Set the value for the new version (use the tag value), instead of using unreleased versions. - --incremental Generate changelog from the last created version, + --incremental, --no-incremental + Generate changelog from the last created version, useful if the changelog has been manually modified. + Use `--no-incremental` to override a + `changelog_incremental` setting enabled in the + configuration. --start-rev START_REV Start rev of the changelog. If not set, it will generate changelog from the beginning. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_changelog_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_changelog_.txt index 2d1135af74..7bea3466bb 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_changelog_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_changelog_.txt @@ -1,6 +1,7 @@ usage: cz changelog [-h] [--dry-run] [--file-name FILE_NAME] - [--unreleased-version UNRELEASED_VERSION] [--incremental] - [--start-rev START_REV] [--merge-prerelease] + [--unreleased-version UNRELEASED_VERSION] + [--incremental | --no-incremental] [--start-rev START_REV] + [--merge-prerelease] [--version-scheme {pep440,semver,semver2}] [--export-template EXPORT_TEMPLATE] [--template TEMPLATE] [--extra EXTRA] [--tag-format TAG_FORMAT] @@ -20,8 +21,12 @@ options: --unreleased-version UNRELEASED_VERSION Set the value for the new version (use the tag value), instead of using unreleased versions. - --incremental Generate changelog from the last created version, + --incremental, --no-incremental + Generate changelog from the last created version, useful if the changelog has been manually modified. + Use `--no-incremental` to override a + `changelog_incremental` setting enabled in the + configuration. --start-rev START_REV Start rev of the changelog. If not set, it will generate changelog from the beginning. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_changelog_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_changelog_.txt index 2d1135af74..7bea3466bb 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_changelog_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_changelog_.txt @@ -1,6 +1,7 @@ usage: cz changelog [-h] [--dry-run] [--file-name FILE_NAME] - [--unreleased-version UNRELEASED_VERSION] [--incremental] - [--start-rev START_REV] [--merge-prerelease] + [--unreleased-version UNRELEASED_VERSION] + [--incremental | --no-incremental] [--start-rev START_REV] + [--merge-prerelease] [--version-scheme {pep440,semver,semver2}] [--export-template EXPORT_TEMPLATE] [--template TEMPLATE] [--extra EXTRA] [--tag-format TAG_FORMAT] @@ -20,8 +21,12 @@ options: --unreleased-version UNRELEASED_VERSION Set the value for the new version (use the tag value), instead of using unreleased versions. - --incremental Generate changelog from the last created version, + --incremental, --no-incremental + Generate changelog from the last created version, useful if the changelog has been manually modified. + Use `--no-incremental` to override a + `changelog_incremental` setting enabled in the + configuration. --start-rev START_REV Start rev of the changelog. If not set, it will generate changelog from the beginning. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_changelog_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_changelog_.txt index 50ab468d64..85d31048aa 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_changelog_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_changelog_.txt @@ -1,6 +1,7 @@ usage: cz changelog [-h] [--dry-run] [--file-name FILE_NAME] - [--unreleased-version UNRELEASED_VERSION] [--incremental] - [--start-rev START_REV] [--merge-prerelease] + [--unreleased-version UNRELEASED_VERSION] + [--incremental | --no-incremental] [--start-rev START_REV] + [--merge-prerelease] [--version-scheme {pep440,semver,semver2}] [--export-template EXPORT_TEMPLATE] [--template TEMPLATE] [--extra EXTRA] [--tag-format TAG_FORMAT] @@ -20,8 +21,12 @@ options: --unreleased-version UNRELEASED_VERSION Set the value for the new version (use the tag value), instead of using unreleased versions. - --incremental Generate changelog from the last created version, + --incremental, --no-incremental + Generate changelog from the last created version, useful if the changelog has been manually modified. + Use `--no-incremental` to override a + `changelog_incremental` setting enabled in the + configuration. --start-rev START_REV Start rev of the changelog. If not set, it will generate changelog from the beginning. diff --git a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_changelog_.txt b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_changelog_.txt index 50ab468d64..85d31048aa 100644 --- a/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_changelog_.txt +++ b/tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_changelog_.txt @@ -1,6 +1,7 @@ usage: cz changelog [-h] [--dry-run] [--file-name FILE_NAME] - [--unreleased-version UNRELEASED_VERSION] [--incremental] - [--start-rev START_REV] [--merge-prerelease] + [--unreleased-version UNRELEASED_VERSION] + [--incremental | --no-incremental] [--start-rev START_REV] + [--merge-prerelease] [--version-scheme {pep440,semver,semver2}] [--export-template EXPORT_TEMPLATE] [--template TEMPLATE] [--extra EXTRA] [--tag-format TAG_FORMAT] @@ -20,8 +21,12 @@ options: --unreleased-version UNRELEASED_VERSION Set the value for the new version (use the tag value), instead of using unreleased versions. - --incremental Generate changelog from the last created version, + --incremental, --no-incremental + Generate changelog from the last created version, useful if the changelog has been manually modified. + Use `--no-incremental` to override a + `changelog_incremental` setting enabled in the + configuration. --start-rev START_REV Start rev of the changelog. If not set, it will generate changelog from the beginning. From 3b41e05197f1637111ce1eee3c37c35c0298853f Mon Sep 17 00:00:00 2001 From: Yu-Ting Hsiung Date: Mon, 14 Sep 2026 06:34:22 +0800 Subject: [PATCH 4/4] test(changelog): add --no-incremental regression test, address review feedback - Add test_changelog_no_incremental_overrides_config_with_revision covering --no-incremental combined with a rev_range when changelog_incremental=true is set in config. - Clarify the comment in Changelog.__init__ to explicitly reference the --no-incremental flag needed to opt out. - Regenerate the stale docs/images/cli_help/cz_changelog___help.svg screenshot to include the new --no-incremental option. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- commitizen/commands/changelog.py | 4 +- docs/images/cli_help/cz_changelog___help.svg | 214 ++++++++++--------- tests/commands/test_changelog_command.py | 26 +++ 3 files changed, 143 insertions(+), 101 deletions(-) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index be2ba9c367..a697923652 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -81,8 +81,8 @@ def __init__(self, config: BaseConfig, arguments: ChangelogArgs) -> None: # `--incremental`/`--no-incremental` on the CLI always takes precedence over # the `changelog_incremental` setting. When neither flag is passed, the # argument is `None` and we fall back to the config value. This lets a - # one-off invocation (e.g. `cz changelog `) opt out of an - # incremental default enabled in the configuration. + # one-off invocation (e.g. `cz changelog --no-incremental `) opt + # out of an incremental default enabled in the configuration. incremental_arg = arguments.get("incremental") self.incremental = ( incremental_arg diff --git a/docs/images/cli_help/cz_changelog___help.svg b/docs/images/cli_help/cz_changelog___help.svg index 00031d48f6..375878d37e 100644 --- a/docs/images/cli_help/cz_changelog___help.svg +++ b/docs/images/cli_help/cz_changelog___help.svg @@ -1,4 +1,4 @@ - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + - + - + - - $ cz changelog --help -usage: cz changelog [-h][--dry-run][--file-name FILE_NAME] -[--unreleased-version UNRELEASED_VERSION][--incremental] -[--start-rev START_REV][--merge-prerelease] -[--version-scheme {pep440,semver,semver2}] -[--export-template EXPORT_TEMPLATE][--template TEMPLATE] -[--extra EXTRA][--tag-format TAG_FORMAT] - - -Generate changelog (note that it will overwrite existing files) - -positional arguments: -  rev_range             Generate changelog for the given version (e.g., 1.5.3) -                        or version range (e.g., 1.5.3..1.7.9). - -options: -  -h, --help            show this help message and exit -  --dry-run             Show changelog to stdout. -  --file-name FILE_NAME -                        File name of changelog (default: 'CHANGELOG.md'). -  --unreleased-version UNRELEASED_VERSION -                        Set the value for the new version (use the tag value), -                        instead of using unreleased versions. -  --incremental         Generate changelog from the last created version, -                        useful if the changelog has been manually modified. -  --start-rev START_REV -                        Start rev of the changelog. If not set, it will -                        generate changelog from the beginning. -  --merge-prerelease    Collect all changes from prereleases into the next -                        non-prerelease. If not set, it will include -                        prereleases in the changelog. -  --version-scheme {pep440,semver,semver2} -                        Choose version scheme. -  --export-template EXPORT_TEMPLATE -                        Export the changelog template into this file instead -                        of rendering it. -  --template TEMPLATE, -t TEMPLATE -                        Changelog template file name (relative to the current -                        working directory). -  --extra EXTRA, -e EXTRA -                        Changelog extra variables (in the form 'key=value'). -  --tag-format TAG_FORMAT -                        The format of the tag, wrap around simple quotes. - + + $ cz changelog --help +usage: cz changelog [-h][--dry-run][--file-name FILE_NAME] +[--unreleased-version UNRELEASED_VERSION] +[--incremental | --no-incremental][--start-rev START_REV] +[--merge-prerelease] +[--version-scheme {pep440,semver,semver2}] +[--export-template EXPORT_TEMPLATE][--template TEMPLATE] +[--extra EXTRA][--tag-format TAG_FORMAT] + + +Generate changelog (note that it will overwrite existing files) + +positional arguments: +  rev_range             Generate changelog for the given version (e.g., 1.5.3) +                        or version range (e.g., 1.5.3..1.7.9). + +options: +  -h, --help            show this help message and exit +  --dry-run             Show changelog to stdout. +  --file-name FILE_NAME +                        File name of changelog (default: 'CHANGELOG.md'). +  --unreleased-version UNRELEASED_VERSION +                        Set the value for the new version (use the tag value), +                        instead of using unreleased versions. +  --incremental, --no-incremental +                        Generate changelog from the last created version, +                        useful if the changelog has been manually modified. +                        Use `--no-incremental` to override a +                        `changelog_incremental` setting enabled in the +                        configuration. +  --start-rev START_REV +                        Start rev of the changelog. If not set, it will +                        generate changelog from the beginning. +  --merge-prerelease    Collect all changes from prereleases into the next +                        non-prerelease. If not set, it will include +                        prereleases in the changelog. +  --version-scheme {pep440,semver,semver2} +                        Choose version scheme. +  --export-template EXPORT_TEMPLATE +                        Export the changelog template into this file instead +                        of rendering it. +  --template, -t TEMPLATE +                        Changelog template file name (relative to the current +                        working directory). +  --extra, -e EXTRA     Changelog extra variables (in the form 'key=value'). +  --tag-format TAG_FORMAT +                        The format of the tag, wrap around simple quotes. + diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 469f9e88e1..3af00d01c0 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -464,6 +464,32 @@ def test_changelog_incremental_with_revision(util: UtilFixture): util.run_cli("changelog", "--incremental", "0.2.0") +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changelog_no_incremental_overrides_config_with_revision( + config_path: Path, util: UtilFixture +): + """--no-incremental must override a config-enabled `changelog_incremental`. + + Regression test for a one-off `cz changelog ` invocation + (e.g. used to build release notes for a specific version) that previously + always raised `NotAllowed` once `changelog_incremental = true` was set, + with no CLI-side way to opt out. + """ + with config_path.open("a", encoding="utf-8") as f: + f.write("changelog_incremental = true\n") + + util.create_file_and_commit("feat: new file") + util.create_tag("0.2.0") + + # Config-enabled incremental mode still conflicts with a rev_range... + with pytest.raises(NotAllowed): + util.run_cli("changelog", "0.2.0") + + # ...unless explicitly overridden with --no-incremental. + with pytest.raises(DryRunExit): + util.run_cli("changelog", "--no-incremental", "--dry-run", "0.2.0") + + @pytest.mark.usefixtures("chdir") def test_changelog_in_non_git_project(util: UtilFixture): with pytest.raises(NotAGitProjectError):