Skip to content

Commit d767e6f

Browse files
committed
build: add commit message validation workflow
1 parent e9f7cae commit d767e6f

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

.github/workflows/commit-check.yml

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: 'Check Commit Messages'
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
jobs:
8+
check-commits:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
with:
13+
fetch-depth: 0
14+
15+
- name: Check Commits and Update Labels
16+
uses: actions/github-script@v7
17+
with:
18+
github-token: ${{ secrets.GITHUB_TOKEN }}
19+
script: |
20+
const { issue: { number: issue_number }, repo: { owner, repo } } = context;
21+
22+
// Get commits in the PR
23+
const { data: commits } = await github.rest.pulls.listCommits({
24+
owner,
25+
repo,
26+
pull_number: issue_number
27+
});
28+
29+
// Define valid types and their corresponding labels
30+
const typeToLabel = {
31+
'feat': 'type: new feature',
32+
'fix': 'type: bug',
33+
'docs': 'type: doc',
34+
'test': 'type: test',
35+
'chore': 'type: chore',
36+
'enhance': 'type: enhancement',
37+
'amend': 'type: amend',
38+
'style': 'type: chore',
39+
'refactor': 'type: enhancement',
40+
'perf': 'type: enhancement',
41+
'build': 'type: chore'
42+
};
43+
44+
const validTypes = Object.keys(typeToLabel);
45+
const pattern = new RegExp(`^(${validTypes.join('|')})(\(.+\))?!?: .+`);
46+
47+
let isValid = true;
48+
let invalidCommits = [];
49+
50+
// Check each commit
51+
for (const commit of commits) {
52+
const message = commit.commit.message.split('\n')[0]; // Get first line
53+
if (!pattern.test(message)) {
54+
isValid = false;
55+
invalidCommits.push(message);
56+
}
57+
}
58+
59+
// Get the first valid commit to determine the type
60+
const firstValidCommit = commits.find(commit => {
61+
const message = commit.commit.message.split('\n')[0];
62+
return pattern.test(message);
63+
});
64+
65+
// Remove existing type labels
66+
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
67+
owner,
68+
repo,
69+
issue_number
70+
});
71+
72+
for (const label of currentLabels) {
73+
if (label.name.startsWith('type:')) {
74+
await github.rest.issues.removeLabel({
75+
owner,
76+
repo,
77+
issue_number,
78+
name: label.name
79+
});
80+
}
81+
}
82+
83+
if (isValid && firstValidCommit) {
84+
// Extract type from first valid commit
85+
const type = firstValidCommit.commit.message.match(pattern)[1];
86+
const labelToAdd = typeToLabel[type];
87+
88+
// Add appropriate label
89+
await github.rest.issues.addLabels({
90+
owner,
91+
repo,
92+
issue_number,
93+
labels: [labelToAdd]
94+
});
95+
96+
// Add success comment
97+
await github.rest.issues.createComment({
98+
owner,
99+
repo,
100+
issue_number,
101+
body: '✅ All commit messages follow the conventional format.'
102+
});
103+
} else {
104+
// Create error comment
105+
const errorMessage = `
106+
❌ Some commit messages don't follow the conventional format.
107+
108+
Invalid commits:
109+
${invalidCommits.map(msg => `- \`${msg}\``).join('\n')}
110+
111+
Please update your commits to follow the format:
112+
\`\`\`
113+
type: description
114+
115+
Valid types:
116+
- feat: New feature (type: new feature)
117+
- fix: Bug fix (type: bug)
118+
- docs: Documentation changes (type: doc)
119+
- test: Adding/updating tests (type: test)
120+
- chore: Maintenance tasks (type: chore)
121+
- enhance: Enhancement to existing features (type: enhancement)
122+
- amend: Small amendments (type: amend)
123+
- style: Code formatting (type: chore)
124+
- refactor: Code restructuring (type: enhancement)
125+
- perf: Performance improvements (type: enhancement)
126+
- build: Build system changes (type: chore)
127+
\`\`\`
128+
129+
You can update your commit messages using:
130+
\`\`\`bash
131+
git rebase -i HEAD~n # where n is the number of commits to edit
132+
# Change 'pick' to 'reword' for commits you want to edit
133+
\`\`\`
134+
`;
135+
136+
await github.rest.issues.createComment({
137+
owner,
138+
repo,
139+
issue_number,
140+
body: errorMessage
141+
});
142+
}

0 commit comments

Comments
 (0)