by thetestingacademy
Teach agents to define and enforce CI quality gates for diff coverage, flaky tests, performance budgets, security thresholds, and regression health.
npx @qaskills/cli add quality-gates-ciAuto-detects your AI agent and installs the skill. Works with Claude Code, Cursor, Copilot, and more.
You are a CI quality architect who turns quality expectations into pass or fail gates for code coverage, regression health, flake budgets, performance budgets, security thresholds, and review discipline.
Create a CI quality directory.
mkdir -p ci/quality-gates ci/reports scripts
touch ci/quality-gates/policy.json
touch scripts/check-quality-gates.sh
chmod +x scripts/check-quality-gates.sh
Define a policy file.
{
"diffCoverage": 80,
"flakeRate": 2,
"maxHighSecurityFindings": 0,
"maxCriticalSecurityFindings": 0,
"maxLcpMs": 2500,
"maxBundleKb": 300
}
Use one wrapper to make gate behavior consistent.
#!/usr/bin/env bash
set -euo pipefail
echo "Running quality gates"
npm run lint
npm run test:unit -- --coverage
npm run test:e2e -- --reporter=line
npm run security:scan
npm run perf:budget
echo "Quality gates passed"
Require new or changed code to meet a threshold.
// ci/quality-gates/check-diff-coverage.ts
type CoverageSummary = {
changedLines: number;
coveredChangedLines: number;
};
export function diffCoveragePercent(summary: CoverageSummary): number {
if (summary.changedLines === 0) return 100;
return Math.round((summary.coveredChangedLines / summary.changedLines) * 10000) / 100;
}
export function assertDiffCoverage(summary: CoverageSummary, threshold: number): void {
const percent = diffCoveragePercent(summary);
if (percent < threshold) {
throw new Error(`Diff coverage ${percent}% is below ${threshold}%`);
}
}
assertDiffCoverage({ changedLines: 20, coveredChangedLines: 18 }, 80);
Track flaky tests as a first-class signal.
// ci/quality-gates/check-flake-budget.ts
type TestAttempt = {
testId: string;
attempt: number;
status: 'passed' | 'failed';
};
export function calculateFlakeRate(attempts: TestAttempt[]): number {
const byTest = new Map<string, TestAttempt[]>();
for (const attempt of attempts) {
byTest.set(attempt.testId, [...(byTest.get(attempt.testId) || []), attempt]);
}
const flaky = [...byTest.values()].filter((items) => {
const statuses = new Set(items.map((item) => item.status));
return statuses.has('passed') && statuses.has('failed');
}).length;
return Math.round((flaky / Math.max(byTest.size, 1)) * 10000) / 100;
}
Run gates in parallel where possible, then require the aggregate result.
name: quality-gates
on:
pull_request:
jobs:
gates:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: bash scripts/check-quality-gates.sh
- uses: actions/upload-artifact@v4
if: always()
with:
name: quality-gate-reports
path: ci/reports
| Gate | Pass | Fail | Evidence |
|---|---|---|---|
| Lint | No errors | Any error | Lint log |
| Unit tests | Required suites pass | Confirmed failure | Coverage report |
| Diff coverage | At or above threshold | Below threshold | Coverage diff |
| E2E smoke | Critical paths pass | Any critical fail | Playwright report |
| Flake budget | Under budget | Over budget | Retry history |
| Security | No high or critical | High or critical | Scanner report |
| Performance | Within budget | Budget exceeded | Trace or metrics |
- name: Install QA Skills
run: npx @qaskills/cli add quality-gates-ci12 of 29 agents supported
Build AI agents that write, run, and fix tests. Playwright, LLM evals, and CI in one live cohort.
Use code AITESTER at checkout