You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
gstack-pregate: .bats tests are never recognised, so lanes always fails in bats repos #3161
In a repository whose tests are bats files (*.bats), gstack-pregate stage 2 fails every /ship with PREGATE_NO_LANE: each touched file "has no test lane", including the .bats file itself. No .gstack/pregate.json can fix it, because the pre-gate never treats a .bats file as a test:
lib/pregate/import-graph.ts: TEST_FILE_RE matches *.test|spec.[cm]?[jt]sx?, test_*.py, _test.(py|go|rb) and _spec.rb only. A dependencies entry pointing a source glob at tests/foo.bats therefore selects nothing.
lib/pregate/lane-selection.ts: a selection manifest's output is parsed with a similar pattern, so a manifest that prints every .bats file yields 0 files.
lanes cannot be downgraded via warn, so the only way to get past it is declaring the files [] ("no lane needed"), which makes the check pass without exercising anything.
Repro
A repo with scripts/foo.sh and tests/foo.bats that runs it, and a CI job that runs bats.
.gstack/pregate.json with "runner": "bats {files}" and "dependencies": {"scripts/**": ["tests/foo.bats"]}.
Touch scripts/foo.sh and run gstack-pregate --allow-repo-commands --policy-from head --explain.
Observed: FAIL lanes - scripts/foo.sh has no test lane, and with a selection manifest that prints tests/foo.bats, lane <id>: 0 files from manifest.
Suggested fix
Recognise .bats (and probably *_test.sh / test_*.sh) in TEST_FILE_RE and in the selection-output pattern, judged by the bats TAP summary (1..N, ok/not ok) for the zero-run rule.
+1, with a second real repo hitting this, and a test of #3177 against real bats-core.
Repo: a private agent-config repo (shell scripts, hooks, bootstrap installers). Its tests are 14 bats files, 426 tests, on Bats 1.13.0. There are also some node --test files.
What we see today:
With no .gstack/pregate.json, 290 of 361 tracked files fail lanes with PREGATE_NO_LANE.
The only way through is the workaround described here: map every shell and bats path to []. The pre-gate then passes without running a single bats test.
A whole-suite guards entry is no substitute. The suite takes 377 s, and the slowest file takes 97 s.
A guard that buffers its output so it can check the test count prints nothing for that long. That runs into the 300 s stall_timeout_s default added in v1.91.107.
fail: local lane exited 1 (1 failed of 40 ran; 1 files; pipefail)
script mapped to a .bats file with no @test
failPREGATE_NO_LANE
fail: ZERO-RUN: the runner reported 0 tests for 1 selected file(s)
no dependencies entry
failPREGATE_NO_LANE
failPREGATE_NO_LANE (the bats file reaches the script through $BATS_TEST_DIRNAME/../scripts/tool, which the literal scan doesn't follow, so the mapping must be declared)
The pass, fail and zero-run paths all behave as the PR describes on a real suite. We haven't tried a lane long enough to test the stall supervisor.
One question for the design:runner is a single command, so in a repo with both bats and node --test tests, every selected file goes to that one command.
One way to handle that is a wrapper runner that sends .bats files to bats and .test.mjs files to node --test. With a wrapper, though, parseSummary no longer sees bats in the runner name, so it tries the other runners' summary formats first and treats bats as a last resort.
Is a wrapper the intended shape for mixed repos, or would a per-extension runner (for example {".bats": "bats {files}", ".mjs": "node --test {files}"}) fit better?
Activity
liveness screenshot for garrytan#3161
v1.91.117.0 fix: pregate bats lanes, WTREE_UNAVAILABLE, doctor rows, …
yolo-jared commentedon Oct 17, 2026
+1, with a second real repo hitting this, and a test of #3177 against real bats-core.
Repo: a private agent-config repo (shell scripts, hooks, bootstrap installers). Its tests are 14 bats files, 426 tests, on Bats 1.13.0. There are also some
node --testfiles.What we see today:
.gstack/pregate.json, 290 of 361 tracked files faillaneswithPREGATE_NO_LANE.[]. The pre-gate then passes without running a single bats test.guardsentry is no substitute. The suite takes 377 s, and the slowest file takes 97 s.stall_timeout_sdefault added in v1.91.107.#3177 on real bats.
.gstack/pregate.jsonand Bats 1.13.0.mainat0bf9d508, the commit fix(pregate): recognise bats test files so lanes does not fail in bats repos #3177 is based on. After = fix(pregate): recognise bats test files so lanes does not fail in bats repos #3177's head commit444f4e76, which is that samemainplus the PR's changes.gstack-pregate --base main --policy-from head --allow-repo-commands --stage testswith"runner": "bats {files}".scripts/tool, mapped with"scripts/tool": ["tests/tool.bats"].tests/tool.batshas 40 tests.0bf9d508)444f4e76).batsfilefailPREGATE_NO_LANEpass:40 tests ran in 1 file(s), exit 0(25.7 s)false)failPREGATE_NO_LANEfail:local lane exited 1 (1 failed of 40 ran; 1 files; pipefail).batsfile with no@testfailPREGATE_NO_LANEfail:ZERO-RUN: the runner reported 0 tests for 1 selected file(s)dependenciesentryfailPREGATE_NO_LANEfailPREGATE_NO_LANE(the bats file reaches the script through$BATS_TEST_DIRNAME/../scripts/tool, which the literal scan doesn't follow, so the mapping must be declared)The pass, fail and zero-run paths all behave as the PR describes on a real suite. We haven't tried a lane long enough to test the stall supervisor.
One question for the design:
runneris a single command, so in a repo with both bats andnode --testtests, every selected file goes to that one command..batsfiles to bats and.test.mjsfiles tonode --test. With a wrapper, though,parseSummaryno longer seesbatsin the runner name, so it tries the other runners' summary formats first and treats bats as a last resort.runner(for example{".bats": "bats {files}", ".mjs": "node --test {files}"}) fit better?