Claude
Skills
Sign in
Back

github-workflows

Included with Lifetime
$97 forever

Write and optimize GitHub Actions workflows. Use when creating CI/CD pipelines, configuring workflow triggers, managing artifacts, or debugging workflow runs.

Cloud & DevOps

What this skill does


# 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

```yaml
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

```yaml
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

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

### Schedule (Cron)

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

### Manual Trigger (workflow_dispatch)

```yaml
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

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

## Jobs

### Basic Job Configuration

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
steps:
  - name: Lint (optional)
    continue-on-error: true
    run: npm run lint

  - name: Test (required)
    run: npm test
```

## Environment Variables and Secrets

### Global Variables

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

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

### Job-Level Variables

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

### Step-Level Variables

```yaml
steps:
  - name: Configure
    env:
      CONFIG_PATH: ./config.json
    run: cat $CONFIG_PATH
```

### Using Secrets

```yaml
steps:
  - name: Deploy
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
    run: ./deploy.sh
```

### Setting Variables Between Steps

```yaml
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

```yaml
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

```yaml
env:
  MY_VAR: value

steps:
  - run: echo "${{ env.MY_VAR }}"
```

### job Context

```yaml
steps:
  - name: Job status
    if: job.status == 'success'
    run: echo "Job succeeded"
```

### steps Context

```yaml
steps:
  - id: first-step
    run: echo "output=hello" >> $GITHUB_OUTPUT

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

### runner Context

```yaml
steps:
  - run: |
      echo "OS: ${{ runner.os }}"
      echo "Arch: ${{ runner.arch }}"
      echo "Temp: ${{ runner.temp }}"
```

### matrix Context

```yaml
strategy:
  matrix:
    version: [18, 20]

steps:
  - run: echo "Node ${{ matrix.version }}"
```

## Expressions

### Operators

```yaml
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

```yaml
steps:
  # Status functions
  - if: success()        # Previous steps succeeded
  - if: failure()        # Any previous step 

Related in Cloud & DevOps