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 buildfrom 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 oflatest, 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?