-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcliff.toml
More file actions
165 lines (159 loc) · 7.62 KB
/
cliff.toml
File metadata and controls
165 lines (159 loc) · 7.62 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
# SPDX-FileCopyrightText: 2025 Knitli Inc.
# SPDX-FileContributor: Adam Poulemanos <adam@knit.li>
#
# SPDX-License-Identifier: MIT OR Apache-2.0
# git-cliff configuration for automated changelog generation
# See: https://git-cliff.org/docs/configuration
[changelog]
# Template for the changelog header
header = """
# Changelog
Here is what we've been working on!
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
"""
# Template for the changelog body
# Available variables:
# - version: Version number
# - message: Commit message
# - date: Commit date
# - commits: List of commits for this version
body = """
{% if version -%}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else -%}
## [Unreleased]
{% endif -%}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{%- for commit in commits -%}
{%- if commit.message is starting_with("SQUASH | ") -%}
{# Handle squash merge format: "SQUASH | description | #123" #}
{%- set_global parts = commit.message | split(pat=" | ") -%}
{%- set_global pr_desc = parts | nth(n=1) | trim -%}
{%- set_global pr_num = parts | nth(n=2) | replace(from="#", to="") | trim -%}
{%- if pr_num is matching("^[0-9]+$") -%}
- {{ pr_desc }} ([#{{ pr_num }}](https://github.com/knitli/codeweaver/pull/{{ pr_num }}))
{%- else -%}
- {{ pr_desc }}
{%- endif -%}
{%- elif commit.message is starting_with("Merge pull request") -%}
{# Handle regular merge format: "Merge pull request #123 from org/branch | Description" #}
{%- set_global pr_num = commit.message | replace(from="Merge pull request #", to="") | split(pat=" ") | first | trim -%}
{%- if commit.message is containing(" | ") -%}
{%- set_global parts = commit.message | split(pat=" | ") -%}
{%- if parts | length >= 2 -%}
{%- set_global pr_desc = parts | slice(start=1) | join(sep=" | ") | trim -%}
{%- else -%}
{%- set_global pr_desc = "No description" -%}
{%- endif -%}
{%- endif %}
{%- if pr_num is matching("^[0-9]+$") -%}
- {{ pr_desc }} ([#{{ pr_num }}](https://github.com/knitli/codeweaver/pull/{{ pr_num }}))
{%- else -%}
- {{ pr_desc }}
{%- endif -%}
{%- else %}
- {{ commit.message | upper_first }}
{%- endif -%}
{%- if commit.breaking %}
- **BREAKING**: {{ commit.breaking_description }}
{%- endif -%}
{% endfor %}
{% endfor %}
"""
# Template for the changelog footer
footer = """
<!-- generated by git-cliff -->
"""
# Remove the leading and trailing whitespace from the templates
trim = true
# Postprocessors to apply after rendering the changelog
# postprocessors = [
# # Replace issue/PR numbers with links
# { pattern = '\(#([0-9]+)\)', replace = "([#${1}](https://github.com/knitli/codeweaver/pull/${1}))" },
# ]
[git]
# Parse commits based on https://www.conventionalcommits.org
conventional_commits = false
# Filter out commits that are not conventional
filter_unconventional = false
# Process merge commits - THIS IS KEY for PR-based changelog
split_commits = false
# Preprocessors for both merge commits and squash merges
commit_preprocessors = [
# 1. Extract PR description from merge commits and append to subject
# Input: "Merge pull request #123 from org/branch\n\nPR Description"
# Output: "Merge pull request #123 from org/branch | PR Description"
{ pattern = 'Merge pull request (#[0-9]+) from ([^\n]+)\n+([\s\S]+)', replace = "Merge pull request ${1} from ${2} | ${3}" },
# 2. Mark squash merge commits for easier template detection
# Input: "feat: some feature (#123)"
# Output: "SQUASH | feat: some feature | #123"
{ pattern = '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+?\))?: (.+) \(#([0-9]+)\)$', replace = "SQUASH | ${1}${2}: ${3} | #${4}" },
# 3. Catch squash merges without conventional commit prefix
# Input: "Some change (#123)"
# Output: "SQUASH | Some change | #123"
{ pattern = '^(.+) \(#([0-9]+)\)$', replace = "SQUASH | ${1} | #${2}" },
]
# Parse both merge commits and squash merges to extract PR info
# NOTE: Order matters! Commits are matched top-to-bottom, first match wins
commit_parsers = [
# Skip non-PR merge commits (like "Merge branch 'main'")
{ message = "^Merge branch", skip = true },
# === Squash Merge Parsers (conventional commits) ===
# After preprocessing, squash merges are in format: "SQUASH | type: description | #123"
{ message = "^SQUASH \\| feat", group = "Features" },
{ message = "^SQUASH \\| fix", group = "Bug Fixes" },
{ message = "^SQUASH \\| docs", group = "Documentation" },
{ message = "^SQUASH \\| perf", group = "Performance" },
{ message = "^SQUASH \\| refactor", group = "Refactoring" },
{ message = "^SQUASH \\| test", group = "Testing" },
{ message = "^SQUASH \\| build", group = "Build System" },
{ message = "^SQUASH \\| ci", group = "CI/CD" },
{ message = "^SQUASH \\| chore", group = "Maintenance" },
{ message = "^SQUASH \\| revert", group = "Reverts" },
{ message = "^SQUASH \\|", group = "Other Changes" },
# === Regular Merge Commit Parsers (branch-based) ===
# Features - check branch name patterns
{ message = "^Merge pull request #[0-9]+ from .*/feat", group = "Features" },
{ message = "^Merge pull request #[0-9]+ from .*/feature", group = "Features" },
# Fixes - multiple patterns for fix-related branches
{ message = "^Merge pull request #[0-9]+ from .*/fix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/bugfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/hotfix", group = "Bug Fixes" },
{ message = "^Merge pull request #[0-9]+ from .*/issue-", group = "Bug Fixes" },
# Documentation
{ message = "^Merge pull request #[0-9]+ from .*/docs", group = "Documentation" },
{ message = "^Merge pull request #[0-9]+ from .*/doc", group = "Documentation" },
# Performance
{ message = "^Merge pull request #[0-9]+ from .*/perf", group = "Performance" },
{ message = "^Merge pull request #[0-9]+ from .*/optimize", group = "Performance" },
# Refactoring
{ message = "^Merge pull request #[0-9]+ from .*/refactor", group = "Refactoring" },
# Testing
{ message = "^Merge pull request #[0-9]+ from .*/test", group = "Testing" },
# CI/CD and tooling
{ message = "^Merge pull request #[0-9]+ from .*/ci", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/workflow", group = "CI/CD" },
{ message = "^Merge pull request #[0-9]+ from .*/build", group = "Build System" },
# Chores and maintenance
{ message = "^Merge pull request #[0-9]+ from .*/chore", group = "Maintenance" },
# Catch-all for other PRs (will be categorized as miscellaneous)
{ message = "^Merge pull request #[0-9]+", group = "Other Changes" },
]
# Protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
# Filter commits - when true, only commits matching a non-skip parser are included
filter_commits = true
# Regex for tags to include in the changelog
tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+.*"
# Skip tags matching this regex
skip_tags = ""
# Ignore tags matching this regex
ignore_tags = ""
# Sort tags chronologically
date_order = false
# Sort commits inside sections by oldest/newest order
sort_commits = "newest"
# Limit the number of commits included in the changelog
# limit_commits = 42