andrewneilson

github-actions

0
0
# Install this skill:
npx skills add andrewneilson/github-actions-skill

Or install specific skill: npx add-skill https://github.com/andrewneilson/github-actions-skill

# Description

Write and modify GitHub Actions workflows and custom actions. Use when working with .github/workflows files, CI/CD pipelines, workflow triggers, jobs, steps, secrets, runners, or creating custom actions. Covers workflow syntax, expressions, contexts, events, and deployment.

# SKILL.md


name: github-actions
description: Write and modify GitHub Actions workflows and custom actions. Use when working with .github/workflows files, CI/CD pipelines, workflow triggers, jobs, steps, secrets, runners, or creating custom actions. Covers workflow syntax, expressions, contexts, events, and deployment.
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

GitHub-Hosted Runners

Label OS CPUs RAM
ubuntu-latest Ubuntu 24.04 4 (public) / 2 (private) 16GB / 7GB
windows-latest Windows Server 2025 4 / 2 16GB / 7GB
macos-latest macOS 15 (arm64) 3 7GB

Self-Hosted Runners

runs-on: [self-hosted, linux, x64]

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

OIDC Authentication (AWS)

permissions:
  id-token: write
  contents: read

steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789:role/my-role
      aws-region: us-east-1

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*'

Troubleshooting

  1. Workflow not triggering: Check branch/path filters, verify file is in .github/workflows/
  2. Permission denied: Add required permissions: block
  3. Secret not found: Verify secret name matches exactly (case-sensitive)
  4. Step output empty: Ensure using >> "$GITHUB_OUTPUT" (not deprecated set-output)
  5. Matrix job failing: Check exclude/include syntax and values

References

For detailed information, see:
- references/WORKFLOW-SYNTAX.md - Full workflow syntax reference
- references/EXPRESSIONS.md - Contexts and functions
- references/TRIGGERS.md - Event details and filtering
- references/ACTIONS.md - Creating custom actions
- references/SECURITY.md - Secrets, OIDC, security practices
- references/RUNNERS.md - Runner configuration
- references/PATTERNS.md - AWS deployment and language patterns

# README.md


name: github-actions
description: Write and modify GitHub Actions workflows and custom actions. Use when working with .github/workflows files, CI/CD pipelines, workflow triggers, jobs, steps, secrets, runners, or creating custom actions. Covers workflow syntax, expressions, contexts, events, and deployment.
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

GitHub-Hosted Runners

Label OS CPUs RAM
ubuntu-latest Ubuntu 24.04 4 (public) / 2 (private) 16GB / 7GB
windows-latest Windows Server 2025 4 / 2 16GB / 7GB
macos-latest macOS 15 (arm64) 3 7GB

Self-Hosted Runners

runs-on: [self-hosted, linux, x64]

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

OIDC Authentication (AWS)

permissions:
  id-token: write
  contents: read

steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789:role/my-role
      aws-region: us-east-1

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*'

Troubleshooting

  1. Workflow not triggering: Check branch/path filters, verify file is in .github/workflows/
  2. Permission denied: Add required permissions: block
  3. Secret not found: Verify secret name matches exactly (case-sensitive)
  4. Step output empty: Ensure using >> "$GITHUB_OUTPUT" (not deprecated set-output)
  5. Matrix job failing: Check exclude/include syntax and values

References

For detailed information, see:
- references/WORKFLOW-SYNTAX.md - Full workflow syntax reference
- references/EXPRESSIONS.md - Contexts and functions
- references/TRIGGERS.md - Event details and filtering
- references/ACTIONS.md - Creating custom actions
- references/SECURITY.md - Secrets, OIDC, security practices
- references/RUNNERS.md - Runner configuration
- references/PATTERNS.md - AWS deployment and language patterns

# 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.