#!/bin/sh # script/lint: run the linter. # # golangci-lint keeps two pieces of per-user global state, and both of # them break when several checkouts on one host lint concurrently: # # 1. Its analysis cache (GOLANGCI_LINT_CACHE, default # ~/.cache/golangci-lint). Entries are keyed by content, not by # checkout, so a hit written by another checkout is replayed # verbatim - including that checkout's file paths. The run then # reports findings for files it never linted. # # 2. Its "one runner at a time" lock, which does NOT live in the # cache directory: golangci-lint locks # $(os.TempDir())/golangci-lint.lock, i.e. # "$TMPDIR"/golangci-lint.lock (pkg/commands/run.go, # acquireFileLock). It waits 5s, then aborts with "parallel # golangci-lint is running" - a non-result that looks like a lint # failure. Setting GOLANGCI_LINT_CACHE alone does not move it. # # So both are pinned under the checkout root. The cache is never shared, # and TMPDIR makes the lock file per-checkout, which keeps the lock # doing its actual job (serialising runs that share one cache) at the # right scope. .lint-cache/ is git-ignored and Docker-ignored, and # caching still works: it persists across runs in this checkout. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" main() { cd "$ROOT" GOLANGCI_LINT_CACHE="$ROOT/.lint-cache/cache" TMPDIR="$ROOT/.lint-cache/tmp" export GOLANGCI_LINT_CACHE TMPDIR mkdir -p "$GOLANGCI_LINT_CACHE" "$TMPDIR" golangci-lint run --config .golangci.yml ./... } main "$@"