Skip to content

Commit 40e78a9

Browse files
authored
ci: add conventional commits changelog generation and commit linting (#641)
- Add git-cliff config (cliff.toml) for changelog generation from conventional commits - Add GitHub Actions workflow to generate CHANGELOG.md on tag push or manual trigger - Add commitlint config enforcing conventional commit format on PRs - Add commitlint GitHub Actions workflow for PR validation Supported commit types: feat, fix, docs, example, examples, chore, refactor, perf, test, ci, revert
1 parent 24c3f61 commit 40e78a9

4 files changed

Lines changed: 181 additions & 0 deletions

File tree

.github/workflows/changelog.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Changelog
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: "Version tag to generate changelog for (e.g. v1.0.0)"
11+
required: true
12+
type: string
13+
14+
permissions:
15+
contents: write
16+
17+
jobs:
18+
changelog:
19+
name: Generate Changelog
20+
runs-on: ubuntu-latest
21+
env:
22+
VERSION_TAG: ${{ inputs.version || github.ref_name }}
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Generate changelog
30+
uses: orhun/git-cliff-action@v4
31+
id: git-cliff
32+
with:
33+
config: cliff.toml
34+
args: --verbose --tag ${{ env.VERSION_TAG }}
35+
env:
36+
OUTPUT: CHANGELOG.md
37+
GITHUB_REPO: ${{ github.repository }}
38+
39+
- name: Commit changelog
40+
run: |
41+
git config user.name "github-actions[bot]"
42+
git config user.email "github-actions[bot]@users.noreply.github.com"
43+
git add CHANGELOG.md
44+
git commit -m "chore: update changelog for ${{ env.VERSION_TAG }}" || true
45+
git push origin HEAD:main
46+
47+
- name: Create/update GitHub release body
48+
uses: orhun/git-cliff-action@v4
49+
with:
50+
config: cliff.toml
51+
args: --verbose --latest --strip header
52+
env:
53+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
54+
GITHUB_REPO: ${{ github.repository }}

.github/workflows/commitlint.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Commit Lint
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
commitlint:
13+
name: Lint Commit Messages
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Setup Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: 20
25+
26+
- name: Install commitlint
27+
run: npm install --save-dev @commitlint/{cli,config-conventional}
28+
29+
- name: Lint commits
30+
run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose

cliff.toml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
[changelog]
2+
header = """
3+
# Changelog
4+
5+
All notable changes to this project will be documented in this file.
6+
7+
This changelog is automatically generated based on [Conventional Commits](https://www.conventionalcommits.org/).\n
8+
"""
9+
body = """
10+
{%- macro remote_url() -%}
11+
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
12+
{%- endmacro -%}
13+
14+
{% if version -%}
15+
## [{{ version | trim_start_matches(pat="v") }}]\
16+
{% if commit_id %}({{ self::remote_url() }}/tree/{{ version }}){% endif %}\
17+
{% if timestamp %} - {{ timestamp | date(format="%Y-%m-%d") }}{% endif %}
18+
{% else -%}
19+
## [Unreleased]
20+
{% endif -%}
21+
22+
{% for group, commits in commits | group_by(attribute="group") %}
23+
### {{ group | striptags | trim | upper_first }}
24+
{% for commit in commits
25+
| filter(attribute="scope")
26+
| sort(attribute="scope") %}
27+
- *({{ commit.scope }})* {{ commit.message | upper_first }}\
28+
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif -%}
29+
{% if commit.github.pr_number %} in \
30+
[#{{ commit.github.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.github.pr_number }})\
31+
{%- endif %}
32+
{%- endfor -%}
33+
{% for commit in commits %}
34+
{%- if not commit.scope %}
35+
- {{ commit.message | upper_first }}\
36+
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif -%}
37+
{% if commit.github.pr_number %} in \
38+
[#{{ commit.github.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.github.pr_number }})\
39+
{%- endif %}
40+
{%- endif -%}
41+
{%- endfor -%}
42+
{% endfor %}
43+
"""
44+
footer = ""
45+
trim = true
46+
47+
[git]
48+
conventional_commits = true
49+
filter_unconventional = false
50+
split_commits = false
51+
commit_parsers = [
52+
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
53+
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
54+
{ message = "^perf", group = "<!-- 2 -->⚡ Performance" },
55+
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
56+
{ message = "^example", group = "<!-- 4 -->📦 Examples" },
57+
{ message = "^refactor", group = "<!-- 5 -->🔧 Refactoring" },
58+
{ message = "^chore\\(deps\\)", group = "<!-- 6 -->📦 Dependencies" },
59+
{ message = "^chore|^ci", group = "<!-- 7 -->🏗️ Maintenance" },
60+
{ message = "^test", group = "<!-- 8 -->🧪 Testing" },
61+
{ message = "^Bump ", group = "<!-- 6 -->📦 Dependencies" },
62+
{ message = "^.*", group = "<!-- 9 -->🔀 Other" },
63+
]
64+
protect_breaking_commits = true
65+
filter_commits = false
66+
tag_pattern = "v[0-9].*"
67+
sort_commits = "newest"
68+
69+
[remote.github]
70+
owner = "awslabs"
71+
repo = "aws-lambda-web-adapter"

commitlint.config.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = {
2+
extends: ['@commitlint/config-conventional'],
3+
rules: {
4+
'type-enum': [
5+
2,
6+
'always',
7+
[
8+
'feat',
9+
'fix',
10+
'docs',
11+
'example',
12+
'examples',
13+
'chore',
14+
'refactor',
15+
'perf',
16+
'test',
17+
'ci',
18+
'revert',
19+
],
20+
],
21+
'subject-case': [0],
22+
'body-max-line-length': [0],
23+
'footer-max-line-length': [0],
24+
'header-max-length': [2, 'always', 120],
25+
},
26+
};

0 commit comments

Comments
 (0)