Appearance
CI/CD Integration
This guide covers integrating GitLint into CI/CD pipelines for automated commit message validation.
GitHub Actions
Basic Validation
yaml
# .github/workflows/commit-lint.yml
name: Commit Lint
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v1
- name: Install GitLint
run: bun add @stacksjs/gitlint
- name: Lint commits
run: |
git log --format=%B ${{ github.event.pull_request.base.sha }}..${{ github.sha }} | \
while read -r line; do
if [ -n "$line" ]; then
echo "$line" | bunx gitlint
fi
doneValidate PR Commits
yaml
name: Validate PR Commits
on:
pull_request:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v1
- name: Install dependencies
run: bun install
- name: Validate all PR commits
run: |
COMMITS=$(git log --format='%H' ${{ github.event.pull_request.base.sha }}..${{ github.sha }})
FAILED=0
for sha in $COMMITS; do
MSG=$(git log -1 --format=%B $sha)
echo "Checking: $sha"
echo "$MSG"
if ! echo "$MSG" | bunx gitlint; then
FAILED=1
fi
echo "---"
done
exit $FAILEDWith Detailed Report
yaml
name: Commit Lint Report
on:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v1
- name: Install GitLint
run: bun add @stacksjs/gitlint
- name: Create lint report
id: lint
run: |
echo "## Commit Lint Report" > report.md
echo "" >> report.md
COMMITS=$(git log --format='%H' ${{ github.event.pull_request.base.sha }}..${{ github.sha }})
TOTAL=0
PASSED=0
FAILED=0
for sha in $COMMITS; do
TOTAL=$((TOTAL + 1))
MSG=$(git log -1 --format=%s $sha)
if git log -1 --format=%B $sha | bunx gitlint 2>/dev/null; then
PASSED=$((PASSED + 1))
echo "- $MSG" >> report.md
else
FAILED=$((FAILED + 1))
echo "- $MSG" >> report.md
fi
done
echo "" >> report.md
echo "**Results:** $PASSED/$TOTAL passed" >> report.md
echo "total=$TOTAL" >> $GITHUB_OUTPUT
echo "passed=$PASSED" >> $GITHUB_OUTPUT
echo "failed=$FAILED" >> $GITHUB_OUTPUT
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs')
const report = fs.readFileSync('report.md', 'utf8')
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: report
})
- name: Check result
if: steps.lint.outputs.failed > 0
run: exit 1GitLab CI
Basic Pipeline
yaml
# .gitlab-ci.yml
stages:
- lint
commit-lint:
stage: lint
image: oven/bun:latest
script:
- bun add @stacksjs/gitlint
- |
if [ "$CI_PIPELINE_SOURCE" = "merge_request_event" ]; then
git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
COMMITS=$(git log --format=%H origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME..HEAD)
for sha in $COMMITS; do
git log -1 --format=%B $sha | bunx gitlint
done
fi
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"With Artifacts
yaml
commit-lint:
stage: lint
image: oven/bun:latest
script:
- bun add @stacksjs/gitlint
- |
git log --format="%H %s" origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME..HEAD > commits.txt
while read sha msg; do
if git log -1 --format=%B $sha | bunx gitlint 2>&1 | tee -a lint-output.txt; then
echo "PASS: $msg" >> results.txt
else
echo "FAIL: $msg" >> results.txt
fi
done < commits.txt
artifacts:
paths:
- results.txt
- lint-output.txt
when: alwaysCircleCI
yaml
# .circleci/config.yml
version: 2.1
jobs:
lint-commits:
docker:
- image: oven/bun:latest
steps:
- checkout
- run:
name: Install GitLint
command: bun add @stacksjs/gitlint
- run:
name: Lint commits
command: |
if [ -n "$CIRCLE_PULL_REQUEST" ]; then
BASE_SHA=$(git merge-base origin/main HEAD)
git log --format=%B $BASE_SHA..HEAD | bunx gitlint
fi
workflows:
version: 2
lint:
jobs:
- lint-commitsJenkins
groovy
// Jenkinsfile
pipeline {
agent {
docker {
image 'oven/bun:latest'
}
}
stages {
stage('Lint Commits') {
when {
changeRequest()
}
steps {
sh 'bun add @stacksjs/gitlint'
sh '''
COMMITS=$(git log --format=%H origin/${CHANGE_TARGET}..HEAD)
for sha in $COMMITS; do
git log -1 --format=%B $sha | bunx gitlint
done
'''
}
}
}
}Azure DevOps
yaml
# azure-pipelines.yml
trigger:
- main
pr:
- main
pool:
vmImage: ubuntu-latest
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
- script: |
npm install -g bun
bun add @stacksjs/gitlint
displayName: Install GitLint
- script: |
COMMITS=$(git log --format=%H origin/main..HEAD)
for sha in $COMMITS; do
git log -1 --format=%B $sha | bunx gitlint
done
displayName: Lint Commits
condition: eq(variables['Build.Reason'], 'PullRequest')Pre-commit Integration
Using pre-commit framework
yaml
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: gitlint
name: GitLint
entry: bunx gitlint
language: system
stages: [commit-msg]Programmatic Integration
Custom CI Script
typescript
// scripts/ci-lint.ts
import { lintCommitMessage } from '@stacksjs/gitlint'
import { $ } from 'bun'
async function main() {
const baseRef = process.env.BASE_REF || 'origin/main'
const headRef = process.env.HEAD_REF || 'HEAD'
const { stdout } = await $`git log --format=%H ${baseRef}..${headRef}`.quiet()
const commits = stdout.trim().split('\n').filter(Boolean)
let hasErrors = false
for (const sha of commits) {
const { stdout: message } = await $`git log -1 --format=%B ${sha}`.quiet()
const result = lintCommitMessage(message.trim())
if (!result.valid) {
console.error(`Commit ${sha.slice(0, 7)}:`)
console.error(` Message: ${message.split('\n')[0]}`)
result.errors.forEach(e => console.error(` Error: ${e}`))
hasErrors = true
}
}
if (hasErrors) {
process.exit(1)
}
console.log(`All ${commits.length} commits validated successfully`)
}
main()Run in CI
yaml
- name: Validate commits
run: bun run scripts/ci-lint.ts
env:
BASE_REF: ${{ github.event.pull_request.base.sha }}
HEAD_REF: ${{ github.sha }}Best Practices
- Validate all PR commits: Not just the latest
- Provide clear feedback: Show which commits failed
- Use same config as local: Consistency matters
- Cache dependencies: Speed up CI runs
- Fail fast: Exit on first error for quick feedback
Next Steps
- Configuration - CI-specific config
- Performance - Optimize for CI
- Git Hooks - Local validation