Lesson 04 GitHub Actions Pipeline
Theme:
Lesson 04 · Slide 1

Lesson 04 — GitHub Actions Pipeline

Build, test, and lint the URL shortener on every push.

Cloud & DevOps Module 2

Lesson 04 · Slide 2

Why CI exists

Without CI, the team becomes the test suite — manually verifying changes before every merge.

Lesson 04 · Slide 3

The shape of a GitHub Actions workflow

Hierarchy:

  • Workflow — one YAML file in .github/workflows/
  • Jobs — run in parallel by default on isolated runners
  • Steps — run sequentially; share the runner’s filesystem

Key idea: jobs are isolated from each other; steps inside a job are not.

  workflow (ci.yml)
  ├── job: lint
  │   ├── step: checkout
  │   ├── step: setup-python
  │   └── step: ruff check
  ├── job: test
  │   ├── step: checkout
  │   ├── step: pytest
  └── job: build
      ├── step: checkout
      └── step: docker build
      
Lesson 04 · Slide 4

Triggers — on:

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
Path filters: add paths-ignore: ['**.md'] to skip CI for documentation-only edits — free savings on a monorepo.
Lesson 04 · Slide 5

Runners

Self-hosted runners exist for special needs: GPU workloads, access to private networks, compliance requirements. The runner agent connects outbound to GitHub — no inbound ports required.

Rule of thumb: Use ubuntu-latest unless you have a concrete reason not to. The cost difference adds up quickly in a matrix.
Lesson 04 · Slide 6

Job basics

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: "3.11" }
      - run: pip install -r api/requirements.txt
      - run: pytest api/tests
Lesson 04 · Slide 7

Matrix builds

strategy:
  matrix:
    python-version: ["3.10", "3.11", "3.12"]
steps:
  - uses: actions/setup-python@v5
    with: { python-version: "${{ matrix.python-version }}" }
Trade-off: matrix is N× minutes consumed — and N× cost on macOS/Windows runners. Start with 2 versions and expand when needed.
Lesson 04 · Slide 8

Caching dependencies

- uses: actions/setup-python@v5
  with:
    python-version: "3.11"
    cache: pip
    cache-dependency-path: api/requirements.txt

The cache: pip shortcut on setup-python stores the pip download cache keyed on the hash of your requirements file. On subsequent runs with the same requirements, installation is skipped entirely.

Lesson 04 · Slide 9

Linting in CI

- name: Install ruff
  run: pip install ruff==0.6.9
- name: Lint
  run: ruff check cloud-devops/sample-app/api cloud-devops/sample-app/worker
- name: Format check
  run: ruff format --check cloud-devops/sample-app/api cloud-devops/sample-app/worker

Pinning ruff==0.6.9 prevents a new ruff release from suddenly failing your build.

Lesson 04 · Slide 10

Building the Docker image in CI

- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
  with:
    context: ./api
    push: false
    tags: api:ci
    cache-from: type=gha
    cache-to: type=gha,mode=max
Lesson 04 · Slide 11

Status checks and the “green check” workflow

The green check is the PR contract: “this code passed lint, test, and build on a clean runner.” L05 makes it a hard gate; L06 makes it the deploy trigger.
Lesson 04 · Slide 12

What we’ll build in lab

The ci.yml pipeline for the URL-shortener sample app:

The concurrency block cancels superseded runs on the same branch — no wasted minutes when you push twice in quick succession.
Lesson 04 · Slide 13

Common gotchas

Lesson 04 · Slide 14

Recap & what’s next

Coming up: Lesson 05 — security scans, SBOMs, and image signing as required checks.
1 / ?