Automate software workflows directly in your GitHub repository with GitHub Actions.
When to Use This Skill
Use this skill when:
- Setting up CI/CD pipelines for GitHub repositories
- Automating build, test, and deployment workflows
- Creating reusable workflow components
- Configuring self-hosted runners
- Managing workflow secrets and variables
- Debugging failed workflow runs
Scope and Fragment Prerequisites
Examples are independent YAML fragments, not a complete deployable pipeline. Each new job needs its own checkout, tool setup, locked dependency installation and artifact transfer; jobs do not share a working directory. Review untrusted event inputs, least-privilege permissions, protected environments and secret exposure before adoption. Image push, deployment and runner registration require authorization.
Prerequisites
- GitHub repository with write access
- Understanding of YAML syntax
- For self-hosted runners: server with Docker (optional)
Workflow File Structure
Workflows are defined in .github/workflows/ directory:
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- run: npm test
Common Triggers
Push and Pull Request
on:
push:
branches: [main]
paths:
- 'src/**'
- 'package.json'
pull_request:
branches: [main]
Scheduled Runs
on:
schedule:
- cron: '0 2 * * *' # Daily at 2 AM UTC
Manual Dispatch
on:
workflow_dispatch:
inputs:
environment:
description: 'Deployment environment'
required: true
default: 'staging'
type: choice
options:
- staging
- production
Job Configuration
Matrix Builds
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22, 24]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm test
Job Dependencies
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: npm run build
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: npm test
deploy:
needs: [build, test]
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
Environment Protection
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- run: ./deploy.sh
Secrets and Variables
Using Secrets
steps:
- name: Deploy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: aws s3 sync ./dist s3://my-bucket
Using Variables
steps:
- name: Build
env:
API_URL: ${{ vars.API_URL }}
run: npm run build
Caching Dependencies
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Artifacts
Upload Artifacts
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 5
Download Artifacts
- uses: actions/download-artifact@v4
with:
name: build-output
path: dist/
Docker Builds
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: user/app:latest
Reusable Workflows
Define Reusable Workflow
# .github/workflows/reusable-deploy.yml
name: Reusable Deploy
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
deploy_key:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- name: Report selected environment
env:
DEPLOY_ENVIRONMENT: ${{ inputs.environment }}
run: printf 'Deploying to %s\n' "$DEPLOY_ENVIRONMENT"
Call Reusable Workflow
jobs:
deploy-staging:
uses: ./.github/workflows/reusable-deploy.yml
with:
environment: staging
secrets:
deploy_key: ${{ secrets.STAGING_KEY }}
Self-Hosted Runners
Register Runner
Use the selected repository's current runner setup instructions. Verify the official release checksum before extracting or executing it, choose the intended architecture, and use a short-lived registration token without printing it. Do not use a historical hardcoded runner version. Treat self-hosted runner access as host code execution: never run untrusted fork PR code on a persistent privileged runner.
Use Self-Hosted Runner
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
Debugging Workflows
Enable Debug Logging
Set repository secrets:
ACTIONS_RUNNER_DEBUG:trueACTIONS_STEP_DEBUG:true
Debug Step
Print only explicitly selected non-secret fields needed for the failure. Full GitHub/job context dumps can reveal tokens and sensitive metadata; do not copy them into logs.
Common Issues
Issue: Workflow Not Triggering
Problem: Workflow doesn't run on push/PR Solution: Check branch filters, path filters, and ensure workflow file is on the default branch
Issue: Permission Denied
Problem: Actions can't push or create PRs
Solution: Configure permissions in workflow or update repository settings
permissions:
contents: write
pull-requests: write
Issue: Cache Not Restoring
Problem: Cache misses despite existing cache Solution: Verify cache key matches exactly, check runner OS
Best Practices
- Pin reviewed third-party actions to full immutable commit SHAs; example tags below describe interfaces, not production trust pins
- Use caching for dependencies to speed up builds
- Minimize secrets exposure with environment scoping
- Use matrix builds for cross-platform testing
- Required tests and security checks must fail the job when they fail. Use
continue-on-erroronly for declared nonblocking advisory checks and report their actual outcome. - Keep workflows DRY with reusable workflows and composite actions
Related Skills
- gitlab-ci (
gitlab-ci) - GitLab CI/CD alternative - docker-management (
docker-management) - Container builds - semantic-versioning (
semantic-versioning) - Automated releases
Limitations
- Guidance executes against real environments: confirm target, blast radius, and rollback plan before applying anything.
- Never deploy to production without explicit approval. Docs-only import: upstream scripts and templates not bundled.
Example
git status && git diff --stat
gh run view <actual-run-id> --log-failed
Adapted from BagelHole/DevOps-Security-Agent-Skills (MIT); frontmatter, When to Use/Limitations, and safety boundaries added for upstream compliance. Docs-only import: helper scripts and templates not bundled.