Skip to content

Commit bca649e

Browse files
committed
chore: wip
1 parent 6bf5b78 commit bca649e

9 files changed

Lines changed: 1858 additions & 76 deletions

File tree

docs/advanced/ci-cd-integration.md

Lines changed: 371 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
1+
# CI/CD Integration
2+
3+
This guide covers integrating GitLint into CI/CD pipelines for automated commit message validation.
4+
5+
## GitHub Actions
6+
7+
### Basic Validation
8+
9+
```yaml
10+
# .github/workflows/commit-lint.yml
11+
name: Commit Lint
12+
13+
on:
14+
pull_request:
15+
types: [opened, synchronize, reopened]
16+
17+
jobs:
18+
lint:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
25+
- uses: oven-sh/setup-bun@v1
26+
27+
- name: Install GitLint
28+
run: bun add @stacksjs/gitlint
29+
30+
- name: Lint commits
31+
run: |
32+
git log --format=%B ${{ github.event.pull_request.base.sha }}..${{ github.sha }} | \
33+
while read -r line; do
34+
if [ -n "$line" ]; then
35+
echo "$line" | bunx gitlint
36+
fi
37+
done
38+
```
39+
40+
### Validate PR Commits
41+
42+
```yaml
43+
name: Validate PR Commits
44+
45+
on:
46+
pull_request:
47+
48+
jobs:
49+
validate:
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v4
53+
with:
54+
fetch-depth: 0
55+
56+
- uses: oven-sh/setup-bun@v1
57+
58+
- name: Install dependencies
59+
run: bun install
60+
61+
- name: Validate all PR commits
62+
run: |
63+
COMMITS=$(git log --format='%H' ${{ github.event.pull_request.base.sha }}..${{ github.sha }})
64+
FAILED=0
65+
66+
for sha in $COMMITS; do
67+
MSG=$(git log -1 --format=%B $sha)
68+
echo "Checking: $sha"
69+
echo "$MSG"
70+
71+
if ! echo "$MSG" | bunx gitlint; then
72+
FAILED=1
73+
fi
74+
echo "---"
75+
done
76+
77+
exit $FAILED
78+
```
79+
80+
### With Detailed Report
81+
82+
```yaml
83+
name: Commit Lint Report
84+
85+
on:
86+
pull_request:
87+
88+
jobs:
89+
lint:
90+
runs-on: ubuntu-latest
91+
steps:
92+
- uses: actions/checkout@v4
93+
with:
94+
fetch-depth: 0
95+
96+
- uses: oven-sh/setup-bun@v1
97+
98+
- name: Install GitLint
99+
run: bun add @stacksjs/gitlint
100+
101+
- name: Create lint report
102+
id: lint
103+
run: |
104+
echo "## Commit Lint Report" > report.md
105+
echo "" >> report.md
106+
107+
COMMITS=$(git log --format='%H' ${{ github.event.pull_request.base.sha }}..${{ github.sha }})
108+
TOTAL=0
109+
PASSED=0
110+
FAILED=0
111+
112+
for sha in $COMMITS; do
113+
TOTAL=$((TOTAL + 1))
114+
MSG=$(git log -1 --format=%s $sha)
115+
116+
if git log -1 --format=%B $sha | bunx gitlint 2>/dev/null; then
117+
PASSED=$((PASSED + 1))
118+
echo "- $MSG" >> report.md
119+
else
120+
FAILED=$((FAILED + 1))
121+
echo "- $MSG" >> report.md
122+
fi
123+
done
124+
125+
echo "" >> report.md
126+
echo "**Results:** $PASSED/$TOTAL passed" >> report.md
127+
128+
echo "total=$TOTAL" >> $GITHUB_OUTPUT
129+
echo "passed=$PASSED" >> $GITHUB_OUTPUT
130+
echo "failed=$FAILED" >> $GITHUB_OUTPUT
131+
132+
- name: Comment on PR
133+
uses: actions/github-script@v7
134+
with:
135+
script: |
136+
const fs = require('fs')
137+
const report = fs.readFileSync('report.md', 'utf8')
138+
139+
github.rest.issues.createComment({
140+
issue_number: context.issue.number,
141+
owner: context.repo.owner,
142+
repo: context.repo.repo,
143+
body: report
144+
})
145+
146+
- name: Check result
147+
if: steps.lint.outputs.failed > 0
148+
run: exit 1
149+
```
150+
151+
## GitLab CI
152+
153+
### Basic Pipeline
154+
155+
```yaml
156+
# .gitlab-ci.yml
157+
stages:
158+
- lint
159+
160+
commit-lint:
161+
stage: lint
162+
image: oven/bun:latest
163+
script:
164+
- bun add @stacksjs/gitlint
165+
- |
166+
if [ "$CI_PIPELINE_SOURCE" = "merge_request_event" ]; then
167+
git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
168+
COMMITS=$(git log --format=%H origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME..HEAD)
169+
for sha in $COMMITS; do
170+
git log -1 --format=%B $sha | bunx gitlint
171+
done
172+
fi
173+
rules:
174+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
175+
```
176+
177+
### With Artifacts
178+
179+
```yaml
180+
commit-lint:
181+
stage: lint
182+
image: oven/bun:latest
183+
script:
184+
- bun add @stacksjs/gitlint
185+
- |
186+
git log --format="%H %s" origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME..HEAD > commits.txt
187+
while read sha msg; do
188+
if git log -1 --format=%B $sha | bunx gitlint 2>&1 | tee -a lint-output.txt; then
189+
echo "PASS: $msg" >> results.txt
190+
else
191+
echo "FAIL: $msg" >> results.txt
192+
fi
193+
done < commits.txt
194+
artifacts:
195+
paths:
196+
- results.txt
197+
- lint-output.txt
198+
when: always
199+
```
200+
201+
## CircleCI
202+
203+
```yaml
204+
# .circleci/config.yml
205+
version: 2.1
206+
207+
jobs:
208+
lint-commits:
209+
docker:
210+
- image: oven/bun:latest
211+
steps:
212+
- checkout
213+
- run:
214+
name: Install GitLint
215+
command: bun add @stacksjs/gitlint
216+
- run:
217+
name: Lint commits
218+
command: |
219+
if [ -n "$CIRCLE_PULL_REQUEST" ]; then
220+
BASE_SHA=$(git merge-base origin/main HEAD)
221+
git log --format=%B $BASE_SHA..HEAD | bunx gitlint
222+
fi
223+
224+
workflows:
225+
version: 2
226+
lint:
227+
jobs:
228+
- lint-commits
229+
```
230+
231+
## Jenkins
232+
233+
```groovy
234+
// Jenkinsfile
235+
pipeline {
236+
agent {
237+
docker {
238+
image 'oven/bun:latest'
239+
}
240+
}
241+
242+
stages {
243+
stage('Lint Commits') {
244+
when {
245+
changeRequest()
246+
}
247+
steps {
248+
sh 'bun add @stacksjs/gitlint'
249+
sh '''
250+
COMMITS=$(git log --format=%H origin/${CHANGE_TARGET}..HEAD)
251+
for sha in $COMMITS; do
252+
git log -1 --format=%B $sha | bunx gitlint
253+
done
254+
'''
255+
}
256+
}
257+
}
258+
}
259+
```
260+
261+
## Azure DevOps
262+
263+
```yaml
264+
# azure-pipelines.yml
265+
trigger:
266+
- main
267+
268+
pr:
269+
- main
270+
271+
pool:
272+
vmImage: ubuntu-latest
273+
274+
steps:
275+
- task: NodeTool@0
276+
inputs:
277+
versionSpec: '20.x'
278+
279+
- script: |
280+
npm install -g bun
281+
bun add @stacksjs/gitlint
282+
displayName: Install GitLint
283+
284+
- script: |
285+
COMMITS=$(git log --format=%H origin/main..HEAD)
286+
for sha in $COMMITS; do
287+
git log -1 --format=%B $sha | bunx gitlint
288+
done
289+
displayName: Lint Commits
290+
condition: eq(variables['Build.Reason'], 'PullRequest')
291+
```
292+
293+
## Pre-commit Integration
294+
295+
### Using pre-commit framework
296+
297+
```yaml
298+
# .pre-commit-config.yaml
299+
repos:
300+
- repo: local
301+
hooks:
302+
- id: gitlint
303+
name: GitLint
304+
entry: bunx gitlint
305+
language: system
306+
stages: [commit-msg]
307+
```
308+
309+
## Programmatic Integration
310+
311+
### Custom CI Script
312+
313+
```typescript
314+
// scripts/ci-lint.ts
315+
import { lintCommitMessage } from '@stacksjs/gitlint'
316+
import { $ } from 'bun'
317+
318+
async function main() {
319+
const baseRef = process.env.BASE_REF || 'origin/main'
320+
const headRef = process.env.HEAD_REF || 'HEAD'
321+
322+
const { stdout } = await $`git log --format=%H ${baseRef}..${headRef}`.quiet()
323+
const commits = stdout.trim().split('\n').filter(Boolean)
324+
325+
let hasErrors = false
326+
327+
for (const sha of commits) {
328+
const { stdout: message } = await $`git log -1 --format=%B ${sha}`.quiet()
329+
const result = lintCommitMessage(message.trim())
330+
331+
if (!result.valid) {
332+
console.error(`Commit ${sha.slice(0, 7)}:`)
333+
console.error(` Message: ${message.split('\n')[0]}`)
334+
result.errors.forEach(e => console.error(` Error: ${e}`))
335+
hasErrors = true
336+
}
337+
}
338+
339+
if (hasErrors) {
340+
process.exit(1)
341+
}
342+
343+
console.log(`All ${commits.length} commits validated successfully`)
344+
}
345+
346+
main()
347+
```
348+
349+
### Run in CI
350+
351+
```yaml
352+
- name: Validate commits
353+
run: bun run scripts/ci-lint.ts
354+
env:
355+
BASE_REF: ${{ github.event.pull_request.base.sha }}
356+
HEAD_REF: ${{ github.sha }}
357+
```
358+
359+
## Best Practices
360+
361+
1. **Validate all PR commits**: Not just the latest
362+
2. **Provide clear feedback**: Show which commits failed
363+
3. **Use same config as local**: Consistency matters
364+
4. **Cache dependencies**: Speed up CI runs
365+
5. **Fail fast**: Exit on first error for quick feedback
366+
367+
## Next Steps
368+
369+
- [Configuration](/advanced/configuration) - CI-specific config
370+
- [Performance](/advanced/performance) - Optimize for CI
371+
- [Git Hooks](/features/git-hooks) - Local validation

0 commit comments

Comments
 (0)