[feature] Read Conventional Commits by default - #153
Merged
Conversation
BREAKING CHANGE: commit messages are now read as Conventional Commits, `type(scope): description`, rather than Finch's `[tag] description`. Projects using the original convention keep it with one line — `commit_style: delimited` under `format:` — and nothing else about their configuration changes. Finch asked for a convention it had invented, which is the complaint. The type and every scope become tags, so `feat(app-store): …` carries both `feat` and `app-store` and `--required-tags app-store` goes on matching. A `!` before the colon, or a line opening `BREAKING CHANGE:`, adds a `breaking` tag, which leads the tag list so that a breaking change is filed under that heading ahead of its own type. The default sections gain one for it, and `fix` joins Bug Fixes so the defaults suit either convention. All of this lands in one place. `CommitParser` now owns every read of a commit message — which tags it carries, what is left to print, and whether a line opens an entry of its own — where those three questions used to be three regular expressions consulted from two files. Body lines are held to a stricter standard than subjects. A subject is known to be a commit message, so any lower-case type is read from it, custom types included. A body line is not: running this against Finch's own history turned a wrapped paragraph — `…was right for the build and wrong for the` / `tests: the file is regenerated…` — into a `tests` entry. Body lines are therefore limited to the types the specification names. Prose which merely contains a colon, `Note: …` or `Fixes: #123`, was never eligible: a type must be lower case, which is also why `BREAKING CHANGE:` is matched separately. Tags now come from the message rather than the whole log line, which is a fix in its own right: an author address of `dependabot[bot]@…` had been contributing a phantom `bot` tag to every dependabot commit. While there, a `[tag]: description` subject — dependabot writes exactly that — no longer leaves its colon behind once the tag is removed. This project's own history predates all of this, so .finch/config.release.yml opts into `delimited`. Without it Finch's release notes would come out empty, which is the migration in miniature and worth seeing.
`commit_style` could only be set in configuration, which is the right home for a project-wide convention but awkward for a single run — comparing versions either side of a migration, most obviously. `--commit-style` overrides whatever the configuration files resolved to. It lands among the global options rather than on `compare` alone, since that is where `AppRunner` already reads the values it builds the `App` from, and the override is a property of the app's configuration rather than of one command. `Configuration.applying(commitStyle:)` is the seam: a copy with the style replaced, so the resolved configuration stays immutable. The `ExpressibleByArgument` conformance sits in FinchApp, because FinchCore has no business importing an argument parser. Notably it needs no `@retroactive` — the compiler recognises both modules as this package's own, so the conformance cannot be claimed from under us. Also replaces `launchPath` and `launch()`, deprecated in favour of `executableURL` and `run()`, which warned on every build. The availability branch around them was already dead: it tested for macOS 10.13 against a package which now declares 10.15, and swift-corelibs-foundation has had the replacements for years, so the fallback only ever served Linux — where it was the sole path, and the only one warning.
Carries the Swift 6.0 toolchain requirement and the commit style flip, both breaking, so the minor rather than the patch.
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.
Warning
BREAKING CHANGE — commit messages are read as Conventional Commits rather than Finch's
[tag] description. Projects on the original convention keep it with one line:Addresses the complaint that Finch asked for a convention it had invented rather than the one everybody else uses.
How it reads
type(scope): description. The type and every scope become tags, sofeat(app-store): …carries bothfeatandapp-store— which is what--required-tags app-storematches on, unchanged. A!before the colon, or a line openingBREAKING CHANGE:, adds abreakingtag.breakingleads the tag list, because sections are matched in tag order and a breaking change belongs under that heading ahead of its own type. The default sections gain one for it, andfixjoins Bug Fixes so the defaults suit either convention.Multiple entries per commit (#131) composes with it — one commit, two sections:
Where it lives
CommitParsernow owns every read of a commit message — which tags it carries, what is left to print, whether a line opens an entry — where those three questions used to be three regular expressions consulted from two files.Body lines are stricter than subjects, and here's why
A subject is known to be a commit message, so any lower-case type is read from it, custom types included. A body line is not. Running this against Finch's own history turned a wrapped paragraph into an entry:
→
- The file is regenerated from the build graph by anything which knows nothing of FINCH_TESTS…So body lines are held to the types the specification names. Prose which merely contains a colon —
Note: …,Fixes: #123— was never eligible, since a type must be lower case; that is also whyBREAKING CHANGE:is matched separately rather than as a type.I first tried allowing the project's own section tags as body types. That backfired on this very repo, which configures
testsas a section tag — so the union re-admitted the exact line it was meant to exclude. Dropped it.Two fixes carried along
dependabot[bot]@…had been contributing a phantombottag to every dependabot commit. Visible whenever a format string prints tags.[tag]: descriptionno longer keeps its colon once the tag is removed. Dependabot writes exactly that shape, so it appeared in this repo's changelog as- : Bump github.com/mxcl/version….This repo eats it
.finch/config.release.ymlopts intodelimited, because Finch's own history predates all of this. Without that line its release notes come out empty — I ran it to be sure. That is the migration in miniature, and worth having in the tree.Test plan
CommitParserTestscovers types, multi-scope, both breaking forms, untagged subjects, prose-with-colon rejection, and that the delimited style is unchanged.commit_style: delimited, which is the compatibility proof — those fixtures and snapshots are untouched apart from the new config key.swiftformat --lint .clean.🤖 Generated with Claude Code