GitHub Actions Cheatsheet
Installation & Setup
GitHub CLI (gh)
Self-Hosted Runner Setup
| Platform | Setup Commands |
|---|
| Linux | mkdir actions-runner && cd actions-runner && curl -o actions-runner-linux-x64-2.311.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz && tar xzf ./actions-runner-linux-x64-2.311.0.tar.gz |
| macOS | mkdir actions-runner && cd actions-runner && curl -o actions-runner-osx-x64-2.311.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-osx-x64-2.311.0.tar.gz && tar xzf ./actions-runner-osx-x64-2.311.0.tar.gz |
| Windows | mkdir actions-runner; cd actions-runner; Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-win-x64-2.311.0.zip -OutFile actions-runner-win-x64-2.311.0.zip |
Basic GitHub CLI Commands
| Command | Description |
|---|
gh run list | List all workflow runs in the repository |
gh run view <run-id> | View details of a specific workflow run |
gh run watch <run-id> | Watch a workflow run in real-time |
gh run view <run-id> --log | View logs for a specific workflow run |
gh run download <run-id> | Download artifacts from a workflow run |
gh workflow list | List all workflows in the repository |
gh workflow view <workflow-name> | View details of a specific workflow |
gh workflow enable <workflow-name> | Enable a disabled workflow |
gh workflow disable <workflow-name> | Disable a workflow |
gh workflow run <workflow-name> | Manually trigger a workflow |
gh workflow run <workflow-name> -f key=value | Trigger workflow with input parameters |
gh run cancel <run-id> | Cancel a running workflow |
gh run rerun <run-id> | Rerun a completed workflow |
gh run rerun <run-id> --failed | Rerun only failed jobs in a workflow |
gh auth login | Authenticate GitHub CLI with your account |
Self-Hosted Runner Management
| Command | Description |
|---|
./config.sh --url https://github.com/ORG/REPO --token TOKEN | Configure a new self-hosted runner |
sudo ./svc.sh install | Install runner as a system service (Linux/macOS) |
sudo ./svc.sh start | Start the runner service |
sudo ./svc.sh stop | Stop the runner service |
sudo ./svc.sh status | Check runner service status |
sudo ./svc.sh uninstall | Uninstall runner service |
./config.sh remove --token TOKEN | Remove runner from repository |
./run.sh | Run the runner interactively (not as service) |
gh api repos/:owner/:repo/actions/runners | List all self-hosted runners via API |
gh api -X DELETE repos/:owner/:repo/actions/runners/RUNNER_ID | Remove runner via API |
Local Testing with Act
| Command | Description |
|---|
act -l | List all workflows and jobs available locally |
act | Run the default event (push) locally |
act push | Run workflows triggered by push event |
act pull_request | Run workflows triggered by pull request event |
act -j job-name | Run a specific job by name |
act -s GITHUB_TOKEN=token | Run with a secret value |
act -s SECRET_NAME | Prompt for secret value interactively |
act --secret-file .secrets | Load secrets from a file |
act -P ubuntu-latest=nektos/act-environments-ubuntu:18.04 | Use specific Docker image for runner |
act -n | Dry run - show what would be executed |
act -v | Verbose output for debugging |
act --container-architecture linux/amd64 | Specify container architecture |
act -W .github/workflows/ci.yml | Run specific workflow file |
act --env-file .env | Load environment variables from file |
Advanced GitHub CLI Commands
| Command | Description |
|---|
gh run list --workflow=ci.yml | List runs for a specific workflow |
gh run list --branch=main --limit=20 | List runs for specific branch with limit |
gh run view --log-failed | View only failed job logs |
gh run view --job=12345 | View specific job within a run |
gh workflow run deploy.yml -f environment=production -f version=1.2.3 | Trigger workflow with multiple inputs |
gh api repos/:owner/:repo/actions/runs/:run_id/logs | Download run logs via API |
gh api repos/:owner/:repo/actions/workflows | List workflows via API |
gh api repos/:owner/:repo/actions/secrets | List repository secrets |
gh secret set SECRET_NAME < secret.txt | Set a repository secret from file |
gh secret set SECRET_NAME --body "value" | Set a repository secret from string |
gh secret list | List all repository secrets |
gh secret remove SECRET_NAME | Remove a repository secret |
gh api repos/:owner/:repo/actions/caches | List workflow caches |
gh api -X DELETE repos/:owner/:repo/actions/caches/:cache_id | Delete a specific cache |
gh run download <run-id> -n artifact-name | Download specific artifact by name |
Workflow File Structure
Basic Workflow Template
name: CI Pipeline
# Trigger configuration
on:
push:
branches: [ main, develop ]
paths:
- 'src/**'
- '**.js'
pull_request:
branches: [ main ]
workflow_dispatch: # Manual trigger
inputs:
environment:
description: 'Environment to deploy'
required: true
default: 'staging'
# Environment variables
env:
NODE_VERSION: '18'
CACHE_KEY: v1
# Jobs definition
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
CI: true
- name: Build application
run: npm run build
Matrix Strategy
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
include:
- os: ubuntu-latest
node-version: 20
experimental: true
exclude:
- os: macos-latest
node-version: 16
fail-fast: false
max-parallel: 3
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm test
Conditional Execution
jobs:
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Deploy to staging
if: contains(github.event.head_commit.message, '[staging]')
run: ./deploy.sh staging
- name: Deploy to production
if: startsWith(github.ref, 'refs/tags/v')
run: ./deploy.sh production
- name: Conditional step with multiple conditions
if: |
success() &&
github.actor == 'dependabot[bot]' &&
contains(github.event.pull_request.labels.*.name, 'automerge')
run: echo "Auto-merging PR"
Caching Configuration
steps:
# Cache npm dependencies
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# Cache pip dependencies
- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
# Cache Gradle dependencies
- name: Cache Gradle
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
# Cache Docker layers
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
Artifacts Management
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Build application
run: npm run build
# Upload artifacts
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-output
path: |
dist/
build/
!dist/**/*.map
retention-days: 30
if-no-files-found: error
# Upload test results
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-results-${{ matrix.os }}
path: test-results/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
# Download artifacts
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-output
path: ./artifacts
- name: Deploy artifacts
run: ./deploy.sh ./artifacts
Environment and Secrets
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com
env:
NODE_ENV: production
API_URL: https://api.example.com
steps:
- name: Deploy with secrets
run: |
echo "Deploying to $NODE_ENV"
./deploy.sh
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Use GitHub token
run: |
gh api user
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Composite Actions
File: .github/actions/setup-project/action.yml
name: 'Setup Project'
description: 'Setup Node.js and install dependencies'
inputs:
node-version:
description: 'Node.js version'
required: false
default: '18'
cache-key:
description: 'Cache key prefix'
required: false
default: 'v1'
outputs:
cache-hit:
description: 'Whether cache was hit'
value: ${{ steps.cache.outputs.cache-hit }}
runs:
using: 'composite'
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- name: Cache dependencies
id: cache
uses: actions/cache@v3
with:
path: node_modules
key: ${{ inputs.cache-key }}-${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: npm ci
shell: bash
Using composite action:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup project
uses: ./.github/actions/setup-project
with:
node-version: '20'
cache-key: 'v2'
- name: Build
run: npm run build
Reusable Workflows
File: .github/workflows/reusable-deploy.yml
name: Reusable Deploy Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
version:
required: false
type: string
default: 'latest'
secrets:
deploy-key:
required: true
outputs:
deployment-url:
description: "Deployment URL"
value: ${{ jobs.deploy.outputs.url }}
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
outputs:
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- name: Deploy
id: deploy
run: |
./deploy.sh ${{ inputs.environment }} ${{ inputs.version }}
echo "url=https://${{ inputs.environment }}.example.com" >> $GITHUB_OUTPUT
env:
DEPLOY_KEY: ${{ secrets.deploy-key }}
Calling reusable workflow:
jobs:
deploy-staging:
uses: ./.github/workflows/reusable-deploy.yml
with:
environment: staging
version: '1.2.3'
secrets:
deploy-key: ${{ secrets.STAGING_DEPLOY_KEY }}
deploy-production:
needs: deploy-staging
uses: ./.github/workflows/reusable-deploy.yml
with:
environment: production
version: '1.2.3'
secrets:
deploy-key: ${{ secrets.PROD_DEPLOY_KEY }}
Common Workflow Triggers
| Trigger | Description | Example |
|---|
push | On push to branches | on: push: branches: [main] |
pull_request | On PR events | on: pull_request: types: [opened, synchronize] |
workflow_dispatch | Manual trigger | on: workflow_dispatch: inputs: ... |
schedule | Cron schedule | on: schedule: - cron: '0 0 * * *' |
release | On release events | on: release: types: [published] |
issues | On issue events | on: issues: types: [opened, labeled] |
issue_comment | On issue comments | on: issue_comment: types: [created] |
repository_dispatch | External webhook | on: repository_dispatch: types: [deploy] |
workflow_run | After another workflow | on: workflow_run: workflows: [CI] |
pull_request_target | PR from forks (careful!) | on: pull_request_target |
Context Variables
| Context | Description | Example Usage |
|---|
github.actor | User who triggered workflow | ${{ github.actor }} |
github.event_name | Event that triggered workflow | ${{ github.event_name }} |
github.ref | Branch or tag ref | ${{ github.ref }} |
github.sha | Commit SHA | ${{ github.sha }} |
github.repository | Owner/repo name | ${{ github.repository }} |
github.workspace | Workspace directory path | ${{ github.workspace }} |
runner.os | Operating system | ${{ runner.os }} |
runner.temp | Temp directory path | ${{ runner.temp }} |
secrets.GITHUB_TOKEN | Auto-generated token | ${{ secrets.GITHUB_TOKEN }} |
env.VAR_NAME | Environment variable | ${{ env.NODE_VERSION }} |
matrix.value | Matrix value | ${{ matrix.node-version }} |
needs.job.outputs.var | Output from previous job | ${{ needs.build.outputs.version }} |
steps.step_id.outputs.var | Output from step | ${{ steps.build.outputs.artifact }} |
job.status | Job status | ${{ job.status }} |
Common Use Cases
Use Case 1: Node.js CI/CD Pipeline
name: Node.js CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
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 -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
build:
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: dist
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://example.com
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: dist
path: dist/
- name: Deploy to production
run: |
# Deploy commands here
echo "Deploying to production..."
Use Case 2: Docker Build and Push
name: Docker Build and Push
on:
push:
branches: [ main ]
tags: [ 'v*' ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container 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=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- 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
Use Case 3: Multi-Cloud Deployment
name: Multi-Cloud Deploy
on:
workflow_dispatch:
inputs:
environment:
type: choice
description: 'Deployment environment'
options:
- staging
- production
required: true
jobs:
deploy-aws:
runs-on: ubuntu-latest
environment: ${{ github.event.inputs.environment }}
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-