diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fda1d5346..fca45c7a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -229,6 +229,21 @@ jobs: dirs="$(printf '%s\n' "$changed" | { grep '\.go$' || true; } | xargs -r -n1 dirname | sort -u)" pkgs="" for dir in $dirs; do + # A DIRECTORY UNDER ITS OWN go.mod IS ANOTHER MODULE, not a package + # of this one, and `go test ./that/dir` from the root answers + # "main module does not contain package" and fails the job as a + # setup error. The bench fixtures under bench/bashloop/fixtures + # are exactly that: small programs the task door edits, each with + # a go.mod of its own. Walking up from the directory to the first + # go.mod is what tells the two apart. This walk is the same one + # the Makefile's test-touched target does, and the two must keep + # deriving the same set or `make pr-ready` stops predicting CI. + nested=0; walk="$dir" + while [ "$walk" != "." ] && [ "$walk" != "/" ]; do + if [ -f "$walk/go.mod" ]; then nested=1; break; fi + walk="$(dirname "$walk")" + done + if [ "$nested" = 1 ]; then continue; fi # A directory the change emptied has no package left to test. if ls "$dir"/*.go >/dev/null 2>&1; then pkgs="$pkgs ./$dir"; fi done diff --git a/Makefile b/Makefile index 5fd000683..51ebe4956 100644 --- a/Makefile +++ b/Makefile @@ -185,6 +185,9 @@ test-touched-preflight: exit 2; \ fi +# A directory under its own go.mod is another module — a bench fixture the +# task door edits, not a package of this one — and `go test ./that/dir` from +# here answers "does not contain package". The walk skips those. test-touched: test-touched-preflight @set -eu; \ base="$${BASE:-origin/dev}"; \ @@ -197,6 +200,12 @@ test-touched: test-touched-preflight done | sort -u)"; \ pkgs=""; \ for dir in $$dirs; do \ + nested=0; walk="$$dir"; \ + while test "$$walk" != "." && test "$$walk" != "/"; do \ + if test -f "$$walk/go.mod"; then nested=1; break; fi; \ + walk="$$(dirname "$$walk")"; \ + done; \ + if test "$$nested" = 1; then continue; fi; \ if ls "$$dir"/*.go >/dev/null 2>&1; then pkgs="$$pkgs ./$$dir"; fi; \ done; \ fi; \ diff --git a/docs/changes/unreleased/1332-touched-packages-skip-nested-modules.md b/docs/changes/unreleased/1332-touched-packages-skip-nested-modules.md new file mode 100644 index 000000000..c70954e63 --- /dev/null +++ b/docs/changes/unreleased/1332-touched-packages-skip-nested-modules.md @@ -0,0 +1,15 @@ +--- +kind: fixed +title: a changed directory in a nested module is not a package of the root module +pr: 1332 +surface: [build] +invalidates: + - "The `touched packages` job derived its test set as every directory holding a changed `.go` file, with no test for which module that directory belongs to. A change that edits a bench fixture under `bench/bashloop/fixtures/` fed `go test` a directory under its own `go.mod`, which answers `main module (github.com/Agent-Field/codeaf) does not contain package …` and failed the job as a setup error while every real package passed. The job now walks up from each directory to the first `go.mod` and keeps the directory only when that `go.mod` is the root's." + - "`.github/workflows/ci.yml` and the Makefile's `test-touched` target derived the touched set separately, and only one of them was ever fixed. They now carry the same walk, so `make pr-ready` predicts the gate again." +--- + +The bench fixtures are small programs the task door edits during a bench run, and +each carries a `go.mod` of its own so a worker can build and test it in place. +That makes them modules, not packages of this one, and `go test ./that/dir` from +the root has always refused them. Nothing had touched one in the same change as a +Go file before, so the gap was latent until a branch that edits both.