Skip to main content

Agent Skills Framework Extension

CI/CD Automation Patterns Skill

When to Use This Skill

Use this skill when implementing cicd automation patterns patterns in your codebase.

How to Use This Skill

  1. Review the patterns and examples below
  2. Apply the relevant patterns to your implementation
  3. Follow the best practices outlined in this skill

Pipeline automation, deployment strategies, and artifact management for production-grade continuous delivery.

Core Capabilities

  1. Multi-Stage Pipelines - Build, test, security scan, deploy
  2. Deployment Strategies - Blue-green, canary, rolling updates
  3. Artifact Management - Versioning, caching, distribution
  4. Test Automation - Unit, integration, E2E, load testing
  5. Security Scanning - SAST, DAST, dependency scanning

Pipeline Stage Requirements Matrix

StagePurposeRequired GatesTimeoutRetry
1. CheckoutGet codeNone2 min3x
2. InstallDependenciesCache hit/miss5 min2x
3. LintCode quality0 errors5 min0
4. Type CheckType safety0 errors5 min0
5. Unit TestLogic verification100% pass, >80% coverage10 min0
6. BuildCreate artifactsSuccessful compile10 min2x
7. Integration TestService integration100% pass15 min1x
8. Security ScanVulnerability checkNo critical/high10 min1x
9. E2E TestUser flow validation100% pass20 min1x
10. Docker BuildContainer imageValid image pushed15 min2x
11. Deploy StagingPre-prod validationHealth check pass10 min2x
12. Smoke TestBasic functionalityAll pass5 min1x
13. Deploy ProductionReleaseHealth + canary pass15 min0

Stage Dependencies:

Checkout → Install → [Lint, Type Check, Unit Test] → Build

Integration Test ← Build Artifacts

Security Scan → E2E Test

Docker Build → Deploy Staging

Smoke Test → Deploy Production

Environment-Specific Requirements:

EnvironmentApprovalTest CoverageSecurity GatesRollback
DevelopmentNone60% minimumWarnings onlyN/A
StagingAuto80% minimumNo high severityManual
ProductionManual80%+ enforcedNo critical/highAuto

Deployment Strategy Selection:

StrategyUse WhenRisk LevelRollback SpeedComplexity
RollingStandard updates, low riskLowMinutesLow
Blue-GreenZero-downtime requiredMediumSecondsMedium
CanaryHigh-risk changes, gradual rolloutLowSecondsHigh
Feature FlagA/B testing, gradual exposureVery LowInstantMedium
RecreateDev/test environments onlyHighMinutesLow

Quick Decision: Pipeline Complexity

What's your deployment context?
├── Single developer, no prod → Basic (lint + test + deploy)
├── Small team, staging only → Standard (+ security scan + E2E)
├── Production with SLA → Full (+ canary + rollback + monitoring)
├── Regulated industry → Enterprise (+ compliance gates + audit logs)
└── Microservices → Per-service + integration tests + contract testing

Pipeline Health Checklist:

  • All stages have explicit timeouts
  • Failed tests block deployment (no continue-on-error: true)
  • Security scans run before deployment
  • Artifacts versioned with git SHA
  • Secrets in GitHub Secrets (not in code)
  • Production requires manual approval
  • Rollback tested and documented
  • Cache improves build time by >30%

Production GitHub Actions Pipeline

# .github/workflows/production-cicd.yml
name: Production CI/CD

on:
push:
branches: [main]
pull_request:
branches: [main]
release:
types: [published]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
NODE_VERSION: '18'
PYTHON_VERSION: '3.11'

jobs:
# Stage 1: Code Quality & Security
quality:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for SonarQube

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Type check
run: npm run type-check

- name: Run SonarQube scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high

- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: snyk.sarif

# Stage 2: Build & Test
build-and-test:
runs-on: ubuntu-latest
needs: quality
strategy:
matrix:
node-version: [16, 18, 20]

steps:
- uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Run unit tests
run: npm test -- --coverage

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
flags: unittests-node-${{ matrix.node-version }}

- name: Archive build artifacts
uses: actions/upload-artifact@v4
with:
name: build-node-${{ matrix.node-version }}
path: dist/
retention-days: 5

# Stage 3: Integration Tests
integration-test:
runs-on: ubuntu-latest
needs: build-and-test

services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

redis:
image: redis:7
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-node-${{ env.NODE_VERSION }}
path: dist/

- name: Install dependencies
run: npm ci

- name: Run database migrations
env:
DATABASE_URL: postgresql://postgres:testpass@localhost:5432/testdb
run: npm run migrate:test

- name: Run integration tests
env:
DATABASE_URL: postgresql://postgres:testpass@localhost:5432/testdb
REDIS_URL: redis://localhost:6379
run: npm run test:integration

