Modern TDD with Python in 2025 — Step by Step, with AI at Your Side [part 5/10]

Modern TDD with Python in 2025 — Step by Step, with AI at Your Side [part 5/10]
Photo by Catherine Heath / Unsplash

GitHub Actions + Pre-commit — Guardrails, Not Bureaucracy

“Stop pushing broken code. Gently.”

So you’re flying.

You’ve written clean tests. You’re in the vibe. You’re pairing with GPT.

Your code is elegant, correct… and only tested locally.

But one day — future-you (or your teammate) does this:

git commit -m "fix: final tweak for production"

They push.

CI runs.

Tests fail.

Because a typo slipped through that “totally safe last change.”

Oops.

That’s why today’s chapter is all about safety nets:

  • Automatically running your tests and linters before code is committed
  • Automatically checking everything in GitHub Actions after every push

In other words:

Your vibe is safe. Your future self is grateful.

Step 1: Add Pre-commit Hooks

“Like flossing. But for code.”
  1. Create .pre-commit-config.yaml at your project root:
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.4.3
    hooks:
      - id: ruff
      - id: ruff-format

  - repo: https://github.com/pre-commit/mirrors-pytest
    rev: v7.4.2
    hooks:
      - id: pytest
These will:
Run pytest before every commit
Lint + format your code with Ruff
  1. Install pre-commit in your environment (you likely did in Part 1):
uv pip install pre-commit
  1. Activate hooks:
pre-commit install

From now on, every git commit will:

  • Lint your code
  • Format it if needed
  • Run all tests

If anything fails — the commit is blocked.

Annoying? Maybe.

But Future You will love it.


Step 2: Set Up GitHub Actions CI

“Let the cloud be your co-reviewer.”

We want:

  • A .yml file that runs pytest and ruff automatically on every push/PR
  • To mirror what we check locally — but in the cloud
  1. Create folder & file:
mkdir -p .github/workflows
touch .github/workflows/test.yml
  1. Add this:
name: Test and Lint

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: |
          pip install uv
          uv venv && source .venv/bin/activate
          uv pip install typer pytest ruff hypothesis

      - name: Run Ruff linter
        run: ruff check .

      - name: Run tests
        run: pytest
  1. Push your code to GitHub

After a few seconds, check the “Actions” tab.

You’ll see a green or red telling you if things passed.

No more guessing.


GPT Prompt of the Day

Try this after writing .pre-commit-config.yaml and .yml CI file:
Here's my pre-commit config and GitHub Actions workflow for a Python project. Can you suggest improvements? Are there any hooks or steps I’m missing to catch common issues before production?

Let GPT do the paranoia work. You stay creative.


Editor Add-ons

Zed

  • Just rely on terminal: git commit, hooks run
  • CI results visible in GitHub
  • No distractions

VSCode

  • Extensions like:
    • GitHub Actions: View workflows & logs
    • Pre-commit: Highlights what will trigger
  • Push button comfort with test automation power

Bonus: Pre-commit Gotchas & Tips

  • You can skip hooks temporarily (not recommended):
git commit --no-verify
  • Want to run all hooks manually?
pre-commit run --all-files
  • Add more hooks:
    • trailing-whitespace
    • check-yaml
    • black (if not using Ruff’s formatter)

Recap: Invisible Confidence

With just a few lines of config, you’ve now:

  • Automated your local sanity checks
  • Automated your cloud sanity checks
  • Prevented silly mistakes from leaking into main

This is the “safety harness” that lets you vibe harder and move faster.

And the best part?

It’s now running quietly in the background — so you can focus on creating.


Next Up:

Part 6: Adding a Real Feature with AI-TDD Pairing