Claude Code Plugins

Community-maintained marketplace

Feedback

github-workflows

@vinnie357/claude-skills
0
0

Write, configure, and optimize GitHub Actions workflows including syntax, triggers, jobs, contexts, expressions, artifacts, and CI/CD patterns

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name github-workflows
description Write, configure, and optimize GitHub Actions workflows including syntax, triggers, jobs, contexts, expressions, artifacts, and CI/CD patterns

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