fix(ci): build the frontend before any Go typecheck
main.go embeds frontend/dist, so lint, test and bindings-check all fail on a fresh clone until pnpm build has run. Invisible locally because anyone who has started the app has a dist/ lying around, and the container prototype missed it because both job scripts shared one mounted directory, so job 1 consumed a dist/ that job 2's dev-headless had built on an earlier run.
This commit is contained in:
@@ -113,6 +113,16 @@ jobs:
|
|||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
npx playwright install --with-deps chromium
|
npx playwright install --with-deps chromium
|
||||||
|
|
||||||
|
# main.go embeds the built frontend (`//go:embed all:frontend/dist`),
|
||||||
|
# so *every* Go typecheck needs it to exist first — lint, test and
|
||||||
|
# bindings-check all fail with "pattern all:frontend/dist: no
|
||||||
|
# matching files found" on a fresh clone. This never bites locally
|
||||||
|
# because anyone who has run the app once has a dist/ lying around,
|
||||||
|
# which is exactly why CI has to do it explicitly.
|
||||||
|
- name: Build the frontend
|
||||||
|
working-directory: /src/frontend
|
||||||
|
run: pnpm build
|
||||||
|
|
||||||
# `make lint` and `make test` each run all three build
|
# `make lint` and `make test` each run all three build
|
||||||
# configurations (app / indexbuild / dev) with matching tag sets.
|
# configurations (app / indexbuild / dev) with matching tag sets.
|
||||||
- name: Lint
|
- name: Lint
|
||||||
|
|||||||
@@ -638,3 +638,30 @@ WebKit2GTK signal we otherwise have no way to get. And it is cheap
|
|||||||
enough that the earlier plan to scope it (skip `testctl.spec.ts`,
|
enough that the earlier plan to scope it (skip `testctl.spec.ts`,
|
||||||
which tests Go and has no engine content) is not worth the
|
which tests Go and has no engine content) is not worth the
|
||||||
complexity at 11 s.
|
complexity at 11 s.
|
||||||
|
|
||||||
|
## Every Go typecheck needs a built frontend, and a shared prototype dir hid it
|
||||||
|
|
||||||
|
`main.go` embeds the built assets (`//go:embed all:frontend/dist`), so
|
||||||
|
`make lint`, `make test` and `make bindings-check` all fail on a fresh
|
||||||
|
clone with `pattern all:frontend/dist: no matching files found
|
||||||
|
(typecheck)` until `pnpm build` has run once. It never bites locally
|
||||||
|
because anyone who has started the app has a `dist/` lying around, and
|
||||||
|
it is not a Go dependency anything declares — which is why CI is the
|
||||||
|
only place it shows up. Job 1 now builds the frontend before linting.
|
||||||
|
|
||||||
|
**The prototype missed it for an embarrassing and reusable reason.**
|
||||||
|
Both job scripts were run against the *same* mounted directory, and
|
||||||
|
job 2 runs `dev-headless`, which builds the frontend. So job 1 was
|
||||||
|
silently consuming an artifact job 2 had produced on an earlier run,
|
||||||
|
in an order CI never uses. A container proved the commands work; it did
|
||||||
|
not prove the *inputs* were what CI would have, because the directory
|
||||||
|
had accumulated state exactly the way a developer machine does.
|
||||||
|
|
||||||
|
The fix for the technique, not just the workflow: verify each job in a
|
||||||
|
**fresh `git clone --no-hardlinks` of the pushed commit** (a plain
|
||||||
|
`git clone` of a repo on the same filesystem fails with "Invalid
|
||||||
|
cross-device link" into `/tmp` on a different device), not in an rsync
|
||||||
|
of the working tree, and never two jobs in one directory. The
|
||||||
|
distinction that matters is not clean-vs-dirty but *whose* dirt: a
|
||||||
|
working-tree copy carries a developer's accumulated build output, which
|
||||||
|
is the one thing CI is supposed to be checking you do not depend on.
|
||||||
|
|||||||
Reference in New Issue
Block a user