@@ -113,6 +113,87 @@ jobs:
113113 shell : bash
114114 run : sh scripts/test-completion.sh
115115
116+ # Which `commands search` queries a PR fixed and broke, against its base,
117+ # written to the job summary. It reports and never fails: the floors that
118+ # `cargo test` holds in the build job are the gate. A job summary rather
119+ # than a PR comment because it needs no write token, so a PR from a fork
120+ # gets one too. One runner: ranking is the same everywhere.
121+ search-eval :
122+ name : commands search eval
123+ runs-on : ubuntu-latest
124+ timeout-minutes : 20
125+ permissions :
126+ contents : read
127+ steps :
128+ # Whole history, so the base commit is there to check out beside it.
129+ # No credential left behind: nothing here pushes or fetches again.
130+ - uses : actions/checkout@v7
131+ with :
132+ fetch-depth : 0
133+ persist-credentials : false
134+
135+ # As in the build job: install exactly the pinned toolchain.
136+ - name : Read the pinned toolchain
137+ id : toolchain
138+ run : |
139+ echo "toolchain=$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -1)" >>"$GITHUB_OUTPUT"
140+
141+ - name : Install Rust
142+ uses : dtolnay/rust-toolchain@stable
143+ with :
144+ toolchain : ${{ steps.toolchain.outputs.toolchain }}
145+
146+ # The exit status is recorded rather than failing the step: a run below
147+ # its floor still writes its reports, the build job is where that
148+ # failure is reported, and the summary needs the status to say whether
149+ # missing reports mean a failed run or one with no eval to run.
150+ - name : Run the eval on this branch
151+ id : head
152+ run : |
153+ status=0
154+ MAPBOX_SEARCH_EVAL_REPORT="$RUNNER_TEMP/eval-head" cargo test --locked --bin mapbox eval_set || status=$?
155+ echo "status=$status" >>"$GITHUB_OUTPUT"
156+
157+ # In a worktree sharing this target directory, so only the crate itself
158+ # rebuilds. It rebuilds only because the worktree is added after the
159+ # head build: cargo goes by mtime, and base sources older than that
160+ # build would reuse its binary. Keep this step after the head run.
161+ # A base from before the eval or its reports passes and writes none;
162+ # one that fails to build or check out exits non-zero. The summary
163+ # tells the two apart by the status.
164+ - name : Run the eval on the base
165+ id : base
166+ if : github.event_name == 'pull_request'
167+ env :
168+ BASE_SHA : ${{ github.event.pull_request.base.sha }}
169+ run : |
170+ status=0
171+ {
172+ git worktree add --detach "$RUNNER_TEMP/base" "$BASE_SHA" &&
173+ cd "$RUNNER_TEMP/base" &&
174+ CARGO_TARGET_DIR="$GITHUB_WORKSPACE/target" \
175+ MAPBOX_SEARCH_EVAL_REPORT="$RUNNER_TEMP/eval-base" \
176+ cargo test --locked --bin mapbox eval_set
177+ } || status=$?
178+ echo "status=$status" >>"$GITHUB_OUTPUT"
179+
180+ # No `--base` on a push: the script then says there was no base rather
181+ # than that the base had no reports. A status left empty by a step that
182+ # never finished reads as "did not finish".
183+ - name : Write the summary
184+ if : ${{ !cancelled() }}
185+ env :
186+ EVENT : ${{ github.event_name }}
187+ HEAD_STATUS : ${{ steps.head.outputs.status }}
188+ BASE_STATUS : ${{ steps.base.outputs.status }}
189+ run : |
190+ set -- --head "$RUNNER_TEMP/eval-head" --head-status "$HEAD_STATUS" \
191+ --sets tests/fixtures/commands_search
192+ if [ "$EVENT" = pull_request ]; then
193+ set -- "$@" --base "$RUNNER_TEMP/eval-base" --base-status "$BASE_STATUS"
194+ fi
195+ python3 scripts/commands-search-report.py "$@" >>"$GITHUB_STEP_SUMMARY"
196+
116197 # No Rust: this is where the repo's shell gets checked, install.sh above all
117198 # — it is served to machines we do not control, and this is the only thing
118199 # that checks it. Both runners, because the portability it has to get right
@@ -136,6 +217,7 @@ jobs:
136217 sh -n scripts/install.sh
137218 sh -n scripts/test-install.sh
138219 sh -n scripts/test-completion.sh
220+ sh -n scripts/test-commands-search-report.sh
139221
140222 # -s sh, not the default: bash would accept things `curl | sh` will not.
141223 # Once is enough — the findings do not depend on the runner. The version
@@ -145,11 +227,19 @@ jobs:
145227 # Kept clean against 0.9, 0.10 and 0.11.
146228 - name : Shellcheck
147229 if : runner.os == 'Linux'
148- run : shellcheck -s sh scripts/install.sh scripts/test-install.sh scripts/test-completion.sh
230+ run : shellcheck -s sh scripts/install.sh scripts/test-install.sh scripts/test-completion.sh scripts/test-commands-search-report.sh
149231
150232 - name : Install, verify and prompt against a local channel
151233 run : sh scripts/test-install.sh
152234
235+ # The `commands search eval` job's summary script, against hand-written
236+ # reports: that job never fails, so this is where a summary that says
237+ # the wrong thing would be caught. Python only, so it lives here rather
238+ # than beside the Rust. Once is enough, as for shellcheck.
239+ - name : Summarize hand-written search eval reports
240+ if : runner.os == 'Linux'
241+ run : sh scripts/test-commands-search-report.sh
242+
153243 # The other half of the same job, for the installer install.sh stops short
154244 # of. Both shells, because both are on a stock Windows 11 and they differ
155245 # exactly where this script lives: the default TLS versions, what `2>` does
0 commit comments