🐛 fix(release): generate consistent CHANGELOG heading levels#1032
Merged
gaborbernat merged 3 commits intoApr 13, 2026
Conversation
Every release since 1.4.1 produced a CHANGELOG entry whose heading characters did not match prior entries, breaking sphinx -W with "Inconsistent title style: skip from level 1 to 3" and pinning Read the Docs' stable version at 1.4.0 since no tagged build after that could complete. The root cause is that `top_underline` has never been a towncrier config key. The settings loader only reads `underlines`, and towncrier passes `underlines[0]` into the template as the `top_underline` variable. PR pypa#1002 added `top_underline = "#"` intending to drive the version heading, but towncrier silently ignored it and kept emitting `*` for the top line and `=` for sections, neither of which matched the `#`/`*` hierarchy established by every historical entry. docstrfmt then rejected the hybrid file, and the release script's first pre-commit pass left the new entry half-rewritten. Prepend `#` to `underlines` so towncrier feeds `#` as the top underline and `*` as the section underline, matching the existing changelog and docstrfmt's expectations. Rewrite the 1.4.3 entry to the correct hierarchy so the current docs build succeeds without a follow-up patch commit. Add a docs build step to the pre-release workflow as a backstop so any future regression fails the run before a tag is pushed.
henryiii
approved these changes
Apr 13, 2026
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.
Read the Docs'
stableversion has been pinned at 1.4.0 since January because every tagged release after it (1.4.1, 1.4.2, 1.4.3) shipped aCHANGELOG.rstentry whose heading characters did not match prior entries, andsphinx -Wrejected the file withInconsistent title style: skip from level 1 to 3. The previous two releases were patched up by hand after the fact; 1.4.3 has not been, which is what issue #1031 reports. 🐛The root cause traces back to #1002, which added
top_underline = "#"to[tool.towncrier]intending to drive the version overline character.top_underlinehas never been a towncrier config key, though. Its settings loader only readsunderlines, and internally towncrier passesunderlines[0]into the template as thetop_underlinevariable. The addition was silently ignored from the day it landed, and every subsequent release kept emitting*for the version heading and=for the section headings, neither of which match the#/*hierarchy the rest of the changelog uses. When the release script then ranpre-commit, docstrfmt rejected the hybrid file and left the new entry half-rewritten.The fix prepends
#tounderlinesso towncrier feeds#as the top underline and*as the section underline, which matches both the historical changelog and docstrfmt's expectations. The 1.4.3 entry is rewritten to the correct hierarchy so the current docs build succeeds without another follow-up patch commit. As a backstop, thepre-releaseworkflow now runstox r -e docsagainst the generated release commit before pushing, so any future regression fails the workflow instead of shipping a tag whose docs cannot build.Verified end-to-end by running
tox r -e release -- --version 1.4.3 --no-pushagainst the pre-1.4.3 commit in a worktree: with the config fix, the release script completes,docstrfmtstays idempotent, andsphinx -W -nbuilds cleanly. Once 1.4.4 tags with this fix, RTD'sstablewill catch up.Closes #1031.