Claude Code Plugins

Community-maintained marketplace

Feedback

ci-cd-pipeline-patterns

@manutej/luxor-claude-marketplace
6
0

Comprehensive CI/CD pipeline patterns skill covering GitHub Actions, workflows, automation, testing, deployment strategies, and release management for modern software delivery

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name ci-cd-pipeline-patterns
description Comprehensive CI/CD pipeline patterns skill covering GitHub Actions, workflows, automation, testing, deployment strategies, and release management for modern software delivery

CI/CD Pipeline Patterns

A comprehensive skill for designing, implementing, and optimizing CI/CD pipelines using GitHub Actions and modern DevOps practices. Master workflow automation, testing strategies, deployment patterns, and release management for continuous software delivery.

When to Use This Skill

Use this skill when:

  • Setting up continuous integration and deployment pipelines for projects
  • Automating build, test, and deployment workflows
  • Implementing multi-environment deployment strategies (staging, production)
  • Managing release automation and versioning
  • Configuring matrix builds for multi-platform testing
  • Securing CI/CD pipelines with secrets and OIDC
  • Optimizing pipeline performance with caching and parallelization
  • Building containerized applications with Docker in CI
  • Deploying to cloud platforms (AWS, Azure, GCP, Vercel, Netlify)
  • Implementing infrastructure as code with Terraform/CloudFormation
  • Setting up monorepo CI/CD patterns
  • Creating reusable workflow templates and custom actions
  • Implementing deployment strategies (blue-green, canary, rolling)
  • Automating changelog generation and semantic versioning
  • Integrating quality gates and code coverage checks

Core Concepts

CI/CD Fundamentals

Continuous Integration (CI): Automatically building and testing code changes as developers commit to the repository.

Continuous Deployment (CD): Automatically deploying code changes to production after passing tests.

Continuous Delivery: Keeping code in a deployable state, with manual approval for production deployment.

GitHub Actions Architecture

GitHub Actions provides event-driven automation directly integrated with your repository.

Workflows

YAML files in .github/workflows/ that define automated processes:

name: CI Pipeline
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build project
        run: npm run build

Key Components:

  • name: Human-readable workflow name
  • on: Events that trigger the workflow (push, pull_request, schedule, workflow_dispatch)
  • jobs: Collection of steps that run in sequence or parallel
  • runs-on: The runner environment (ubuntu-latest, windows-latest, macos-latest)

Jobs

Groups of steps executed on the same runner:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  deploy:
    needs: test  # Runs after 'test' job completes
    runs-on: ubuntu-latest
    steps:
      - run: npm run deploy

Job Features:

  • needs: Define job dependencies (sequential execution)
  • if: Conditional execution based on expressions
  • strategy: Matrix builds for multiple configurations
  • outputs: Share data between jobs
  • environment: Deployment environments with protection rules

Steps

Individual tasks within a job:

steps:
  - name: Checkout code
    uses: actions/checkout@v4

  - name: Setup Node.js
    uses: actions/setup-node@v4
    with:
      node-version: '20'

  - name: Install dependencies
    run: npm ci

  - name: Run tests
    run: npm test

Step Types:

  • uses: Run a pre-built action from marketplace or repository
  • run: Execute shell commands
  • with: Provide inputs to actions
  • env: Set environment variables for the step

Actions

Reusable units of code that perform specific tasks:

Official Actions:

  • actions/checkout@v4: Check out repository code
  • actions/setup-node@v4: Setup Node.js environment
  • actions/cache@v4: Cache dependencies
  • actions/upload-artifact@v4: Upload build artifacts
  • actions/download-artifact@v4: Download artifacts from previous jobs

Marketplace Actions:

  • docker/build-push-action@v5: Build and push Docker images
  • aws-actions/configure-aws-credentials@v4: Configure AWS credentials
  • codecov/codecov-action@v4: Upload code coverage
  • google-github-actions/auth@v2: Authenticate with Google Cloud

Secrets and Variables

Secrets: Encrypted sensitive data (API keys, credentials, tokens)

steps:
  - name: Deploy to production
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
    run: npm run deploy

Variables: Non-sensitive configuration data

env:
  NODE_ENV: ${{ vars.NODE_ENV }}
  API_ENDPOINT: ${{ vars.API_ENDPOINT }}

Secret Types:

  • Repository secrets: Available to all workflows in a repository
  • Environment secrets: Scoped to specific environments (production, staging)
  • Organization secrets: Shared across repositories in an organization

Artifacts

