#!/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. Both flags below must stay: do # not "simplify" either one 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: # $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. # # --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 "$@"