Comments and documentation only; the docker build invocation and its flags are untouched, and .dockerignore's effective rules are unchanged. Two prose gaps from review. First, "both flags below must stay" had lost its anchor: it ended a paragraph naming only --no-cache-filter, --target was not introduced until the next one, and three flags follow on the command, so a reader could pick the wrong pair. It now names --target and --no-cache-filter explicitly. Second, the list of things the tooling does not check covered the $stage seam but not .dockerignore, which sits in the same trust boundary and is the more likely thing to be edited — the first review on this change actively suggested extending it for build artifacts. Only what reaches the container is linted, so excluding a Go source there removes it from the lint with no warning. Verified rather than asserted: a planted violation plus that one path in .dockerignore yields `0 issues.` at exit 0 with the violation still in the working tree, while excluding a file other code still references fails loudly on `undefined:` typecheck errors instead. The warning is recorded in script/lint alongside the $stage seam and in .dockerignore itself, where the edit would actually be made.
66 lines
3.1 KiB
Bash
Executable File
66 lines
3.1 KiB
Bash
Executable File
#!/bin/sh
|
|
# script/lint: run the linter. golangci-lint is never installed locally:
|
|
# it runs via docker only, one way, everywhere — script/lint builds
|
|
# Dockerfile.lint, which COPYs the repo into the pinned golangci-lint
|
|
# image and lints as a build step. This works even when the docker daemon
|
|
# is remote and bind mounts are impossible.
|
|
#
|
|
# --no-cache-filter forces the lint stage to re-execute every run, so an
|
|
# unchanged tree is still actually linted; the deps stage keeps its cache,
|
|
# so the module download is not repeated. It and --target must both stay,
|
|
# for the reason in the next paragraph: do not "simplify" either of those
|
|
# two away.
|
|
#
|
|
# The stage name is written ONCE, in $stage, and passed to both --target
|
|
# and --no-cache-filter, so the two flags cannot come to name different
|
|
# stages. That is the whole point of the variable. BuildKit silently
|
|
# ignores --no-cache-filter when no stage matches its argument: a filter
|
|
# naming a stage that does not exist is a no-op, the lint layer is served
|
|
# from cache, and script/lint reports green having linted nothing — the
|
|
# false green this setup exists to prevent. --target, by contrast, fails
|
|
# loudly on a name that is not in the file. With a single shared name, a
|
|
# typo or a stale rename therefore becomes a hard error instead of a
|
|
# silent skip, because the one name reaches both flags.
|
|
#
|
|
# What the tooling does NOT check, and is left to whoever edits this:
|
|
#
|
|
# 1. $stage must name the stage in Dockerfile.lint that actually runs
|
|
# golangci-lint. --target verifies that the name exists, not that it is
|
|
# the right stage, and it stops the build at that stage — so moving the
|
|
# lint step into a different stage, or adding a stage after this one,
|
|
# would not be caught here. Keep this file and Dockerfile.lint in sync.
|
|
#
|
|
# 2. .dockerignore decides what reaches the container, and only what
|
|
# reaches it gets linted. Excluding a Go file there removes it from the
|
|
# lint with no warning: verified by planting a real violation and adding
|
|
# just that file's path to .dockerignore, which produced `0 issues.` at
|
|
# exit 0 with the violation still sitting in the working tree. It shows
|
|
# up only if the rest of the package still references the excluded file,
|
|
# in which case the build fails loudly on `undefined:` typecheck errors;
|
|
# a self-contained file drops out silently. So .dockerignore is part of
|
|
# this gate, not housekeeping — keep it to build inputs the lint does
|
|
# not read, and never exclude Go sources, go.mod/go.sum or
|
|
# .golangci.yml.
|
|
#
|
|
# --output=type=cacheonly skips the image export. Nothing consumes the
|
|
# image — the deliverable of this build is an exit code — and exporting it
|
|
# costs seconds per run and leaves a dangling image behind every time. The
|
|
# lint stage still executes and a lint failure still exits non-zero.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
# Must match the stage name in Dockerfile.lint.
|
|
stage=lint
|
|
|
|
main() {
|
|
cd "$ROOT"
|
|
docker build \
|
|
--target "$stage" \
|
|
--no-cache-filter="$stage" \
|
|
--output=type=cacheonly \
|
|
-f Dockerfile.lint .
|
|
}
|
|
|
|
main "$@"
|