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