github-workflows

Activate when creating, modifying, debugging, or optimizing GitHub Actions workflow files. This skill covers workflow syntax, structure, best practices, and common CI/CD patterns.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "github-workflows" with this command: npx skills add vinnie357/claude-skills/vinnie357-claude-skills-github-workflows

GitHub Workflows

Activate when creating, modifying, debugging, or optimizing GitHub Actions workflow files. This skill covers workflow syntax, structure, best practices, and common CI/CD patterns.

When to Use This Skill

Activate when:

  • Writing .github/workflows/*.yml files

  • Configuring workflow triggers and events

  • Defining jobs, steps, and dependencies

  • Using expressions and contexts

  • Managing secrets and environment variables

  • Implementing CI/CD pipelines

  • Optimizing workflow performance

  • Debugging workflow failures

Workflow File Structure

Basic Anatomy

name: CI # Workflow name (optional)

on: # Trigger events push: branches: [main, develop] pull_request:

env: # Global environment variables NODE_VERSION: '20'

jobs: # Job definitions build: name: Build and Test # Job name (optional) runs-on: ubuntu-latest # Runner environment

steps:
  - name: Checkout code         # Step name (optional)
    uses: actions/checkout@v4   # Use an action

  - name: Run tests
    run: npm test               # Run command

File Location

Workflows must be in .github/workflows/ directory:

.github/ └── workflows/ ├── ci.yml ├── deploy.yml └── release.yml

Trigger Events (on:)

Push Events

on: push: branches: - main - 'release/' # Glob patterns tags: - 'v*' # Version tags paths: - 'src/' # Only when these paths change - '!docs/**' # Ignore docs changes

Pull Request Events

on: pull_request: types: - opened - synchronize # New commits pushed - reopened branches: - main paths-ignore: - '**.md'

Schedule (Cron)

on: schedule: # Every day at 2am UTC - cron: '0 2 * * *' # Every Monday at 9am UTC - cron: '0 9 * * 1'

Manual Trigger (workflow_dispatch)

on: workflow_dispatch: inputs: environment: description: 'Deployment environment' required: true type: choice options: - development - staging - production debug: description: 'Enable debug logging' required: false type: boolean default: false

Multiple Events

on: push: branches: [main] pull_request: workflow_dispatch: schedule: - cron: '0 0 * * 0' # Weekly

Jobs

Basic Job Configuration

jobs: build: name: Build Application runs-on: ubuntu-latest timeout-minutes: 30

steps:
  - uses: actions/checkout@v4
  - run: npm ci
  - run: npm run build

Runner Selection

jobs: test: runs-on: ubuntu-latest # Ubuntu (fastest, most common)

test-macos: runs-on: macos-latest # macOS

test-windows: runs-on: windows-latest # Windows

test-specific: runs-on: ubuntu-22.04 # Specific version

Matrix Strategy

jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] node: [18, 20, 21] exclude: - os: macos-latest node: 18 fail-fast: false # Continue on failure max-parallel: 4 # Concurrent jobs limit

steps:
  - uses: actions/checkout@v4
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node }}
  - run: npm test

Job Dependencies

jobs: build: runs-on: ubuntu-latest steps: - run: npm run build

test: needs: build # Wait for build runs-on: ubuntu-latest steps: - run: npm test

deploy: needs: [build, test] # Wait for multiple jobs runs-on: ubuntu-latest steps: - run: npm run deploy

Conditional Execution

jobs: deploy: if: github.ref == 'refs/heads/main' && github.event_name == 'push' runs-on: ubuntu-latest steps: - run: npm run deploy

notify: if: failure() # Run only if previous jobs failed needs: [build, test] runs-on: ubuntu-latest steps: - run: echo "Build failed"

Steps

Using Actions

steps:

  • name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 # Full history submodules: recursive # Include submodules

  • name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm'

Running Commands

steps:

  • name: Single command run: npm install

  • name: Multi-line script run: | echo "Installing dependencies" npm ci npm run build

  • name: Shell selection shell: bash run: echo "Using bash"

Conditional Steps

steps:

  • name: Run on main branch only if: github.ref == 'refs/heads/main' run: npm run deploy

  • name: Run on PR only if: github.event_name == 'pull_request' run: npm run test:pr

Continue on Error

steps:

  • name: Lint (optional) continue-on-error: true run: npm run lint

  • name: Test (required) run: npm test

Environment Variables and Secrets

Global Variables

env: NODE_ENV: production API_URL: https://api.example.com

jobs: build: runs-on: ubuntu-latest steps: - run: echo $NODE_ENV

Job-Level Variables

jobs: build: env: BUILD_TYPE: release steps: - run: echo $BUILD_TYPE

Step-Level Variables

steps:

  • name: Configure env: CONFIG_PATH: ./config.json run: cat $CONFIG_PATH

Using Secrets

steps:

  • name: Deploy env: API_KEY: ${{ secrets.API_KEY }} DB_PASSWORD: ${{ secrets.DB_PASSWORD }} run: ./deploy.sh

Setting Variables Between Steps

steps:

  • name: Set version id: version run: echo "VERSION=$(cat version.txt)" >> $GITHUB_OUTPUT

  • name: Use version run: echo "Version is ${{ steps.version.outputs.VERSION }}"

Contexts

github Context

steps:

  • name: Context information run: | echo "Repository: ${{ github.repository }}" echo "Branch: ${{ github.ref_name }}" echo "SHA: ${{ github.sha }}" echo "Actor: ${{ github.actor }}" echo "Event: ${{ github.event_name }}" echo "Run ID: ${{ github.run_id }}"

env Context

env: MY_VAR: value

steps:

  • run: echo "${{ env.MY_VAR }}"

job Context

steps:

  • name: Job status if: job.status == 'success' run: echo "Job succeeded"

steps Context

steps:

  • id: first-step run: echo "output=hello" >> $GITHUB_OUTPUT

  • run: echo "${{ steps.first-step.outputs.output }}"

runner Context

steps:

  • run: | echo "OS: ${{ runner.os }}" echo "Arch: ${{ runner.arch }}" echo "Temp: ${{ runner.temp }}"

matrix Context

strategy: matrix: version: [18, 20]

steps:

  • run: echo "Node ${{ matrix.version }}"

Expressions

Operators

steps:

Comparison

  • if: github.ref == 'refs/heads/main'

Logical

  • if: github.event_name == 'push' && github.ref == 'refs/heads/main'
  • if: github.event_name == 'pull_request' || github.event_name == 'push'

Negation

  • if: "!cancelled()"

Contains

  • if: contains(github.event.head_commit.message, '[skip ci]')

StartsWith/EndsWith

  • if: startsWith(github.ref, 'refs/tags/v')
  • if: endsWith(github.ref, '-beta')

Functions

steps:

Status functions

  • if: success() # Previous steps succeeded
  • if: failure() # Any previous step failed
  • if: always() # Always run
  • if: cancelled() # Workflow cancelled

String functions

  • run: echo "${{ format('Hello {0}', github.actor) }}"
  • if: contains(github.event.pull_request.labels.*.name, 'deploy')

JSON functions

  • run: echo '${{ toJSON(github.event) }}'
  • run: echo '${{ fromJSON(env.CONFIG).database.host }}'

Hash function

  • run: echo "${{ hashFiles('**/package-lock.json') }}"