# Stage 4: E2E Tests
e2e-test:
runs-on: ubuntu-latest
needs: integration-test

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install Playwright
run: npx playwright install --with-deps

- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-node-${{ env.NODE_VERSION }}
path: dist/

- name: Run E2E tests
run: npm run test:e2e

- name: Upload E2E test results
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30

# Stage 5: Build Docker Image
docker-build:
runs-on: ubuntu-latest
needs: [integration-test, e2e-test]
if: github.event_name != 'pull_request'
permissions:
contents: read
packages: write

outputs:
image-digest: ${{ steps.build.outputs.digest }}
image-tag: ${{ steps.meta.outputs.tags }}

steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-

- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ github.sha }}
BUILD_DATE=${{ github.event.head_commit.timestamp }}

- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: spdx-json
output-file: sbom.spdx.json

- name: Scan image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: sarif
output: trivy-results.sarif

- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: trivy-results.sarif

# Stage 6: Deploy to Staging
deploy-staging:
runs-on: ubuntu-latest
needs: docker-build
if: github.ref == 'refs/heads/main'
environment:
name: staging
url: https://staging.example.com

steps:
- uses: actions/checkout@v4

- name: Setup kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.28.0'

- name: Configure kubectl context
run: |
echo "${{ secrets.KUBECONFIG_STAGING }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
kubectl config use-context staging

- name: Update deployment
run: |
kubectl set image deployment/myapp \
myapp=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
-n staging

- name: Wait for rollout
run: |
kubectl rollout status deployment/myapp -n staging --timeout=5m

- name: Run smoke tests
run: |
npm run test:smoke -- --env staging

# Stage 7: Deploy to Production
deploy-production:
runs-on: ubuntu-latest
needs: deploy-staging
if: github.event_name == 'release'
environment:
name: production
url: https://example.com

steps:
- uses: actions/checkout@v4

- name: Setup kubectl
uses: azure/setup-kubectl@v3

- name: Configure kubectl context
run: |
echo "${{ secrets.KUBECONFIG_PRODUCTION }}" | base64 -d > kubeconfig
export KUBECONFIG=kubeconfig
kubectl config use-context production

- name: Canary deployment (10%)
run: |
kubectl apply -f k8s/canary/deployment.yaml
kubectl set image deployment/myapp-canary \
myapp=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
-n production

- name: Monitor canary metrics
run: |
# Wait 5 minutes and check error rates
sleep 300
./scripts/check-canary-health.sh

- name: Full production rollout
if: success()
run: |
kubectl set image deployment/myapp \
myapp=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
-n production
kubectl rollout status deployment/myapp -n production --timeout=10m

- name: Rollback on failure
if: failure()
run: |
kubectl rollout undo deployment/myapp -n production
kubectl delete deployment myapp-canary -n production

- name: Create GitHub deployment
uses: actions/github-script@v7
with:
script: |
await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.sha,
environment: 'production',
auto_merge: false,
required_contexts: []
});

Artifact Versioning & Caching

# .github/workflows/artifact-management.yml
name: Artifact Management

on:
workflow_call:
inputs:
cache-key:
required: true
type: string

jobs:
cache-dependencies:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Cache Node modules
uses: actions/cache@v3
id: cache-node
with:
path: |
node_modules
~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Cache Python packages
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-

- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-

version-artifacts:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.versioning.outputs.version }}
semver: ${{ steps.versioning.outputs.semver }}

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Calculate version
id: versioning
run: |
# Get latest tag
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")

# Calculate next version based on commit messages
if git log $LATEST_TAG..HEAD --pretty=format:%s | grep -q "^feat"; then
# Minor version bump for features
NEXT_VERSION=$(echo $LATEST_TAG | awk -F. '{$2++; print $1"."$2".0"}')
elif git log $LATEST_TAG..HEAD --pretty=format:%s | grep -q "^fix"; then
# Patch version bump for fixes
NEXT_VERSION=$(echo $LATEST_TAG | awk -F. '{$3++; print}')
else
NEXT_VERSION=$LATEST_TAG
fi

# Add build metadata
BUILD_META="+build.${{ github.run_number }}.sha.${GITHUB_SHA:0:7}"
FULL_VERSION="${NEXT_VERSION}${BUILD_META}"

echo "version=$FULL_VERSION" >> $GITHUB_OUTPUT
echo "semver=$NEXT_VERSION" >> $GITHUB_OUTPUT

- name: Create version file
run: |
cat > version.json <<EOF
{
"version": "${{ steps.versioning.outputs.version }}",
"semver": "${{ steps.versioning.outputs.semver }}",
"commit": "${{ github.sha }}",
"build_number": "${{ github.run_number }}",
"build_date": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
"branch": "${{ github.ref_name }}"
}
EOF

- name: Upload version artifact
uses: actions/upload-artifact@v4
with:
name: version-metadata
path: version.json

