feat(template): add commit_groups filter for ordered group rendering#1518
Open
ChrisJr404 wants to merge 2 commits into
Open
feat(template): add commit_groups filter for ordered group rendering#1518ChrisJr404 wants to merge 2 commits into
ChrisJr404 wants to merge 2 commits into
Conversation
Tera's built-in `group_by(attribute="group")` filter backs its result with a BTreeMap, so groups always come out in alphabetical (or emoji-codepoint) order regardless of the order in which they were declared in `commit_parsers`. This is the long-standing behavior tracked in orhun#9 and the reason most users prefix group names with `<!-- N -->` HTML comments and strip them with `striptags` to coerce a particular order. The project's own `cliff.toml` does this too. This change keeps `group_by` untouched and adds a new filter, `commit_groups`, that yields entries as an array of `{ name, commits }` records, so iteration order is deterministic and template-defined. The filter has two modes: * No `groups` argument: groups appear in the order they first occur in the input list, matching commit chronology. * With a `groups=...` argument (an array of group names): groups are sorted to match that order, with any unlisted groups appended afterward in first-appearance order. To make the common case ergonomic, `Changelog::build` now injects the ordered list of group names from `commit_parsers` into the template context as `commit_parsers_groups`, so users can write: {% for entry in commits | commit_groups(groups=commit_parsers_groups) %} ### {{ entry.name }} {% for commit in entry.commits %}- {{ commit.message }} {% endfor %} {% endfor %} and get groups in the order they wrote them in `cliff.toml`. The default templates and `group_by` callers are left as-is; this is purely additive. A regression test using the reproducer from orhun#9 verifies the order, plus unit tests cover the no-args case, the `groups=` argument, the unknown- group fallthrough, and the null-group skip behavior. Closes orhun#9
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1518 +/- ##
==========================================
+ Coverage 48.90% 49.88% +0.98%
==========================================
Files 26 26
Lines 2272 2310 +38
==========================================
+ Hits 1111 1152 +41
+ Misses 1161 1158 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
Closes #9.
Background
commits | group_by(attribute="group")is Tera's built-in filter, and it backs the grouped result with aBTreeMap. That means groups always come out in alphabetical (or emoji-codepoint) order, regardless of the order in which they were declared incommit_parsers. The thread on #9 covers this and the workaround that's spread across the ecosystem: prefix group names with<!-- 0 -->,<!-- 1 -->, ..., then strip the comments withstriptags. The project's owncliff.tomluses that workaround.What this PR does
It leaves
group_byalone (so existing templates keep working byte-for-byte) and adds a new filter,commit_groups, that returns an array of{ name, commits }records instead of a map. Because the result is an array, iteration order is deterministic and template-defined.The filter has two modes:
groupsargument: groups appear in the order they first occur in the commit list, which matches commit chronology.groups=...argument (an array of group names): groups are sorted to match that order. Any group not ingroupsis appended afterward in first-appearance order.To make the common case ergonomic,
Changelog::buildnow injects the ordered list of group names fromcommit_parsersinto the template context ascommit_parsers_groups. So a user template can simply write:and get groups in the order they wrote them in
cliff.toml, with no<!-- N -->hack and nostriptagsfilter. With the same input, switching to the existinggroup_byfilter still produces alphabetical order, so this is purely additive.Reproducer from the issue
Given the configuration from arthrarnld's comment:
and four commits in
chore -> fix -> perf -> featorder, the existinggroup_bytemplate renders:After this PR, switching the template to
commit_groups(groups=commit_parsers_groups)renders:Tests
template::test::test_commit_groups_filter_preserves_first_appearance_when_no_groupstemplate::test::test_commit_groups_filter_uses_groups_argumenttemplate::test::test_commit_groups_filter_appends_unknown_groupstemplate::test::test_commit_groups_filter_skips_null_groupschangelog::test::changelog_group_order_matches_commit_parsers(regression test using the issue reproducer end-to-end throughChangelog::generate)Notes
group_byis unchanged. Default templates are unchanged. Adoption is opt-in via the new filter.commit_parsers_groupscontext key is set byChangelog::buildbefore any user-supplied context is added, soadd_context("commit_parsers_groups", ...)still wins if a caller wants to override it.commit-groups-filter-improvedbranch) but keeps the state on theTemplateinstance instead of a global static, and uses tera's filter-arg mechanism to plumb the order list through.Test plan
cargo test --workspace --lib(all new tests pass; pre-existingrepo::test::*failures reproduce onmainand are env-dependent)cargo clippy --all-targets --workspaceintroduces no new lintscargo fmt --checkintroduces no new diffs against the existing baselinecommit_parsers), no-args (chronology), and existinggroup_by(alphabetical, unchanged)