Artifacts

Upload Artifacts

steps:

  • name: Build run: npm run build

  • name: Upload artifacts uses: actions/upload-artifact@v4 with: name: build-files path: | dist/ build/ retention-days: 7 if-no-files-found: error

Download Artifacts

jobs: build: steps: - run: npm run build - uses: actions/upload-artifact@v4 with: name: dist path: dist/

test: needs: build steps: - uses: actions/download-artifact@v4 with: name: dist path: dist/ - run: npm test

Caching

npm Cache

steps:

  • uses: actions/checkout@v4
  • uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm'
  • run: npm ci

Manual Cache

steps:

  • uses: actions/cache@v4 with: path: | ~/.npm node_modules key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node-

Permissions

Repository Token Permissions

permissions: contents: read # Repository content pull-requests: write # PR comments issues: write # Issue creation/comments checks: write # Check runs statuses: write # Commit statuses deployments: write # Deployments packages: write # Package registry

jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4

Job-Level Permissions

jobs: build: permissions: contents: read pull-requests: write steps: - uses: actions/checkout@v4

Concurrency

Prevent Concurrent Runs

concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true # Cancel running workflows

jobs: deploy: runs-on: ubuntu-latest steps: - run: ./deploy.sh

Job-Level Concurrency

jobs: deploy: concurrency: group: deploy-${{ github.ref }} cancel-in-progress: false steps: - run: ./deploy.sh

Reusable Workflows

Define Reusable Workflow

.github/workflows/reusable-test.yml

name: Reusable Test Workflow

on: workflow_call: inputs: node-version: required: true type: string coverage: required: false type: boolean default: false outputs: test-result: description: "Test execution result" value: ${{ jobs.test.outputs.result }} secrets: token: required: true