Files produced by workflows that can be downloaded or used by other jobs:

- name: Upload build artifacts
  uses: actions/upload-artifact@v4
  with:
    name: dist-files
    path: dist/
    retention-days: 7

- name: Download artifacts
  uses: actions/download-artifact@v4
  with:
    name: dist-files
    path: ./dist

Workflow Triggers

Event Triggers

Push Events:

on:
  push:
    branches:
      - main
      - develop
      - 'release/**'
    paths:
      - 'src/**'
      - 'package.json'
    tags:
      - 'v*'

Pull Request Events:

on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches:
      - main
    paths-ignore:
      - 'docs/**'
      - '**.md'

Schedule (Cron):

on:
  schedule:
    - cron: '0 0 * * *'  # Daily at midnight UTC
    - cron: '0 */6 * * *'  # Every 6 hours

Manual Triggers (workflow_dispatch):

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Environment to deploy to'
        required: true
        type: choice
        options:
          - staging
          - production
      version:
        description: 'Version to deploy'
        required: true
        type: string

Release Events:

on:
  release:
    types: [published, created, released]

Workflow Call (Reusable Workflows):

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
    secrets:
      api-key:
        required: true

Matrix Builds

Run jobs across multiple configurations in parallel:

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [18, 20, 22]
        include:
          - os: ubuntu-latest
            node-version: 20
            coverage: true
        exclude:
          - os: macos-latest
            node-version: 18
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm test
      - if: matrix.coverage
        run: npm run coverage

Matrix Features:

  • Parallel execution: All combinations run simultaneously
  • include: Add specific configurations
  • exclude: Remove specific combinations
  • fail-fast: Stop all jobs if one fails (default: true)
  • max-parallel: Limit concurrent jobs

Caching Strategies

Speed up workflows by caching dependencies:

Node.js Caching:

- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'  # Automatically caches npm dependencies

Custom Caching:

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

Docker Layer Caching:

- uses: docker/build-push-action@v5
  with:
    context: .
    cache-from: type=gha
    cache-to: type=gha,mode=max

Testing Strategies in CI

Unit Testing

Fast, isolated tests for individual components:

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

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

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          files: ./coverage/coverage-final.json
          flags: unit-tests
          token: ${{ secrets.CODECOV_TOKEN }}

Integration Testing

Test interactions between components and services:

jobs:
  integration-tests:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
        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
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

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

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

End-to-End Testing

Test complete user workflows:

jobs:
  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Build application
        run: npm run build

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

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

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

Performance Testing

Benchmark and performance regression testing:

jobs:
  performance-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Build for production
        run: npm run build

      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v11
        with:
          urls: |
            http://localhost:3000
            http://localhost:3000/dashboard
          uploadArtifacts: true
          temporaryPublicStorage: true

      - name: Run load tests
        run: npm run test:load

Code Quality and Linting

Enforce code standards and quality gates:

jobs:
  code-quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Run Prettier check
        run: npm run format:check

      - name: Run TypeScript check
        run: npm run type-check

      - name: Run security audit
        run: npm audit --audit-level=moderate

      - name: SonarCloud Scan
        uses: SonarSource/sonarcloud-github-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

Deployment Patterns

Blue-Green Deployment

Zero-downtime deployment by maintaining two identical environments:

jobs:
  deploy-blue-green:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Green environment
        run: |
          # Deploy new version to green environment
          ./deploy.sh green

      - name: Run smoke tests on Green
        run: |
          # Verify green environment is healthy
          curl -f https://green.example.com/health

      - name: Switch traffic to Green
        run: |
          # Update load balancer to point to green
          aws elbv2 modify-rule --rule-arn $RULE_ARN \
            --actions Type=forward,TargetGroupArn=$GREEN_TG

      - name: Monitor Green environment
        run: |
          # Monitor for 5 minutes
          ./monitor.sh green 300

      - name: Rollback if needed
        if: failure()
        run: |
          # Switch back to blue
          aws elbv2 modify-rule --rule-arn $RULE_ARN \
            --actions Type=forward,TargetGroupArn=$BLUE_TG

Canary Deployment

Gradual rollout to a subset of users:

