ENGIMY.IO - CHEATSHEET
GITHUB ACTIONS × WORKFLOW AUTOMATION
REFERENCE vGitHub Actions (YAML)

GitHub Actions Quick Reference

Automate, build, test, and deploy directly from your GitHub repository.

Workflow Basics

A workflow is a YAML file stored in .github/workflows/ directory.

name: CI Pipeline

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm ci
      - name: Run tests
        run: npm test

Trigger Events (on)

Push & Pull Request
on:
  push:
    branches: [ main, develop ]
    tags: [ v* ]
    paths:
      - 'src/**'
      - '!docs/**'
  pull_request:
    branches: [ main ]
    types: [ opened, synchronize, reopened ]
Schedule (Cron)
on:
  schedule:
    - cron: '0 2 * * *'   # daily at 2 AM UTC
    - cron: '0 8 * * 1'   # every Monday at 8 AM
Manual Trigger (workflow_dispatch)
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy environment'
        required: true
        type: choice
        options:
          - staging
          - production
      version:
        description: 'Version to deploy'
        required: false
        type: string
Other Events
  • release – when a release is published
  • issue_comment – when comments are added
  • workflow_run – on completion of another workflow
  • workflow_call – reusable workflow

Jobs

Basic Job
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."
    env:
      NODE_ENV: production
Dependencies (needs)
jobs:
  lint:
    runs-on: ubuntu-latest
    steps: [ ... ]
  test:
    needs: lint
    runs-on: ubuntu-latest
    steps: [ ... ]
  deploy:
    needs: [ lint, test ]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps: [ ... ]
Job Outputs
jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.get_version.outputs.version }}
    steps:
      - id: get_version
        run: echo "version=v1.2.3" >> $GITHUB_OUTPUT
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying version ${{ needs.build.outputs.version }}"
Matrix Strategy
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16, 18, 20]
        os: [ubuntu-latest, windows-latest]
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm test
Fail‑Fast and Continue‑on‑Error
strategy:
  fail-fast: false   # continue even if one matrix job fails
  max-parallel: 4    # run at most 4 jobs in parallel

Steps

Actions
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  with:
    node-version: '18'
- uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
Shell Commands (run)
- run: npm install
- name: Build application
  run: npm run build
- name: Multi-line script
  run: |
    echo "First line"
    echo "Second line"
- run: echo "Running on ${{ runner.os }}"
  shell: bash  # default; can be pwsh, python, etc.
Conditional Steps (if)
- name: Deploy only on main branch
  if: github.ref == 'refs/heads/main'
  run: ./deploy.sh

- name: Skip if PR
  if: github.event_name != 'pull_request'
  run: npm run integration-tests

- name: Run step only on failure
  if: failure()
  run: echo "Previous step failed"

- name: Run on success
  if: success()
  run: echo "Everything succeeded"

- name: Always run
  if: always()
  run: echo "Runs even if previous step failed"
Environment Variables and Secrets
env:
  NODE_ENV: production
  API_URL: https://api.example.com

- name: Use secret
  run: echo "Deploying with secret ${{ secrets.DEPLOY_TOKEN }}"

- name: Set environment variable dynamically
  run: echo "VERSION=$(git describe --tags)" >> $GITHUB_ENV

- name: Use dynamic env var
  run: echo "Version is ${{ env.VERSION }}"

Built‑in Contexts and Functions

Context Description Example
githubInfo about the event, repo, actor${{ github.repository }}
runnerInfo about the runner (OS, temp dir)${{ runner.os }}
envEnvironment variables set in workflow${{ env.NODE_ENV }}
secretsEncrypted secrets from repo settings${{ secrets.GITHUB_TOKEN }}
strategyMatrix strategy values${{ strategy.job-index }}
needsOutputs from dependent jobs${{ needs.build.outputs.version }}
Common Expressions
  • github.event_name – e.g., "push", "pull_request"
  • github.ref – branch or tag reference
  • github.sha – commit SHA
  • github.actor – user who triggered the workflow
  • github.run_id – unique run ID
  • github.workspace – default working directory

