Build with --no-cache so the check layer actually runs (closes #26)
script/cibuild was a plain `docker build .` and the Dockerfile does `COPY . .` followed by `RUN make check`, so on an unchanged tree Docker served the check layer from cache: the suite never ran and the build still exited 0. Measured here before the change, a second run on a byte-identical tree returned in 0.286s with `RUN make check` CACHED. script/cibuild and script/docker now pass --no-cache. The canonical text asserting that a bare `docker build .` proves the checks ran was wrong in REPO_POLICIES.md, both checklists and the Go styleguide, and is corrected in all of them. Model: opus-5
This commit is contained in:
@@ -123,9 +123,10 @@ alpine. We provide:
|
||||
- `script/check` — run all checks: `test`, `lint`, `fmt-check` (our own
|
||||
extension)
|
||||
- `script/docker` — build the Docker image, tagged via `script/projectname`
|
||||
(byte-identical across repos)
|
||||
- `script/cibuild` — cd to the repo root and `docker build .` (what CI runs; the
|
||||
image build runs `script/check`)
|
||||
(byte-identical across repos); builds with `--no-cache`, like `script/cibuild`
|
||||
- `script/cibuild` — cd to the repo root and `docker build --no-cache .` (what
|
||||
CI runs; the image build runs `script/check`, and `--no-cache` is what stops
|
||||
Docker serving those checks from cache on an unchanged tree)
|
||||
- `script/precommit` — run by the git pre-commit hook (our own extension); calls
|
||||
`script/check`
|
||||
- `script/install-precommit` — installs the git pre-commit hook (our own
|
||||
|
||||
5
TODO.md
5
TODO.md
@@ -21,6 +21,11 @@ fmt-check, and commit.
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-09-08: Closed the false green in the canonical CI gate: `script/cibuild`
|
||||
and `script/docker` now build with `--no-cache`, so the Dockerfile's check
|
||||
layers cannot be served from cache on an unchanged tree, and the text claiming
|
||||
a bare `docker build .` proves the checks ran is corrected in
|
||||
`REPO_POLICIES.md`, both checklists and the Go styleguide.
|
||||
- 2026-08-07: Set the canonical `.golangci.yml` to the org-standard v2-schema
|
||||
config already deployed byte-identical across the org's Go repos (settings
|
||||
under `linters.settings` so thresholds like lll/funlen/cyclop/dupl actually
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Code Styleguide — Go
|
||||
last_modified: 2026-03-18
|
||||
last_modified: 2026-09-08
|
||||
---
|
||||
|
||||
1. Try to hard wrap long lines at 77 characters or less.
|
||||
@@ -101,9 +101,12 @@ last_modified: 2026-03-18
|
||||
`golangci-lint`.
|
||||
|
||||
1. Write a `Dockerfile` for every repo, even if it only runs the tests and
|
||||
linting. `docker build .` should always make sure that the code is in an
|
||||
able-to-be-compiled state, linted, and any tests run. The Docker build
|
||||
should fail if linting doesn't pass.
|
||||
linting. `script/cibuild` and `script/docker` should always make sure that
|
||||
the code is in an able-to-be-compiled state, linted, and any tests run, and
|
||||
the build should fail if linting doesn't pass. Go through those scripts
|
||||
rather than a bare `docker build .`: they pass `--no-cache`, without which
|
||||
an unchanged tree serves the check layers from cache and the build reports a
|
||||
green it never ran.
|
||||
|
||||
1. Every repo must have a `Makefile`. See
|
||||
[Repository Policies](https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Existing Repo Checklist
|
||||
last_modified: 2026-07-06
|
||||
last_modified: 2026-09-08
|
||||
---
|
||||
|
||||
Use this checklist when beginning work in a repo that may not yet conform to our
|
||||
@@ -30,9 +30,10 @@ with your task.
|
||||
- [ ] `.editorconfig` exists — fetch from
|
||||
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig`
|
||||
- [ ] `Dockerfile` and `.dockerignore` exist; Dockerfile runs `make check` as a
|
||||
build step — fetch `.dockerignore` from
|
||||
build step, and `script/cibuild` and `script/docker` build it with
|
||||
`--no-cache` — fetch `.dockerignore` from
|
||||
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.dockerignore`
|
||||
- [ ] Gitea Actions workflow in `.gitea/workflows/` runs `docker build .` on
|
||||
- [ ] Gitea Actions workflow in `.gitea/workflows/` runs `script/cibuild` on
|
||||
push — reference
|
||||
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml`
|
||||
- [ ] Language-specific config:
|
||||
@@ -106,5 +107,6 @@ with your task.
|
||||
# Final
|
||||
|
||||
- [ ] `make check` passes
|
||||
- [ ] `docker build` succeeds
|
||||
- [ ] `script/cibuild` succeeds and demonstrably executed the checks — a
|
||||
sub-second build, or `CACHED` on a check layer, means nothing ran
|
||||
- [ ] Commit and merge fixes before starting your actual task
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: New Repo Checklist
|
||||
last_modified: 2026-07-06
|
||||
last_modified: 2026-09-08
|
||||
---
|
||||
|
||||
Use this checklist when creating a new repository from scratch. Follow the steps
|
||||
@@ -90,8 +90,11 @@ are thin shims calling them. Model scripts:
|
||||
- [ ] `script/projectname` — outputs the project name (used by `script/docker`
|
||||
for the image tag)
|
||||
- [ ] `script/docker` / `make docker` — builds Docker image, tagged via
|
||||
`script/projectname` (byte-identical across repos)
|
||||
- [ ] `script/cibuild` — cd to repo root, `docker build .` (what CI runs)
|
||||
`script/projectname` (byte-identical across repos); passes `--no-cache`
|
||||
like `script/cibuild`
|
||||
- [ ] `script/cibuild` — cd to repo root, `docker build --no-cache .` (what CI
|
||||
runs; without `--no-cache` an unchanged tree serves the check layers from
|
||||
cache and the build reports a green it never ran)
|
||||
- [ ] `script/precommit` — called by the pre-commit hook; runs `script/check`
|
||||
- [ ] `script/install-precommit` — installs the pre-commit hook that runs
|
||||
`script/precommit`
|
||||
@@ -103,6 +106,8 @@ are thin shims calling them. Model scripts:
|
||||
|
||||
- [ ] `make check` passes
|
||||
- [ ] `make docker` succeeds
|
||||
- [ ] `script/cibuild` succeeds and demonstrably executed the checks — a
|
||||
sub-second build, or `CACHED` on a check layer, means nothing ran
|
||||
- [ ] No secrets in repo
|
||||
- [ ] No mutable image/package references
|
||||
- [ ] No unnecessary files in repo root
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Repository Policies
|
||||
last_modified: 2026-08-19
|
||||
last_modified: 2026-09-08
|
||||
---
|
||||
|
||||
This document covers repository structure, tooling, and workflow standards. Code
|
||||
@@ -60,10 +60,10 @@ style conventions are in separate documents:
|
||||
prerequisite since nvm requires bash. yarn is then pinned via
|
||||
`corepack prepare yarn@<version> --activate`. Never install "latest" or "lts";
|
||||
always exact versions. `script/cibuild` runs the CI build: it changes to the
|
||||
repo root and runs `docker build .`; the Gitea workflow calls it. Four further
|
||||
scripts are our own extensions to the standard: `script/check` runs
|
||||
`script/test`, `script/lint`, and `script/fmt-check`; `script/precommit` is
|
||||
what the git pre-commit hook runs, and it calls `script/check`;
|
||||
repo root and runs `docker build --no-cache .`; the Gitea workflow calls it.
|
||||
Four further scripts are our own extensions to the standard: `script/check`
|
||||
runs `script/test`, `script/lint`, and `script/fmt-check`; `script/precommit`
|
||||
is what the git pre-commit hook runs, and it calls `script/check`;
|
||||
`script/install-precommit` installs the git pre-commit hook (the `make hooks`
|
||||
target shims to it); and `script/projectname` (literally that filename) simply
|
||||
outputs the project's name. Scripts that need the name call
|
||||
@@ -99,6 +99,15 @@ style conventions are in separate documents:
|
||||
`yarn.lock`, `go.mod` + `go.sum`, etc.) before running it so the bootstrap
|
||||
layer stays cached until dependencies change.
|
||||
|
||||
- **Any build that runs checks is built with `--no-cache`.** Docker invalidates
|
||||
a `COPY` layer only when the copied content changes, so on an unchanged tree
|
||||
the check `RUN` is served from cache, nothing executes, and the build still
|
||||
exits 0. `script/cibuild` and `script/docker` therefore pass `--no-cache`, and
|
||||
a bare `docker build .` is not evidence that anything ran: a sub-second build
|
||||
reporting success is a cache hit, not a result. Never invalidate by pruning —
|
||||
`docker builder prune` and friends destroy a build cache shared with every
|
||||
other build on the host.
|
||||
|
||||
- **Dockerfiles must use a separate lint stage for fail-fast feedback.** Go
|
||||
repos use a multistage build where linting runs in an independent stage based
|
||||
on the `golangci/golangci-lint` image (pinned by hash). This stage runs
|
||||
@@ -167,9 +176,10 @@ style conventions are in separate documents:
|
||||
artifacts or heavier dependencies.
|
||||
|
||||
- Every repo should have a Gitea Actions workflow (`.gitea/workflows/`) that
|
||||
runs `script/cibuild` (which runs `docker build .`) on push. Since the
|
||||
Dockerfile already runs `make check`, a successful build implies all checks
|
||||
pass.
|
||||
runs `script/cibuild` (which runs `docker build --no-cache .`) on push. Since
|
||||
the Dockerfile already runs `make check`, a successful build implies all
|
||||
checks pass — an implication that holds only because of the `--no-cache`
|
||||
above.
|
||||
|
||||
- Use platform-standard formatters: `black` for Python, `prettier` for
|
||||
JS/CSS/Markdown/HTML, `go fmt` for Go. Always use default configuration with
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#!/bin/sh
|
||||
# script/cibuild: run the CI build. The Dockerfile runs script/check, so
|
||||
# a successful build implies all checks pass.
|
||||
# script/cibuild: run the CI build. --no-cache because the checks are
|
||||
# RUN steps: on an unchanged tree Docker serves them from cache and the
|
||||
# build exits 0 having run nothing.
|
||||
set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
|
||||
main() {
|
||||
cd "$ROOT"
|
||||
docker build .
|
||||
docker build --no-cache .
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
# script/docker: build the Docker image tagged with the project name.
|
||||
# Identical in all repos; the tag comes from script/projectname.
|
||||
# --no-cache for the same reason as script/cibuild: a cached check layer
|
||||
# is a check that did not run.
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
@@ -8,7 +10,7 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
||||
|
||||
main() {
|
||||
cd "$ROOT"
|
||||
docker build -t "$("$SCRIPT_DIR/projectname")" .
|
||||
docker build --no-cache -t "$("$SCRIPT_DIR/projectname")" .
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user