Skip to content
All essays
CraftJanuary 25, 202513 min

CI/CD Pipelines with GitHub Actions: Automated Workflows

Build automated CI/CD pipelines with GitHub Actions. Learn testing, building, deploying, and best practices.

Ü
Ümit Uz
Mobile & Full Stack Developer

What is CI/CD?

  • CI (Continuous Integration): Automate testing and integration
  • CD (Continuous Deployment): Automate deployment to production

GitHub Actions Basics

Workflow File

yaml
# .github/workflows/ci.yml
name: CI

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

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run tests
      run: npm test

    - name: Build
      run: npm run build

Testing Pipeline

yaml
name: Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x, 18.x, 20.x]
        os: [ubuntu-latest, windows-latest, macos-latest]

    steps:
    - uses: actions/checkout@v3

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}

    - name: Install dependencies
      run: npm ci

    - name: Run linter
      run: npm run lint

    - name: Run tests
      run: npm test

    - name: Generate coverage
      run: npm run test:coverage

    - name: Upload coverage
      uses: codecov/codecov-action@v3

Build and Push Docker Image

yaml
name: Docker

on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

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

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

    - name: Build and push
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: |
          myapp:latest
          myapp:${{ github.ref_name }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

Deploy to Production

yaml
name: Deploy

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    steps:
    - uses: actions/checkout@v3

    - name: Deploy to server
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ${{ secrets.SERVER_USER }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          cd /var/www/myapp
          git pull origin main
          npm ci --production
          npm run build
          pm2 restart myapp

Environment Variables

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      NODE_ENV: production
      API_URL: ${{ secrets.API_URL }}

    steps:
    - name: Run with env vars
      run: npm run build
      env:
        CUSTOM_VAR: ${{ secrets.CUSTOM_VAR }}

Caching

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

Parallel Jobs

yaml
jobs:
  test:
    runs-on: ubuntu-latest
    steps: [...]

  build:
    runs-on: ubuntu-latest
    needs: test
    steps: [...]

  deploy:
    runs-on: ubuntu-latest
    needs: [test, build]
    steps: [...]

Matrix Strategy

yaml
strategy:
  matrix:
    node: [16, 18, 20]
    os: [ubuntu-latest, windows-latest]
    include:
      - os: ubuntu-latest
        node: 18
        experimental: true
    exclude:
      - os: windows-latest
        node: 16

Secrets Management

bash
# Add secret via GitHub UI
Settings Secrets Actions New repository secret

# Use in workflow
${{ secrets.MY_SECRET }}

Best Practices

  1. 1Use specific versions: Avoid @latest tags
  2. 2Cache dependencies: Speed up workflows
  3. 3Use matrix strategy: Test across multiple versions
  4. 4Separate workflows: CI and CD in different files
  5. 5Monitor failures: Get notifications for failed runs
  6. 6Use environments: Separate staging and production
  7. 7Keep secrets secure: Never log sensitive data

Conclusion

GitHub Actions provides powerful automation for CI/CD. Start simple and expand as needed.

Related essays

Next essay
Kubernetes from Beginner to Pro: Container Orchestration