Re-vendor the canonical files from sneak/prompts at c55a0cb (closes #95)
check / check (push) Waiting to run
check / check (push) Waiting to run
Every vendored file, REPO_POLICIES.md and every model script is the copy at sneak/prompts c55a0cb, with this repository's own entries kept after the canonical content. Lint and test are phases of the Dockerfile that write no image, built uncached. make test runs the suite under the race detector as nobody, because root reads the files the tests make unreadable. Dockerfile.lint, script/verify-lint-image-pin and make test-race are gone. Prettier runs on the host, from the node and yarn that script/bootstrap installs. golangci-lint v2.14.0 raises no findings. .claude/settings.json is deleted. Deviation: the set comes from c55a0cb on next rather than dd4027b, as the instructions on sneak/prompts#78 allow. Model: opus-5-5
This commit is contained in:
@@ -746,104 +746,62 @@ entrypoints are:
|
||||
- `script/bootstrap` — install everything needed to build and develop this
|
||||
repository, idempotently, assuming nothing is present. `git`, `make`, and `go`
|
||||
come from the first of nix, apt, brew, or apk found on the host, and are
|
||||
presence-checked only. `golangci-lint` and prettier are deliberately **not**
|
||||
installed: they run in Docker (see `script/lint` and `script/fmt`) and never
|
||||
from a host install, so there is no host copy to drift from the pin. A missing
|
||||
`docker` is warned about rather than installed or treated as fatal —
|
||||
everything except linting, formatting and `make test-race` works without it.
|
||||
Ends with `go mod download`.
|
||||
presence-checked only. An installed node is used as it is; otherwise node
|
||||
22.17.0 is installed through nvm, which comes from a release archive whose
|
||||
sha256 the script checks. A yarn already on `PATH` is used as it is; otherwise
|
||||
yarn 1.22.22 is activated through corepack, or installed with `npm` when there
|
||||
is no corepack. `yarn install --frozen-lockfile` then installs the prettier
|
||||
that `package.json` and `yarn.lock` pin. `golangci-lint` is never installed:
|
||||
it runs in Docker (see `script/lint`). `docker` is not installed either;
|
||||
testing, linting and the image build need it. Ends with `go mod download`.
|
||||
- `script/setup` — make a fresh clone ready for development: runs
|
||||
`script/bootstrap`, then `script/install-precommit`.
|
||||
- `script/projectname` — print this project's name (`sfdupes`). Scripts that
|
||||
need the name call it, so they stay identical across repositories.
|
||||
- `script/test` — run the test suite with a 30-second timeout and coverage
|
||||
enabled, rerunning verbosely on failure so the logs show which test failed.
|
||||
- `script/test-race` — run the test suite under the race detector with a
|
||||
60-second timeout. The detector needs cgo and a C compiler, which the build
|
||||
never uses, so the tests run in a digest-pinned Debian `golang` image that has
|
||||
`gcc`, with the checkout mounted read-only; the container is removed when it
|
||||
exits. They run as the calling user, or as `nobody` when that is root, because
|
||||
several tests make a file unreadable and root reads it anyway; only then must
|
||||
the checkout be readable by other users. Not part of `script/check`. Every run
|
||||
starts with empty caches, so it needs the network and takes minutes, and the
|
||||
mount needs a local docker daemon.
|
||||
- `script/lint` — run the linter. It builds `Dockerfile.lint`, which copies the
|
||||
repository into the digest-pinned `golangci/golangci-lint` image and runs
|
||||
`golangci-lint config verify` and `golangci-lint run` as build steps, so a
|
||||
successful build is a clean lint. That exit status is all it produces, so it
|
||||
runs with `--output=type=cacheonly` and writes no image; a run leaves only
|
||||
build cache. The linter is never run on the host, which makes a working
|
||||
`docker` the one prerequisite for linting — and therefore for `make check` and
|
||||
the pre-commit hook. Offline machines: the gate steps themselves make no
|
||||
network calls. `golangci-lint run` does not, and neither does
|
||||
`golangci-lint config verify` — it validates against a schema the pinned
|
||||
binary embeds, measured under `--network none` to both pass a valid config and
|
||||
reject an invalid one. The build around them does. `Dockerfile.lint` runs
|
||||
`go mod download` before the gates and this module has external dependencies,
|
||||
so a first lint on a machine with a cold BuildKit cache reaches the network
|
||||
there (as well as pulling the pinned image); under `--network none` it fails
|
||||
at that step, before any gate. That layer sits above the gates and stays
|
||||
cached, so once it is warm `script/lint` — and with it `make check` — runs
|
||||
entirely offline, until `go.mod` or `go.sum` changes and the download layer
|
||||
goes cold again. Because the daemon only ever sees a build context, this works
|
||||
when the docker daemon is remote and bind mounts are impossible.
|
||||
- `script/test` — run the test suite under the race detector, with a 90-second
|
||||
timeout and coverage enabled, rerunning verbosely on failure so the logs show
|
||||
which test failed. It builds the `Dockerfile`'s `test` phase alone and writes
|
||||
no image. The race detector needs cgo and a C compiler, which the build never
|
||||
uses, so the phase starts from a digest-pinned Debian `golang` image, which
|
||||
has `gcc`. The tests run as `nobody`, because several of them make a file
|
||||
unreadable and root reads it anyway.
|
||||
- `script/lint` — run the linter. It builds the `Dockerfile`'s `lint` phase
|
||||
alone and writes no image: in the digest-pinned `golangci/golangci-lint`
|
||||
image, the gofmt check, `golangci-lint config verify` and `golangci-lint run`
|
||||
run as build steps, so a successful build is a clean lint. The linter is never
|
||||
run on the host, which makes a working `docker` the one prerequisite for
|
||||
linting.
|
||||
- `script/fmt` — format in place: the Go sources with `gofmt -s -w`, and every
|
||||
Markdown file with prettier, at the settings in `.prettierrc` (4-space
|
||||
indents, prose wrapped at 80 columns). prettier is pinned by hash through
|
||||
`package.json` and `yarn.lock` and never installed on the host: this builds
|
||||
the `Dockerfile`'s `prettier` stage, a digest-pinned node image into which
|
||||
`yarn install --frozen-lockfile` installs it, tagged `sfdupes-prettier`, and
|
||||
runs that with the repository mounted, as the calling user. Needs `docker`,
|
||||
and because of the mount, unlike `script/lint`, a local docker daemon.
|
||||
- `script/fmt-check` — the read-only counterpart of `script/fmt`, with the
|
||||
repository mounted read-only: prints any unformatted file and exits non-zero
|
||||
instead of writing. gofmt and prettier both run every time, and each names
|
||||
itself when it fails. The `Dockerfile` runs the same two checks as gates: the
|
||||
gofmt check in its lint stage, prettier in its `markdown` stage.
|
||||
indents, prose wrapped at 80 columns). Both run on the host, prettier through
|
||||
yarn at the version `yarn.lock` pins. When yarn is not on `PATH`, this loads
|
||||
the node 22.17.0 that `script/bootstrap` installed through nvm.
|
||||
- `script/fmt-check` — the read-only counterpart of `script/fmt`: prints any
|
||||
unformatted file and exits non-zero instead of writing. gofmt and prettier
|
||||
both run every time, and each names itself when it fails. The `Dockerfile`'s
|
||||
`lint` phase runs the same gofmt check.
|
||||
- `script/check` — run `script/test`, `script/lint`, and `script/fmt-check`, in
|
||||
that order. Modifies nothing. Needs `docker`, because `script/lint` and
|
||||
`script/fmt-check` do.
|
||||
that order. Modifies nothing. The first two need `docker`, the third what
|
||||
`script/bootstrap` installs.
|
||||
- `script/docker` — build the Docker image, tagged with the name from
|
||||
`script/projectname`. The `Dockerfile` runs the gates as build steps, so this
|
||||
is also the check a developer or reviewer runs by hand.
|
||||
- `script/cibuild` — build the Docker image untagged. This is what the Gitea
|
||||
workflow runs on push; because the gates run as build steps, a successful
|
||||
build implies the repository is green.
|
||||
`script/projectname`, passing the output of
|
||||
`git describe --tags --always --dirty` (or `unknown` when that is empty) as
|
||||
the `VERSION` build argument. The `Dockerfile`'s build stage depends on its
|
||||
`lint` and `test` phases, so this also runs the tests and the linter.
|
||||
- `script/cibuild` — run `script/bootstrap`, then `script/check`, then build the
|
||||
image as `script/docker` does. This is what the Gitea workflow runs on push; a
|
||||
successful run means every check passed. The tests and the linter run twice:
|
||||
once in `script/check`, and again as stages of the image build.
|
||||
- `script/precommit` — run by the git pre-commit hook: `go mod tidy` must be a
|
||||
no-op (a resulting change to `go.mod` or `go.sum` fails the commit), then
|
||||
`script/check`.
|
||||
- `script/install-precommit` — install the git pre-commit hook that runs
|
||||
`script/precommit`. The hook is written to the common git directory, so the
|
||||
main checkout and every worktree share it.
|
||||
- `script/verify-lint-image-pin` — fail unless the `golangci/golangci-lint`
|
||||
reference in `Dockerfile.lint` and the one in the `Dockerfile` lint stage are
|
||||
the same image at the same digest, naming both if not. The linter is pinned in
|
||||
those two files and nothing else keeps them in sync, so a bump applied to one
|
||||
alone would leave `make lint` and the `Dockerfile`'s fail-fast lint stage
|
||||
checking the same tree against different rulesets, both green. The guard
|
||||
restates neither pin — a third copy would be the same drift one file further
|
||||
out — and runs as a gate in both files, so `make lint`, `make check` and
|
||||
`make docker` all catch it.
|
||||
- `script/install-precommit` — install the git pre-commit hook, as
|
||||
`.git/hooks/pre-commit`, that runs `script/precommit`.
|
||||
|
||||
`script/verify-linter-pin` used to live here. It compared a linter binary
|
||||
against a version pin in `script/bootstrap`, and both of its subjects are gone:
|
||||
no linter binary is copied between build stages any more, and bootstrap pins no
|
||||
version because it installs no linter. The drift it existed to catch has moved
|
||||
from binary-versus-pin to pin-versus-pin, which is what
|
||||
`script/verify-lint-image-pin` above checks.
|
||||
|
||||
`script/lint`, `script/docker` and `script/cibuild` all pass a freshly computed
|
||||
`CHECK_EPOCH` build argument, and the gate steps in `Dockerfile.lint` and
|
||||
`Dockerfile` reference it. Without that, an unchanged tree lets Docker serve the
|
||||
gate layers from cache and the build exits 0 having executed no tests and no
|
||||
lint — a green it never earned, and one this repository has produced twice.
|
||||
`CHECK_EPOCH` invalidates the gate layers on every run while leaving the pinned
|
||||
base images and the dependency layers cached. Each script's value carries the
|
||||
process id as well as the epoch, because two runs land inside the same second
|
||||
easily and a bare epoch would cache the second one. Each `Dockerfile` stage with
|
||||
gates fails when the value is empty, so a bare `docker build .` stops with
|
||||
`CHECK_EPOCH is unset; build via script/cibuild or script/docker` instead of
|
||||
serving the gates from cache.
|
||||
Every `docker build` in `script/` passes `--no-cache`. On an unchanged tree
|
||||
Docker would serve the gate steps from its cache, and the build would pass
|
||||
having run no test and no linter. Every run therefore downloads the Go modules
|
||||
again and needs the network.
|
||||
|
||||
## Build
|
||||
|
||||
@@ -855,17 +813,15 @@ compile recipe:
|
||||
the default target.
|
||||
- `make bootstrap` — install the build and development dependencies.
|
||||
- `make setup` — prepare a fresh clone: `bootstrap` plus the pre-commit hook.
|
||||
- `make test` — run the test suite (30-second timeout; reruns with `-v` on
|
||||
failure).
|
||||
- `make test-race` — run the test suite under the race detector, in Docker (see
|
||||
`script/test-race`); requires `docker`. Not part of `make check`.
|
||||
- `make lint` — run `golangci-lint` with the repo config, in Docker (see
|
||||
`script/lint`); requires `docker`.
|
||||
- `make test` — run the test suite under the race detector, in Docker (90-second
|
||||
timeout; reruns with `-v` on failure; see `script/test`); requires `docker`.
|
||||
- `make lint` — run `golangci-lint` with the repo config and the gofmt check, in
|
||||
Docker (see `script/lint`); requires `docker`.
|
||||
- `make fmt` / `make fmt-check` — format the Go sources and the Markdown /
|
||||
verify formatting without writing; requires `docker`, for prettier (see
|
||||
`script/fmt`).
|
||||
verify formatting without writing, on the host; requires `go` and what
|
||||
`make bootstrap` installs (see `script/fmt`).
|
||||
- `make check` — `test`, `lint`, and `fmt-check`; modifies nothing. Requires
|
||||
`docker`, via `lint` and `fmt-check`.
|
||||
`docker` and what `make bootstrap` installs.
|
||||
- `make docker` — build the Docker image, which runs the gates as build stages.
|
||||
- `make hooks` — install the pre-commit hook.
|
||||
- `make clean` — remove the binary.
|
||||
|
||||
Reference in New Issue
Block a user