CI/CD Quality Gate Config
A GitHub Actions workflow that enforces code quality gates — linting, type checking, tests, coverage thresholds, and build verification before merging.
Description
A comprehensive GitHub Actions CI pipeline that acts as a quality gate for pull requests. It runs lint, type checks, unit tests with coverage, and build verification in parallel — blocking merges that don’t meet quality standards.
Features
- Parallel jobs — lint, typecheck, test, and build run simultaneously
- Coverage threshold — fails if coverage drops below 80%
- Dependency caching — npm cache for fast installs
- PR comments — posts coverage report as a PR comment
- Branch protection — designed to be a required status check
The Workflow
# .github/workflows/quality-gate.yml
name: Quality Gate
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
NODE_VERSION: "20"
jobs:
# ── Lint ──
lint:
name: 🔍 Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- run: npm ci
- run: npm run lint -- --max-warnings=0
# ── Type Check ──
typecheck:
name: 🔷 Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- run: npm ci
- run: npx tsc --noEmit
# ── Tests + Coverage ──
test:
name: 🧪 Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- run: npm ci
- name: Run tests with coverage
run: npm run test -- --coverage --coverageReporters=json-summary --coverageReporters=text
- name: Check coverage threshold
run: |
COVERAGE=$(node -e "
const report = require('./coverage/coverage-summary.json');
const { lines, branches, functions, statements } = report.total;
const avg = (lines.pct + branches.pct + functions.pct + statements.pct) / 4;
console.log(Math.round(avg * 100) / 100);
")
echo "Coverage: ${COVERAGE}%"
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "❌ Coverage ${COVERAGE}% is below 80% threshold"
exit 1
fi
echo "✅ Coverage ${COVERAGE}% meets threshold"
- name: Comment coverage on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
const { lines, branches, functions, statements } = report.total;
const body = `## 📊 Coverage Report
| Metric | Coverage |
|--------|----------|
| Lines | ${lines.pct}% |
| Branches | ${branches.pct}% |
| Functions | ${functions.pct}% |
| Statements | ${statements.pct}% |
${lines.pct >= 80 ? '✅' : '❌'} Threshold: 80%`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body,
});
# ── Build ──
build:
name: 📦 Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
- run: npm ci
- run: npm run build
- name: Check build output
run: |
if [ ! -d "dist" ]; then
echo "❌ Build output directory 'dist' not found"
exit 1
fi
echo "✅ Build successful — $(find dist -type f | wc -l) files generated"
# ── Gate ──
quality-gate:
name: ✅ Quality Gate
needs: [lint, typecheck, test, build]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check all jobs
run: |
if [ "${{ needs.lint.result }}" != "success" ] || \
[ "${{ needs.typecheck.result }}" != "success" ] || \
[ "${{ needs.test.result }}" != "success" ] || \
[ "${{ needs.build.result }}" != "success" ]; then
echo "❌ Quality gate failed"
echo " Lint: ${{ needs.lint.result }}"
echo " Types: ${{ needs.typecheck.result }}"
echo " Tests: ${{ needs.test.result }}"
echo " Build: ${{ needs.build.result }}"
exit 1
fi
echo "✅ All quality checks passed!"
Branch Protection Setup
In GitHub repository settings → Branches → Branch protection rules:
- Require status checks before merging
- Add
✅ Quality Gateas a required check - Require branches to be up to date
- Optionally require PR reviews
Usage
# The workflow runs automatically on PRs to main/develop
# No manual setup needed after adding the file
# To test locally before pushing:
npm run lint -- --max-warnings=0
npx tsc --noEmit
npm test -- --coverage
npm run build