βοΈ GitHub Actions Workflows
GitHub Actions is Maxi's Computers' primary CI/CD automation platform. Workflows are YAML files stored in .github/workflows/ and run on GitHub-hosted or self-hosted runners in response to repository events.
Workflow Syntax
yaml
# .github/workflows/ci.yml
name: CI
on: # Triggers
push:
branches: [main, dev]
pull_request:
branches: [main]
defaults:
run:
shell: bash
jobs:
test:
name: Test Suite
runs-on: ubuntu-latest # GitHub-hosted runner
timeout-minutes: 15 # Kill runaway jobs
permissions:
contents: read
id-token: write # For OIDC / AWS assume role
steps:
- name: Checkout source
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for git blame/changelog
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
NODE_ENV: test
DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
- name: Upload coverage report
uses: codecov/codecov-action@v4
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
Triggers
yaml
# Common trigger patterns
on:
# Push to specific branches
push:
branches: [main, 'release/**']
paths:
- 'src/**' # Only when src changes
- 'package.json'
# PRs targeting main
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
# Manual trigger with inputs
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options: [dev, staging, prod]
image_tag:
description: 'Docker image tag to deploy'
required: true
# Scheduled (cron)
schedule:
- cron: '0 6 * * 1-5' # 6 AM UTC, Mon-Fri
# On release creation
release:
types: [published]
Secrets & Variables
Use OIDC for AWS Prefer OpenID Connect (OIDC) over long-lived AWS access keys in secrets. OIDC tokens are short-lived and scoped to the specific workflow run.
yaml
# OIDC β AWS assume role (no static keys)
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
role-session-name: GitHubActions-${{ github.run_id }}
aws-region: us-east-1
# Reference secrets and variables in steps
- run: |
echo "Deploying to ${{ vars.ENVIRONMENT }}"
echo "Slack webhook: [REDACTED]"
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
APP_VERSION: ${{ github.sha }}
# Mask a dynamically generated value
- run: |
TOKEN=$(generate-token.sh)
echo "::add-mask::$TOKEN"
echo "TOKEN=$TOKEN" >> $GITHUB_ENV
Matrix Builds
yaml
# Run tests across Node versions and OSes
test:
strategy:
fail-fast: false # Don't cancel other matrix jobs on failure
matrix:
node: ['18', '20', '22']
os: [ubuntu-latest, macos-latest]
exclude:
- os: macos-latest # Skip Node 18 on macOS (cost saving)
node: '18'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci && npm test
Dependency Caching
yaml
# Manual cache control
- name: Cache node_modules
uses: actions/cache@v4
id: cache-node
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-
# Docker layer caching
- name: Build and push
uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
push: true
tags: ${{ steps.meta.outputs.tags }}
Reusable Workflows
yaml
# .github/workflows/_deploy.yml (reusable)
on:
workflow_call:
inputs:
environment:
required: true
type: string
image_tag:
required: true
type: string
secrets:
AWS_DEPLOY_ROLE_ARN:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v4
- name: Configure AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
aws-region: us-east-1
- name: Helm deploy
run: |
aws eks update-kubeconfig --name mc-${{ inputs.environment }}-eks
helm upgrade --install mc-api ./charts/api \
--set image.tag=${{ inputs.image_tag }} \
--namespace ${{ inputs.environment }}
# Caller workflow
jobs:
deploy-prod:
uses: ./.github/workflows/_deploy.yml
with:
environment: production
image_tag: ${{ needs.build.outputs.image-tag }}
secrets:
AWS_DEPLOY_ROLE_ARN: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
Environments & Protection Rules
GitHub Environments add protection gates before jobs can run against protected resources:
- Required reviewers β Designated people must approve before deployment proceeds.
- Wait timer β Delay deployment by N minutes (useful for canary monitoring).
- Deployment branches β Restrict which branches can deploy to an environment.
- Environment secrets β Secrets scoped to a specific environment (e.g., prod DB credentials).
Best Practices
- Pin action versions to a full SHA:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683prevents supply-chain attacks. - Set
timeout-minuteson every job to prevent runaway billing. - Use
permissions: {}at the workflow level and grant only what's needed per job. - Cache aggressively β Use
actions/cacheor built-in caching in setup actions. - Fail fast on PRs, not on main β Use
fail-fast: truefor PR checks andfalsefor release pipelines. - Use
concurrencyto cancel in-progress runs when new commits are pushed to the same branch.