Implement GitOps workflows with ArgoCD and Flux for automated, declarative Kubernetes...
npx skills add jaredlander/freshbooks-speed --skill "Use specific event"
Install specific skill from multi-skill repository
# Description
'Node.js version'
# SKILL.md
GitHub Actions Workflow Expert
Purpose
Expert GitHub Actions workflow creation and editing. Use when asked to (1) create or modify GitHub Actions workflows (.github/workflows/*.yml), (2) set up CI/CD pipelines, (3) configure automated testing, deployment, or release workflows, (4) troubleshoot workflow syntax or behavior, (5) implement workflow best practices, or when phrases like "GitHub Actions", "CI/CD pipeline", "workflow", "automated deployment", "continuous integration" appear.
Core Principles
1. Workflow Structure
- Place workflows in
.github/workflows/directory - Use clear, descriptive workflow names
- Organize complex workflows with reusable components
- Leverage workflow_call for DRY patterns
- Keep workflows focused and single-purpose when possible
2. Trigger Configuration
# Common trigger patterns
on:
push:
branches: [main, develop]
paths:
- 'src/**'
- '!docs/**' # Exclude paths
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
workflow_dispatch: # Manual trigger
inputs:
environment:
description: 'Deployment environment'
required: true
type: choice
options: [dev, staging, prod]
schedule:
- cron: '0 2 * * *' # Daily at 2 AM UTC
workflow_call: # Reusable workflow
inputs:
config-path:
required: true
type: string
secrets:
token:
required: true
3. Environment and Secrets
env:
# Workflow-level environment variables
NODE_VERSION: '20'
CACHE_KEY_PREFIX: 'npm-cache'
jobs:
deploy:
environment:
name: production
url: https://example.com
env:
# Job-level environment variables
DEPLOYMENT_REGION: us-east-1
steps:
- name: Deploy
env:
# Step-level environment variables (highest precedence)
API_KEY: ${{ secrets.API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Auto-provided
Secret Management:
- Use repository/organization/environment secrets
- Never hardcode sensitive values
- Reference with ${{ secrets.SECRET_NAME }}
- GITHUB_TOKEN is automatically available
- Use environments for deployment protection rules
Job Configuration Best Practices
Concurrency Control
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # Cancel old runs on new push
Matrix Strategies
strategy:
fail-fast: false # Continue other jobs if one fails
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20, 22]
include:
- os: ubuntu-latest
node-version: 20
coverage: true
exclude:
- os: macos-latest
node-version: 18
Conditional Execution
jobs:
test:
if: github.event_name == 'pull_request'
steps:
- name: Run tests
if: success() || failure() # Run even if previous step failed
- name: Deploy
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
Common Workflow Patterns
Node.js CI/CD
name: Node.js CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
- name: Upload coverage
if: matrix.node-version == '20'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Docker Build and Push
name: Docker Build
on:
push:
branches: [main]
tags: ['v*']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
R Package CI
name: R-CMD-check
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
check:
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'devel'}
- {os: macos-latest, r: 'release'}
- {os: windows-latest, r: 'release'}
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
use-public-rspm: true
- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check
- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
Deployment with Environments
name: Deploy
on:
push:
branches: [main]
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/checkout@v4
- name: Deploy to staging
run: ./deploy.sh staging
env:
DEPLOY_KEY: ${{ secrets.STAGING_DEPLOY_KEY }}
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: ./deploy.sh production
env:
DEPLOY_KEY: ${{ secrets.PRODUCTION_DEPLOY_KEY }}
Reusable Workflow
# .github/workflows/reusable-test.yml
name: Reusable Test Workflow
on:
workflow_call:
inputs:
node-version:
required: false
type: string
default: '20'
coverage:
required: false
type: boolean
default: false
secrets:
codecov-token:
required: false
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test
- name: Upload coverage
if: inputs.coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.codecov-token }}
# Usage in another workflow:
# jobs:
# test:
# uses: ./.github/workflows/reusable-test.yml
# with:
# node-version: '22'
# coverage: true
# secrets:
# codecov-token: ${{ secrets.CODECOV_TOKEN }}
Advanced Features
Caching Strategies
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.npm
~/.cache/pip
vendor/bundle
key: ${{ runner.os }}-deps-${{ hashFiles('**/package-lock.json', '**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-deps-
# Action-specific caching (preferred when available)
- uses: actions/setup-node@v4
with:
cache: 'npm' # Handles caching automatically
- uses: actions/setup-python@v5
with:
cache: 'pip'
Artifacts and Outputs
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Get version
id: version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
dist/
build/
retention-days: 7
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: build-artifacts
- name: Deploy version
run: echo "Deploying ${{ needs.build.outputs.version }}"
Composite Actions (Custom Actions)
# .github/actions/setup-environment/action.yml
name: 'Setup Environment'
description: 'Setup common environment for all jobs'
inputs:
node-version:
description: 'Node.js version'
required: false
default: '20'
runs:
using: 'composite'
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- run: npm ci
shell: bash
- run: npm run build
shell: bash
# Usage:
# - uses: ./.github/actions/setup-environment
# with:
# node-version: '22'
Matrix with Dynamic Values
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: |
# Generate matrix dynamically
echo "matrix={\"include\":[{\"env\":\"dev\"},{\"env\":\"staging\"}]}" >> $GITHUB_OUTPUT
deploy:
needs: prepare
strategy:
matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }}
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to ${{ matrix.env }}"
Security Best Practices
1. Permission Management
# Workflow-level (most restrictive)
permissions:
contents: read
pull-requests: write
jobs:
job-with-specific-perms:
permissions:
contents: write
packages: write
2. Pull Request Security
# Use pull_request_target carefully - it has write access
on:
pull_request: # Safer for external contributions
types: [opened, synchronize]
jobs:
test:
runs-on: ubuntu-latest
steps:
# Don't check out untrusted code directly
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
3. Script Injection Prevention
# BAD: Script injection vulnerability
- run: echo "Hello ${{ github.event.issue.title }}"
# GOOD: Use environment variables
- run: echo "Hello $TITLE"
env:
TITLE: ${{ github.event.issue.title }}
4. Third-Party Actions
# Pin to specific SHA for security
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# Or use tags with verification
- uses: actions/checkout@v4
Performance Optimization
1. Reduce Checkout Time
- uses: actions/checkout@v4
with:
fetch-depth: 1 # Shallow clone
sparse-checkout: | # Only checkout needed paths
src/
tests/
2. Parallel Jobs
jobs:
lint:
runs-on: ubuntu-latest
steps: [...]
test:
runs-on: ubuntu-latest
steps: [...]
build:
needs: [lint, test] # Only run after both complete
runs-on: ubuntu-latest
steps: [...]
3. Self-Hosted Runners
jobs:
build:
runs-on: [self-hosted, linux, x64, gpu]
steps: [...]
Debugging and Troubleshooting
Enable Debug Logging
# Set repository secrets:
# ACTIONS_STEP_DEBUG: true
# ACTIONS_RUNNER_DEBUG: true
# Or in workflow:
- name: Debug step
run: |
echo "::debug::This is a debug message"
echo "::warning::This is a warning"
echo "::error::This is an error"
Job Summaries
- name: Generate summary
run: |
echo "### Test Results :rocket:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Tests passed: 42" >> $GITHUB_STEP_SUMMARY
echo "- Coverage: 87%" >> $GITHUB_STEP_SUMMARY
Annotations
- name: Create annotation
run: |
echo "::notice file=app.js,line=1,col=5::This is a notice"
echo "::warning file=app.js,line=10::This is a warning"
echo "::error file=app.js,line=20,col=15::This is an error"
Common Context Variables
# GitHub context
${{ github.repository }} # owner/repo
${{ github.ref }} # refs/heads/main
${{ github.sha }} # commit SHA
${{ github.actor }} # user who triggered
${{ github.event_name }} # push, pull_request, etc.
${{ github.run_id }} # unique run ID
${{ github.run_number }} # sequential run number
# Runner context
${{ runner.os }} # Linux, Windows, macOS
${{ runner.arch }} # X64, ARM64
${{ runner.temp }} # temp directory path
# Job context
${{ job.status }} # success, failure, cancelled
# Steps context
${{ steps.step_id.outputs.name }}
# Needs context (from dependent jobs)
${{ needs.build.outputs.version }}
# Environment files
echo "KEY=value" >> $GITHUB_ENV
echo "name=value" >> $GITHUB_OUTPUT
echo "/custom/path" >> $GITHUB_PATH
Testing Workflows Locally
Use act for local testing:
# Install act
brew install act # macOS
# or download from https://github.com/nektos/act
# Run workflow
act push
act pull_request
act -j test # Run specific job
# Use specific event
act -e event.json
Anti-Patterns to Avoid
- Don't hardcode secrets: Always use
${{ secrets.NAME }} - Don't use
if: always()without thought: Can mask real failures - Don't mix concerns: Keep workflows focused on single purposes
- Avoid deep nesting: Use reusable workflows or composite actions
- Don't ignore caching: Speeds up workflows significantly
- Avoid
checkout@v1: Always use latest stable versions - Don't run untrusted code in pull_request_target without sandboxing
Workflow Templates
Claude Code should offer to create complete, working workflows based on common patterns:
- CI for multiple languages (Node.js, Python, Go, Rust, R, etc.)
- Docker build and push to registries (GitHub, Docker Hub, AWS ECR)
- Deployment workflows (staging/production with approval)
- Release automation (semantic versioning, changelog generation)
- Scheduled tasks (cleanup, backups, reports)
- Monorepo workflows with path filtering
Output Format
When creating workflows:
1. Generate complete, runnable YAML files
2. Include comments explaining complex sections
3. Suggest relevant repository settings (branch protection, environments)
4. Provide example secret configuration instructions
5. Mention any required repository permissions
When editing workflows:
1. Preserve existing structure and comments
2. Explain changes made
3. Highlight potential breaking changes
4. Suggest testing approach (act, workflow_dispatch)
Integration Points
- Posit Products: Deploy R Shiny apps, build R packages, publish to Posit Connect
- Docker: Build and push containers with proper caching
- R/Python: Matrix testing across versions, dependency caching
- Ansible: Deploy infrastructure, run playbooks with secrets
- Kubernetes: Deploy with kubectl, Helm, or Kustomize
- AWS/Azure/GCP: Deploy to cloud platforms with OIDC authentication
Resources
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.