Skip to content

build: bump Go to 1.27 and pin golangci-lint in go.mod - #910

Merged
nooga merged 1 commit into
nooga:mainfrom
nnunley:build/go-1.27
Sep 19, 2026
Merged

nooga merged 1 commit into
nooga:mainfrom
nnunley:build/go-1.27

Conversation

@nnunley

@nnunley nnunley commented Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Move the project onto the current Go release line. Every workflow resolves its Go version with go-version-file: go.mod, so go.mod is the single place to change and local builds and CI move together.

Two toolchain pins have to move with it, because both refuse Go 1.27 outright:

tool before after why
golangci-lint v2.12.2 v2.13.2 v2.12.2 is built with go1.26.2: "the Go language version (go1.26) used to build golangci-lint is lower than the targeted Go version (1.27.1)". v2.13.2 is built with go1.27.0.
TinyGo v0.41.1 v0.42.0 v0.41.1: "requires go version 1.19 through 1.26, got go1.27". v0.42.0 raises the maximum supported Go version to 1.27.

Both were verified rather than inferred — the golangci-lint figures come from go version run against the actual released binaries.

One pin, in go.mod

golangci-lint was pinned in two places that had to be updated in lockstep by hand, and asymmetrically: Makefile pinned the exact patch (v2.12.2) while the workflow pinned the minor (v2.12, silently resolving to the newest 2.12.x). They could drift within a minor with nothing to catch it.

It now has exactly one pin — the tool directive in go.mod — and both consumers read it from there:

  • make lint runs go tool golangci-lint run.
  • The CI action takes no version: input; with it unset the action reads the version from go.mod itself. A version: input would silently win over go.mod, so the workflow comment says not to add one back.

This mirrors how go.mod already pins the Go toolchain. The tool directive also records golangci-lint's dependency graph, which the module was always building against but never stated — that is the bulk of the go.sum diff.

Incidental fix

make lint was broken on any host with go on PATH. $(GO) is defined only when makeplus/makes is included, which is skipped when go is already present, so $(GO) install … ran BSD install and exited 64. Running through go tool removes the install machinery and the bug with it.

Verification

On go1.27.1 / darwin-arm64:

check result
make build (forced clean, incl. smoke + boot budget) pass
make lint (go tool golangci-lint, v2.13.2) 0 issues
go vet ./... clean
make check-default-deps OK
make check-generated OK — every artifact in lockstep
go test -short ./... -skip TestClojureTestSuite pass
go build -tags gogen_ir ./... pass
go build -tags glplat_ebiten . pass

Go 1.27.1 is allocation-neutral against 1.26.5 on identical source: IRCompile 5,229,208 → 5,218,304 B/op, InitFromLGB 14,353 → 14,353 allocs/op.

Note for contributors after this lands

pkg/genmanifest/depmanifest.go runs its dependency query with GOTOOLCHAIN=local on purpose, so the committed manifest describes one reference graph on every host. That means the go on your PATH must itself be ≥ 1.27 — it cannot switch toolchains. With an older go first on PATH (a version manager pinning 1.26.x, say), make generate and make check-generated fail with:

go: go.mod requires go >= 1.27 (running go 1.26.5; GOTOOLCHAIN=local)

CI is unaffected, since setup-go installs the version named in go.mod.

Note on the pre-push ratchet

Pushed past the local bench-ratchet pre-push gate deliberately. The gate is red on main itself for unrelated reasons: check exits non-zero from the deterministic (allocs/bytes) comparison before timing is considered, and the four failing metrics trace to two deliberate commits — see #912 (#764's array-map trade) and #913 (#838/#863 on InitFromLGB). This change touches neither.

A Go version bump also moves the ratchet's machine fingerprint (go1.26.5 → go1.27.1), so the arm64/Apple M3 profile recaptured in #891 will want recapturing under the new toolchain once this lands.

🤖 Generated with Claude Code

@nnunley nnunley changed the title build: bump Go to 1.27 (toolchain go1.27.1) build: bump Go to 1.27 and pin golangci-lint in go.mod Sep 19, 2026

@nooga nooga left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI green after rebasing onto main (which picked up #909's TinyGo 0.42.0 bump, resolving the earlier lint/tinygo-wasi-build failures). Mechanical, well-verified toolchain bump: single go.mod/go.sum pin for golangci-lint, matching Makefile fix. No concerns.

CI resolves Go from go.mod (go-version-file), so the version bump moves
local builds and every workflow together. Two toolchain pins had to move
with it, because both refuse Go 1.27:

  - golangci-lint v2.12.2 is built with go1.26.2, and fails with "the Go
    language version (go1.26) used to build golangci-lint is lower than
    the targeted Go version (1.27.1)". v2.13.2 is built with go1.27.0.
  - TinyGo v0.41.1 accepts "go version 1.19 through 1.26"; v0.42.0
    raises the maximum supported Go version to 1.27.

golangci-lint was pinned twice -- exactly in the Makefile, by minor in
the workflow -- so the two could drift within a minor unnoticed. It now
has one pin, the go.mod tool directive, which both consumers read:
'go tool' in the Makefile, and the CI action, which finds the version in
go.mod when no 'version:' input is set. That mirrors how go.mod already
pins the Go toolchain itself. The tool directive records golangci-lint's
dependency graph, which the module was always building against but never
stated.

Moving the Makefile to 'go tool' also fixes 'make lint', which was broken
on any host with go on PATH: $(GO) is only defined when makeplus/makes is
included, so the recipe ran BSD 'install' and exited 64.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants