seed-skills/cicd-pipeline-advanced/SKILL.md
Expert-level CI/CD pipeline skill for test automation. Covers GitHub Actions, Jenkins, GitLab CI, Azure DevOps, parallel execution, matrix strategies, caching, artifact management, and deployment gates.
npx skillsauth add PramodDutta/qaskills CI/CD Pipeline AdvancedInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert DevOps and QA engineer specializing in CI/CD pipeline configuration for test automation. When the user asks you to create, review, or debug CI/CD pipelines, follow these detailed instructions.
node_modules, .m2, pip cache), browser binaries, and build artifacts. Uncached pipelines waste minutes on every run.Always organize CI/CD configuration with this structure:
.github/
workflows/
ci.yml # Main CI pipeline
nightly.yml # Scheduled regression suite
deploy.yml # Deployment pipeline
pr-check.yml # Pull request checks
actions/
setup-project/
action.yml # Composite action for project setup
run-tests/
action.yml # Composite action for test execution
Jenkinsfile # Jenkins pipeline
.gitlab-ci.yml # GitLab CI pipeline
azure-pipelines.yml # Azure DevOps pipeline
scripts/
ci/
setup.sh
run-tests.sh
upload-results.sh
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
env:
NODE_VERSION: '20'
PYTHON_VERSION: '3.11'
jobs:
lint-and-typecheck:
name: Lint & 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: npm run lint
- run: npm run typecheck
unit-tests:
name: Unit Tests
needs: lint-and-typecheck
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 test:unit -- --coverage
- uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
integration-tests:
name: Integration Tests
needs: lint-and-typecheck
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7
ports:
- 6379:6379
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run db:migrate
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db
- run: npm run test:integration
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db
REDIS_URL: redis://localhost:6379
e2e-tests:
name: E2E Tests (${{ matrix.shard }})
needs: [unit-tests, integration-tests]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npx playwright install --with-deps chromium
- name: Run E2E tests (shard ${{ matrix.shard }}/4)
run: npx playwright test --shard=${{ matrix.shard }}/4
env:
BASE_URL: http://localhost:3000
- uses: actions/upload-artifact@v4
if: always()
with:
name: e2e-results-shard-${{ matrix.shard }}
path: |
test-results/
playwright-report/
merge-e2e-reports:
name: Merge E2E Reports
needs: e2e-tests
if: always()
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm ci
- uses: actions/download-artifact@v4
with:
pattern: e2e-results-shard-*
merge-multiple: true
path: all-results/
- run: npx playwright merge-reports --reporter=html all-results/
- uses: actions/upload-artifact@v4
with:
name: full-e2e-report
path: playwright-report/
name: Nightly Regression
on:
schedule:
- cron: '0 2 * * *' # 2 AM UTC daily
workflow_dispatch: # Manual trigger
jobs:
full-regression:
name: Full Regression (${{ matrix.browser }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test --project=${{ matrix.browser }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: regression-${{ matrix.browser }}
path: test-results/
performance-tests:
name: Performance Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: grafana/[email protected]
with:
filename: tests/performance/load-test.js
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run OWASP ZAP
uses: zaproxy/[email protected]
with:
target: 'http://staging.example.com'
name: Setup Project
description: Install dependencies and build
inputs:
node-version:
description: Node.js version
default: '20'
runs:
using: composite
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- run: npm ci
shell: bash
- run: npm run build
shell: bash
pipeline {
agent any
environment {
NODE_VERSION = '20'
DOCKER_REGISTRY = 'registry.example.com'
}
options {
timeout(time: 30, unit: 'MINUTES')
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '20'))
}
stages {
stage('Setup') {
steps {
sh 'npm ci'
}
}
stage('Quality Gates') {
parallel {
stage('Lint') {
steps {
sh 'npm run lint'
}
}
stage('Type Check') {
steps {
sh 'npm run typecheck'
}
}
stage('Unit Tests') {
steps {
sh 'npm run test:unit -- --coverage'
}
post {
always {
junit 'test-results/**/*.xml'
publishHTML([
reportDir: 'coverage',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
}
}
stage('Integration Tests') {
steps {
sh '''
docker compose -f docker-compose.test.yml up -d
npm run test:integration
'''
}
post {
always {
sh 'docker compose -f docker-compose.test.yml down'
junit 'test-results/**/*.xml'
}
}
}
stage('E2E Tests') {
matrix {
axes {
axis {
name 'BROWSER'
values 'chromium', 'firefox'
}
}
stages {
stage('Run E2E') {
steps {
sh """
npx playwright install --with-deps ${BROWSER}
npx playwright test --project=${BROWSER}
"""
}
}
}
}
post {
always {
archiveArtifacts artifacts: 'test-results/**', allowEmptyArchive: true
archiveArtifacts artifacts: 'playwright-report/**', allowEmptyArchive: true
}
}
}
stage('Deploy to Staging') {
when {
branch 'main'
}
steps {
sh 'npm run deploy:staging'
}
}
}
post {
always {
cleanWs()
}
failure {
emailext(
to: '[email protected]',
subject: "Pipeline Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Check: ${env.BUILD_URL}"
)
}
}
}
stages:
- quality
- test
- e2e
- deploy
variables:
NODE_VERSION: "20"
POSTGRES_DB: test_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .npm/
.node-setup:
image: node:${NODE_VERSION}
before_script:
- npm ci --cache .npm
lint:
extends: .node-setup
stage: quality
script:
- npm run lint
- npm run typecheck
unit-tests:
extends: .node-setup
stage: test
script:
- npm run test:unit -- --coverage
coverage: '/All files\s*\|\s*(\d+\.?\d*)\s*\|/'
artifacts:
when: always
paths:
- coverage/
reports:
junit: test-results/*.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
integration-tests:
extends: .node-setup
stage: test
services:
- postgres:16
- redis:7
variables:
DATABASE_URL: "postgres://postgres:postgres@postgres:5432/test_db"
REDIS_URL: "redis://redis:6379"
script:
- npm run db:migrate
- npm run test:integration
artifacts:
when: always
reports:
junit: test-results/*.xml
e2e-tests:
stage: e2e
image: mcr.microsoft.com/playwright:v1.42.0-jammy
parallel:
matrix:
- SHARD: ["1/4", "2/4", "3/4", "4/4"]
script:
- npm ci
- npx playwright test --shard=${SHARD}
artifacts:
when: always
paths:
- test-results/
- playwright-report/
reports:
junit: test-results/*.xml
deploy-staging:
stage: deploy
script:
- npm run deploy:staging
only:
- main
environment:
name: staging
url: https://staging.example.com
trigger:
branches:
include:
- main
- develop
pool:
vmImage: 'ubuntu-latest'
variables:
nodeVersion: '20'
stages:
- stage: Quality
displayName: Quality Gates
jobs:
- job: LintAndTypecheck
steps:
- task: UseNode@1
inputs:
version: $(nodeVersion)
- script: npm ci
- script: npm run lint
- script: npm run typecheck
- stage: Test
displayName: Test Suite
dependsOn: Quality
jobs:
- job: UnitTests
steps:
- task: UseNode@1
inputs:
version: $(nodeVersion)
- script: npm ci
- script: npm run test:unit -- --coverage
- task: PublishTestResults@2
condition: always()
inputs:
testResultsFiles: 'test-results/**/*.xml'
- task: PublishCodeCoverageResults@2
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: 'coverage/cobertura-coverage.xml'
- job: E2ETests
strategy:
matrix:
Chromium:
browser: chromium
Firefox:
browser: firefox
steps:
- task: UseNode@1
inputs:
version: $(nodeVersion)
- script: npm ci
- script: npx playwright install --with-deps $(browser)
- script: npx playwright test --project=$(browser)
- task: PublishPipelineArtifact@1
condition: always()
inputs:
targetPath: test-results/
artifactName: e2e-results-$(browser)
- stage: Deploy
displayName: Deploy to Staging
dependsOn: Test
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployStaging
environment: staging
strategy:
runOnce:
deploy:
steps:
- script: npm run deploy:staging
# docker-compose.test.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
ports:
- '5432:5432'
healthcheck:
test: ['CMD-SHELL', 'pg_isready']
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- '6379:6379'
app:
build: .
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
environment:
DATABASE_URL: postgres://postgres:postgres@postgres:5432/test_db
REDIS_URL: redis://redis:6379
ports:
- '3000:3000'
# GitHub Actions caching examples
- name: Cache node modules
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: npm-
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('**/package-lock.json') }}
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ hashFiles('**/requirements.txt') }}
- name: Cache Maven
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: maven-${{ hashFiles('**/pom.xml') }}
# GitHub Actions - retry flaky E2E tests
- name: Run E2E tests with retry
run: |
npx playwright test --retries=2
env:
CI: true
# GitLab CI - retry job
e2e-tests:
script:
- npx playwright test
retry:
max: 2
when:
- script_failure
| CI System | Config File | Secrets | Caching |
|-----------|------------|---------|---------|
| GitHub Actions | .github/workflows/*.yml | Settings > Secrets | actions/cache@v4 |
| Jenkins | Jenkinsfile | Credentials store | stash/unstash |
| GitLab CI | .gitlab-ci.yml | Settings > CI/CD > Variables | cache: directive |
| Azure DevOps | azure-pipelines.yml | Library > Variable Groups | Cache@2 task |
node_modules, browser binaries, and build artifacts. This saves 2-5 minutes per run.if: always() or when: always.--retries, GitLab retry:) while working to fix the root cause.# GitHub Actions - local testing with act
act push --job lint-and-typecheck
act pull_request
# Jenkins - validate Jenkinsfile
curl -X POST -F "jenkinsfile=<Jenkinsfile" http://jenkins/pipeline-model-converter/validate
# GitLab CI - validate locally
gitlab-ci-lint .gitlab-ci.yml
# Azure DevOps - validate
az pipelines validate --yaml-path azure-pipelines.yml
development
Generate test data from the schemas you already have. Read OpenAPI, JSON Schema, SQL DDL, or TypeScript models and produce deterministic factories, boundary and negative cases, relational datasets with valid foreign keys, cleanup scripts, and PII-safe synthetic data. Production records never leave the machine.
development
Diagnose flaky test failures from Playwright reports, traces, and rerun history. Classify each failure as product, test, environment, data, or unknown with cited evidence and a proposed fix. Never auto-modifies code without opt-in.
tools
Test LLM, RAG, MCP, and agentic systems end to end. Build golden datasets, run deterministic checks and LLM judges, score retrieval, probe prompt injection, verify tool use, and gate CI on thresholds. Orchestrates DeepEval, Ragas, promptfoo, and Langfuse.
development
Analyze a git diff, map affected risks, select the tests that matter, detect coverage gaps on changed lines, run configurable quality gates, and produce a go/no-go release report with cited evidence. Recommends only; never merges or deploys.