Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 46 additions & 13 deletions .github/workflows/docs-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ on:
- 'web/sites/guides/package.json'
- 'web/sites/guides/src/sidebars/v4-0-0.json'
- '.github/workflows/docs-verify.yml'
# The harness exercises the checkout's CLI module (overlaid onto the
# installed brew CLI below), so CLI changes can flip {test:cli} blocks
# red — run the docs gate when the CLI module changes (#3042).
- 'cli/lucli/**'

jobs:
verify:
Expand All @@ -21,6 +25,13 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 20

env:
# Attestation mode (#3042): consumed by lib/exec.mjs
# wheelsBinaryAttestation() and echoed by the smoke-test step, so the
# log states exactly whose CLI code the {test:cli}/{test:tutorial}
# blocks dispatched to. github.sha is hex-only (injection-safe).
WHEELS_ATTEST_MODE: "checkout cli/lucli module overlay @ ${{ github.sha }} (released LuCLI runtime via brew)"

steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -70,23 +81,45 @@ jobs:
sed -i 's|/openjdk.jdk/Contents/Home||g' "$WRAPPER"
grep JAVA_HOME "$WRAPPER"

- name: Overlay checkout CLI module (branch attestation)
# Binary attestation (#3042): `wheels` is the released LuCLI runtime
# plus a CFML module — and the module IS this repo's cli/lucli/ (the
# brew formula ships it verbatim as wheels-module-<ver>.tar.gz, plus
# vendor/wheels/ staged inside it). The wrapper installed above syncs
# that released module to $HOME/.wheels/modules/wheels the first time
# a non-intercepted command runs. Write that directory from the
# CHECKOUT instead, before anything triggers the first-run sync, so
# every `wheels` invocation in this job dispatches to the branch's
# CLI module. {test:cli} blocks then attest to the tree under review:
# a branch change to a command's output flips its block red.
#
# The .module-version marker is copied from the formula so the
# wrapper's version-diff sync never overwrites the overlay with the
# released module mid-job. (Note: `wheels --version` and `--help`
# are intercepted in the wrapper itself — kept in sync with
# Module.cfc — so those two surfaces still answer with released
# wrapper text; every real subcommand runs branch code.)
#
# Out of scope: the LuCLI runtime stays at the released version the
# formula pins — runtime changes ship via LuCLI releases, not this
# repo's PRs.
run: |
MODULE_DST="$HOME/.wheels/modules/wheels"
rm -rf "$MODULE_DST"
mkdir -p "$MODULE_DST/vendor/wheels"
cp -R "$GITHUB_WORKSPACE/cli/lucli/." "$MODULE_DST/"
cp -R "$GITHUB_WORKSPACE/vendor/wheels/." "$MODULE_DST/vendor/wheels/"
cp "$(brew --prefix wheels)/share/wheels/.module-version" "$MODULE_DST/.module-version"
echo "Overlaid $MODULE_DST from checkout (marker: $(cat "$MODULE_DST/.module-version"))"

- name: Smoke-test the CLI (binary attestation)
# Binary attestation (#3042): this workflow installs the RELEASED
# brew CLI, so {test:cli}/{test:compile}/{test:tutorial} blocks
# attest to that release — not a CLI built from this checkout.
# verify-docs.mjs prints the same "wheels binary: <path> ... " line
# at run start. To attest to a branch-built CLI instead, export
# WHEELS_BIN pointing at it (not wired up yet — issue #3042 tracks
# building the CLI from the checkout here).
# verify-docs.mjs prints the full attestation line (binary path,
# resolution source, version, and WHEELS_ATTEST_MODE) at run start;
# this step is the early, human-greppable copy of the same facts.
run: |
command -v wheels
wheels --version

- name: Warm up wheels module (first-run copy)
# Homebrew wrapper copies the module to $HOME/.wheels/modules/wheels
# on first invocation. Trigger it so the module is in place before
# the harness spawns `wheels`.
run: wheels --version >/dev/null
echo "attest mode: $WHEELS_ATTEST_MODE"

- name: Run harness unit tests
working-directory: web/sites/guides
Expand Down
34 changes: 22 additions & 12 deletions web/sites/guides/scripts/verify-docs/VALIDATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,22 +192,32 @@ binary (`drivers/tutorial.mjs`, `ensureServer()`), not a fresh `PATH`
lookup — so `WHEELS_BIN` redirects it like every other spawn.

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

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

A green run only attests to the binary named on that line.

