orhun / git-cliff

A highly customizable Changelog Generator that follows Conventional Commit specifications ⛰️
https://git-cliff.org
Apache License 2.0
8.65k stars 183 forks source link

Group order doesn't match the order of `commit_parsers` #9

Open arthrarnld opened 3 years ago

arthrarnld commented 3 years ago

Describe the bug As I was tweaking my cliff.toml file to get the changelog to look exactly how I want it, I noticed the order of the groups is not affected by the elements in commit_parsers, but rather seems to be alphabetical on the group name.

Expected behavior I hoped the groups would appear in the markdown in the same order as the commit_parsers array. Maybe there's a way to work around this? Thanks!

arthrarnld commented 3 years ago

Ok, I used a dirty trick to get the groups to be placed as I want them to be. I prefixed group names with an HTML comment <!-- n --> where n is the desired position. I'm not sure if sorting them alphabetically was the intended behaviour in the first place. If so, I reckon this issue can be closed.

Thanks for the project anyway. It works wonderfully 🥳

orhun commented 3 years ago

Hi! I was just looking into this :D Can you give an example about your dirty trick?

I'm not sure if sorting them alphabetically was the intended behaviour in the first place. If so, I reckon this issue can be closed.

Not really. It'd be nice to preserve the order in the configuration file somehow.

Thanks for the project anyway. It works wonderfully

\o/

arthrarnld commented 3 years ago

Sure thing! Check this out:

commit_parsers = [
    # Since the groups come out in alphabetical order, use HTML comments
    # to force them into their desired positions.
    { message = "^feat*", group = "<!-- 0 -->:rocket: New features" },
    { message = "^fix*", group = "<!-- 1 -->:bug: Bug fixes" },
    { message = "^perf*", group = "<!-- 2 -->:zap: Performance" },
    { message = "^chore*", group = "<!-- 3 -->:gear: Miscellaneous" },
]

This produces the order I want:

If you remove the HTML comments, you'll get

(Keeping in mind that the emoji names are part of the string and therefore part of the sorting.)

orhun commented 3 years ago

Thank you for sharing! Maybe we should mention this workaround in commit_parsers section 😋 (feel free to submit a PR)

I digged this issue a little bit and it turns out alphabetical order is caused by tera's group_by filter:

https://github.com/Keats/tera/blob/edee1ac3462193cb697e912d7d1cfefc9e478b8c/src/builtins/filters/array.rs#L165

It uses serde_json::Map and it has a feature called preserve_oder which does the following:

By default the map is backed by a BTreeMap. Enable the preserve_order feature of serde_json to use LinkedHashMap instead.

#[cfg(not(feature = "preserve_order"))]
type MapImpl<K, V> = BTreeMap<K, V>;
#[cfg(feature = "preserve_order")]
type MapImpl<K, V> = LinkedHashMap<K, V>;

Luckily, tera has a feature to enable this feature as well: https://github.com/Keats/tera/blob/f4c855a1452a6b0c5555b83fbc96ed517f957b62/Cargo.toml#L47

[features]
default = ["builtins"]
builtins = ["slug", "percent-encoding", "humansize", "chrono", "chrono-tz", "rand"]
preserve_order = ["serde_json/preserve_order"]

Unfortunately, enabling this feature on git-cliff makes the group order match the order of the commits. So if you have the following git history:

refactor: add x
feat: add y

You will get the following order:

## Refactor
- add x

## Feat
- add y

I'll debug this further soon but your workaround seems like the best solution so far.

azzamsa commented 2 years ago

Come here for the same thing.

So to recap the situation: the current fix is using arthrarnld's hacks described in https://github.com/orhun/git-cliff/issues/9#issuecomment-914521594. As Orhun (The awesome git-cliff author) still still searching for backward-compatible workaround.

jmatth commented 2 years ago

Just came across this thread after running into the same issue. If anyone else wants to preserve the order but doesn't like having the HTML comment tags visible in the markdown, you can strip them out with with this series of filters:

    ### {{ group | striptags | trim | upper_first }}