Course outline · 0% complete

0/29 lessons0%

Course overview →

Fail fast: test, then build

lesson 7-3 · ~11 min · 21/29

Order steps to fail fast

A CI job stops at the first failing step, so put the cheapest, most likely to fail checks first. Standard order: install → lint → test → docker build. No point spending two minutes building an image (unit 3) for code whose tests already failed in ten seconds.

Shell scripts get the same behavior with set -e, which you will see inside CI steps constantly: it makes the script exit at the first failing command instead of blundering on.

set -e
pip install -r requirements.txt
pytest
docker build -t myapp .

With set -e, if pytest exits non-zero, docker build never runs. Without it, bash would shrug and keep going, and you could ship an image whose tests failed. The next block simulates exactly this.

Code exercise · bash

Run this simulated pipeline. The parentheses create a subshell whose set -e aborts at the first failure. false stands in for a failing test suite. Notice the build step never prints.

Code exercise · bash

Your turn: the team fixed the failing test. Replace the failing command with a passing one (true) so every step runs and the pipeline exits 0.

The same idea as a real workflow

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install -r requirements.txt
      - run: pytest
      - run: docker build -t myapp:${{ github.sha }} .

Two new things:

  • Runners come with Docker preinstalled, so docker build from lesson 3-1 just works
  • ${{ github.sha }} is an Actions expression that expands to the commit hash being tested. Tagging the image with the exact commit (instead of latest, see lesson 6-1) means every image traces back to the code that produced it

What's missing is docker push, because the runner has no registry credentials yet. Secrets are the first stop of unit 8.

Quiz

Why do teams run pytest before docker build in the pipeline, not after?

Problem

What line, placed at the top of a bash script, makes it stop at the first failing command instead of continuing?