[feature] Render the text of a BREAKING CHANGE footer - #155
Merged
Conversation
0.5.0 learned to recognise a `BREAKING CHANGE:` footer, but only far enough to
tag the commit. The footer's own words — the part telling somebody what to do
about it — became a separate, unattached entry, so the release notes for that
very version had to be written by hand afterwards.
A footer describes the commit rather than standing on its own, so it is now
read as the commit's breaking change instead of as an entry: its text rides
with the entry it describes, wrapped footers are joined, and the entry earns
the `breaking` tag exactly as a `!` would. `RawLog` carries the description
alongside the sha and author it already carries, which keeps it available to a
per-line component without the body having to survive entry extraction.
`<< breaking_change >>` prints it. A commit with a footer reads
- |breaking||feat||api| drop the v1 endpoints — v1 is gone. Move to v2.
and one without prints nothing where the description would be — along with the
separator introducing it, which would otherwise dangle. That rule is general
rather than specific to this component: a separator preceding a component which
renders nothing is dropped, which also tidies `<< tags >>` on an untagged
commit. The separator opening a line is kept, being a bullet rather than a join.
Footers are read whichever style the subjects use, so .finch/config.release.yml
takes a Breaking Changes section despite reading its own history as delimited.
Finch can now describe what it breaks in its own release notes, which is what
started this.
SwiftFormat wraps the brace of a multi-line condition onto its own line, which SwiftLint's opening_brace rule then rejects — the two disagree, and only CI runs both. Naming the condition sidesteps the disagreement and reads better than five clauses in an if.
namolnad
added a commit
that referenced
this pull request
Aug 14, 2026
SwiftFormat moves the brace of a multiline condition onto its own line; SwiftLint's opening_brace rule rejects exactly that. Only CI runs both, so the disagreement shows up as a failed lint job after `swiftformat --lint` has passed locally — which is how it found #155. Disabling the rule settles it in SwiftLint's favour. No existing file changes shape, since none currently carries a wrapped condition.
namolnad
added a commit
that referenced
this pull request
Aug 14, 2026
A condition long enough for SwiftFormat to wrap is long enough to deserve a name, so a SwiftLint custom rule now asks for one — the shape settled on in #155. Scoped to `if`: the multi-line `guard … else { return }` form reads fine and appears across five files, so it is untouched. Nothing in Sources or Tests matches today. CI proved the rule fires before it landed, against a deliberate violation which was then removed, since SwiftLint runs nowhere but CI and a green run would have shown only that the config parses.
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.
0.5.0 learned to recognise a
BREAKING CHANGE:footer, but only far enough to tag the commit. The footer's own words — the part telling somebody what to do about it — became a separate, unattached entry. Which is why 0.5.0's release notes needed a hand-written section afterwards.What changes
A footer describes the commit rather than standing on its own, so it is now read as the commit's breaking change instead of as an entry:
breakingtag exactly as a!would, sochore: tidy analyticswith a footer files under Breaking ChangesdelimitedincludedRawLogcarries the description alongside the sha and author it already carries, which keeps it available to a per-line component without the commit body having to survive entry extraction.Printing it
<< breaking_change >>is a new format component:That third entry has no footer, and its
—is dropped rather than left dangling. The rule is general, not specific to this component: a separator preceding a component which renders nothing is omitted, which also tidies<< tags >>on an untagged commit. The separator opening a line is kept, being a bullet rather than a join — otherwise an untagged entry would lose its-.Finch describes what it breaks
.finch/config.release.ymltakes a Breaking Changes section. Run against commits shaped like this release cycle's:Had this existed a day earlier, 0.5.0's notes would have carried both breaking changes on their own.
Test plan
BREAKING-CHANGE:spelling, footers under the delimited style, and that a footer no longer opens an entry.!-plus-wrapped-footer commit, a footer-only commit, and a breaking commit with no footer — the three cases that differ.swiftformat --lint .clean.🤖 Generated with Claude Code