`n

GitHub Actions Automation - Complete Guide

Published: September 25, 2024 | Reading time: 21 minutes

GitHub Actions Overview

GitHub Actions automates software development workflows:

GitHub Actions Benefits
# GitHub Actions Benefits
- Automated CI/CD pipelines
- Integrated with GitHub
- Extensive marketplace
- Free for public repositories
- Scalable infrastructure
- Easy workflow creation
- Team collaboration features

Basic Workflow Structure

Workflow Components

Basic Workflow Example
# Basic GitHub Actions Workflow
# .github/workflows/ci.yml

name: CI

# Trigger events
on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

# Environment variables
env:
  NODE_VERSION: '18'
  NPM_CACHE: '~/.npm'

# Jobs
jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Run tests
      run: npm test
      
    - name: Run linting
      run: npm run lint
      
    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage/lcov.info

  build:
    runs-on: ubuntu-latest
    needs: test
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Build application
      run: npm run build
      
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build-files
        path: dist/

Advanced Workflow Patterns

Complex Automation Scenarios

Advanced Workflow Patterns
# Advanced GitHub Actions Patterns

# 1. Matrix Build Strategy
# .github/workflows/matrix-build.yml
name: Matrix Build

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

jobs:
  test-matrix:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [16, 18, 20]
        exclude:
          - os: windows-latest
            node-version: 16
        include:
          - os: ubuntu-latest
            node-version: 21
            experimental: true
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Run tests
      run: npm test
      env:
        EXPERIMENTAL: ${{ matrix.experimental }}

# 2. Conditional Steps
# .github/workflows/conditional.yml
name: Conditional Workflow

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

jobs:
  conditional-test:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      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 unit tests
      if: github.event_name == 'pull_request'
      run: npm run test:unit
      
    - name: Run integration tests
      if: github.ref == 'refs/heads/main'
      run: npm run test:integration
      
    - name: Run e2e tests
      if: github.event_name == 'push' && github.ref == 'refs/heads/main'
      run: npm run test:e2e

# 3. Parallel Jobs with Dependencies
# .github/workflows/parallel.yml
name: Parallel Workflow

on:
  push:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      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 linting
      run: npm run lint
      
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      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
      
  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
    - name: Checkout code
      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: Build application
      run: npm run build
      
    - name: Upload artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build-artifacts
        path: dist/

# 4. Reusable Workflows
# .github/workflows/reusable.yml
name: Reusable Workflow

on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
      test-command:
        required: false
        type: string
        default: 'npm test'
    secrets:
      NPM_TOKEN:
        required: false

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: ${{ inputs.node-version }}
        cache: 'npm'
        registry-url: 'https://registry.npmjs.org'
        
    - name: Install dependencies
      run: npm ci
      env:
        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        
    - name: Run tests
      run: ${{ inputs.test-command }}

# 5. Workflow Dispatch
# .github/workflows/manual.yml
name: Manual Workflow

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

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Deploy to ${{ inputs.environment }}
      run: |
        echo "Deploying to ${{ inputs.environment }}"
        if [ "${{ inputs.version }}" != "" ]; then
          echo "Deploying version ${{ inputs.version }}"
        fi
        # Add deployment commands here

Deployment Automation

CI/CD Pipeline Implementation

Deployment Automation
# Deployment Automation Workflows

# 1. AWS S3 Deployment
# .github/workflows/deploy-s3.yml
name: Deploy to S3

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      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: Build application
      run: npm run build
      
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-1
        
    - name: Deploy to S3
      run: |
        aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete
        
    - name: Invalidate CloudFront
      run: |
        aws cloudfront create-invalidation \
          --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
          --paths "/*"

# 2. Docker Deployment
# .github/workflows/docker-deploy.yml
name: Docker Deployment

on:
  push:
    branches: [ main ]
    tags: [ 'v*' ]

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      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: Extract metadata
      id: meta
      uses: docker/metadata-action@v4
      with:
        images: ${{ secrets.DOCKER_USERNAME }}/my-app
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=semver,pattern={{version}}
          type=semver,pattern={{major}}.{{minor}}
          type=raw,value=latest,enable={{is_default_branch}}
          
    - name: Build and push
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

# 3. Kubernetes Deployment
# .github/workflows/k8s-deploy.yml
name: Kubernetes Deployment

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup kubectl
      uses: azure/setup-kubectl@v3
      with:
        version: 'v1.24.0'
        
    - name: Configure kubectl
      run: |
        echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig
        export KUBECONFIG=kubeconfig
        
    - name: Deploy to Kubernetes
      run: |
        export KUBECONFIG=kubeconfig
        kubectl apply -f k8s/
        
    - name: Wait for deployment
      run: |
        export KUBECONFIG=kubeconfig
        kubectl rollout status deployment/my-app

# 4. Multi-Environment Deployment
# .github/workflows/multi-env-deploy.yml
name: Multi-Environment Deployment

on:
  push:
    branches: [ main, develop ]
  workflow_dispatch:
    inputs:
      environment:
        description: 'Environment to deploy to'
        required: true
        type: choice
        options:
        - staging
        - production

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Determine environment
      id: env
      run: |
        if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
          echo "environment=${{ github.event.inputs.environment }}" >> $GITHUB_OUTPUT
        elif [ "${{ github.ref }}" == "refs/heads/main" ]; then
          echo "environment=production" >> $GITHUB_OUTPUT
        elif [ "${{ github.ref }}" == "refs/heads/develop" ]; then
          echo "environment=staging" >> $GITHUB_OUTPUT
        fi
        
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Build application
      run: npm run build
      env:
        NODE_ENV: ${{ steps.env.outputs.environment }}
        
    - name: Deploy to ${{ steps.env.outputs.environment }}
      run: |
        echo "Deploying to ${{ steps.env.outputs.environment }}"
        # Add deployment commands here

Workflow Optimization

Performance and Efficiency

Workflow Optimization
# Workflow Optimization Techniques

# 1. Caching Dependencies
# .github/workflows/optimized-cache.yml
name: Optimized Cache

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

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'
        
    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: ~/.npm
        key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-node-
          
    - name: Install dependencies
      run: npm ci --prefer-offline --no-audit
      
    - name: Run tests
      run: npm test

# 2. Parallel Job Execution
# .github/workflows/parallel-jobs.yml
name: Parallel Jobs

on:
  push:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      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 linting
      run: npm run lint
      
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      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
      
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      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: Build application
      run: npm run build
      
    - name: Upload artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build-artifacts
        path: dist/

# 3. Conditional Execution
# .github/workflows/conditional-execution.yml
name: Conditional Execution

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

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      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 unit tests
      if: github.event_name == 'pull_request'
      run: npm run test:unit
      
    - name: Run integration tests
      if: github.ref == 'refs/heads/main'
      run: npm run test:integration
      
    - name: Run e2e tests
      if: github.event_name == 'push' && github.ref == 'refs/heads/main'
      run: npm run test:e2e

# 4. Workflow Reuse
# .github/workflows/reusable-workflow.yml
name: Reusable Workflow

on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
      test-command:
        required: false
        type: string
        default: 'npm test'
    secrets:
      NPM_TOKEN:
        required: false

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: ${{ inputs.node-version }}
        cache: 'npm'
        registry-url: 'https://registry.npmjs.org'
        
    - name: Install dependencies
      run: npm ci
      env:
        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        
    - name: Run tests
      run: ${{ inputs.test-command }}

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

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      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: Build application
      run: npm run build
      
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build-artifacts
        path: dist/
        retention-days: 30
        
    - name: Upload test results
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: test-results
        path: test-results/
        retention-days: 7

# 6. Workflow Monitoring
# .github/workflows/monitoring.yml
name: Workflow Monitoring

on:
  workflow_run:
    workflows: ["CI"]
    types: [completed]

jobs:
  notify:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion != 'success' }}
    
    steps:
    - name: Notify on failure
      uses: 8398a7/action-slack@v3
      with:
        status: failure
        text: "Workflow ${{ github.event.workflow_run.name }} failed"
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Security and Secrets

Secure Workflow Implementation

Security Best Practices
# Security and Secrets Management

# 1. Secrets Management
# Repository Settings > Secrets and variables > Actions

# Add secrets:
# - AWS_ACCESS_KEY_ID
# - AWS_SECRET_ACCESS_KEY
# - DOCKER_USERNAME
# - DOCKER_PASSWORD
# - NPM_TOKEN
# - SLACK_WEBHOOK_URL

# 2. Secure Workflow
# .github/workflows/secure-workflow.yml
name: Secure Workflow

on:
  push:
    branches: [ main ]

jobs:
  secure-deploy:
    runs-on: ubuntu-latest
    environment: production
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'
        registry-url: 'https://registry.npmjs.org'
        
    - name: Install dependencies
      run: npm ci
      env:
        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        
    - name: Build application
      run: npm run build
      
    - name: Deploy to AWS
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-1
        
    - name: Deploy to S3
      run: |
        aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete

# 3. Environment Protection
# Repository Settings > Environments > production
# Protection rules:
# - Required reviewers
# - Wait timer
# - Deployment branches

# 4. OIDC Authentication
# .github/workflows/oidc-auth.yml
name: OIDC Authentication

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
      
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v2
      with:
        role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
        aws-region: us-east-1
        
    - name: Deploy to AWS
      run: |
        aws s3 sync dist/ s3://my-bucket --delete

# 5. Secret Scanning
# .github/workflows/secret-scanning.yml
name: Secret Scanning

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

jobs:
  secret-scan:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
      
    - name: Run secret scanning
      uses: trufflesecurity/trufflehog@main
      with:
        path: ./
        base: main
        head: HEAD
        extra_args: --debug --only-verified

# 6. Dependency Scanning
# .github/workflows/dependency-scanning.yml
name: Dependency Scanning

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

jobs:
  dependency-scan:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      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 security audit
      run: npm audit --audit-level moderate
      
    - name: Run dependency check
      uses: dependency-check/Dependency-Check_Action@main
      with:
        project: 'my-project'
        path: '.'
        format: 'JSON'
        out: 'reports'

Best Practices

Workflow Guidelines

Workflow Best Practices

  • Use caching for dependencies
  • Implement proper error handling
  • Use environment protection
  • Keep workflows simple and focused
  • Use reusable workflows
  • Monitor workflow performance
  • Implement security best practices

Common Mistakes

  • Not using caching
  • Exposing secrets in logs
  • Not handling failures gracefully
  • Creating overly complex workflows
  • Not using environment protection
  • Ignoring security best practices
  • Not monitoring workflow performance

Summary

GitHub Actions automation involves several key components:

  • Workflow Structure: Triggers, jobs, steps, environment variables
  • Advanced Patterns: Matrix builds, conditional execution, parallel jobs
  • Deployment Automation: AWS, Docker, Kubernetes, multi-environment
  • Optimization: Caching, parallel execution, artifact management
  • Security: Secrets management, environment protection, scanning
  • Best Practices: Guidelines, common mistakes, performance optimization

Need More Help?

Struggling with GitHub Actions automation or need help implementing effective CI/CD workflows? Our automation experts can help you optimize your GitHub Actions setup.

Get GitHub Actions Help