name: github-actions description: 'Write and modify GitHub Actions workflows and custom actions. Covers CI/CD, workflow triggers, jobs, steps, secrets, runners, matrix builds, caching, artifacts, environments, and reusable workflows.' allowed-tools: Read Edit Write Grep Glob Bash
GitHub Actions Skill
This skill helps write and modify GitHub Actions workflows and custom actions.
Workflow Basics
Workflows are YAML files stored in .github/workflows/. They define automated processes triggered by events.
Minimal Workflow Structure
name: CI # Optional: Display name
on: push # Trigger event(s)
jobs:
build: # Job ID (must be unique)
runs-on: ubuntu-latest # Runner environment
steps:
- uses: actions/checkout@v5 # Use an action
- run: echo "Hello" # Run a command
Triggers (on:)
Common Events
on: push # Any push
on: [push, pull_request] # Multiple events
on:
push:
branches: [main, 'releases/**'] # Branch filter
paths: ['src/**'] # Path filter
pull_request:
types: [opened, synchronize] # Activity types
workflow_dispatch: # Manual trigger
inputs:
environment:
description: 'Deploy target'
required: true
type: choice
options: [dev, staging, prod]
schedule:
- cron: '0 0 * * *' # Daily at midnight UTC
Key Events Reference
| Event | Use Case |
|-------|----------|
| push | Commits pushed to branches/tags |
| pull_request | PR opened, updated, closed |
| pull_request_target | PR from fork (runs in base context) |
| workflow_dispatch | Manual trigger with inputs |
| workflow_call | Reusable workflow |
| schedule | Cron-based scheduling |
| release | Release published/created |
| workflow_run | After another workflow completes |
Jobs
Job Dependencies and Outputs
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.value }}
steps:
- id: version
run: echo "value=1.0.0" >> "$GITHUB_OUTPUT"
deploy:
needs: build # Depends on build job
runs-on: ubuntu-latest
steps:
- run: echo "Deploying ${{ needs.build.outputs.version }}"
Job Conditions
jobs:
deploy:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
Matrix Strategy
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node: [18, 20]
exclude:
- os: windows-latest
node: 18
include:
- os: ubuntu-latest
node: 20
coverage: true
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
Steps
Using Actions
steps:
- uses: actions/checkout@v5 # Public action (owner/repo@ref)
- uses: actions/checkout@8f4b7f84... # Pin to commit SHA (most secure)
- uses: ./.github/actions/my-action # Local action
- uses: docker://alpine:3.8 # Docker image
Running Commands
steps:
- run: npm install
- run: |
echo "Multi-line"
echo "commands"
shell: bash
working-directory: ./app
Step Conditions
steps:
- run: echo "Always runs"
if: always()
- run: echo "On failure"
if: failure()
- run: echo "Main branch only"
if: github.ref == 'refs/heads/main'
- run: echo "Not cancelled"
if: ${{ !cancelled() }}
Expressions and Contexts
Expression Syntax
Use ${{ expression }} to evaluate expressions. In if: conditions, ${{ }} is optional.
Common Contexts
| Context | Description |
|---------|-------------|
| github.* | Workflow run info (ref, sha, actor, repository) |
| env.* | Environment variables |
| vars.* | Repository/org variables |
| secrets.* | Secrets |
| steps.<id>.outputs.* | Step outputs |
| needs.<job>.outputs.* | Job outputs |
| matrix.* | Matrix values |
| runner.* | Runner info (os, arch) |
Useful Expressions
# Context access
${{ github.event_name }}
${{ github.ref_name }}
${{ github.sha }}
${{ github.actor }}
# Conditionals
${{ github.ref == 'refs/heads/main' }}
${{ contains(github.event.head_commit.message, '[skip ci]') }}
${{ startsWith(github.ref, 'refs/tags/') }}
# Default values
${{ github.head_ref || github.run_id }}
# JSON manipulation
${{ toJSON(github.event) }}
${{ fromJSON(needs.job1.outputs.matrix) }}
Built-in Functions
| Function | Example |
|----------|---------|
| contains(search, item) | contains(github.event.issue.labels.*.name, 'bug') |
| startsWith(str, value) | startsWith(github.ref, 'refs/tags/') |
| endsWith(str, value) | endsWith(github.repository, '-demo') |
| format(str, ...) | format('Hello {0}', github.actor) |
| join(array, sep) | join(matrix.os, ', ') |
| toJSON(value) | toJSON(steps.test.outputs) |
| fromJSON(str) | fromJSON(needs.setup.outputs.matrix) |
| hashFiles(path) | hashFiles('**/package-lock.json') |
Secrets and Variables
Accessing Secrets
steps:
- run: echo "Token: $TOKEN"
env:
TOKEN: ${{ secrets.MY_TOKEN }}
- uses: some-action@v1
with:
api-key: ${{ secrets.API_KEY }}
Environment Variables
env: # Workflow-level
NODE_ENV: production
jobs:
build:
env: # Job-level
CI: true
steps:
- run: echo $MY_VAR
env: # Step-level
MY_VAR: value
Setting Outputs
steps:
- id: set-output
run: echo "result=success" >> "$GITHUB_OUTPUT"
- run: echo "${{ steps.set-output.outputs.result }}"
Runners
Common labels: ubuntu-latest, windows-latest, macos-latest. Self-hosted: runs-on: [self-hosted, linux, x64]. See references/RUNNERS.md for full specs.
Permissions
permissions:
contents: read
pull-requests: write
id-token: write # Required for OIDC
# Or disable all
permissions: {}
Concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Artifacts and Caching
Upload/Download Artifacts
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
- uses: actions/download-artifact@v4
with:
name: build-output
Dependency Caching
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
Environments
jobs:
deploy:
environment:
name: production
url: https://example.com
runs-on: ubuntu-latest
Reusable Workflows
Calling a Reusable Workflow
jobs:
call-workflow:
uses: owner/repo/.github/workflows/reusable.yml@main
with:
input1: value
secrets:
token: ${{ secrets.TOKEN }}
Creating a Reusable Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
token:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to ${{ inputs.environment }}"
env:
TOKEN: ${{ secrets.token }}
Common Patterns
Checkout and Setup
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
Conditional on File Changes
on:
push:
paths:
- 'src/**'
- '!src/**/*.md'
Run on Tag Push
on:
push:
tags:
- 'v*'
Workflow Commands Quick Reference
# Step outputs (use in later steps via steps.<id>.outputs.<name>)
echo "name=value" >> "$GITHUB_OUTPUT"
# Set environment variable for subsequent steps
echo "VAR_NAME=value" >> "$GITHUB_ENV"
# Job summary (supports markdown)
echo "### Build Results :rocket:" >> "$GITHUB_STEP_SUMMARY"
echo "| Test | Status |" >> "$GITHUB_STEP_SUMMARY"
echo "| --- | --- |" >> "$GITHUB_STEP_SUMMARY"
echo "| Unit | Passed |" >> "$GITHUB_STEP_SUMMARY"
# Add to PATH for subsequent steps
echo "/path/to/tool" >> "$GITHUB_PATH"
# Log annotations
echo "::error file=app.js,line=10::Something failed"
echo "::warning::Deprecation notice"
echo "::notice::FYI message"
# Mask a value from logs
echo "::add-mask::$SECRET_VALUE"
See references/WORKFLOW-COMMANDS.md for full details including ::group::, ::debug::, multiline values, and GITHUB_STATE.
Key Limits
| Limit | Value | |-------|-------| | Workflow run time | 35 days | | Job execution time | 6 hours (self-hosted: unlimited) | | Matrix combinations | 256 per workflow | | Concurrent jobs (Free) | 20 (macOS: 5) | | Concurrent jobs (Team/Enterprise) | 60 (macOS: 5) | | Workflow file size | 512 KB | | Caches total per repo | 10 GB | | Artifact retention | 90 days (configurable) | | Log retention | 400 days (configurable to 90) |
See references/LIMITS.md for full limits including API rates and storage quotas.
Troubleshooting
- Workflow not triggering: Check branch/path filters, verify file is in
.github/workflows/ - Permission denied: Add required
permissions:block - Secret not found: Verify secret name matches exactly (case-sensitive)
- Step output empty: Ensure using
>> "$GITHUB_OUTPUT"(not deprecated set-output) - Matrix job failing: Check
exclude/includesyntax and values - Debug logging: Re-run workflow with
ACTIONS_RUNNER_DEBUG: trueorACTIONS_STEP_DEBUG: true
References
Core:
references/WORKFLOW-SYNTAX.md- Full workflow YAML syntaxreferences/EXPRESSIONS.md- Contexts, functions, operatorsreferences/TRIGGERS.md- Event types and filteringreferences/WORKFLOW-COMMANDS.md- GITHUB_OUTPUT, GITHUB_ENV, annotations, job summariesreferences/LIMITS.md- Time limits, quotas, rate limits by plan
Build and deploy:
references/ACTIONS.md- Creating custom actions (JS, Docker, composite)references/RUNNERS.md- Runner specs, self-hosted configurationreferences/PATTERNS.md- Common workflow patternsreferences/LANGUAGE-CI.md- CI setup per language (Node, Python, Java, Go, Rust, Ruby, .NET, Swift)references/PUBLISHING.md- Publish to npm, PyPI, Docker Hub, GHCR, Maven Centralreferences/CLOUD-DEPLOYMENTS.md- Deploy to AWS, Azure, GCP with OIDC
Security and ops:
references/SECURITY.md- Secrets, OIDC (AWS/Azure/GCP), attestations, script injectionreferences/MIGRATION.md- Migrate from Jenkins, Travis CI, CircleCI, GitLab, Azure DevOpsreferences/ENTERPRISE.md- ARC, runner groups, larger runners, billing, private networking
Docker Compose Architect
DevOps
Designs optimized Docker Compose configurations.
Incident Postmortem Writer
DevOps
Writes structured and blameless incident postmortem reports.
Runbook Creator
DevOps
Creates clear operational runbooks for common DevOps procedures.