You will write a GitHub Actions workflow that lints and tests your code on every push. By the end, broken code is caught automatically before it can be merged into main.

Learning Objectives

  • Define triggers, jobs, and steps in workflow YAML.
  • Cache dependencies to speed up runs.
  • Make the workflow a required status check.
  • Time: ~3 hours · Difficulty: Intermediate · Prereqs: a GitHub repo with tests.

Architecture Overview

Environment Setup

You will need: a GitHub repo with a test command (for example pytest or npm test).

Before you begin: workflows live in .github/workflows/.

Step-by-Step Execution

01
Write the workflow
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: '3.11', cache: 'pip' }
      - run: pip install -r requirements.txt
      - run: pytest -q
02
Push and watch the run
$ git push && gh run watch
CI ยท test (push) completed success
03
Require the check on main

Set the workflow as a required status check in branch protection so failing code cannot merge.

gh api repos/:owner/:repo/branches/main/protection -X PUT -f required_status_checks.strict=true

Progress So Far

Testing & Validation

gh run list --limit 1 && gh run view --log-failed 2>/dev/null | head

The latest run should show success. Push a deliberately failing test and confirm the workflow goes red and blocks the merge.

Troubleshooting
  • Workflow not triggering: the file must be in .github/workflows/ on the default branch.
  • Cache misses: ensure the cache key matches the lockfile path.
  • Secrets needed: add them under repo Settings, reference via ${{ secrets.NAME }}.

Extension Ideas

Key Results

  • Ran lint and tests automatically on every push and PR.
  • Sped up runs with dependency caching.
  • Made CI a required check protecting main.
  • Confirmed failing code is blocked from merge.