| name | github-actions |
| description | GitHub Actions for CI/CD workflows. Use for automated testing, building, and deployment pipelines. |
| allowed-tools | Bash, Read, Edit |
| user-invocable | true |
github-actions
GitHub Actions for CI/CD - automated testing, building, and deployment.
Workflow Basics
Location
.github/workflows/
├── ci.yml
├── deploy.yml
└── release.yml
Basic Structure
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run build
- run: npm test
Triggers
Push/PR
on:
push:
branches: [main, develop]
paths:
- 'src/**'
- 'package.json'
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
Schedule (Cron)
on:
schedule:
- cron: '0 0 * * *'
Manual
on:
workflow_dispatch:
inputs:
environment:
description: 'Deploy environment'
required: true
default: 'staging'
type: choice
options:
- staging
- production
Release
on:
release:
types: [published]
Common Workflows
CI (Test + Build)
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test:coverage
- uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build
path: dist/
Deploy to Vercel
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
Docker Build & Push
name: Docker
on:
push:
branches: [main]
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: meta
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
E2E Tests with Playwright
name: E2E
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run test:e2e
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/
Release with Changelog
name: Release
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate changelog
id: changelog
uses: orhun/git-cliff-action@v3
with:
args: --latest --strip header
- uses: softprops/action-gh-release@v1
with:
body: ${{ steps.changelog.outputs.content }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Matrix Builds
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [18, 20, 22]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
Secrets & Variables
Using Secrets
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
steps:
- run: echo "Deploying to ${{ vars.ENVIRONMENT }}"
Setting via CLI
gh secret set API_KEY --body "secret-value"
gh secret list
gh variable set ENVIRONMENT --body "production"
Caching
npm
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
pnpm
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
Custom Cache
- uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Conditions
steps:
- run: npm run deploy
if: github.ref == 'refs/heads/main'
- run: npm run test
if: github.event_name == 'pull_request'
- run: npm run notify
if: always()
- run: npm run cleanup
if: failure()
- run: npm run report
if: success()
Outputs & Artifacts
Job Outputs
jobs:
build:
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- id: version
run: echo "version=$(cat package.json | jq -r .version)" >> $GITHUB_OUTPUT
deploy:
needs: build
steps:
- run: echo "Deploying version ${{ needs.build.outputs.version }}"
Upload/Download Artifacts
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 7
- uses: actions/download-artifact@v4
with:
name: build-output
path: dist/
Environment Protection
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.com
steps:
- run: npm run deploy
Reusable Workflows
Define (.github/workflows/reusable-build.yml)
name: Reusable Build
on:
workflow_call:
inputs:
node-version:
required: false
type: string
default: '20'
secrets:
NPM_TOKEN:
required: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
- run: npm run build
Use
jobs:
build:
uses: ./.github/workflows/reusable-build.yml
with:
node-version: '20'
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Useful Actions
| Action | Purpose |
|---|
actions/checkout@v4 | Clone repo |
actions/setup-node@v4 | Setup Node.js |
actions/cache@v4 | Cache dependencies |
actions/upload-artifact@v4 | Upload files |
actions/download-artifact@v4 | Download files |
docker/build-push-action@v5 | Build & push Docker |
softprops/action-gh-release@v1 | Create GitHub release |
peaceiris/actions-gh-pages@v4 | Deploy to GitHub Pages |
Debugging
steps:
- run: echo "${{ toJson(github) }}"
- run: npm run build
env:
ACTIONS_STEP_DEBUG: true
Re-run with Debug
gh run rerun <run-id> --debug
Best Practices
- Use specific action versions (
@v4 not @main)
- Cache dependencies for faster builds
- Use matrix for cross-platform testing
- Protect secrets with environments
- Fail fast in PRs, retry in main
- Use reusable workflows to reduce duplication
- Set timeouts to prevent hanging jobs