feat(parser): allow commits to be parsed by multiple parsers - #1611
Conversation
Add an opt-in `continue` field to commit parsers. When set, parsing keeps going after a parser matches, so a commit can be handled by more than one parser in order (e.g. one sets the scope, the next sets the group). Default behavior is unchanged: the first matching parser wins and short-circuits.
|
The Test suite red here isn't coming from this PR. All the tests pass; it's the codecov upload step failing on gpg signature verification (Can't check signature: No public key), the same failure that's red on main right now. Should sort itself out on a re-run. |
|
Hey, thanks for the PR! There are a couple of issues:
Does
|
A terminal parser (one without continue) used to overwrite group, scope and default_scope wholesale, so a scope set by a preceding continue parser was reset to None when a later parser only matched to set the group. Make terminal parsers override just the fields they set, matching the sha-based match path, so composing parsers augment instead of clobbering each other. Add a unit case and a test-multiple-commit-parsers fixture that derive a scope from a git footer and then group by conventional type, and update the docs with that real-world use case.
Resolve the parser loop conflict: keep the labeled 'parsers loop and the missing-field fall-through from main alongside the continue flag and the matched tracking from this branch. Keep both new tests.
|
Good catch, and yes, I confirmed it. With the original version of this branch, I think that's surprising rather than intended, so I fixed it: a terminal parser now only overrides the fields it actually sets and leaves the rest alone, which is what the sha-based match path was already doing. So a later parser augments the commit instead of blanking out earlier fields. This is backward compatible, because without Also done:
|
There was a problem hiding this comment.
Looks good!
I found another issue:
[git]
commit_parsers = [
{ footer = "^Component: Billing$", scope = "billing", continue = true },
{ field = "scope", pattern = "^billing$", group = "Billing changes" },
]The second parser sees the scope from before parsing, not "billing".
So I think this should be either documented or behavior should be updated.
…caveat Trim the git.md write-up to a short example and move the fuller walkthrough to tips and tricks. Document that parser matching evaluates against the original commit, so a later parser cannot match on a field set by an earlier one.
|
Shortened the On the scope-field question: you are right, |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1611 +/- ##
==========================================
+ Coverage 52.68% 52.82% +0.14%
==========================================
Files 27 27
Lines 2597 2613 +16
==========================================
+ Hits 1368 1380 +12
- Misses 1229 1233 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Closes #117. Adds an opt-in
continuefield on commit parsers so a commit can be processed by more than one parser instead of stopping at the first match.Today the parser loop returns as soon as a commit matches a parser, so you can't have one parser set the scope and a later one set the group. The config from #117 (
{ message = "(scope)", scope = "..." }followed by{ message = "^feat", group = "..." }) only ever applies the first parser and the group is never set. The only workaround is spelling out every scope/group combination in a single parser, which gets tedious fast.With this change you mark the parsers you want to compose with
continue = true:A parser with
continue = trueonly writes the fields it actually sets (here justscope), then parsing moves on to the next parser, which fills in the group. Parsers without the flag behave exactly as before: first match wins and the loop short-circuits. So existing configs are untouched — the flag defaults to unset.One thing worth a look: when several parsers should stack, each contributing one, they all need
continue = true(a parser without it is treated as terminal and overwrites with its own fields, matching the current overwrite semantics). That felt like the least surprising reading of the issue, but I'm happy to change the shape if you had something else in mind — the thread left the design open ("needs some brainstorming").Also handled the filtering edge case: a commit matched only by
continueparsers (e.g. one that just sets a scope, no group) is kept whenfilter_commitsis on, same as a normal match would be.Tests in
git-cliff-core/src/commit.rs(parse_commit_multiple_parsers) cover three things: the default first-match-wins path is unchanged, scope-then-group composition works with the flag, and a scope-onlycontinueparser survives filtering.cargo test -p git-cliff-coreis green (73 passed),cargo clippy --all-featuresclean, docs added underconfiguration/git.md.