Skip to content

Commit 4dbbe22

Browse files
bpamiriclaude
andauthored
ci(docs): exercise the checkout's CLI module in docs-verify and attest the mode (#3170)
The wheels CLI is the released LuCLI runtime plus this repo's cli/lucli/ module. docs-verify now overlays the checkout's cli/lucli/ (and vendor/wheels/) onto $HOME/.wheels/modules/wheels before any command runs, so every {test:cli}/{test:tutorial} block dispatches to the branch under review instead of the released brew module. cli/lucli/** is added to the workflow's path filter so CLI PRs run the docs gate. The attestation line gains a mode segment fed by WHEELS_ATTEST_MODE (default: 'as-installed (no module overlay declared)'), so every run states whose CLI code it exercised; CI sets it to the overlay + sha. Also strengthens six of the wheels --version-only {test:cli} blocks to command-specific assertions: migrate info / seed / routes now pin the documented no-running-server refusal (exit 1 + message), and the three install-verification blocks pin the documented 'Wheels Version:' line. Closes #3042 Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 5d89911 commit 4dbbe22

10 files changed

Lines changed: 129 additions & 44 deletions

File tree

.github/workflows/docs-verify.yml

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ on:
99
- 'web/sites/guides/package.json'
1010
- 'web/sites/guides/src/sidebars/v4-0-0.json'
1111
- '.github/workflows/docs-verify.yml'
12+
# The harness exercises the checkout's CLI module (overlaid onto the
13+
# installed brew CLI below), so CLI changes can flip {test:cli} blocks
14+
# red — run the docs gate when the CLI module changes (#3042).
15+
- 'cli/lucli/**'
1216

1317
jobs:
1418
verify:
@@ -21,6 +25,13 @@ jobs:
2125
runs-on: ubuntu-latest
2226
timeout-minutes: 20
2327

28+
env:
29+
# Attestation mode (#3042): consumed by lib/exec.mjs
30+
# wheelsBinaryAttestation() and echoed by the smoke-test step, so the
31+
# log states exactly whose CLI code the {test:cli}/{test:tutorial}
32+
# blocks dispatched to. github.sha is hex-only (injection-safe).
33+
WHEELS_ATTEST_MODE: "checkout cli/lucli module overlay @ ${{ github.sha }} (released LuCLI runtime via brew)"
34+
2435
steps:
2536
- name: Checkout
2637
uses: actions/checkout@v6
@@ -70,23 +81,45 @@ jobs:
7081
sed -i 's|/openjdk.jdk/Contents/Home||g' "$WRAPPER"
7182
grep JAVA_HOME "$WRAPPER"
7283
84+
- name: Overlay checkout CLI module (branch attestation)
85+
# Binary attestation (#3042): `wheels` is the released LuCLI runtime
86+
# plus a CFML module — and the module IS this repo's cli/lucli/ (the
87+
# brew formula ships it verbatim as wheels-module-<ver>.tar.gz, plus
88+
# vendor/wheels/ staged inside it). The wrapper installed above syncs
89+
# that released module to $HOME/.wheels/modules/wheels the first time
90+
# a non-intercepted command runs. Write that directory from the
91+
# CHECKOUT instead, before anything triggers the first-run sync, so
92+
# every `wheels` invocation in this job dispatches to the branch's
93+
# CLI module. {test:cli} blocks then attest to the tree under review:
94+
# a branch change to a command's output flips its block red.
95+
#
96+
# The .module-version marker is copied from the formula so the
97+
# wrapper's version-diff sync never overwrites the overlay with the
98+
# released module mid-job. (Note: `wheels --version` and `--help`
99+
# are intercepted in the wrapper itself — kept in sync with
100+
# Module.cfc — so those two surfaces still answer with released
101+
# wrapper text; every real subcommand runs branch code.)
102+
#
103+
# Out of scope: the LuCLI runtime stays at the released version the
104+
# formula pins — runtime changes ship via LuCLI releases, not this
105+
# repo's PRs.
106+
run: |
107+
MODULE_DST="$HOME/.wheels/modules/wheels"
108+
rm -rf "$MODULE_DST"
109+
mkdir -p "$MODULE_DST/vendor/wheels"
110+
cp -R "$GITHUB_WORKSPACE/cli/lucli/." "$MODULE_DST/"
111+
cp -R "$GITHUB_WORKSPACE/vendor/wheels/." "$MODULE_DST/vendor/wheels/"
112+
cp "$(brew --prefix wheels)/share/wheels/.module-version" "$MODULE_DST/.module-version"
113+
echo "Overlaid $MODULE_DST from checkout (marker: $(cat "$MODULE_DST/.module-version"))"
114+
73115
- name: Smoke-test the CLI (binary attestation)
74-
# Binary attestation (#3042): this workflow installs the RELEASED
75-
# brew CLI, so {test:cli}/{test:compile}/{test:tutorial} blocks
76-
# attest to that release — not a CLI built from this checkout.
77-
# verify-docs.mjs prints the same "wheels binary: <path> ... " line
78-
# at run start. To attest to a branch-built CLI instead, export
79-
# WHEELS_BIN pointing at it (not wired up yet — issue #3042 tracks
80-
# building the CLI from the checkout here).
116+
# verify-docs.mjs prints the full attestation line (binary path,
117+
# resolution source, version, and WHEELS_ATTEST_MODE) at run start;
118+
# this step is the early, human-greppable copy of the same facts.
81119
run: |
82120
command -v wheels
83121
wheels --version
84-
85-
- name: Warm up wheels module (first-run copy)
86-
# Homebrew wrapper copies the module to $HOME/.wheels/modules/wheels
87-
# on first invocation. Trigger it so the module is in place before
88-
# the harness spawns `wheels`.
89-
run: wheels --version >/dev/null
122+
echo "attest mode: $WHEELS_ATTEST_MODE"
90123
91124
- name: Run harness unit tests
92125
working-directory: web/sites/guides

web/sites/guides/scripts/verify-docs/VALIDATION.md

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -192,22 +192,32 @@ binary (`drivers/tutorial.mjs`, `ensureServer()`), not a fresh `PATH`
192192
lookup — so `WHEELS_BIN` redirects it like every other spawn.
193193

194194
`verify-docs.mjs` prints an attestation line at run start stating the
195-
resolved path, how it was resolved, and the binary's `--version` output:
195+
resolved path, how it was resolved, the binary's `--version` output, and
196+
the **mode** — whose CLI code the binary dispatches to:
196197

197198
```
198-
verify-docs: wheels binary: /opt/homebrew/bin/wheels (via PATH discovery) — ...
199+
verify-docs: wheels binary: /opt/homebrew/bin/wheels (via PATH discovery) — Wheels Version: 4.0.3 — mode: as-installed (no module overlay declared)
199200
```
200201

201-
A green run only attests to the binary named on that line.
202-
203-
**CI implication:** `.github/workflows/docs-verify.yml` installs the
204-
**released** brew CLI and does not set `WHEELS_BIN`, so a green CI run of
205-
`{test:cli}` / `{test:compile}` / `{test:tutorial}` blocks attests to the
206-
released CLI — not to a CLI built from the PR's checkout. Wiring CI to a
207-
branch-built CLI (so a CLI behavior change in a PR can flip a cli block
208-
red) is tracked in [#3042](https://github.com/wheels-dev/wheels/issues/3042).
209-
To attest to a locally built CLI, point `WHEELS_BIN` at it before running
210-
the harness.
202+
A green run only attests to the binary + mode named on that line. The mode
203+
comes from `WHEELS_ATTEST_MODE` (free-form text, set by whoever arranged a
204+
non-default module); when unset it reports `as-installed`.
205+
206+
**CI (#3042):** the `wheels` CLI is the released LuCLI runtime plus a CFML
207+
module, and that module is this repo's `cli/lucli/`. `.github/workflows/docs-verify.yml`
208+
installs the released brew CLI, then **overlays the checkout's `cli/lucli/`
209+
(plus `vendor/wheels/`) onto `$HOME/.wheels/modules/wheels`** before any
210+
command runs, and sets `WHEELS_ATTEST_MODE` accordingly. So a green CI run
211+
of `{test:cli}` / `{test:tutorial}` blocks attests to the PR branch's CLI
212+
module on the released runtime — a branch change to a command's behavior
213+
flips its block red. Two caveats: the LuCLI runtime itself stays at the
214+
released version (runtime changes ship via LuCLI releases, not this repo),
215+
and bare `wheels --version` / `wheels --help` are intercepted by the brew
216+
wrapper script before the module is consulted, so those two surfaces still
217+
answer with released wrapper text.
218+
219+
To attest to a locally built CLI, point `WHEELS_BIN` at it (and set
220+
`WHEELS_ATTEST_MODE` to describe it) before running the harness.
211221

212222
## Running the harness locally
213223

web/sites/guides/scripts/verify-docs/lib/exec.mjs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,20 @@ export const RESOLVED_WHEELS = resolveWheels();
3737

3838
/**
3939
* One-line attestation of WHICH `wheels` binary this run exercises:
40-
* the resolved path, how it was resolved, and its `--version` output.
41-
* A green run only attests to the binary named here — on CI the
42-
* docs-verify workflow installs the released brew CLI, so cli blocks
43-
* attest to that release, not the checkout, unless WHEELS_BIN points
44-
* at a branch-built CLI (issue #3042).
40+
* the resolved path, how it was resolved, its `--version` output, and
41+
* the MODE — whose CLI code the binary actually dispatches to (#3042).
42+
*
43+
* Mode comes from WHEELS_ATTEST_MODE. The CI docs-verify workflow sets
44+
* it after overlaying the checkout's cli/lucli module onto the installed
45+
* CLI's module dir, so a green CI run attests to the branch's CLI module
46+
* (on the released LuCLI runtime). Without the env var the line says
47+
* "as-installed": whatever module the resolved binary shipped with —
48+
* locally that's the released brew CLI, and a green run only attests
49+
* to that release, not your checkout.
4550
*/
4651
export async function wheelsBinaryAttestation() {
4752
const source = process.env.WHEELS_BIN ? 'WHEELS_BIN' : 'PATH discovery';
53+
const mode = process.env.WHEELS_ATTEST_MODE || 'as-installed (no module overlay declared)';
4854
const r = await runExec('wheels', ['--version']);
4955
const firstLine = `${r.stdout}\n${r.stderr}`
5056
.split('\n')
@@ -54,7 +60,7 @@ export async function wheelsBinaryAttestation() {
5460
r.code === 0 && firstLine
5561
? firstLine
5662
: `--version failed (exit ${r.code}${firstLine ? `: ${firstLine}` : ''})`;
57-
return `wheels binary: ${RESOLVED_WHEELS} (via ${source}) — ${version}`;
63+
return `wheels binary: ${RESOLVED_WHEELS} (via ${source}) — ${version} — mode: ${mode}`;
5864
}
5965

6066
/**
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { test } from 'node:test';
2+
import { strict as assert } from 'node:assert';
3+
import { wheelsBinaryAttestation } from '../lib/exec.mjs';
4+
5+
const TIMEOUT = 120_000;
6+
7+
// The attestation line must state which MODE the run exercised (#3042):
8+
// CI sets WHEELS_ATTEST_MODE when it overlays the checkout's cli/lucli
9+
// module onto the installed CLI; without it the line must say the binary
10+
// ran as-installed so a green run is never mistaken for branch coverage.
11+
12+
test('attestation includes mode from WHEELS_ATTEST_MODE', { timeout: TIMEOUT }, async () => {
13+
const prev = process.env.WHEELS_ATTEST_MODE;
14+
process.env.WHEELS_ATTEST_MODE = 'checkout cli/lucli module overlay @ deadbeef';
15+
try {
16+
const line = await wheelsBinaryAttestation();
17+
assert.match(line, /mode: checkout cli\/lucli module overlay @ deadbeef/);
18+
} finally {
19+
if (prev === undefined) delete process.env.WHEELS_ATTEST_MODE;
20+
else process.env.WHEELS_ATTEST_MODE = prev;
21+
}
22+
});
23+
24+
test('attestation defaults to as-installed mode when WHEELS_ATTEST_MODE is unset', { timeout: TIMEOUT }, async () => {
25+
const prev = process.env.WHEELS_ATTEST_MODE;
26+
delete process.env.WHEELS_ATTEST_MODE;
27+
try {
28+
const line = await wheelsBinaryAttestation();
29+
assert.match(line, /mode: as-installed/);
30+
// Still carries the original path + resolution + version segments.
31+
assert.match(line, /wheels binary: /);
32+
assert.match(line, /\(via (WHEELS_BIN|PATH discovery)\)/);
33+
} finally {
34+
if (prev !== undefined) process.env.WHEELS_ATTEST_MODE = prev;
35+
}
36+
});

web/sites/guides/src/content/docs/v4-0-0/basics/migrations.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ Migrations are versioned CFCs that carry your schema forward and back. Each one
2525

2626
## Running migrations
2727

28-
Four subcommands cover the day-to-day workflow. Each one connects to your app's datasource and reads the migration history out of `wheels_migrator_versions`, so the app has to be running for them to work — see [Installing Wheels](/v4-0-0/start-here/installing/) for the server setup.
28+
Four subcommands cover the day-to-day workflow. Each one connects to your app's datasource and reads the migration history out of `wheels_migrator_versions`, so the app has to be running for them to work — without a server, every `wheels migrate` subcommand refuses with a pointer at `wheels start` instead of guessing at a database. See [Installing Wheels](/v4-0-0/start-here/installing/) for the server setup.
2929

30-
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels"}
31-
wheels --version
30+
```bash {test:cli cmd="wheels migrate info" asserts-output="No running Wheels server" asserts-exit=1}
31+
wheels migrate info
3232
```
3333

3434
- `wheels migrate latest` — apply every pending migration in order. The most common command; you'll run it after pulling someone else's changes.

web/sites/guides/src/content/docs/v4-0-0/basics/routing.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,13 @@ Rename the resource once in `routes.cfm` and every helper updates. See [Forms an
159159

160160
## Listing all routes
161161

162-
When a route isn't matching what you expect, print the registered route table. `wheels routes` shows every route's method, path, controller#action, and name. For a smoke test that your CLI is installed and responding:
162+
When a route isn't matching what you expect, print the registered route table. `wheels routes` shows every route's method, path, controller#action, and name. It reads the table from your *running* app — with no server up, it refuses and tells you to `wheels start` first:
163163

164-
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels"}
165-
wheels --version
164+
```bash {test:cli cmd="wheels routes" asserts-output="No running Wheels server" asserts-exit=1}
165+
wheels routes
166166
```
167167

168-
Then in your app directory, run `wheels routes` to see the full table.
168+
Start the server, then run `wheels routes` in your app directory to see the full table.
169169

170170
## Related guides
171171

web/sites/guides/src/content/docs/v4-0-0/basics/seeding.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ Execution order is fixed: `app/db/seeds.cfm` runs first (always), then `app/db/s
8585

8686
## Running seeds
8787

88-
Seeds run against your app's datasource, so the server has to be up.
88+
Seeds run against your app's datasource, so the server has to be up — with no server running, `wheels seed` refuses and points you at `wheels start` rather than seeding the wrong database.
8989

90-
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels"}
91-
wheels --version
90+
```bash {test:cli cmd="wheels seed" asserts-output="No running Wheels server" asserts-exit=1}
91+
wheels seed
9292
```
9393

9494
The commands you'll actually use day-to-day:

web/sites/guides/src/content/docs/v4-0-0/command-line-tools/installation.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ This path exists for people who already run LuCLI for other modules and don't wa
201201

202202
After any of the four paths, confirm the binary resolves and reports a version:
203203

204-
```bash {test:cli cmd="wheels --version" asserts-output="Wheels"}
204+
```bash {test:cli cmd="wheels --version" asserts-output="Wheels Version:"}
205205
wheels --version
206206
```
207207

web/sites/guides/src/content/docs/v4-0-0/start-here/first-15-minutes.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Fifteen minutes. Zero explanations. You run commands, you see results, you know
2424

2525
First, confirm the CLI is installed:
2626

27-
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels"}
27+
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels Version:"}
2828
wheels --version
2929
```
3030

web/sites/guides/src/content/docs/v4-0-0/start-here/installing.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ The two are mutually exclusive — both expose the `wheels` binary. You install
9999

100100
3. Verify:
101101

102-
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels"}
102+
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels Version:"}
103103
wheels --version
104104
```
105105

0 commit comments

Comments
 (0)