Skip to content

Commit 9fe5218

Browse files
committed
Add script to check PR commit messages
1 parent 6cc8c27 commit 9fe5218

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

.github/pull_request_template.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
<!--
22
Please make sure your Pull Request is targeting the develop branch.
3+
4+
Please make sure your commit messages conform to the checks contained in
5+
.github/scripts/lint-commits.js.
36
-->

.github/scripts/lint-commits.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"use strict";
2+
3+
const { URL } = require("url");
4+
5+
const titleRegex = /^(.+?)(?:(?:\r?\n){2}|$)/us;
6+
const titleOf = (message) => message.match(titleRegex)[1];
7+
const bodyOf = (message) => message.slice(titleOf(message).length).trimStart();
8+
9+
const urlRegex = /^(?:https?|ftp):\/\//u;
10+
function isURL(string) {
11+
if (urlRegex.test(string)) {
12+
try {
13+
new URL(string);
14+
return true;
15+
} catch {}
16+
}
17+
18+
return false;
19+
}
20+
21+
const checkers = [{
22+
error: "Commit message must not contain carriage return (\\r) characters",
23+
check: (message) => !message.includes("\r"),
24+
}, {
25+
error: "Commit title must not contain newline (\\n) characters",
26+
check: (message) => !titleOf(message).includes("\n"),
27+
}, {
28+
error: "Commit title must be 50 characters long or less",
29+
check: (message) => titleOf(message).length <= 50,
30+
}, {
31+
error: "Commit title must start with an uppercase letter",
32+
check(message) {
33+
const firstChar = titleOf(message).charAt(0);
34+
const firstCharUpper = firstChar.toUpperCase();
35+
return firstChar === firstCharUpper
36+
&& "A" <= firstCharUpper
37+
&& firstCharUpper <= "Z";
38+
},
39+
}, {
40+
error: "Commit title must not end with a period",
41+
check: (message) => titleOf(message).trimEnd().slice(-1) !== ".",
42+
}, {
43+
error: "Commit body lines must be 72 characters long or less (except URLs)",
44+
check(message) {
45+
const body = bodyOf(message);
46+
if (body.trimEnd() !== "") {
47+
for (const line of body.split("\n")) {
48+
if (line.length > 72 && !isURL(line)) {
49+
return false;
50+
}
51+
}
52+
}
53+
54+
return true;
55+
},
56+
}];
57+
58+
async function readJsonFromStdin() {
59+
const chunks = [];
60+
for await (const chunk of process.stdin) {
61+
chunks.push(chunk);
62+
}
63+
64+
return Buffer.concat(chunks).toString();
65+
}
66+
67+
function runChecker({ check, error }) {
68+
return check(this.message) ? [] : [error];
69+
}
70+
71+
async function main() {
72+
const commits = JSON.parse(await readJsonFromStdin());
73+
74+
let exitCode = 0;
75+
for (const { commit, sha } of commits) {
76+
const errors = checkers.flatMap(runChecker, commit);
77+
if (errors.length === 0) {
78+
continue;
79+
}
80+
81+
if (exitCode !== 0) {
82+
console.log("");
83+
}
84+
exitCode = 1;
85+
86+
console.log("Commit %s failed these checks:", sha);
87+
for (const error of errors) {
88+
console.log(" %s", error);
89+
}
90+
}
91+
92+
return exitCode;
93+
}
94+
95+
main().catch((error) => {
96+
console.error(error);
97+
return 1;
98+
}).then((code) => { process.exitCode = code; });

.github/workflows/lint-commits.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Lint commits
2+
3+
on:
4+
pull_request_target:
5+
branches:
6+
- develop
7+
8+
jobs:
9+
lint-commits:
10+
if: github.repository_owner == 'friendlyanon'
11+
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Get PR commits
16+
id: commits
17+
uses: IdanHo/get-pr-commits@d94b66d146a31ef91e54a2597dee4fb523157232
18+
with: { token: "${{ github.token }}" }
19+
20+
- name: Check commits
21+
run: |
22+
node .github/scripts/lint-commits.js << 'JSON'
23+
${{ steps.commits.outputs.commits }}
24+
JSON

0 commit comments

Comments
 (0)