jobs:
  canary-deployment:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy canary (10% traffic)
        run: |
          kubectl set image deployment/app app=myapp:${{ github.sha }}
          kubectl scale deployment/app-canary --replicas=1
          kubectl annotate service app-service \
            traffic-split='{"canary": 10, "stable": 90}'

      - name: Monitor canary metrics
        run: |
          # Monitor error rates, latency for 15 minutes
          ./monitor-canary.sh 900

      - name: Increase canary traffic (50%)
        run: |
          kubectl annotate service app-service \
            traffic-split='{"canary": 50, "stable": 50}' --overwrite

      - name: Monitor again
        run: ./monitor-canary.sh 600

      - name: Full rollout (100%)
        run: |
          kubectl set image deployment/app-stable app=myapp:${{ github.sha }}
          kubectl scale deployment/app-canary --replicas=0

      - name: Rollback canary
        if: failure()
        run: |
          kubectl scale deployment/app-canary --replicas=0

Rolling Deployment

Sequential update of instances:

jobs:
  rolling-deployment:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy with rolling update
        run: |
          kubectl set image deployment/app \
            app=myapp:${{ github.sha }} \
            --record

      - name: Wait for rollout to complete
        run: |
          kubectl rollout status deployment/app --timeout=10m

      - name: Verify deployment
        run: |
          kubectl get pods -l app=myapp
          curl -f https://api.example.com/health

      - name: Rollback on failure
        if: failure()
        run: |
          kubectl rollout undo deployment/app

Multi-Environment Deployment

Deploy to staging, then production with approvals:

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.example.com
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to staging
        run: ./deploy.sh staging

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://example.com
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: ./deploy.sh production

Security Best Practices

Secret Management

Using GitHub Secrets:

steps:
  - name: Configure AWS credentials
    uses: aws-actions/configure-aws-credentials@v4
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      aws-region: us-east-1

Environment-Scoped Secrets:

jobs:
  deploy:
    environment: production  # Uses production-scoped secrets
    steps:
      - name: Deploy
        env:
          API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
        run: ./deploy.sh

OIDC (OpenID Connect)

Authenticate without long-lived credentials:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: us-east-1

      - name: Deploy to AWS
        run: aws s3 sync ./dist s3://my-bucket

Google Cloud OIDC:

- name: Authenticate to Google Cloud
  uses: google-github-actions/auth@v2
  with:
    workload_identity_provider: 'projects/123/locations/global/workloadIdentityPools/pool/providers/provider'
    service_account: 'github-actions@project.iam.gserviceaccount.com'

Secure Workflows

Restrict permissions:

permissions:
  contents: read      # Read repository contents
  pull-requests: write # Comment on PRs
  id-token: write     # OIDC token generation
  actions: read       # Read workflow runs

Pin action versions to SHA:

# Less secure (tag can be moved)
- uses: actions/checkout@v4

# More secure (immutable SHA)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

Prevent script injection:

# Vulnerable to injection
- run: echo "Hello ${{ github.event.issue.title }}"

# Safe approach
- run: echo "Hello $TITLE"
  env:
    TITLE: ${{ github.event.issue.title }}

Docker in CI/CD

Building Docker Images

jobs:
  build-docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

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

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: myorg/myapp
          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
        uses: docker/build-push-action@v5
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Multi-Stage Docker Builds

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
EXPOSE 3000
CMD ["npm", "start"]

Container Scanning

- name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'myorg/myapp:${{ github.sha }}'
    format: 'sarif'
    output: 'trivy-results.sarif'

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

Release Automation

Semantic Versioning

Automatically version releases based on commit messages:

jobs:
  release:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Semantic Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx semantic-release

Configuration (.releaserc.json):

{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/npm",
    "@semantic-release/github",
    ["@semantic-release/git", {
      "assets": ["CHANGELOG.md", "package.json"],
      "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
    }]
  ]
}

Changelog Generation

- name: Generate changelog
  uses: mikepenz/release-changelog-builder-action@v4
  with:
    configuration: '.github/changelog-config.json'
    outputFile: 'CHANGELOG.md'
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create GitHub Release
  uses: ncipollo/release-action@v1
  with:
    tag: ${{ steps.version.outputs.tag }}
    name: Release ${{ steps.version.outputs.tag }}
    bodyFile: 'CHANGELOG.md'
    artifacts: 'dist/*'

Release Notes Automation

- name: Build Release Notes
  id: release_notes
  uses: mikepenz/release-changelog-builder-action@v4
  with:
    configurationJson: |
      {
        "categories": [
          {
            "title": "## 🚀 Features",
            "labels": ["feature", "enhancement"]
          },
          {
            "title": "## 🐛 Fixes",
            "labels": ["bug", "fix"]
          },
          {
            "title": "## 📝 Documentation",
            "labels": ["documentation"]
          }
        ]
      }
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Monorepo CI/CD Patterns