**CI implication:** `.github/workflows/docs-verify.yml` installs the
**released** brew CLI and does not set `WHEELS_BIN`, so a green CI run of
`{test:cli}` / `{test:compile}` / `{test:tutorial}` blocks attests to the
released CLI — not to a CLI built from the PR's checkout. Wiring CI to a
branch-built CLI (so a CLI behavior change in a PR can flip a cli block
red) is tracked in [#3042](https://github.com/wheels-dev/wheels/issues/3042).
To attest to a locally built CLI, point `WHEELS_BIN` at it before running
the harness.
A green run only attests to the binary + mode named on that line. The mode
comes from `WHEELS_ATTEST_MODE` (free-form text, set by whoever arranged a
non-default module); when unset it reports `as-installed`.

**CI (#3042):** the `wheels` CLI is the released LuCLI runtime plus a CFML
module, and that module is this repo's `cli/lucli/`. `.github/workflows/docs-verify.yml`
installs the released brew CLI, then **overlays the checkout's `cli/lucli/`
(plus `vendor/wheels/`) onto `$HOME/.wheels/modules/wheels`** before any
command runs, and sets `WHEELS_ATTEST_MODE` accordingly. So a green CI run
of `{test:cli}` / `{test:tutorial}` blocks attests to the PR branch's CLI
module on the released runtime — a branch change to a command's behavior
flips its block red. Two caveats: the LuCLI runtime itself stays at the
released version (runtime changes ship via LuCLI releases, not this repo),
and bare `wheels --version` / `wheels --help` are intercepted by the brew
wrapper script before the module is consulted, so those two surfaces still
answer with released wrapper text.

To attest to a locally built CLI, point `WHEELS_BIN` at it (and set
`WHEELS_ATTEST_MODE` to describe it) before running the harness.

## Running the harness locally

Expand Down
18 changes: 12 additions & 6 deletions web/sites/guides/scripts/verify-docs/lib/exec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,20 @@ export const RESOLVED_WHEELS = resolveWheels();

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

/**
Expand Down
36 changes: 36 additions & 0 deletions web/sites/guides/scripts/verify-docs/test/exec.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { wheelsBinaryAttestation } from '../lib/exec.mjs';

const TIMEOUT = 120_000;

// The attestation line must state which MODE the run exercised (#3042):
// CI sets WHEELS_ATTEST_MODE when it overlays the checkout's cli/lucli
// module onto the installed CLI; without it the line must say the binary
// ran as-installed so a green run is never mistaken for branch coverage.

test('attestation includes mode from WHEELS_ATTEST_MODE', { timeout: TIMEOUT }, async () => {
const prev = process.env.WHEELS_ATTEST_MODE;
process.env.WHEELS_ATTEST_MODE = 'checkout cli/lucli module overlay @ deadbeef';
try {
const line = await wheelsBinaryAttestation();
assert.match(line, /mode: checkout cli\/lucli module overlay @ deadbeef/);
} finally {
if (prev === undefined) delete process.env.WHEELS_ATTEST_MODE;
else process.env.WHEELS_ATTEST_MODE = prev;
}
});

test('attestation defaults to as-installed mode when WHEELS_ATTEST_MODE is unset', { timeout: TIMEOUT }, async () => {
const prev = process.env.WHEELS_ATTEST_MODE;
delete process.env.WHEELS_ATTEST_MODE;
try {
const line = await wheelsBinaryAttestation();
assert.match(line, /mode: as-installed/);
// Still carries the original path + resolution + version segments.
assert.match(line, /wheels binary: /);
assert.match(line, /\(via (WHEELS_BIN|PATH discovery)\)/);
} finally {
if (prev !== undefined) process.env.WHEELS_ATTEST_MODE = prev;
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ Migrations are versioned CFCs that carry your schema forward and back. Each one

## Running migrations

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.
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.

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

- `wheels migrate latest` — apply every pending migration in order. The most common command; you'll run it after pulling someone else's changes.
Expand Down
8 changes: 4 additions & 4 deletions web/sites/guides/src/content/docs/v4-0-0/basics/routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ Rename the resource once in `routes.cfm` and every helper updates. See [Forms an

## Listing all routes

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:
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:

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

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

## Related guides

Expand Down
6 changes: 3 additions & 3 deletions web/sites/guides/src/content/docs/v4-0-0/basics/seeding.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ Execution order is fixed: `app/db/seeds.cfm` runs first (always), then `app/db/s

## Running seeds

Seeds run against your app's datasource, so the server has to be up.
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.

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

The commands you'll actually use day-to-day:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ This path exists for people who already run LuCLI for other modules and don't wa

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

```bash {test:cli cmd="wheels --version" asserts-output="Wheels"}
```bash {test:cli cmd="wheels --version" asserts-output="Wheels Version:"}
wheels --version
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Fifteen minutes. Zero explanations. You run commands, you see results, you know

First, confirm the CLI is installed:

```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels"}
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels Version:"}
wheels --version
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ The two are mutually exclusive — both expose the `wheels` binary. You install

3. Verify:

```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels"}
```bash {test:cli cmd="wheels --version" asserts-stdout="Wheels Version:"}
wheels --version
```

Expand Down
Loading