GitHub Actions Tutorial — Status Functions

2 minute read

Status Functions

Status functions let you react to the outcome of previous steps or jobs. They’re used in if: conditions to control cleanup, notifications, and error handling.


The Four Status Functions

Function Returns true When
success() All previous steps succeeded (default)
failure() Any previous step failed
always() Always (regardless of success/failure/cancellation)
cancelled() The workflow was cancelled

Default Behavior

Without an explicit if:, every step and job has an implicit if: success():


steps:
  - run: echo "Step 1"                     # if: success() (implicit)
  - run: exit 1                            # this fails
  - run: echo "Step 3 — never runs"        # skipped because step 2 failed


always() — Always Execute


steps:
  - run: npm test
  - run: exit 1                            # fails

  - name: Cleanup (always runs)
    if: always()
    run: |
      echo "Cleaning up resources..."
      docker-compose down

Common uses:

  • Cleanup resources (databases, containers)
  • Upload test results or logs
  • Send notifications

failure() — Run on Failure


steps:
  - name: Run tests
    run: npm test

  - name: Upload failure logs
    if: failure()
    uses: actions/upload-artifact@v4
    with:
      name: test-logs
      path: ./logs/

  - name: Notify on failure
    if: failure()
    run: |
      curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
        -d '{"text": "❌ Tests failed in ${{ github.repository }}"}'


cancelled() — Run on Cancellation


steps:
  - name: Long running test
    run: sleep 3600

  - name: Handle cancellation
    if: cancelled()
    run: echo "Workflow was cancelled — cleaning up"


Combining Status Functions


steps:
  - name: Run tests
    id: tests
    run: npm test

  - name: Upload results (success or failure)
    if: success() || failure()
    uses: actions/upload-artifact@v4
    with:
      name: test-results
      path: ./test-results/

  - name: Notify only on failure
    if: failure() && github.ref == 'refs/heads/main'
    run: echo "Main branch is broken!"

success() || failure() vs always()

Expression Runs on success Runs on failure Runs on cancellation
success() ✅ ❌ ❌
failure() ❌ ✅ ❌
always() ✅ ✅ ✅
success() \|\| failure() ✅ ✅ ❌
cancelled() ❌ ❌ ✅

Use success() || failure() when you want to run on both outcomes but NOT on cancellation.


Job-Level Status Functions

Status functions also work at the job level with needs::


jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    # Default: only runs if 'test' succeeded
    steps:
      - run: echo "Deploying..."

  notify:
    needs: test
    if: failure()                    # runs only if 'test' failed
    runs-on: ubuntu-latest
    steps:
      - run: echo "Tests failed!"

  cleanup:
    needs: [test, deploy]
    if: always()                     # runs regardless
    runs-on: ubuntu-latest
    steps:
      - run: echo "Cleaning up..."


Real-World Pattern — CI with Notifications


name: CI Pipeline

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test

      - name: Upload test report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-report
          path: ./reports/

      - name: Slack notification on failure
        if: failure()
        run: |
          curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
            -H "Content-Type: application/json" \
            -d '{"text": "❌ CI failed on main: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}'


Common Mistakes

Mistake Fix
Cleanup step skipped after failure Add if: always() to cleanup steps
Notification runs on cancellation Use if: failure() instead of if: always()
failure() doesn’t trigger at job level Add if: failure() AND the required needs: dependency

Quick Reference

Function When It’s True Common Use
success() All previous OK Default behavior
failure() Something failed Notifications, log upload
always() Always Cleanup, resource teardown
cancelled() Run was cancelled Cancel-specific cleanup

← Previous: Conditionals

Next: String Functions →

Updated: