Skip to content

feat: add changelog_skip_prereleases setting to omit prerelease entries from changelog#1985

Closed
bearomorphism wants to merge 2 commits intocommitizen-tools:masterfrom
bearomorphism:fix/1218-changelog-skip-prereleases
Closed

feat: add changelog_skip_prereleases setting to omit prerelease entries from changelog#1985
bearomorphism wants to merge 2 commits intocommitizen-tools:masterfrom
bearomorphism:fix/1218-changelog-skip-prereleases

Conversation

@bearomorphism
Copy link
Copy Markdown
Collaborator

Description

Adds a new changelog_skip_prereleases configuration setting (default alse). When enabled, all prerelease release entries (tags whose version parses as a prerelease -
c, �lpha, �eta, dev, etc.) are omitted from the generated changelog entirely.

Closes #1218

Why

Currently, users who ship prereleases see cluttered changelogs like:

`

0.1.0-b0 (2024-08-20)

0.1.0-a0 (2024-08-20)

Feat

  • add onboarding modal

0.1.0 (2024-08-20)

`

The only existing option (--merge-prerelease) collapses prereleases into the next stable entry. There is no way to drop them silently. This PR adds that opt-in.

What changed

File Change
commitizen/defaults.py Added changelog_skip_prereleases: bool to Settings TypedDict and DEFAULT_SETTINGS (default alse)
commitizen/tags.py Added skip_prereleases: bool field to TagRules; updated include_in_changelog so that prerelease tags return False when the flag is set; updated rom_settings factory
commitizen/commands/changelog.py Passes skip_prereleases from config when constructing TagRules
ests/test_conf.py Added changelog_skip_prereleases to both expected-settings literals (avoids CI failure)
ests/test_changelog.py Two new unit tests for generate_tree_from_commits
ests/commands/test_changelog_command.py Two new end-to-end tests via cz changelog --dry-run
docs/commands/changelog.md New section next to --merge-prerelease

How it works

TagRules.include_in_changelog is the single gate that decides whether a tag produces a release block in the changelog tree. When skip_prereleases=True the method returns False for any tag whose parsed version satisfies �ersion.is_prerelease, before the merge-prerelease check runs.

Backward compatibility

  • Default is alse; no existing behaviour changes.
  • When both changelog_skip_prereleases = true and changelog_merge_prerelease = true are set, skip wins (documented in the docs and asserted in a test).

Checklist

Was generative AI tooling used to co-author this PR?

  • Yes (please specify the tool below)

Generated-by: Claude following the guidelines

Code Changes

  • Add test cases to all the changes you introduce
  • Run linters and tests locally
  • Manually test the changes
  • Update the documentation for the changes

Documentation Changes

  • Added changelog_skip_prereleases section in docs/commands/changelog.md next to --merge-prerelease

Expected Behavior

Scenario Before After
changelog_skip_prereleases = false (default) Prereleases appear in changelog Same - no change
changelog_skip_prereleases = true N/A Prerelease entries (
c, �lpha, �eta, dev) omitted
Both skip and merge set to rue merge wins skip wins (prereleases dropped, not collapsed)

Steps to Test This Pull Request

`�ash

Clone and set up

git clone https://github.com/bearomorphism/commitizen && cd commitizen
git checkout fix/1218-changelog-skip-prereleases
uv sync --frozen --group base --group test --group linters

Run targeted tests

uv run pytest tests/test_changelog.py::test_generate_tree_from_commits_skip_prereleases
uv run pytest tests/test_changelog.py::test_skip_prereleases_wins_over_merge_prereleases
uv run pytest tests/commands/test_changelog_command.py::test_changelog_config_flag_skip_prereleases
uv run pytest tests/commands/test_changelog_command.py::test_changelog_config_skip_prereleases_wins_over_merge_prerelease
`

Additional Context

Related to #1965 (merge-prerelease) which was the original implementation of prerelease handling in changelogs.

bearomorphism and others added 2 commits May 9, 2026 22:20
Users can now mark a cz_customize input question as required by setting
required = true in their config. The loader converts this into a questionary
validate= callable that rejects empty/whitespace-only answers with the
message 'This answer is required.' The required key is stripped before the
question dict reaches questionary, so questionary never sees the unknown key.

Closes commitizen-tools#1231

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When changelog_skip_prereleases = true is set, prerelease tags (rc,
alpha, beta, dev) are omitted entirely from the generated changelog.
Both cz changelog and cz bump --changelog honour the setting.

When both changelog_skip_prereleases and changelog_merge_prerelease
are set, skip takes precedence and prerelease entries are dropped.

Closes commitizen-tools#1218

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 9, 2026

Codecov Report

