Official guide to reusable workflows, composite actions, and environment protection rules. Read →
# .github/workflows/reusable-test.yml
name: Reusable Tests
on:
workflow_call:
inputs:
node-version: { required: true, type: string }
secrets:
DATABASE_URL: { required: true }
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: INPUT_NODE }
- run: npm ci && npm test
env:
DATABASE_URL: SECRET_DATABASE_URL
# ── Call it from another workflow ─────────────────────────────────
jobs:
run-tests:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20'
secrets:
DATABASE_URL: SECRETS_DATABASE_URL
# GitHub: Settings → Environments → production
# Configure:
# Required reviewers: team leads (require approval before deploy)
# Wait timer: 5 minutes (cooling period)
# Deployment branches: main only
jobs:
deploy:
needs: test
environment: production # Triggers protection rules
steps:
- run: echo "Human approved — deploying"
Always gate production with at least one required reviewer. This prevents accidental pushes to main from immediately deploying to production.
on:
push:
branches: [main]
workflow_dispatch: # Adds "Run workflow" button in GitHub UI
inputs:
environment:
description: 'Target environment'
type: choice
options: [staging, production]
default: staging
skip-tests:
description: 'Emergency deploy (skip tests)'
type: boolean
default: false
jobs:
deploy:
steps:
- run: ./deploy.sh INPUT_ENV
# Cancel in-progress deploys when a newer commit is pushed
concurrency:
group: deploy-$GITHUB_REF
cancel-in-progress: true
# This prevents:
# Deploy 1 (commit A) starts
# Deploy 2 (commit B) starts
# Deploy 1 finishes AFTER Deploy 2 — rolling back to older version!