fix(changelog): clearer error when changelog format cannot be inferred#1973
fix(changelog): clearer error when changelog format cannot be inferred#1973bearomorphism wants to merge 2 commits intocommitizen-tools:masterfrom
Conversation
When `changelog_format` was unset and the changelog filename had an unknown extension (e.g. `CHANGELOG.md.sections`), commitizen raised `Unknown changelog format 'None'` -- which is confusing because the user never set anything to `None`. Improve the two failure paths: * If the user set `changelog_format` to an unknown value, the error echoes that value and lists the registered formats. * If the format had to be inferred from the filename and the inference failed, the error names the offending filename, points to the `changelog_format` setting and lists the registered formats. No behaviour change for the success paths. Closes commitizen-tools#894 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 #1973 +/- ##
=======================================
Coverage 98.23% 98.24%
=======================================
Files 61 61
Lines 2779 2785 +6
=======================================
+ Hits 2730 2736 +6
Misses 49 49 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Pull request overview
This PR improves the UX of cz changelog failures by making ChangelogFormatUnknown errors actionable when the changelog format can’t be determined (either because inference from filename fails, or because an explicit changelog_format is invalid), and updates tests to assert the new messaging.
Changes:
- Split
get_changelog_format’s single error into two distinct messages (explicit invalid format vs. inference failure) and include a “Known formats” list. - Update/extend
tests/test_changelog_formats.pyto assert the new message content for inference failures and explicit invalid names.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
commitizen/changelog_formats/__init__.py |
Adds clearer error branches and appends known format names to the raised error message. |
tests/test_changelog_formats.py |
Strengthens assertions on error messages and adds a regression test for the explicit-invalid-name path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…lid filename Refactor get_changelog_format with explicit branching: when changelog_format is set, look it up directly and raise ChangelogFormatUnknown if missing, regardless of whether the filename extension is recognized. Previously the 'or _guess_changelog_format' fallback could silently ignore an invalid explicit configuration when the filename had a known extension. Add a regression test exercising changelog_format='invalidformat' with filename='CHANGELOG.md'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
Closes #894.
Why
Since commitizen 3.12, running
cz changelogwith a non-standard--file-namesuch asdocs/source/changelog.md.sections(a Sphinx-style sectioned changelog file) fails with the messageUnknown changelog format 'None'. The error is cryptic: it exposes an internalNonePython value rather than explaining what went wrong or what the user should do.The failure path is
get_changelog_format(commitizen/changelog_formats/__init__.py:64–80). Whenchangelog_formatis not set in the config,nameisNone. The function then calls_guess_changelog_format(filename)(__init__.py:83–98), which matches the filename against known extensions. A filename likechangelog.md.sectionsdoes not end with.md—endswithrequires the final suffix — so inference returnsNone. At line 78, the single raise path always formats the message asf"Unknown changelog format '{name}'", which printsUnknown changelog format 'None'regardless of whether the problem was a bad explicit setting or a failed inference. The original reporter (@gsemet) filed the issue in October 2023; a second user (@anthonyfinch) hit the same problem shortly after, and triage in #1964 confirmed the bug is still present against master (v4.15.1).The fix splits the error into two distinct, actionable messages — one for each failure mode — and both messages list the registered format names so users know exactly what to write in
changelog_format.What changed
commitizen/changelog_formats/__init__.pyraise ChangelogFormatUnknowninget_changelog_format(line 78) into two branches: one for an explicitly-set-but-unknown name, one for inference failure; both appendKnown formats: <sorted list>tests/test_changelog_formats.pytest_get_format_empty_filename_no_settingandtest_get_format_unknownto assert the new message content; addedtest_get_format_unknown_name_lists_known_formatsfor the explicit-bad-name pathHow it works
KNOWN_CHANGELOG_FORMATS(commitizen/changelog_formats/__init__.py:58–61) is a dict populated fromcommitizen.changelog_formatentry-points at module import time. Third-party plugins that register their own format are automatically included in the list — the message is always accurate.known = ", ".join(sorted(KNOWN_CHANGELOG_FORMATS))once, then branches:nameis truthy (the user explicitly setchangelog_formatto an unrecognised value):"Unknown changelog format '{name}'. Known formats: {known}."— echoes the bad value so it's easy to spot a typo."Cannot infer changelog format from filename '{filename}'. Set the \changelog_format` setting explicitly. Known formats: {known}."` — names the offending filename and points directly to the fix..rstworkflow and forgets to setchangelog_format = "restructuredtext"would get a Markdown-parsed changelog written into their.rstfile, corrupting it without any warning. An explicit error that explains what to do is safer.sorted(KNOWN_CHANGELOG_FORMATS)rather than a hard-coded string? The list is derived from entry-points, so it includes third-party plugins and stays accurate if a format is added or removed in future releases.get_changelog_formatis updated to referenceChangelogFormatUnknown(not the staleFormatUnknownname) and to describe both failure modes.Backward compatibility
ChangelogFormatUnknownin both new branches.changelog_formatsettings or standard file extensions see no change."Unknown changelog format 'None'".test_changelog_formats.pypass; the two parametrised tests that previously only checkedpytest.raises(ChangelogFormatUnknown)now additionally assert message content.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 testsExpected Behavior
cz changelog --file-name CHANGELOG.weird(nochangelog_formatset)Cannot infer changelog format from filename 'CHANGELOG.weird'. Set the \changelog_format` setting explicitly. Known formats: asciidoc, markdown, restructuredtext, textile.`changelog_format = "definitely-not-a-format"in configUnknown changelog format 'definitely-not-a-format'. Known formats: asciidoc, markdown, restructuredtext, textile.cz changelog --file-name docs/source/changelog.md.sections(exact reproducer from #894)changelog.md.sectionschangelog_format = "markdown"with any filenameSteps to Test This Pull Request
Additional Context
This is one of three bugs surfaced by the triage audit in #1964. The fix is intentionally minimal — error messages only, zero behaviour change on success paths. A follow-up could consider defaulting to
markdownwhen inference fails (as suggested in the triage comment), but that is a separate decision with broader implications and belongs in its own PR.