GitHub Actions Core Knowledge
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: github-actions for comprehensive documentation.
Basic CI Workflow
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
- name: Build
run: npm run build
With Database
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: testdb
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgresql://test:test@localhost:5432/testdb
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx prisma migrate deploy
- run: npm test
Deploy Workflow
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
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'
Matrix Strategy
jobs:
test:
strategy:
matrix:
node: [18, 20, 22]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
Reusable Workflows
# .github/workflows/test.yml
on:
workflow_call:
jobs:
test:
runs-on: ubuntu-latest
steps: [...]
# Usage in another workflow
jobs:
call-tests:
uses: ./.github/workflows/test.yml
When NOT to Use This Skill
Skip this skill when:
- Using GitLab CI/CD (.gitlab-ci.yml) - different syntax
- Using Jenkins, CircleCI, Travis CI - different platforms
- Setting up local development environments - use
docker-compose skill - Building Docker images only (no CI needed) - use
docker skill - Working with Bitbucket Pipelines - different platform
Anti-Patterns
| Anti-Pattern | Problem | Solution |
|---|
| No permission restrictions | Security risk, excessive access | Set minimal permissions: per job |
Using action tags like @v1 | Breaking changes on updates | Pin to SHA: @60edb5dd545a775178f52524783378180af0d1f8 |
| Secrets in logs | Credential exposure | Never echo secrets, use env: only |
| No timeout set | Runaway jobs consuming minutes | Set timeout-minutes: 15 on jobs |
| Caching nothing | Slow builds, wasted time | Cache dependencies with actions/cache |
| Running on every commit | Wasted CI minutes | Use paths: filters or pull_request: only |
| Hardcoded versions | Inconsistent environments | Use matrix strategy or env vars |
| No artifact retention limit | High storage costs | Set retention-days: 7 on artifacts |
| Storing secrets in code | Security breach | Use GitHub Secrets, never commit |
| No branch protection | Bypassing CI checks | Require status checks in branch rules |
Quick Troubleshooting
| Issue | Diagnosis | Fix |
|---|
| Workflow doesn't trigger | Wrong event, branch filter | Check on: triggers and branch names |
| Job fails silently | Script errors ignored | Don't use ` |
| Cache never hits | Cache key changing | Use stable keys: hashFiles('**/package-lock.json') |
| "Resource not accessible" | Wrong permissions | Add required permissions: to job |
| Secrets not available in PR | Forks don't have access | Use pull_request_target (carefully) or skip secret steps |
| Artifact upload fails | Path doesn't exist | Check build output path, use if: always() |
| Matrix job failures | One config fails all | Use fail-fast: false to continue other jobs |
| Workflow takes too long | No caching, sequential jobs | Add caching, parallelize with needs: |
| "Context access might be invalid" | Wrong context syntax | Use ${{}} syntax, check context availability |
| Can't trigger another workflow | No token permission | Use PAT or GITHUB_TOKEN with write permissions |
Production Readiness
Security Best Practices
# Secure workflow
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
# Pin actions to SHA for security
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: '20'
# Use environment secrets
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
run: |
# Never echo secrets
./deploy.sh
Caching Strategy
jobs:
build:
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
# Custom caching
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# Turbo cache for monorepos
- name: Cache Turbo
uses: actions/cache@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-
Artifact Management
jobs:
build:
steps:
- name: Build
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-${{ github.sha }}
path: dist/
retention-days: 7
deploy:
needs: build
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: build-${{ github.sha }}
path: dist/
Environment Protection
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
deploy-production:
runs-on: ubuntu-latest
needs: deploy-staging
environment:
name: production
url: https://example.com
concurrency:
group: production-deploy
cancel-in-progress: false
Error Handling
jobs:
build:
steps:
- name: Run tests
id: tests
continue-on-error: true
run: npm test
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: coverage/
- name: Check test status
if: steps.tests.outcome == 'failure'
run: |
echo "Tests failed"
exit 1
- name: Notify on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{"text": "Build failed: ${{ github.repository }}"}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Dependabot Configuration
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
groups:
development-dependencies:
patterns:
- "@types/*"
- "eslint*"
- "prettier*"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
Release Workflow
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Build
run: npm run build
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true
Monitoring Metrics
| Metric | Target |
|---|
| Build success rate | > 95% |
| Build duration | < 10min |
| Cache hit rate | > 80% |
| Deployment frequency | As needed |
Checklist
- Minimal permissions declared
- Actions pinned to SHA
- Secrets not exposed in logs
- Caching configured
- Timeouts set
- Error notifications
- Environment protection rules
- Dependabot enabled
- Branch protection rules
- Concurrency controls
Reference Documentation