GitHub Actions — Level by Level›01 · Workflows, events and your first pipeline

Lesson 01 of 9 · Level 1 — Foundations

Workflows, events and your first pipeline

Your first GitHub Actions pipeline: where workflows live, which events trigger them, how jobs and steps are written, how to use ready-made actions, secrets and variables, job dependencies, and the permissions of the built-in token.

Beginner
Key wordsGitHub Actionsworkflow.github/workflowsonpushpull_requestworkflow_dispatchschedulejobsstepsusesrunactions/checkoutsecretsvarsneedsGITHUB_TOKENpermissions
Event push · PR · tag Workflow job: test runner A checkout → test job: build runner B image → registry job: deploy environment: prod approval, OIDC needs Registry image@digest GitOps repo new tag → Argo CD
A workflow reacts to an event, runs jobs on runners, and each job runs its steps in order.

Where workflows live

A workflow is a YAML file in .github/workflows/. It says when to run (on:), and what to run (jobs:), each job on a runner (a VM or container) with a sequence of steps.

A workflow is a to-do list pinned to a door. "When someone knocks (an event), do these jobs." Each job is handed to a helper (a runner), who works through the steps in order and reports back.

A first pipeline

# .github/workflows/ci.yml
name: ci

on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt
      - run: pytest --junitxml=reports/unit.xml

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pipx run ruff check .

  build:
    needs: [test, lint]           # only if both succeed
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "build and publish here (lesson 04)"
  • test and lint run in parallel; build waits for both (needs).
  • if: limits build to pushes on main; pull requests only test and lint.
  • actions/checkout fetches the repository into the runner; nothing is there otherwise.

Events you'll use most

Event Runs when Typical use
push Commits pushed (filter by branches, tags, paths) Build main, release tags
pull_request PR opened/updated Tests and checks before merging
workflow_dispatch Someone clicks "Run workflow" (with inputs) Manual jobs, one-off operations
schedule Cron (UTC) Nightly scans, drift checks
release A release is published Publish packages
workflow_call Another workflow calls this one Reusable workflows (lesson 03)

paths: filters let a monorepo run only the workflows affected by a change.

Secrets and variables

  • Secrets (repository, environment or organisation level) are encrypted, masked in logs, and read as ${{ secrets.NAME }}.
  • Variables (${{ vars.NAME }}) are for non-secret configuration.
  • Pass secrets to steps through env:, not by printing them; prefer OIDC over stored cloud keys altogether (lesson 06).
      - run: ./deploy-notify.sh
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
          CHANNEL: ${{ vars.RELEASE_CHANNEL }}

The built-in token and permissions

Every run gets a short-lived GITHUB_TOKEN. Set its permissions explicitly, at the top of the workflow or per job, to exactly what's needed (contents: read, plus packages: write to push images, id-token: write for OIDC, pull-requests: write to comment). Organisation defaults can also be set to read-only.

Try it: first workflow

  1. Add the workflow above to a repository with a tiny Python project (or change the steps to your language).
  2. Push to a branch and open a pull request: test and lint run, build is skipped.
  3. Merge: build runs after the other two.
  4. Use gh run list, gh run watch and gh run view --log-failed after breaking a test on purpose.
  5. Make the test check required in branch protection.

Recap

  • Workflows live in .github/workflows/; on: decides when, jobs: what, each job on a runner.
  • Steps either use an action or run shell; jobs run in parallel unless linked with needs.
  • Secrets and vars for configuration; secrets are withheld from fork PRs.
  • Set permissions for GITHUB_TOKEN explicitly.

This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.