Challenge 2: Trace What Happens on a Pull Request — Possible Solution ==================================================================== WHICH JOBS RUN ------------------ ONLY the test job runs. None of build-and-push, deploy-staging, or deploy-production run at all for a pull request. WHY test RUNS ----------------- The workflow's on: [push, pull_request] trigger includes pull_request, so the workflow itself is triggered — and the test job has no if: condition restricting it at all, so it runs on every trigger, including pull requests. This matches Chapter 2's own trigger-to-stage mapping directly: "Pull request: Build + test only." WHY build-and-push DOES NOT RUN ------------------------------------ This job has the explicit condition: if: github.ref == 'refs/heads/main' github.ref reflects the branch (or ref) the CURRENT WORKFLOW RUN is associated with. For a pull_request-triggered run, this does NOT equal refs/heads/main (a PR run is associated with the PR's own branch/ref, not main directly) — so this condition evaluates to false, and build-and-push is SKIPPED entirely for this trigger, regardless of whether the test job passed. WHY deploy-staging AND deploy-production ALSO DO NOT RUN -------------------------------------------------------------- Both of these jobs have needs: chains leading back to build-and-push (deploy-staging needs: build-and-push; deploy-production needs: deploy-staging, which itself needs: build-and-push). Per Chapter 2's dependency-graph model, if a job a later job depends on is SKIPPED (not just failed, but never run at all because its own if: condition was false), the dependent jobs are also skipped — there's nothing for them to depend on having completed. So even though neither deploy-staging nor deploy-production has its own explicit if: condition, they're transitively skipped because build-and-push, which they both ultimately depend on, never ran. WHY THIS WORKS AS AN ANSWER ------------------------------ The single line if: github.ref == 'refs/heads/main' on build-and-push is doing ALL the work here — it's the one explicit condition in the entire workflow that distinguishes "this is a PR" from "this is a push to main," and everything downstream (via needs: chains) inherits that distinction automatically without needing its own repeated condition. This is exactly Chapter 2's "Pull request: Build + test only" / "Push to main: Build + test + deploy" mapping, implemented concretely through one conditional plus the natural consequences of the job dependency graph.