jobs: test: runs-on: ubuntu-latest outputs: result: ${{ steps.test.outputs.result }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: ${{ inputs.node-version }} - run: npm test id: test

Call Reusable Workflow

jobs: test: uses: ./.github/workflows/reusable-test.yml with: node-version: '20' coverage: true secrets: token: ${{ secrets.GITHUB_TOKEN }}

Common CI/CD Patterns

Node.js CI

name: Node.js CI

on: push: branches: [main] pull_request:

jobs: test: runs-on: ubuntu-latest strategy: matrix: node-version: [18, 20, 21]

steps:
  - uses: actions/checkout@v4
  - uses: actions/setup-node@v4
    with:
      node-version: ${{ matrix.node-version }}
      cache: 'npm'
  - run: npm ci
  - run: npm run lint
  - run: npm test
  - run: npm run build

Docker Build and Push

name: Docker

on: push: branches: [main] tags: ['v*']

jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write

steps:
  - uses: actions/checkout@v4

  - name: Login to GitHub Container Registry
    uses: docker/login-action@v3
    with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}

  - name: Extract metadata
    id: meta
    uses: docker/metadata-action@v5
    with:
      images: ghcr.io/${{ github.repository }}
      tags: |
        type=ref,event=branch
        type=semver,pattern={{version}}

  - name: Build and push
    uses: docker/build-push-action@v5
    with:
      context: .
      push: true
      tags: ${{ steps.meta.outputs.tags }}
      labels: ${{ steps.meta.outputs.labels }}

Deploy on Release

name: Deploy

on: release: types: [published]

jobs: deploy: runs-on: ubuntu-latest environment: name: production url: https://example.com

steps:
  - uses: actions/checkout@v4
  - name: Deploy to production
    env:
      DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
    run: ./deploy.sh

Monorepo with Path Filtering

name: Monorepo CI

on: pull_request: paths: - 'packages/**'

jobs: detect-changes: runs-on: ubuntu-latest outputs: frontend: ${{ steps.filter.outputs.frontend }} backend: ${{ steps.filter.outputs.backend }} steps: - uses: actions/checkout@v4 - uses: dorny/paths-filter@v3 id: filter with: filters: | frontend: - 'packages/frontend/' backend: - 'packages/backend/'

test-frontend: needs: detect-changes if: needs.detect-changes.outputs.frontend == 'true' runs-on: ubuntu-latest steps: - run: npm test --workspace=frontend

test-backend: needs: detect-changes if: needs.detect-changes.outputs.backend == 'true' runs-on: ubuntu-latest steps: - run: npm test --workspace=backend

Debugging Workflows

Enable Debug Logging

Set repository secrets:

  • ACTIONS_RUNNER_DEBUG : true

  • ACTIONS_STEP_DEBUG : true

Debug Steps

steps:

  • name: Debug context run: | echo "Event: ${{ github.event_name }}" echo "Ref: ${{ github.ref }}" echo "SHA: ${{ github.sha }}" echo "Actor: ${{ github.actor }}"

  • name: Dump GitHub context run: echo '${{ toJSON(github) }}'

  • name: Dump runner context run: echo '${{ toJSON(runner) }}'

Tmate Debugging

steps:

  • name: Setup tmate session if: failure() uses: mxschmitt/action-tmate@v3 timeout-minutes: 30

Performance Optimization

Use Caching

  • uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}

Optimize Checkout

  • uses: actions/checkout@v4 with: fetch-depth: 1 # Shallow clone sparse-checkout: | # Partial checkout src/ tests/

Concurrent Jobs

jobs: lint: runs-on: ubuntu-latest steps: - run: npm run lint

test: runs-on: ubuntu-latest steps: - run: npm test

build: needs: [lint, test] # Parallel lint and test runs-on: ubuntu-latest steps: - run: npm run build

Anti-Fabrication Requirements

  • Execute Read tool to verify workflow files exist before claiming structure

  • Use Bash with gh workflow list to confirm actual workflow names before referencing them

  • Execute gh workflow view <workflow> to verify trigger configuration before documenting it

  • Use Glob to find actual workflow files before claiming their presence

  • Execute gh run list to verify actual workflow runs before discussing execution patterns

  • Never claim workflow success rates without actual run history analysis

  • Validate YAML syntax using yamllint or similar tools via Bash before claiming correctness

  • Report actual permission errors from workflow runs, not fabricated authorization issues

  • Execute actual cache operations before claiming cache hit/miss percentages

  • Use Read tool on action.yml files to verify action inputs/outputs before documenting usage

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

github-actions

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

code-review

No summary provided by upstream source.

Repository SourceNeeds Review
General

nushell

No summary provided by upstream source.

Repository SourceNeeds Review