-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathcliff.toml
More file actions
168 lines (154 loc) · 7.68 KB
/
Copy pathcliff.toml
File metadata and controls
168 lines (154 loc) · 7.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# git-cliff ~ configuration file
# https://git-cliff.org/docs/configuration
# Documentation:
# Set a script step like this in the pipeline where git cliff is used:
# wget --output-document cliff.toml https://raw.githubusercontent.com/mendersoftware/mendertesting/master/utils/cliff.toml
[changelog]
# template for the changelog header
header = """---"""
# template for the changelog body
# https://keats.github.io/tera/docs/#introduction
body = """
{% if version %}## {{ version | replace(from="v", to="") }} - {{ timestamp | date(format="%Y-%m-%d") }}{% else %}## [unreleased]{% endif %}
{# Highlights are curated manually at release prep (grammar doc section 4.2). Insert a "## Highlights" block above this line in the release PR. #}
{%- macro entry(commit) -%}
{%- set_global c_line = commit.message | upper_first -%}
{%- set_global c_render_body = false -%}
{%- set_global c_ticket = "" -%}
{%- for f in commit.footers -%}
{# Exact-match keywords only. "All" is a legacy synonym for "Commit". Miscased values
(e.g. "commit") are silently ignored per the grammar -> subject only, no body. #}
{%- if f.token == "Changelog" and (f.value == "Commit" or f.value == "All") -%}{%- set_global c_render_body = true -%}{%- endif -%}
{# A Changelog value that is not a (case-insensitive) known keyword is a free-text sentence override. #}
{%- set kw = f.value | lower -%}
{%- if f.token == "Changelog" and kw != "commit" and kw != "none" and kw != "title" and kw != "all" -%}{%- set_global c_line = f.value -%}{%- endif -%}
{%- if f.token == "Ticket" and f.value != "None" -%}{%- set_global c_ticket = f.value -%}{%- endif -%}
{%- endfor -%}
{{ c_line }}{% if c_ticket %} ([{{ c_ticket }}](https://northerntech.atlassian.net/browse/{{ c_ticket }})){% endif %}
{%- if commit.body and c_render_body %}
{% for l in commit.body | split(pat="\n") %}{% if "(cherry picked from commit" not in l %} {{ l }}
{% endif %}{% endfor %}{%- endif -%}
{%- endmacro entry -%}
{# Entries that would render identically (same scope, subject and tickets — e.g. recurring
dependabot bumps) are listed once. Distinct commits sharing a subject still render,
since their scope or ticket differs. #}
{%- macro list(commits) -%}
{%- set_global seen = [] -%}
{%- for commit in commits | unique(attribute="id") %}
{%- set_global tks = "" -%}
{%- for f in commit.footers %}{% if f.token == "Ticket" %}{% set_global tks = tks ~ f.value %}{% endif %}{% endfor -%}
{%- set sc = commit.scope | default(value="") -%}
{%- set key = sc ~ "|" ~ commit.message ~ "|" ~ tks -%}
{%- if key not in seen %}
{%- set_global seen = seen | concat(with=key) %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}{{ self::entry(commit=commit) }}
{%- endif -%}
{%- endfor -%}
{%- endmacro list -%}
{# 1. Breaking changes #}
{%- set breaking = commits | filter(attribute="breaking", value=true) -%}
{%- if breaking | length > 0 %}
### Breaking changes
{% for commit in breaking %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}{{ self::entry(commit=commit) }}
{%- if commit.breaking_description and commit.breaking_description != commit.message %}
{% raw %} {% endraw %}- **BREAKING**: {{ commit.breaking_description }}
{%- endif -%}
{% endfor -%}
{% endif -%}
{# 2. Deprecations #}
{%- set_global has_dep = false -%}
{%- for commit in commits %}{% for f in commit.footers %}{% if f.token == "Deprecation" %}{% set_global has_dep = true %}{% endif %}{% endfor %}{% endfor -%}
{%- if has_dep %}
### Deprecations
{% for commit in commits %}{% for f in commit.footers %}{% if f.token == "Deprecation" %}
- {{ f.value }}
{%- endif %}{% endfor %}{% endfor -%}
{% endif -%}
{# 3. Ordered type groups (breaking excluded above; Deprecations group rendered above) #}
{%- for group, gc in commits | filter(attribute="breaking", value=false) | group_by(attribute="group") %}
{%- set name = group | split(pat="-->") | last -%}
{%- if name != "Deprecations" %}
### {{ name }}
{{ self::list(commits=gc) }}
{%- endif -%}
{%- endfor -%}
{# 4. All tickets resolved appendix #}
{%- set_global tickets = [] -%}
{%- for commit in commits %}{% for f in commit.footers %}{% if f.token == "Ticket" and f.value != "None" %}{% set_global tickets = tickets | concat(with=f.value) %}{% endif %}{% endfor %}{% endfor -%}
{%- if tickets | length > 0 %}
---
### All tickets resolved in this release
| Ticket |
|---|
{% for t in tickets | unique %}| [{{ t }}](https://northerntech.atlassian.net/browse/{{ t }}) |
{% endfor -%}
{% endif -%}
{%- if not commits %}
No Changelog found.
{% endif %}
{%- raw %}
{% endraw -%}
"""
# template for the changelog footer
footer = """---"""
# remove the leading and trailing whitespace from the templates
trim = true
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# process each line of a commit as an individual commit
split_commits = false
# regex for parsing and grouping commits
commit_parsers = [
# NOTE: git-cliff evaluates parsers first-match-wins and combines a single parser's
# fields with OR. Order therefore matters: type rules come first so a feat/fix that
# merely mentions a CVE, or carries a Deprecation trailer, keeps its own type group.
{ message = "^[^:]+\\(internal\\):", skip = true }, # Skip "internal" scope
{ message = "(?m)^Changelog: None$", skip = true }, # exact footer line only; a sentence starting with "None" is a valid override
# Type groups
{ message = "^feat", group = "<!-- 4 -->New features" },
{ message = "^fix", group = "<!-- 6 -->Bug fixes" },
{ message = "^perf", group = "<!-- 5 -->Improvements" },
{ message = "^refactor", group = "<!-- 5 -->Improvements" },
# CVE-flagged commits that fell through the type rules (i.e. dependency bumps and
# chores) route to Security. This keeps CVE-Security scoped to bumps/chores per the
# grammar, not to any commit that happens to mention a CVE.
{ message = "CVE-\\d{4}-\\d+", group = "<!-- 3 -->Security" },
{ body = "CVE-\\d{4}-\\d+", group = "<!-- 3 -->Security" },
{ footer = "CVE-\\d{4}-\\d+", group = "<!-- 3 -->Security" },
# Non-CVE dependency bumps route to Dependency updates (any deps* scope, plus scopeless bump)
{ message = "^chore: bump", group = "<!-- 7 -->Dependency updates" },
{ message = "^chore\\(deps", group = "<!-- 7 -->Dependency updates" },
# Deprecation-only commits (e.g. a plain chore) are kept out of the skip bucket so the
# template can surface their Deprecation trailer. feat/fix carrying one already matched above.
{ footer = "^Deprecation:", group = "<!-- 2 -->Deprecations" },
# Everything else (docs, style, test, ci, non-bump chore) is skipped
{ message = "^.*", skip = true },
]
link_parsers = [
{ pattern = "MEN-(\\d+)", href = "https://northerntech.atlassian.net/browse/MEN-$1" },
{ pattern = "SEC-(\\d+)", href = "https://northerntech.atlassian.net/browse/SEC-$1" },
{ pattern = "QA-(\\d+)", href = "https://northerntech.atlassian.net/browse/QA-$1" },
{ pattern = "ME-(\\d+)", href = "https://northerntech.atlassian.net/browse/ME-$1" },
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# filter out the commits that are not matched by commit parsers
filter_commits = false
# regex for matching git tags
tag_pattern = "v*[0-9].*"
# regex for skipping tags
skip_tags = ""
# regex for ignoring tags
# Use ignore instead of skip so that a commit with both an rc and a final tag is still processed
ignore_tags = "beta|alpha|rc"
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
[bump]
features_always_bump_minor = true
breaking_always_bump_major = true