Skip to content
Home / Skills / Devops / CI/CD Pipelines
DE

CI/CD Pipelines

Devops core v1.0.0

CI/CD Pipelines

Overview

Continuous Integration and Continuous Delivery (CI/CD) pipelines automate the build, test, security scan, and deployment process for every code change. A well-designed pipeline ensures that code merging to main is always production-ready, with automated quality gates at each stage. GitHub Actions is the default CI/CD platform for the full-lifecycle pipeline, with artifacts flowing through build → test → scan → publish → deploy stages.


Key Concepts

Pipeline Architecture

┌─────────┐   ┌─────────┐   ┌──────────┐   ┌─────────┐   ┌──────────┐
│  Build   │──▶│  Test    │──▶│ Security │──▶│ Publish │──▶│  Deploy  │
│          │   │         │   │   Scan   │   │         │   │          │
│ compile  │   │ unit    │   │ SAST     │   │ Docker  │   │ staging  │
│ lint     │   │ integ   │   │ SCA      │   │ push    │   │ prod     │
│ format   │   │ e2e     │   │ secrets  │   │ SBOM    │   │ smoke    │
└─────────┘   └─────────┘   └──────────┘   └─────────┘   └──────────┘
   ↓ fail       ↓ fail         ↓ fail          ↓ fail       ↓ fail
   ❌ STOP       ❌ STOP        ❌ STOP          ❌ STOP      🔄 ROLLBACK

Pipeline Triggers

TriggerWhenPipeline Scope
push: mainMerge to mainFull pipeline + deploy
pull_requestPR opened/updatedBuild + test + scan (no deploy)
scheduleCron (nightly)Full test suite + dependency scan
workflow_dispatchManual triggerOn-demand deploy or full run
releaseTag createdBuild + publish + production deploy

Quality Gates

GateToolThresholdBlocks
Compilejavac / tsc0 errorsBuild
LintCheckstyle / ESLint0 warningsBuild
Unit TestsJUnit / Jest100% passTest
CoverageJaCoCo / Istanbul80%+ lineTest
SASTCodeQL / Semgrep0 criticalScan
SCADependabot / Trivy0 critical CVEsScan
Container ScanTrivy0 criticalPublish

Best Practices

  1. Fail fast — Run lint and compile before tests; cheapest checks first
  2. Cache dependencies — Cache Maven/npm/Docker layers for 2-5x speed improvement
  3. Use matrix builds — Test across Java 17/21 and Node 18/20 in parallel
  4. Pin action versions — Use SHA hashes, not tags: actions/checkout@v4actions/checkout@abc123
  5. Store secrets in GitHub Secrets — Never hardcode credentials in workflow files
  6. Use reusable workflows — DRY principle: shared .github/workflows/ called by services
  7. Generate SBOM — Software Bill of Materials for every release
  8. Require PR reviews — Branch protection: 1+ approval + CI pass before merge

Code Examples

✅ Good: Complete GitHub Actions Pipeline

# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  contents: read
  packages: write
  security-events: write

env:
  JAVA_VERSION: '21'
  NODE_VERSION: '20'
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: ${{ env.JAVA_VERSION }}
          distribution: 'temurin'
          cache: 'maven'
      - run: mvn compile -B -q
      - run: mvn checkstyle:check -B

  test:
    needs: build
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_DB: testdb
          POSTGRES_PASSWORD: test
        ports: ['5432:5432']
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: ${{ env.JAVA_VERSION }}
          distribution: 'temurin'
          cache: 'maven'
      - run: mvn verify -B
        env:
          SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/testdb
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results
          path: target/surefire-reports/

  security-scan:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: java
      - uses: github/codeql-action/autobuild@v3
      - uses: github/codeql-action/analyze@v3

  publish:
    needs: [test, security-scan]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v5
        with:
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy-staging:
    needs: publish
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - run: echo "Deploy to staging"
      # Add deployment commands here

❌ Bad: Pipeline Anti-Patterns

# No caching — rebuilds everything from scratch
# No quality gates — deploys even if tests fail
# Secrets in plain text — hardcoded credentials
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@main      # Unpinned version
      - run: mvn package -DskipTests     # Skipping tests
      - run: docker build -t myapp .
      - run: docker push myapp
        env:
          DOCKER_PASSWORD: "hardcoded123"  # NEVER do this

Anti-Patterns

  1. Skip tests in CI-DskipTests defeats the purpose of CI
  2. Unpinned action versions@main can break without warning
  3. No caching — Rebuilding dependencies on every run wastes 2-5 minutes
  4. Manual deployments — If it’s not in the pipeline, it’s not reproducible
  5. Single monolithic job — No parallelism; everything runs serially
  6. No branch protection — Direct push to main without PR or CI

Testing Strategies

  • Pipeline dry runs — Use act to test GitHub Actions locally
  • Matrix testing — Test across JDK and Node versions simultaneously
  • Deployment smoke tests — Health check endpoint after each deploy
  • Pipeline performance — Track build times; alert if >10 minutes

References