Skip to content

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

Closed
bearomorphism wants to merge 2 commits into
commitizen-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 into
commitizen-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

FileChange
commitizen/defaults.pyAdded changelog_skip_prereleases: bool to Settings TypedDict and DEFAULT_SETTINGS (default alse)
commitizen/tags.pyAdded 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.pyPasses skip_prereleases from config when constructing TagRules
ests/test_conf.pyAdded changelog_skip_prereleases to both expected-settings literals (avoids CI failure)
ests/test_changelog.pyTwo new unit tests for generate_tree_from_commits
ests/commands/test_changelog_command.pyTwo new end-to-end tests via cz changelog --dry-run
docs/commands/changelog.mdNew 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

ScenarioBeforeAfter
changelog_skip_prereleases = false (default)Prereleases appear in changelogSame - no change
changelog_skip_prereleases = trueN/APrerelease entries (
c, �lpha, �eta, dev) omitted
Both skip and merge set to ruemerge winsskip 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.

bearomorphismand 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.
Closescommitizen-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.
Closescommitizen-tools#1218
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@codecov

codecovBot commented May 9, 2026

Copy link
Copy Markdown

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 linesPatch %Lines
commitizen/question.py0.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.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
commitizen/defaults.pyAdd changelog_skip_prereleases to settings + defaults.
commitizen/tags.pyAdd skip_prereleases to TagRules and filter prerelease tags.
commitizen/commands/changelog.pyWire skip_prereleases and change file-name path resolution logic.
commitizen/question.pyExtend InputQuestion with validate and required.
commitizen/cz/customize/customize.pyImplement required by injecting a validator and stripping the key.
tests/test_conf.pyUpdate expected settings dictionaries with the new key.
tests/test_changelog.pyAdd unit tests for skip-prereleases + refactor file-name resolution test.
tests/commands/test_changelog_command.pyAdd E2E tests for skip-prereleases config behavior.
tests/test_cz_customize.pyAdd unit tests for required questions behavior.
docs/commands/changelog.mdDocument changelog_skip_prereleases and clarify path resolution.
docs/customization/config_file.mdDocument 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 threadcommitizen/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
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
CollaboratorAuthor

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 freeto 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

@bearomorphism