Skip to content

Commit 56a7685

Browse files
committed
project: add release notes generator (git cliff)
1 parent 0d245e1 commit 56a7685

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ long-running-command:
3737
@rm -rf .build/apple && swift build -c release --arch x86_64 --arch arm64 2>&1
3838
.PHONY: long-running-command
3939

40+
generate_release_notes:
41+
@git cliff --latest --strip=all --tag $(VERSION) --output .build/artifacts/release_notes.md
42+
.PHONY: generate_release_notes
43+
4044
prepare_release_artifacts: \
4145
prepare_release_artifacts_linux_arm64 \
4246
prepare_release_artifacts_linux_x86_64 \

cliff.toml

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# git-cliff ~ configuration file
2+
# https://git-cliff.org/docs/configuration
3+
4+
[remote.github]
5+
owner = "kattouf"
6+
repo = "ProgressLine"
7+
# token = ""
8+
9+
[changelog]
10+
# changelog header
11+
header = """
12+
# Changelog\n
13+
"""
14+
# template for the changelog body
15+
# https://keats.github.io/tera/docs/#introduction
16+
body = """
17+
{% if version %}\
18+
{% if previous.version %}\
19+
## [{{ version | trim_start_matches(pat="v") }}]({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
20+
{% else %}\
21+
## {{ version | trim_start_matches(pat="v") }} - {{ timestamp | date(format="%Y-%m-%d") }}
22+
{% endif %}\
23+
{% else %}\
24+
## Unreleased
25+
{% endif %}\
26+
{% for group, commits in commits | group_by(attribute="group") %}
27+
### {{ group | striptags | trim | upper_first }}
28+
29+
{% for commit in commits
30+
| filter(attribute="scope")
31+
| sort(attribute="scope") -%}
32+
{% if commit.scope -%}
33+
* {{self::commit(commit=commit)}}\
34+
{% endif -%}
35+
{% endfor -%}
36+
{% for commit in commits -%}
37+
{% if commit.scope -%}
38+
{% else -%}
39+
* {{self::commit(commit=commit)}}\
40+
{% endif -%}
41+
{% endfor -%}
42+
{% endfor %}
43+
44+
{%- if github -%}
45+
{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
46+
{% raw %}\n{% endraw -%}
47+
## New Contributors
48+
{%- endif %}\
49+
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
50+
* @{{ contributor.username }} made their first contribution
51+
{%- if contributor.pr_number %} in \
52+
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
53+
{%- endif %}
54+
{%- endfor -%}
55+
{%- endif -%}
56+
57+
{% if version %}
58+
{% if previous.version %}
59+
**Full Changelog**: {{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }}
60+
{% endif %}
61+
{% else -%}
62+
{% raw %}\n{% endraw %}
63+
{% endif %}
64+
65+
{%- macro remote_url() -%}
66+
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
67+
{%- endmacro -%}
68+
69+
{% macro commit(commit) -%}
70+
{% if commit.scope %}**({{commit.scope}})** {% endif -%}
71+
{% if commit.breaking %}**breaking** {% endif -%}
72+
{{ commit.message | split(pat="\n") | first | trim }} by \
73+
{% if commit.remote.username %}[@{{commit.remote.username}}](https://github.com/{{commit.remote.username}})\
74+
{% else %}{{commit.author.name}}{% endif %} in \
75+
{% if commit.remote.pr_number %}[#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }})\
76+
{% else %}[{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }})\
77+
{%- endif %}
78+
{% endmacro commit -%}
79+
"""
80+
# template for the changelog footer
81+
footer = """
82+
<!-- generated by git-cliff -->
83+
"""
84+
# remove the leading and trailing whitespace from the template
85+
trim = true
86+
# postprocessors
87+
postprocessors = []
88+
89+
[git]
90+
# parse the commits based on https://www.conventionalcommits.org
91+
conventional_commits = true
92+
# filter out the commits that are not conventional
93+
filter_unconventional = false
94+
# process each line of a commit as an individual commit
95+
split_commits = false
96+
# regex for preprocessing the commit messages
97+
commit_preprocessors = [
98+
# remove issue numbers from commits
99+
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" },
100+
]
101+
# regex for parsing and grouping commits
102+
commit_parsers = [
103+
{ message = '^chore\(release\): Bump version to', skip = true },
104+
{ message = '^(chore|fix)\(deps\):', group = "<!-- 99 -->:package: Dependency Updates", scope = "" },
105+
{ message = '^feat', group = "<!-- 00 -->:rocket: Features" },
106+
{ message = '^fix', group = "<!-- 01 -->:bug: Bug Fixes" },
107+
{ message = '^test', group = "<!-- 02 -->:test_tube: Testing" },
108+
{ message = '^perf', group = "<!-- 03 -->:zap: Performance" },
109+
{ message = '^refactor', group = "<!-- 04 -->:tractor: Refactoring" },
110+
{ message = '^doc', group = "<!-- 05 -->:books: Documentation" },
111+
{ body = '.*security', group = "<!-- 06 -->:shield: Security" },
112+
{ message = '^project', group = "<!-- 07 -->:file_folder: Project" },
113+
{ message = '^revert', group = "<!-- 39 -->:leftwards_arrow_with_hook: Revert" },
114+
{ message = '.', group = "<!-- 49 -->:card_index_dividers: Other Changes" },
115+
]
116+
# filter out the commits that are not matched by commit parsers
117+
filter_commits = false
118+
# sort the tags topologically
119+
topo_order = false
120+
# sort the commits inside sections by oldest/newest order
121+
sort_commits = "newest"

0 commit comments

Comments
 (0)