❌ Patch coverage is 93.10345% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.18%. Comparing base (4b93a50) to head (50d8156).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
commitizen/question.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1985      +/-   ##
==========================================
- Coverage   98.23%   98.18%   -0.06%     
==========================================
  Files          61       61              
  Lines        2779     2804      +25     
==========================================
+ Hits         2730     2753      +23     
- Misses         49       51       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new configuration option to omit prerelease tags from generated changelogs, and also extends the customize question system with a required field while refining changelog file path resolution behavior.

Changes:

  • Add changelog_skip_prereleases setting and plumb it through TagRules and cz changelog.
  • Add required = true support for type = "input" customize questions via a generated validate callback.
  • Adjust changelog output file path handling so CLI --file-name stays CWD-relative while config changelog_file is anchored to the config directory.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
commitizen/defaults.py Add changelog_skip_prereleases to settings + defaults.
commitizen/tags.py Add skip_prereleases to TagRules and filter prerelease tags.
commitizen/commands/changelog.py Wire skip_prereleases and change file-name path resolution logic.
commitizen/question.py Extend InputQuestion with validate and required.
commitizen/cz/customize/customize.py Implement required by injecting a validator and stripping the key.
tests/test_conf.py Update expected settings dictionaries with the new key.
tests/test_changelog.py Add unit tests for skip-prereleases + refactor file-name resolution test.
tests/commands/test_changelog_command.py Add E2E tests for skip-prereleases config behavior.
tests/test_cz_customize.py Add unit tests for required questions behavior.
docs/commands/changelog.md Document changelog_skip_prereleases and clarify path resolution.
docs/customization/config_file.md Document required for input questions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +65 to +83
file_name_from_args: str | None = arguments.get("file_name") or None
file_name_from_config: str | None = self.config.settings.get("changelog_file")
changelog_file_name = file_name_from_args or file_name_from_config
if not isinstance(changelog_file_name, str):
raise NotAllowed(
"Changelog file name is broken.\n"
"Check the flag `--file-name` in the terminal "
f"or the setting `changelog_file` in {self.config.path}"
)
self.file_name = (
Path(self.config.path.parent, changelog_file_name).as_posix()
if self.config.path is not None
else changelog_file_name
)
if file_name_from_args:
# Explicit CLI argument — keep relative to cwd (or use as-is if absolute).
self.file_name = file_name_from_args
elif self.config.path is not None:
# From configuration — anchor to the config file's directory.
self.file_name = Path(
self.config.path.parent, changelog_file_name
).as_posix()
else:
self.file_name = changelog_file_name
Comment on lines 121 to 132
self.tag_rules = TagRules(
scheme=self.scheme,
tag_format=arguments.get("tag_format")
or self.config.settings["tag_format"],
legacy_tag_formats=self.config.settings["legacy_tag_formats"],
ignored_tag_formats=self.config.settings["ignored_tag_formats"],
merge_prereleases=arguments.get("merge_prerelease")
or self.config.settings["changelog_merge_prerelease"],
skip_prereleases=bool(
self.config.settings.get("changelog_skip_prereleases")
),
)
Comment thread commitizen/tags.py
Comment on lines 164 to +176
def include_in_changelog(self, tag: GitTag) -> bool:
"""Check if a tag should be included in the changelog"""
try:
version = self.extract_version(tag)
except InvalidVersion:
return False
return not (self.merge_prereleases and version.is_prerelease)
if version.is_prerelease:
# skip_prereleases wins over merge_prereleases when both are set
if self.skip_prereleases:
return False
if self.merge_prereleases:
return False
return True
Comment thread tests/test_changelog.py
assert "v1.2.0" in versions
assert "v1.0.0" in versions


assert "more stuff" in out


@pytest.mark.usefixtures("tmp_commitizen_project")
Comment on lines +64 to +68
for raw in raw_questions:
q: dict[str, Any] = dict(raw)
if q.get("type") == "input" and q.pop("required", False):
q["validate"] = _required_validator
result.append(q) # type: ignore[arg-type]
@bearomorphism
Copy link
Copy Markdown
Collaborator Author

Closing this PR per maintainer-triage policy: feature-request issues should sit with the maintainers for design / scope review before any implementation lands. The issue's type: feature (or implicit equivalent) label means it's not on a "ready-to-implement" track yet.

The implementation itself is preserved on the branch (fix/1218-changelog-skip-prereleases) — if a maintainer decides this is the direction they want, the PR can be re-opened in one click, or the work can serve as a starting point for a maintainer-led design.

This PR is being closed so that #1218 reverts to "awaiting maintainer triage / decision" rather than "PR pending review", which is the correct state for a feature request.

Closed via the round-2 triage cleanup in #1965.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CHANGELOG should only write down the main release

2 participants