Artifacts and Caching

Upload Artifacts
- name: Upload build artifacts
  uses: actions/upload-artifact@v4
  with:
    name: dist-files
    path: dist/
    retention-days: 7
Download Artifacts
- name: Download artifacts
  uses: actions/download-artifact@v4
  with:
    name: dist-files
    path: ./downloaded
Caching Dependencies
- name: Cache npm dependencies
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

- name: Cache Python packages
  uses: actions/cache@v3
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-pip-

Reusable Workflows

Calling a Reusable Workflow
jobs:
  call-workflow:
    uses: ./.github/workflows/build.yml
    with:
      node-version: '18'
    secrets:
      token: ${{ secrets.GITHUB_TOKEN }}
Reusable Workflow Definition (workflow_call)
on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
    secrets:
      token:
        required: true

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

Container Jobs

jobs:
  test-in-container:
    runs-on: ubuntu-latest
    container:
      image: node:18-alpine
      env:
        NODE_ENV: test
      options: --memory 2GB
    steps:
      - uses: actions/checkout@v4
      - run: npm test
Service Containers (for databases, etc.)
jobs:
  integration-test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: user
          POSTGRES_PASSWORD: pass
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
      redis:
        image: redis:7
        ports:
          - 6379:6379
    steps:
      - uses: actions/checkout@v4
      - run: npm run test:integration

Environment Protection Rules

Deploy to specific environments with required approvals.

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

Common Workflow Examples

Node.js CI
name: Node.js CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm run lint
      - run: npm test
      - run: npm run build
Docker Build and Push
name: Docker Build

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ secrets.DOCKER_USERNAME }}/myapp:latest
Deploy to AWS S3
name: Deploy to S3

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - run: aws s3 sync ./dist s3://my-bucket --delete
PR Comment with Test Results
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test > test-results.txt
      - uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: test-results.txt
      - name: Comment on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const content = fs.readFileSync('test-results.txt', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `Test results:\n\`\`\`\n${content}\n\`\`\``
            });

Best Practices

  • Pin actions to specific versions – e.g., @v4 or commit SHA for security.
  • Use actions/cache – speed up workflow by caching dependencies.
  • Keep secrets in GitHub Secrets – never hard-code tokens or passwords.
  • Use if conditions wisely – avoid unnecessary steps.
  • Break down jobs – separate build, test, deploy for better parallelism.
  • Use matrix for testing across versions – increases confidence.
  • Set environment protection – for production deployments.
  • Use workflow_dispatch – for manual triggers with inputs.
  • Add meaningful names to steps and jobs – improves readability.
  • Limit permissions – use permissions block to restrict token access.
  • Pin base images – use specific tags (e.g., node:18-alpine) not latest.

Troubleshooting

  • Check logs – every step has detailed output.
  • Use ACTIONS_RUNNER_DEBUG = true – enables verbose debugging.
  • Use github.event context – to inspect the payload.
  • Validate YAML – use online linters or GitHub's built-in validation.
  • Re-run failed jobs – with or without debug logging.
// Enable debug logging
env:
  ACTIONS_RUNNER_DEBUG: true

// Dump event data
- name: Dump event
  run: echo "${{ toJson(github.event) }}"

Permissions

Limit the default GITHUB_TOKEN permissions:

permissions:
  contents: read
  pull-requests: write
  deployments: write
  issues: read

Workflow Status Badges

Add badge to README:

![CI](https://github.com/owner/repo/actions/workflows/ci.yml/badge.svg)
📌 Quick Reference
File location: .github/workflows/*.yml
Key sections: name, on, jobs, runs-on, steps
Triggers: push, pull_request, schedule, workflow_dispatch
Caching: actions/cache
Artifacts: upload-artifact, download-artifact
Secrets: stored in repo settings, accessed via ${{ secrets.NAME }}
Matrix: strategy.matrix for parallel testing
Best practice: pin actions, cache deps, use environment protection
← Back to All Cheatsheets