Skip to content

Commit 518e8bb

Browse files
committed
ci: add conventional commits lint (#315)
1 parent 9db6afd commit 518e8bb

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"use strict";
2+
3+
const fs = require("fs");
4+
5+
const TITLE_PATTERN =
6+
/^(?<prefix>[^:!(]+)(?<package>\([^)]+\))?(?<breaking>[!])?:.+$/;
7+
const RELEASE_AS_DIRECTIVE = /^\s*Release-As:/im;
8+
const BREAKING_CHANGE_DIRECTIVE = /^\s*BREAKING[ \t]+CHANGE:/im;
9+
10+
const ALLOWED_CONVENTIONAL_COMMIT_PREFIXES = [
11+
"revert",
12+
"feat",
13+
"fix",
14+
"ci",
15+
"docs",
16+
"chore",
17+
];
18+
19+
const object = process.argv[2];
20+
const payload = JSON.parse(fs.readFileSync(process.stdin.fd, "utf-8"));
21+
22+
let validate = [];
23+
24+
if (object === "pr") {
25+
validate.push({
26+
title: payload.pull_request.title,
27+
content: payload.pull_request.body,
28+
});
29+
} else if (object === "push") {
30+
validate.push(
31+
...payload.commits
32+
.map((commit) => ({
33+
title: commit.message.split("\n")[0],
34+
content: commit.message,
35+
}))
36+
.filter(({ title }) => !title.startsWith("Merge branch ") && !title.startsWith("Revert ")),
37+
);
38+
} else {
39+
console.error(
40+
`Unknown object for first argument "${object}", use 'pr' or 'push'.`,
41+
);
42+
process.exit(0);
43+
}
44+
45+
let failed = false;
46+
47+
validate.forEach((payload) => {
48+
if (payload.title) {
49+
const match = payload.title.match(TITLE_PATTERN);
50+
if (!match) {
51+
return
52+
}
53+
54+
const { groups } = match
55+
56+
if (groups) {
57+
if (groups.breaking) {
58+
console.error(
59+
`PRs are not allowed to declare breaking changes at this stage of the project. Please remove the ! in your PR title or commit message and adjust the functionality to be backward compatible.`,
60+
);
61+
failed = true;
62+
}
63+
64+
if (
65+
!ALLOWED_CONVENTIONAL_COMMIT_PREFIXES.find(
66+
(prefix) => prefix === groups.prefix,
67+
)
68+
) {
69+
console.error(
70+
`PR (or a commit in it) is using a disallowed conventional commit prefix ("${groups.prefix}"). Only ${ALLOWED_CONVENTIONAL_COMMIT_PREFIXES.join(", ")} are allowed. Make sure the prefix is lowercase!`,
71+
);
72+
failed = true;
73+
}
74+
75+
if (groups.package && groups.prefix !== "chore") {
76+
console.warn(
77+
"Avoid using package specifications in PR titles or commits except for the `chore` prefix.",
78+
);
79+
}
80+
} else {
81+
console.error(
82+
"PR or commit title must match conventional commit structure.",
83+
);
84+
failed = true;
85+
}
86+
}
87+
88+
if (payload.content) {
89+
if (payload.content.match(RELEASE_AS_DIRECTIVE)) {
90+
console.error(
91+
"PR descriptions or commit messages must not contain Release-As conventional commit directives.",
92+
);
93+
failed = true;
94+
}
95+
96+
if (payload.content.match(BREAKING_CHANGE_DIRECTIVE)) {
97+
console.error(
98+
"PR descriptions or commit messages must not contain a BREAKING CHANGE conventional commit directive. Please adjust the functionality to be backward compatible.",
99+
);
100+
failed = true;
101+
}
102+
}
103+
});
104+
105+
if (failed) {
106+
process.exit(1);
107+
}
108+
109+
process.exit(0);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Check pull requests
2+
3+
on:
4+
push:
5+
branches-ignore: # Run the checks on all branches but the protected ones
6+
- main
7+
- release/*
8+
9+
pull_request_target:
10+
branches:
11+
- main
12+
- release/*
13+
types:
14+
- opened
15+
- edited
16+
- reopened
17+
- ready_for_review
18+
19+
jobs:
20+
check-conventional-commits:
21+
runs-on: ubuntu-latest
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
sparse-checkout: |
27+
.github
28+
29+
- if: ${{ github.event_name == 'pull_request_target' }}
30+
run: |
31+
set -ex
32+
33+
node .github/workflows/conventional-commits-lint.js pr <<EOF
34+
${{ toJSON(github.event) }}
35+
EOF
36+
37+
- if: ${{ github.event_name == 'push' }}
38+
run: |
39+
set -ex
40+
41+
node .github/workflows/conventional-commits-lint.js push <<EOF
42+
${{ toJSON(github.event) }}
43+
EOF

0 commit comments

Comments
 (0)