{{ message }}
fix(changelog): add changelog_subject_only to skip body parsing - #1974
Closed
bearomorphism wants to merge 3 commits into
Closed
fix(changelog): add changelog_subject_only to skip body parsing#1974bearomorphism wants to merge 3 commits into
bearomorphism wants to merge 3 commits into
Conversation
Closes commitizen-tools#1267. `generate_tree_from_commits()` historically parses the commit subject and each `\n\n`-separated body block against `commit_parser`, so a commit whose subject is `feat: ...` and whose body contains another `refactor: ...` line produces two changelog entries instead of one. Maintainer ack on commitizen-tools#1267 confirms this is undesirable, but changing the default is a behavioural break. This change introduces `changelog_subject_only` (default `false`) on `Settings`. When set to `true`, the body iteration in `generate_tree_from_commits()` is skipped, leaving only the subject line to be matched. The setting is plumbed through `commands/changelog.py` so both `cz changelog` and `cz bump --changelog` honour it. A regression test exercises both modes against a commit whose body contains a parser-matching block. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1974 +/- ##
=======================================
Coverage 98.23% 98.23%
=======================================
Files 61 61
Lines 2779 2782 +3
=======================================
+ Hits 2730 2733 +3
Misses 49 49 ☔ View full report in Codecov by Sentry. |
Followup to fix(changelog): the new default key broke `tests/test_conf.py::TestReadCfg` because the expected `Settings` literals pinned the full dict and didn''t know about the new field. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
30 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new configuration setting to control whether changelog generation should parse commit body blocks as additional changelog entries, addressing issue #1267 while preserving historical behavior by default.
Changes:
- Introduces
changelog_subject_only(defaultfalse) to skip parsing\n\n-separated commit body blocks when generating changelogs. - Plumbs the setting through the
Changelogcommand socz changelog(andcz bump --changelogvia the same command) can honor it. - Adds a regression test for
generate_tree_from_commits(..., subject_only=True)and documents the new setting.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
commitizen/changelog.py |
Adds subject_only parameter to skip body-block parsing when building the changelog tree. |
commitizen/commands/changelog.py |
Passes changelog_subject_only from config into changelog tree generation. |
commitizen/defaults.py |
Adds changelog_subject_only to typed settings and default settings. |
tests/test_changelog.py |
Adds regression coverage for subject-only parsing behavior. |
tests/test_conf.py |
Updates expected/default settings fixtures to include changelog_subject_only. |
docs/commands/changelog.md |
Documents the new changelog_subject_only setting and its effect. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
268
to
280
| tree = changelog.generate_tree_from_commits( | ||
| commits, | ||
| tags, | ||
| commit_parser, | ||
| changelog_pattern, | ||
| self.unreleased_version, | ||
| change_type_map=self.change_type_map, | ||
| changelog_message_builder_hook=self.cz.changelog_message_builder_hook, | ||
| changelog_release_hook=self.cz.changelog_release_hook, | ||
| rules=self.tag_rules, | ||
| during_version_bump=self.during_version_bump, | ||
| subject_only=self.config.settings["changelog_subject_only"], | ||
| ) |
Add an end-to-end test that sets `changelog_subject_only = true` in the project configuration, creates a commit with a parser-matching block in its body, and asserts that `cz changelog --dry-run` only emits the subject entry. Catches typos in the setting key at `commands/changelog.py:279` (which would otherwise silently fall back to `False`); manually verified by injecting a typo, observing the test fail with KeyError, then restoring. Addresses the only review finding from PR commitizen-tools#1974. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
30 tasks
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Description
Closes #1267.
Why
commitizen.changelog.generate_tree_from_commits()parses both the commit subject and each\n\n-separated block ofcommit.bodyagainstcommit_parser. So a commit such asproduces two changelog entries:
This is rarely what the author intended — they wrote one
feat, the body was just a note. The maintainer ack on #1267 confirms the body-parsing is undesirable, but flipping the default would be a behaviour break for existing users (some intentionally rely on it for multi-message commits).What changed
commitizen/defaults.pychangelog_subject_only: boolandDEFAULT_SETTINGS["changelog_subject_only"] = False.commitizen/changelog.pygenerate_tree_from_commits()gains asubject_only: bool = Falsekwarg. WhenTrue, the body iteration is replaced with an empty tuple, so only the subject is matched.commitizen/commands/changelog.pyChangelog.__call__forwardsself.config.settings["changelog_subject_only"]togenerate_tree_from_commits(). This single call site is shared bycz changelogandcz bump --changelog.tests/test_changelog.pytest_generate_tree_from_commits_subject_only_skips_body_blocksexercises both modes against a commit whose body contains a parser-matching block.tests/commands/test_changelog_command.pytest_changelog_subject_only_setting_skips_body_parsingis an end-to-end test (real config file, realcz changeloginvocation) that catches typos in the config-key wiring.tests/test_conf.pySettingsliterals updated to include the new key (otherwise the strict-equality assertions inTestReadCfg::test_load_conffail).docs/commands/changelog.md### changelog_subject_onlysection next to the existing--merge-prereleasedocumentation.How it works
changelog_subject_only = falseis the default in both theSettingsTypedDict andDEFAULT_SETTINGS, soBaseConfig.__init__always seeds the dict-key withFalseand the dict-index access inChangelog.__call__cannotKeyError.chain([subject_match], (body_map_pat.match(block) for block in commit.body.split("\n\n")))ingenerate_tree_from_commits(). Replacing the second argument ofchainwith()whensubject_only=Trueis the entire behavioural change.from __future__ import annotationsmatters. The newbody_matches: Iterable[re.Match[str] | None]annotation only resolves inTYPE_CHECKINGblocks at runtime; withoutfrom __future__ import annotationsthe import would have to leaveTYPE_CHECKING. The file already had it.self.config.settings["changelog_subject_only"]lookup atcommands/changelog.py. The fixup commit292feb4fadds an integration test that constructs a real config and runscz changelog --dry-run, then verified by hand that the test fails (withKeyError) when the config key is mistyped.Backward compatibility
falsepreserves the historical body-parsing behaviour for every user who hasn't opted in.tests/test_changelog.pyandtests/commands/test_changelog_command.pytests pass unchanged.subject_onlykwarg ongenerate_tree_from_commits()defaults toFalse, so any external caller that imports the function continues to work.Checklist
Was generative AI tooling used to co-author this PR?
Generated-by: Claude following the guidelines
Code Changes
uv run poe alllocally to ensure this change passes linter check and tests (poe lintclean; 159 changelog tests pass)Documentation Changes
### changelog_subject_onlysection todocs/commands/changelog.mduv run poe doclocally to ensure the documentation pages render correctlyExpected Behavior
feat: X+ bodyrefactor: Ychangelog_subject_onlyunset (defaultfalse)feat, onerefactor(legacy)changelog_subject_only = truefeat: XApplies to both
cz changelogandcz bump --changelog.Steps to Test This Pull Request
Additional Context
Surfaced while triaging open issues in #1965. Maintainer ack on #1267 confirmed body-parsing is at-best opt-in. The end-to-end integration test was added in fixup commit
292feb4fafter both review passes (sonnet-4.6 and Copilot) flagged the wiring as the only path not exercised by tests.