mirror of
https://github.com/tailscale/tailscale.git
synced 2026-10-09 20:01:54 -04:00
The golang:N-alpine Docker image lags behind Go minor releases by a day or two. When we bump go.mod to a new minor version before the image catches up, the required "Build Docker image" CI check fails with "go.mod requires go >= 1.27.1 (running go 1.27.0; GOTOOLCHAIN=local)" and blocks the toolchain bump from merging. Instead, base the build stage on plain alpine and download the Tailscale Go toolchain release for the revision in go.toolchain.rev, matching how everything else in this repo is built. Fixes #21072 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I1ccb77fa3c7a49532ea87dbdbf9e3340880ec94e
4.8 KiB
4.8 KiB
Go major version bump checklist
Things to update every six months when we move to a new Go major version (e.g. Go 1.NN to Go 1.MM). See the git history of this file and past bump commits (e.g. "go.toolchain.branch: switch to Go 1.26", "go.toolchain.branch: switch to Go 1.27") for worked examples.
Prerequisites
- The
tailscale/gofork has atailscale.goX.YYbranch with our patches rebased onto the new release, and its CI has published a toolchain tarball for that rev. - During the rc period, test the new version via the "next"
toolchain first: update
go.toolchain.next.branchand runTS_GO_NEXT=1 ./pull-toolchain.sh, then let the optionalgo-nextCI jobs find breakage before release day.
Toolchain switch
- Update
go.toolchain.branchto the newtailscale.goX.YYbranch name. - Run
./pull-toolchain.sh. This updates:go.toolchain.rev(andgo.toolchain.next.revif it fell behind)go.toolchain.version- the
godirective ingo.mod flakehashes.json(Nix SRI hashes, viatool/updateflakes)
Version strings elsewhere
README.md: "We always require the latest Go release, currently Go 1.NN"..github/workflows/: grep for hardcoded Go versions. As of Go 1.27 the workflows usego-version-file: go.modand need no changes, but rc-period pins (e.g.actions/setup-gowith an explicit rc version) must be reverted if any were added.
Regenerate derived files
make updatedepsto regenerate alldepaware.txtfiles. The new stdlib usually reshuffles internal dependencies.- Regenerate gzip assets if
compress/flateoutput changed (it did in Go 1.27; thego generatesteps embed compressed bytes and CI checks they are reproducible with the current toolchain):tempfork/spf13/cobra:go generate ./...util/eventbus:go generate ./...Use the new toolchain (./tool/go) onPATHwhen running these.
Things that may need attention
- Lint tools: check that staticcheck and golangci-lint releases
support the new Go version, and bump them in
go.mod/.github/workflows/golangci-lint.ymlif needed (Go 1.26 needed a staticcheck bump). The golangci-lint version pinned in the workflow must be a release built with the new Go version or it fails with "the Go language version (go1.NN) used to build golangci-lint is lower than the targeted Go version"; golangci-lint usually ships such a release within days of the Go release (v2.13.0 for Go 1.27). Verify withgolangci-lint versionand a localgolangci-lint runagainst the repo config before pushing. go.mod/go.sum: run./tool/go mod tidyand eyeball the diff; a new Go version can reorganize the file format or module graph pruning.- New-version breakage in our code or vendored deps: build and
test everything (
./tool/go build ./... && ./tool/go test ./...), including GOOS=darwin,windows,etc. cross-builds, before relying on CI. - The corp repo, Android, iOS, and other downstream repos have their own bumps; this checklist covers only this repo.
Behavior changes that have bitten us
Categories of Go release fallout seen in past bumps (mostly in corp, but the categories generalize); grep for them before blaming the code:
- gofmt output can change; run
gofmt -lacross the tree (and corp) with the new toolchain and reformat (Go 1.27 reformatted two corp files). - encoding/json error strings and UnmarshalTypeError.Field can change. Tests asserting exact error text break, and so can third-party libraries: Go 1.27 reports the full path to the offending value ("errors.deletes.0") where earlier versions reported just the top-level field, which broke dnsimple-go's error-recovery gate (their PR #271).
- Error identity from canceled streaming HTTP requests can change: Go 1.27's http2 surfaces the underlying "use of closed network connection" where Go 1.26 returned the context error. Prefer normalizing to ctx.Err() at the source (see sendMapRequest in control/controlclient) over teaching each test the new string.
- json.Decoder over a reader that gains data after reporting EOF is not guaranteed to see the later writes; Go 1.27 stopped re-polling. Interleaved write-then-decode test helpers should read complete lines instead (corp tslogtest).
- The race detector's cost profile can shift: Go 1.27's race mode made a reflection-heavy corp test several times slower, turning a slow-but-passing 70s test into a 10 minute timeout. Watch race job durations, not just pass/fail.
After the switch
- Send the branch through full CI and fix what falls out; amend this checklist with anything new you discover.
- Once the release is proven, consider a follow-up "use Go 1.NN things" cleanup commit (gofix modernizers, new stdlib APIs), kept separate from the mechanical bump.