Run every lint-class check inside Docker (closes #38)
All checks were successful
check / check (push) Successful in 1m9s
All checks were successful
check / check (push) Successful in 1m9s
Add a root Dockerfile.lint that carries the checks as build steps -- a `lint` stage running `hugo --minify --printPathWarnings` and a `fmt-check` stage running the prettier check -- and reduce script/lint and script/fmt-check to building their stage. A successful build is a clean check. There is no host path and deliberately no "am I already inside a container?" branch, which would be a host lint path in disguise. The two stages share a `base` whose first four instructions are byte-identical to the main Dockerfile's, so the expensive `RUN script/bootstrap` layer that compiles the pinned Hugo from source is a cache hit against the main image instead of a second build of the same thing. Resolve the resulting recursion by splitting the checks by where they run, not with an escape hatch. `make check` runs script/lint, so the main Dockerfile can no longer `RUN make check`: that would be docker-in-docker inside a bare Alpine with no docker client and no daemon socket, and script/cibuild is what CI runs on every push. The main Dockerfile therefore runs `make test`, the production build, and script/cibuild builds it and then calls script/lint and script/fmt-check. CI still covers the production build, lint and the format check, and it runs exactly what a developer runs. script/fmt stays on the host because it rewrites the working tree, which a container build cannot do. That makes it the authoritative copy of the prettier version, scope and flags that the fmt-check stage duplicates; both sides carry a keep-in-sync note. The duplication is forced: any `RUN script/fmt-check` inside the image is the recursion again. Caching is waived for the checks in the shape this repo already settled: `ARG CHECK_EPOCH` with no default, declared and guarded separately in each stage because ARG does not cross a FROM, with the value expanded into the checked command as well as the guard so invalidation does not rest on BuildKit's treatment of an unreferenced ARG. All four image-building entrypoints now generate and pass it -- script/cibuild, script/docker, script/lint, script/fmt-check. Verified: two consecutive script/lint runs on an unchanged tree both executed hugo for real, with script/bootstrap CACHED; a constant-epoch counterfactual restored the false green (exit 0, lint layer CACHED, no hugo output); an empty epoch failed closed on the guard; a broken template failed the lint stage and an unformatted README failed the fmt-check stage, both reverted and re-run clean; script/cibuild and `make check` are green with all three checks demonstrably executing.
This commit is contained in:
43
README.md
43
README.md
@@ -39,8 +39,12 @@ build, and the formatting check:
|
||||
make check
|
||||
```
|
||||
|
||||
The lint build and the formatting check run inside Docker, so `make check` needs
|
||||
a working Docker daemon; there is no host fallback.
|
||||
|
||||
`make fmt` rewrites the repo's markdown and CSS to the project's prettier
|
||||
settings; run it if `make check` fails on formatting.
|
||||
settings; run it if `make check` fails on formatting. It runs on the host,
|
||||
because it writes to your working tree.
|
||||
|
||||
To contribute to this site, contact **sneak@sneak.berlin** for git repository
|
||||
access.
|
||||
@@ -61,22 +65,41 @@ provide:
|
||||
git pre-commit hook
|
||||
- `script/test` — the correctness check: a clean `hugo --minify` production
|
||||
build
|
||||
- `script/lint` — a clean build that surfaces broken links and path collisions
|
||||
- `script/lint` — a clean build that surfaces broken links and path collisions,
|
||||
run inside Docker: it builds the `lint` stage of `Dockerfile.lint`, where the
|
||||
check is a build step, so a successful build is a clean lint
|
||||
- `script/fmt` — format every markdown and CSS file in the repo with prettier;
|
||||
the exclusions live in `.prettierignore` with the reason for each
|
||||
- `script/fmt-check` — check that formatting (read-only)
|
||||
the exclusions live in `.prettierignore` with the reason for each. The one
|
||||
prettier entrypoint that runs on the host, because it writes to your working
|
||||
tree
|
||||
- `script/fmt-check` — check that formatting (read-only), also inside Docker:
|
||||
the `fmt-check` stage of `Dockerfile.lint`
|
||||
- `script/check` — run `script/test`, `script/lint`, then `script/fmt-check`;
|
||||
modifies no tracked files
|
||||
- `script/docker` — build the Docker image tagged with the project name
|
||||
- `script/cibuild` — the CI build; the Dockerfile runs `make check`
|
||||
- `script/cibuild` — the CI build: the main image (the production build), then
|
||||
`script/lint` and `script/fmt-check`
|
||||
- `script/install-precommit` — install the git pre-commit hook that runs
|
||||
`script/check`
|
||||
|
||||
Build the image through `script/cibuild` or `script/docker` only. Both pass a
|
||||
per-invocation `CHECK_EPOCH` build argument that the Dockerfile requires, so the
|
||||
`make check` layer can never be served from cache — without it Docker returns a
|
||||
green it did not earn. A bare `docker build .` fails closed on the Dockerfile's
|
||||
`CHECK_EPOCH` guard rather than caching its way to a false success.
|
||||
Every lint run for this repo happens inside a container. `script/lint` and
|
||||
`script/fmt-check` have no host path and no "already inside a container?"
|
||||
branch, so what a developer runs and what CI runs are the same build.
|
||||
|
||||
That is also why the main `Dockerfile` runs `make test` rather than
|
||||
`make check`: `make check` calls `script/lint`, which is itself a
|
||||
`docker build`, so a `make check` inside an image would be docker-in-docker in a
|
||||
bare Alpine with no docker client and no daemon socket. The checks are split by
|
||||
where they run — the production build in `Dockerfile`, lint and the format check
|
||||
in `Dockerfile.lint` — and `script/cibuild` drives all three, so CI coverage is
|
||||
unchanged.
|
||||
|
||||
Build any image through `script/cibuild`, `script/docker`, `script/lint` or
|
||||
`script/fmt-check` only. All four pass a per-invocation `CHECK_EPOCH` build
|
||||
argument that the Dockerfiles require, so a check layer can never be served from
|
||||
cache — without it Docker returns a green it did not earn. A bare `docker build`
|
||||
fails closed on the `CHECK_EPOCH` guard rather than caching its way to a false
|
||||
success.
|
||||
|
||||
A convenience `make serve` target runs `hugo server` for local preview.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user