From e14b7805517b0c9a7c4f0c11bcb939f99ec9044c Mon Sep 17 00:00:00 2001 From: Sulaiman Dauda Date: Tue, 6 Oct 2026 15:57:00 +0100 Subject: [PATCH 1/2] Make the linter able to read Go 1.27 code, and fail loudly when it cannot CI installs Go `stable`, which moved to 1.27.1. golangci-lint v2.12.2 is built with Go 1.26 and cannot type-check the 1.27 standard library, so it reported two errors in math/rand/v2 instead of the real findings, and continue-on-error hid that the linter had stopped working. v2.14.0 is built with Go 1.27.0. A new step compares the Go the linter was built with against the toolchain and fails the job when the toolchain is newer, so the next Go release cannot silence the linter without anyone noticing. The findings themselves stay advisory (#8), and the comment now points at #8 instead of #1. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yaml | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6250a86..f67e689 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,26 +18,29 @@ jobs: with: go-version: stable - run: go vet ./... - # v6 of the action pulls golangci-lint v1.x, which is built with go1.24 and - # refuses to load a config for a `go 1.26` module: - # can't load config: the Go language version (go1.24) used to build - # golangci-lint is lower than the targeted Go version (1.26) - # v9 pulls golangci-lint v2.x, built with a current toolchain. - # Advisory, not blocking, see issue #1. - # - # The lint step could never actually run before: the action installed - # golangci-lint v1, which refuses a `go 1.26` module. Fixing that revealed - # ~120 pre-existing findings (almost all errcheck on deferred Close calls). - # That is surfaced debt, not a regression, and it is not something to fix - # with a mass edit, each one needs a decision about whether the error - # matters. - # - # So the linter runs and its output is visible on every PR, but it does not - # gate merges until the backlog is cleared. Remove continue-on-error then. + # The linter runs on every PR but does not gate merges until the ~135 + # findings it reports (almost all errcheck on deferred Close calls) are + # cleared, see #8. Each needs a decision about whether the error matters, + # so no mass edit. Remove continue-on-error then. - uses: golangci/golangci-lint-action@v9 continue-on-error: true with: - version: v2.12.2 + version: v2.14.0 + # golangci-lint can only type-check code up to the Go release it was + # built with. When `stable` moved to 1.27, v2.12.2 failed on the standard + # library, reported 2 errors in math/rand/v2 instead of the real findings, + # and continue-on-error hid it. This step is not hidden: when it fails, + # bump the version above to one built with this Go. + - name: Check golangci-lint supports this Go + run: | + built=$(go version "$(command -v golangci-lint)" | awk '{print $2}') + running=$(go env GOVERSION) + minor() { echo "$1" | sed -E 's/^go1\.([0-9]+).*/\1/'; } + if [ "$(minor "$built")" -lt "$(minor "$running")" ]; then + echo "::error::golangci-lint was built with $built and cannot lint code for $running. Bump its version." + exit 1 + fi + echo "golangci-lint built with $built, toolchain $running" - run: go test ./... frontend: From 28aa4e8b61b456f2ecb2f5ecc22f6f5c39b5c544 Mon Sep 17 00:00:00 2001 From: Sulaiman Dauda Date: Tue, 6 Oct 2026 16:23:27 +0100 Subject: [PATCH 2/2] Fail the Go version guard when golangci-lint is missing or unreadable Actions runs this step with bash -e and no pipefail. If the lint action failed to install the binary, the version came back empty, the numeric test errored, and if treated that as false, so the guard passed. It now passes only when it can read both versions and the linter's is at least as new. Comments now match the findings and the original errors. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yaml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f67e689..e1206ea 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,8 +18,8 @@ jobs: with: go-version: stable - run: go vet ./... - # The linter runs on every PR but does not gate merges until the ~135 - # findings it reports (almost all errcheck on deferred Close calls) are + # The linter runs on every PR but does not gate merges until the 135 + # findings it reports (133 of them errcheck, mostly on Close calls) are # cleared, see #8. Each needs a decision about whether the error matters, # so no mass edit. Remove continue-on-error then. - uses: golangci/golangci-lint-action@v9 @@ -27,17 +27,18 @@ jobs: with: version: v2.14.0 # golangci-lint can only type-check code up to the Go release it was - # built with. When `stable` moved to 1.27, v2.12.2 failed on the standard - # library, reported 2 errors in math/rand/v2 instead of the real findings, - # and continue-on-error hid it. This step is not hidden: when it fails, - # bump the version above to one built with this Go. + # built with. When `stable` moved to 1.27, v2.12.2 could not type-check the + # standard library's use of math/rand/v2, reported those 2 errors instead + # of the real findings, and continue-on-error hid it. This step is not + # hidden: when it fails, bump the version above to one built with this Go. - name: Check golangci-lint supports this Go run: | built=$(go version "$(command -v golangci-lint)" | awk '{print $2}') running=$(go env GOVERSION) - minor() { echo "$1" | sed -E 's/^go1\.([0-9]+).*/\1/'; } - if [ "$(minor "$built")" -lt "$(minor "$running")" ]; then - echo "::error::golangci-lint was built with $built and cannot lint code for $running. Bump its version." + minor() { echo "$1" | sed -nE 's/^go1\.([0-9]+).*/\1/p'; } + # Anything unreadable fails too: a missing binary means the install failed. + if ! [ "$(minor "$built")" -ge "$(minor "$running")" ] 2>/dev/null; then + echo "::error::golangci-lint (built with ${built:-unknown, not installed?}) cannot lint code for $running. Bump its version." exit 1 fi echo "golangci-lint built with $built, toolchain $running"