Path-Based Triggers

Run workflows only when specific packages change:

name: Frontend CI
on:
  push:
    paths:
      - 'packages/frontend/**'
      - 'package.json'
      - 'pnpm-lock.yaml'

jobs:
  test-frontend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Test frontend
        run: pnpm --filter frontend test

Affected Package Detection

jobs:
  detect-changes:
    runs-on: ubuntu-latest
    outputs:
      affected: ${{ steps.affected.outputs.packages }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Detect affected packages
        id: affected
        run: |
          # Use tools like Nx or Turborepo to detect changes
          AFFECTED=$(npx nx affected:apps --base=origin/main --plain)
          echo "packages=$AFFECTED" >> $GITHUB_OUTPUT

  test-affected:
    needs: detect-changes
    runs-on: ubuntu-latest
    strategy:
      matrix:
        package: ${{ fromJson(needs.detect-changes.outputs.affected) }}
    steps:
      - uses: actions/checkout@v4
      - name: Test ${{ matrix.package }}
        run: npm run test --workspace=${{ matrix.package }}

Turborepo CI

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: Build with Turborepo
        run: npx turbo build --cache-dir=.turbo

      - name: Cache Turbo
        uses: actions/cache@v4
        with:
          path: .turbo
          key: ${{ runner.os }}-turbo-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-turbo-

Performance Optimization

Parallel Job Execution

jobs:
  # These jobs run in parallel
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run lint

  unit-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run test:unit

  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run build

  # This job waits for all above to complete
  deploy:
    needs: [lint, unit-test, build]
    runs-on: ubuntu-latest
    steps:
      - run: npm run deploy

Conditional Job Execution

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run build

  deploy-staging:
    needs: build
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh staging

  deploy-production:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh production

Dependency Caching

steps:
  # Node.js with npm
  - uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'

  # Python with pip
  - uses: actions/setup-python@v5
    with:
      python-version: '3.11'
      cache: 'pip'

  # Ruby with bundler
  - uses: ruby/setup-ruby@v1
    with:
      ruby-version: '3.2'
      bundler-cache: true

  # Go modules
  - uses: actions/setup-go@v5
    with:
      go-version: '1.21'
      cache: true

Reusable Workflows

Creating Reusable Workflows

# .github/workflows/reusable-deploy.yml
name: Reusable Deploy Workflow

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
      version:
        required: false
        type: string
        default: 'latest'
    secrets:
      deploy-key:
        required: true
    outputs:
      deployment-url:
        description: "URL of the deployment"
        value: ${{ jobs.deploy.outputs.url }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    outputs:
      url: ${{ steps.deploy.outputs.url }}
    steps:
      - uses: actions/checkout@v4

      - name: Deploy
        id: deploy
        env:
          DEPLOY_KEY: ${{ secrets.deploy-key }}
        run: |
          ./deploy.sh ${{ inputs.environment }} ${{ inputs.version }}
          echo "url=https://${{ inputs.environment }}.example.com" >> $GITHUB_OUTPUT

Calling Reusable Workflows

# .github/workflows/main.yml
name: Main Pipeline

on: [push]

jobs:
  deploy-staging:
    uses: ./.github/workflows/reusable-deploy.yml
    with:
      environment: staging
      version: ${{ github.sha }}
    secrets:
      deploy-key: ${{ secrets.STAGING_DEPLOY_KEY }}

  deploy-production:
    needs: deploy-staging
    uses: ./.github/workflows/reusable-deploy.yml
    with:
      environment: production
      version: ${{ github.sha }}
    secrets:
      deploy-key: ${{ secrets.PRODUCTION_DEPLOY_KEY }}

Infrastructure as Code

Terraform Deployment

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.7.0

      - name: Terraform Format
        run: terraform fmt -check

      - name: Terraform Init
        run: terraform init
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Terraform Validate
        run: terraform validate

      - name: Terraform Plan
        run: terraform plan -out=tfplan
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: terraform apply -auto-approve tfplan
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

AWS CloudFormation

jobs:
  deploy-cloudformation:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Deploy CloudFormation stack
        run: |
          aws cloudformation deploy \
            --template-file infrastructure/template.yml \
            --stack-name my-app-stack \
            --parameter-overrides \
              Environment=production \
              Version=${{ github.sha }} \
            --capabilities CAPABILITY_IAM

Best Practices

Workflow Organization

  1. Separate concerns: Different workflows for CI, CD, and scheduled tasks
  2. Use descriptive names: Clear workflow and job names
  3. Organize with directories: Group related workflows
  4. Version control: Track workflow changes like code

Efficiency

  1. Cache dependencies: Reduce build times significantly
  2. Parallel execution: Run independent jobs simultaneously
  3. Conditional runs: Skip unnecessary jobs
  4. Matrix strategies: Test multiple configurations efficiently
  5. Artifact reuse: Share build outputs between jobs

Security

  1. Minimize permissions: Use least-privilege principle
  2. Use OIDC: Avoid long-lived credentials
  3. Secret rotation: Regularly update secrets
  4. Pin dependencies: Use specific versions or SHAs
  5. Scan for vulnerabilities: Automated security checks

Reliability

  1. Timeout settings: Prevent hanging jobs
  2. Retry logic: Handle transient failures
  3. Failure notifications: Alert on critical failures
  4. Rollback mechanisms: Quick recovery from failed deployments
  5. Health checks: Verify deployments before marking complete

Observability

  1. Detailed logging: Clear, actionable logs
  2. Status checks: Prevent merging failing builds
  3. Deployment tracking: Know what's deployed where
  4. Metrics collection: Track pipeline performance
  5. Audit trails: Track who deployed what and when

Failure Handling

Retry Failed Steps

steps:
  - name: Deploy with retry
    uses: nick-fields/retry-action@v2
    with:
      timeout_minutes: 10
      max_attempts: 3
      retry_wait_seconds: 30
      command: npm run deploy

Continue on Error

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Run optional check
        continue-on-error: true
        run: npm run optional-check

      - name: Run required tests
        run: npm test

Conditional Cleanup

steps:
  - name: Deploy
    id: deploy
    run: ./deploy.sh

  - name: Rollback on failure
    if: failure() && steps.deploy.conclusion == 'failure'
    run: ./rollback.sh

  - name: Cleanup
    if: always()
    run: ./cleanup.sh

Advanced Patterns

Dynamic Matrix Generation

jobs:
  generate-matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - uses: actions/checkout@v4
      - id: set-matrix
        run: |
          # Generate matrix based on project structure
          MATRIX=$(find packages -maxdepth 1 -type d -not -name packages | \
            jq -R -s -c 'split("\n")[:-1]')
          echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

  test:
    needs: generate-matrix
    runs-on: ubuntu-latest
    strategy:
      matrix:
        package: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
    steps:
      - uses: actions/checkout@v4
      - run: npm test --workspace=${{ matrix.package }}

Composite Actions

Create reusable action combinations:

# .github/actions/setup-project/action.yml
name: 'Setup Project'
description: 'Setup Node.js and install dependencies'
inputs:
  node-version:
    description: 'Node.js version'
    required: false
    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

Usage:

steps:
  - uses: actions/checkout@v4
  - uses: ./.github/actions/setup-project
    with:
      node-version: '20'

Self-Hosted Runners

jobs:
  deploy:
    runs-on: [self-hosted, linux, production]
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: ./deploy.sh

Benefits:

  • Custom hardware/software requirements
  • Faster builds (pre-cached dependencies)
  • Access to internal networks
  • Cost savings for high-volume CI/CD

Platform-Specific Deployments

Vercel Deployment

jobs:
  deploy-vercel:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

Netlify Deployment

jobs:
  deploy-netlify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build
        run: npm run build

      - name: Deploy to Netlify
        uses: nwtgck/actions-netlify@v3
        with:
          publish-dir: './dist'
          production-branch: main
          github-token: ${{ secrets.GITHUB_TOKEN }}
          deploy-message: 'Deploy from GitHub Actions'
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

AWS ECS Deployment

jobs:
  deploy-ecs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push Docker image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: my-app
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

      - name: Update ECS service
        run: |
          aws ecs update-service \
            --cluster my-cluster \
            --service my-service \
            --force-new-deployment

Kubernetes Deployment

jobs:
  deploy-k8s:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

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

      - name: Configure kubeconfig
        run: |
          echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig.yml
          echo "KUBECONFIG=$(pwd)/kubeconfig.yml" >> $GITHUB_ENV

      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/myapp \
            myapp=myregistry/myapp:${{ github.sha }}
          kubectl rollout status deployment/myapp

Skill Version: 1.0.0 Last Updated: October 2025 Skill Category: DevOps, CI/CD, Automation, Deployment Compatible With: GitHub Actions, Docker, Kubernetes, AWS, Azure, GCP, Vercel, Netlify