GitHub Actions study materials
GitHub Actions study resources

GitHub Actions: Workflow creation: authoring valid, correctly-triggered workflows

GitHub Actions · Work through your exam, one topic at a time.

All guide sections

Workflow creation: authoring valid, correctly-triggered workflows

What this domain tests

Workflow creation covers the file itself: where it lives, which event starts it, how jobs and steps are wired, and which contexts and permissions each key may legally use. Exam items usually show a short YAML fragment and ask why it does not run, runs too often, or fails validation.

File anatomy and triggers

  • Workflows live in .github/workflows/ as YAML files; a repository can hold many, each with its own on block.
  • on accepts one event, a list, or a map with filters. For pull_request, branches filters the base branch, and paths accepts globs plus negations such as !docs/**.
  • schedule uses five-field POSIX cron in UTC, has a minimum interval of five minutes, and always runs the default branch version of the workflow.
  • workflow_dispatch adds a manual Run button; workflow_call makes the file reusable from another workflow's job.
  • Actions are referenced as owner/repo@ref, ./local-path, or docker://image.

Contexts, expressions, permissions

  • ${{ }} is evaluated before the step executes. Availability depends on the key: secrets is rejected in a job-level if, and env is unavailable inside on.
  • Declare permissions: explicitly at workflow or job level. Default token scope depends on repository settings, so never depend on it implicitly.
  • A step-level if implicitly includes success() unless you write always(), failure(), or cancelled().

Worked example

A test workflow that runs on source changes only:

on:
  push:
    branches: [main]
    paths: ['src/**', 'package*.json']
  pull_request:
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true
permissions:
  contents: read
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: {node-version: 20, cache: npm}
      - run: npm ci && npm test

Reasoning: the paths filter keeps documentation-only pushes off the runners; concurrency cancels superseded runs on the same ref; setup-node's built-in cache: npm makes a separate actions/cache step unnecessary; contents: read is the minimum checkout needs.

Traps that cost marks

  • Indentation errors and duplicated keys break parsing silently; lint with actionlint before pushing.
  • Referring to secrets inside a job-level if is a validation error - map the secret into env first.
  • A paths-filtered workflow that never runs leaves a required check pending, which blocks merging rather than passing it.
  • continue-on-error changes a step's conclusion, not its outcome; later steps still read steps.<id>.outcome == 'failure'.
  • Cron times are best-effort; scheduled runs are delayed under load and skipped rather than queued.