Deployment Automation Script

# scripts/deploy_automation.py
"""
Production deployment automation with health checks and rollback
"""
import subprocess
import time
import sys
from dataclasses import dataclass
from typing import List, Optional
import requests

@dataclass
class DeploymentConfig:
"""Deployment configuration"""
environment: str
namespace: str
deployment_name: str
image: str
replicas: int
health_check_url: str
rollback_on_failure: bool = True
canary_percentage: Optional[int] = None

class DeploymentAutomation:
"""Kubernetes deployment automation"""

def __init__(self, config: DeploymentConfig):
self.config = config

def deploy(self) -> bool:
"""Execute deployment with health checks"""
print(f"Starting deployment to {self.config.environment}...")

try:
# 1. Apply configuration changes
self._apply_config_changes()

# 2. Update image
self._update_image()

# 3. Wait for rollout
if not self._wait_for_rollout():
raise Exception("Rollout timeout")

# 4. Run health checks
if not self._health_check():
raise Exception("Health check failed")

# 5. Verify traffic
if not self._verify_traffic():
raise Exception("Traffic verification failed")

print("Deployment successful!")
return True

except Exception as e:
print(f"Deployment failed: {e}")

if self.config.rollback_on_failure:
print("Rolling back...")
self._rollback()

return False

def _apply_config_changes(self):
"""Apply ConfigMaps and Secrets"""
manifests = [
f"k8s/{self.config.environment}/configmap.yaml",
f"k8s/{self.config.environment}/secrets.yaml"
]

for manifest in manifests:
subprocess.run(
["kubectl", "apply", "-f", manifest, "-n", self.config.namespace],
check=True
)

def _update_image(self):
"""Update deployment image"""
cmd = [
"kubectl", "set", "image",
f"deployment/{self.config.deployment_name}",
f"{self.config.deployment_name}={self.config.image}",
"-n", self.config.namespace
]

subprocess.run(cmd, check=True)

def _wait_for_rollout(self, timeout: int = 600) -> bool:
"""Wait for rollout to complete"""
cmd = [
"kubectl", "rollout", "status",
f"deployment/{self.config.deployment_name}",
"-n", self.config.namespace,
f"--timeout={timeout}s"
]

result = subprocess.run(cmd)
return result.returncode == 0

def _health_check(self, retries: int = 10, delay: int = 10) -> bool:
"""Verify application health"""
for attempt in range(retries):
try:
response = requests.get(
self.config.health_check_url,
timeout=5
)

if response.status_code == 200:
print("Health check passed")
return True

except requests.RequestException as e:
print(f"Health check attempt {attempt + 1}/{retries} failed: {e}")

time.sleep(delay)

return False

def _verify_traffic(self) -> bool:
"""Verify traffic is being served"""
# Get pod IPs
cmd = [
"kubectl", "get", "pods",
"-l", f"app={self.config.deployment_name}",
"-n", self.config.namespace,
"-o", "jsonpath='{.items[*].status.podIP}'"
]

result = subprocess.run(cmd, capture_output=True, text=True)
pod_ips = result.stdout.strip("'").split()

if not pod_ips:
print("No pods found!")
return False

# Verify each pod is responding
for ip in pod_ips:
try:
response = requests.get(f"http://{ip}:8080/health", timeout=5)
if response.status_code != 200:
return False
except requests.RequestException:
return False

return True

def _rollback(self):
"""Rollback to previous version"""
cmd = [
"kubectl", "rollout", "undo",
f"deployment/{self.config.deployment_name}",
"-n", self.config.namespace
]

subprocess.run(cmd, check=True)
print("Rollback initiated")

# Wait for rollback to complete
self._wait_for_rollout()

# Example usage
if __name__ == "__main__":
config = DeploymentConfig(
environment="production",
namespace="default",
deployment_name="myapp",
image=f"ghcr.io/org/myapp:{sys.argv[1] if len(sys.argv) > 1 else 'latest'}",
replicas=3,
health_check_url="https://myapp.example.com/health",
rollback_on_failure=True
)

automation = DeploymentAutomation(config)
success = automation.deploy()

sys.exit(0 if success else 1)

Usage Examples

Setup Multi-Stage Pipeline

Apply cicd-automation-patterns skill to create GitHub Actions pipeline with quality gates, testing, and deployment

Artifact Versioning

Apply cicd-automation-patterns skill to implement semantic versioning with build metadata

Deployment Automation

Apply cicd-automation-patterns skill to automate Kubernetes deployment with health checks and rollback

Integration Points

  • cloud-infrastructure-patterns - Infrastructure provisioning
  • deployment-strategy-patterns - Deployment strategies
  • binary-distribution-patterns - Artifact distribution

Success Output

When this skill is successfully applied, output:

✅ SKILL COMPLETE: cicd-automation-patterns

Completed:
- [x] Multi-stage CI/CD pipeline configured (build/test/scan/deploy)
- [x] Test automation integrated (unit/integration/e2e)
- [x] Security scanning gates active (SAST/DAST/dependency)
- [x] Docker image build and push configured
- [x] Deployment automation with health checks
- [x] Artifact versioning with semantic versioning
- [x] Rollback capability tested

Outputs:
- .github/workflows/production-cicd.yml (main pipeline)
- .github/workflows/artifact-management.yml (versioning/caching)
- scripts/deploy_automation.py (deployment script)
- Docker image: <registry>/<image>:<version> (pushed to registry)
- Deployment: <environment> (staging/production)
- Build artifacts cached: Yes/No

Completion Checklist

Before marking this skill as complete, verify:

  • All pipeline stages execute successfully
  • Unit tests pass with coverage report uploaded
  • Integration tests run against services (DB, Redis)
  • E2E tests execute in clean environment
  • Security scans complete (SAST, container, dependency)
  • Docker image builds and pushes to registry
  • SBOM generated for container image
  • Deployment to staging successful with health checks
  • Rollback mechanism tested and working
  • Artifact versioning follows semantic versioning
  • Pipeline caching reduces build time (target: 30%+ reduction)
  • Deployment includes smoke tests validation

Failure Indicators

This skill has FAILED if:

  • ❌ Pipeline stages fail with no retry mechanism
  • ❌ Tests skipped or not enforced in CI/CD
  • ❌ Security scans bypassed or ignored
  • ❌ Docker build fails or image not pushed
  • ❌ Deployment succeeds but application not healthy
  • ❌ Rollback not possible or untested
  • ❌ No artifact versioning (always "latest")
  • ❌ Caching not working (rebuilds everything every time)
  • ❌ Secrets exposed in logs or pipeline config
  • ❌ Production deployment with no approval gate

When NOT to Use

Do NOT use this skill when:

  • Simple script deployment sufficient (use deployment-scripts instead)
  • No automated testing in place yet (set up tests first)
  • Single-developer project with no team (CI/CD overhead not worth it)
  • Prototyping phase (defer until pre-production)
  • Legacy system with no containerization (modernize first)
  • No version control (Git required for CI/CD)
  • Infrastructure not ready (provision cloud resources first)
  • No deployment environments (need staging/production separation)

Use alternatives:

  • simple-deployment-scripts - Manual deployment for small projects
  • monorepo-cicd - CI/CD for monorepo structures
  • serverless-cicd - Lambda/Cloud Functions deployment
  • mobile-cicd - iOS/Android app deployment

Anti-Patterns (Avoid)

Anti-PatternProblemSolution
No test gatesBroken code reaches productionMake tests required; fail pipeline on failure
Slow buildsDeveloper friction, delayed feedbackImplement caching, parallel jobs, incremental builds
Hardcoded secretsSecurity vulnerabilityUse GitHub Secrets, environment variables
No rollback planBroken deployments unrecoverableTest rollback in staging, automate via kubectl undo
Direct to productionHigh risk deploymentsDeploy to staging first, use canary/blue-green
Missing health checksDeploy broken applicationsAdd readiness/liveness probes, smoke tests
Ignoring security scansVulnerabilities in productionBlock merges on critical/high severity findings
Manual artifact versioningInconsistent versionsAutomate with git tags, semver, build metadata
No monitoring integrationBlind deploymentsSend deployment events to monitoring (Datadog, New Relic)
One-size-fits-allAll environments same configEnvironment-specific configs (dev/staging/prod)

Principles

This skill embodies CODITECT core principles:

#1 Recycle → Extend → Re-Use → Create

  • Reuse GitHub Actions from marketplace
  • Extend workflow templates for project needs
  • Build upon proven CI/CD patterns

#3 Keep It Simple

  • Start with essential stages (build/test/deploy)
  • Add complexity only when needed (canary after basic works)
  • Clear pipeline structure easy to debug

#4 Shift Left on Security

  • Security scans in CI/CD before deployment
  • Dependency scanning catches CVEs early
  • SBOM generation for supply chain security

#5 Eliminate Ambiguity

  • Explicit stage dependencies (needs: build-and-test)
  • Clear environment specifications (staging vs production)
  • Versioning includes build metadata for traceability

#7 Separation of Concerns

  • Quality gate separate from build stage
  • Security scanning isolated from functional tests
  • Deployment automation decoupled from pipeline definition

#8 No Assumptions

  • Verify tool installation (kubectl, docker)
  • Validate deployment health before marking success
  • Test rollback mechanism in staging

#9 Evidence-Based Decisions

  • Cache effectiveness measured (build time reduction)
  • Test coverage tracked over time
  • Deployment success rate monitored

Full Standard: CODITECT-STANDARD-AUTOMATION.md