Upgrade Go Version
Upgrade the Go toolchain used by the Okteto CLI to a target version, review the release notes for breaking changes, make sure both Go modules still build and test green, then open a PR.
INPUT
- The target Go version comes from the prompt (e.g.
/upgrade-go-version 1.26.2). - If no version is provided, ask the user for the exact target version (
major.minor.patch) before changing anything. The repo pins the patch level, so a baremajor.minoris not enough.
CONTEXT — where a Go version lives in this repo
This repo has two Go modules plus several pinned images. Only these hold the build toolchain version:
go.mod(modulegithub.com/okteto/okteto) — thegodirective.tools/go.mod(modulegithub.com/okteto/tools) — thegodirective.Dockerfile—ARG GOLANG_VERSION+ARG GOLANG_SHA, used by both thetools-builderandgolang-builderstages (golang:${GOLANG_VERSION}-bookworm@${GOLANG_SHA})..circleci/config.yml+okteto.yml— theokteto/golang-ci:<ver>@sha256:...image, only if the user provides a new golang-ci image (Step 8).
Do NOT touch these — they are not the build toolchain:
okteto/golang:1floating tags (okteto.ymldev,samples/,pkg/linguist/dev.go)okteto/golang:1.22/golang:1.20strings insidepkg/schematests (schema_test.go,test_test.go) andintegration/validate/manifests/(e.g.valid-movies.yml) — they assert manifest parsingsamples/golang/go.mod
WORKFLOW
1. Determine current and target versions
Read the current versions:
grep -E '^go ' go.mod tools/go.mod grep GOLANG_VERSION DockerfileConfirm both modules match. Classify the jump:
- Patch (
1.25.11→1.25.12): security / bug fixes only; breaking changes very unlikely. - Minor (
1.25.x→1.26.x): new language, tooling, and stdlib behavior; breaking changes possible. - Multiple minors (
1.24.x→1.26.x): review every intervening minor.
- Patch (
2. Review release notes for breaking changes
Use WebFetch / WebSearch to read the notes for each minor between current and target:
- Per-minor release notes:
https://go.dev/doc/go1.26(substitute the version) - Full release history + per-patch security fixes:
https://go.dev/doc/devel/release
Focus on: language changes, go command / tooling changes, removed or behavior-changed
standard-library APIs, deprecations, and minimum OS/arch requirements. Summarize the
risky items that could matter to a Go codebase.
3. Evaluate whether our code is affected
- Delegate a focused scan to the
exploresubagent (keeps the main context clean — see the subagent strategy in.claude/CLAUDE.md). For each risky item from Step 2, search both modules (root packages andtools/) for affected stdlib calls, language constructs, build tags, or//go:directives. - Report anything affected or potentially affected, with
file:linereferences. Decide what (if anything) needs changing — but make code edits only after the version bump, when the compiler can confirm (Step 7).
4. Bump the go directive in both modules
Set both modules to the exact target version, preserving the major.minor.patch precision the
repo already uses (run from the repo root — go mod edit takes the target file as its last arg):
go mod edit -go=<target> go.mod
go mod edit -go=<target> tools/go.mod
Editing the go line by hand is equivalent. Do not add a toolchain directive if none
exists today.
5. Update the Dockerfile base image and pin by sha256
Set
ARG GOLANG_VERSION=<target>(must match thegodirective patch version).Resolve the multi-arch manifest-list (index) digest for
golang:<target>-bookworm— the CLI is built for multiple arches, so a single-platform digest is wrong:docker buildx imagetools inspect golang:<target>-bookworm --format '{{.Manifest.Digest}}' # alternative: crane digest golang:<target>-bookwormSet
ARG GOLANG_SHA=sha256:<digest>to the value returned above.
6. Tidy both modules
The version bump (and any module-graph changes it pulls in) can leave go.mod / go.sum out of
sync. Run go mod tidy in both modules so each is consistent before building:
go mod tidy # root module
cd tools && go mod tidy && cd ..
Review the resulting diff — bumping only the go directive should produce minimal churn, so
investigate anything unexpected before moving on.
7. Build to surface compilation errors, then fix
- Preferred:
okteto build(builds thecliimage from the Dockerfile remotely; any compilation error shows in the build output). Build a single service if needed:okteto build cli. - Local fallback (no okteto context):
docker build -t okteto-cli:test .. - If the build fails, fix the code for the new Go version (apply the Step 3 findings). Read code before editing, keep changes minimal, preserve the existing Apache 2.0 license headers, and follow existing patterns. Re-build until green.
8. Ask about the golang-ci image (CI dependency)
Do this before running the tests: okteto test unit and the CI lint / unit-test jobs all run
inside the okteto/golang-ci image (pinned in the .circleci/config.yml executor and in
okteto.yml under test.unit). If that image's bundled Go toolchain is older than the new go
directive, CI will fail and the local run won't truly exercise the new toolchain — so settle the
image first.
Use AskUserQuestion: "Is there an okteto/golang-ci image that already supports Go <target>?
If so, paste the full version@sha256:... reference."
If provided: replace every pinned occurrence (grep first so none are missed):
grep -rn 'okteto/golang-ci:' .circleci/config.yml okteto.ymlUpdate both to
okteto/golang-ci:<ver>@sha256:<digest>. Step 9 then runs the tests on the new toolchain (sinceokteto test unitreads the image fromokteto.yml).If not provided: warn the user clearly — "CI (golangci-lint + unit tests) will fail until a golang-ci image supporting Go
<target>is published and these references are updated." You may still open the PR, but record this as an explicit blocker in the description, and note that the Step 9 results do not reflect the target toolchain.
9. Run the tests
- Preferred:
okteto test unit(runs thetest.unitsuite →make test). - ⚠️ This runs inside the
okteto/golang-ciimage from Step 8. If Step 8 produced an updated image, the suite exercises the new toolchain. If not, the image still ships the old toolchain (Go may auto-download the target viaGOTOOLCHAIN, or silently run on the old one) — call this out in the results and re-run once the updated golang-ci image lands. - Local fallback:
make test(root) andcd tools && make test.
10. Open the PR
Only after build + tests pass (note any golang-ci caveat from Step 8).
Use
AskUserQuestion: "Is there a Jira ticket associated with this upgrade? If so, paste the ticket key (e.g.OKT-1234) or its URL."- If provided: include the ticket key in the PR title (suffix:
… (OKT-1234)) and add aJira: <key or URL>line near the top of the PR description. - If not provided: skip it — no placeholder.
- If provided: include the ticket key in the PR title (suffix:
Make sure you are on a feature branch, not
master:git checkout -b chore/upgrade-go-<target>.Commit signed (DCO), ending the message with a
Co-Authored-Bytrailer for the running Claude model:git commit -s \ -m "chore: upgrade Go to <target>" \ -m "Co-Authored-By: <running Claude model> <noreply@anthropic.com>"Create the PR with the required labels (drop the
(<ticket>)suffix if there is no ticket):gh pr create \ --label "release/internal" \ --label "run-e2e" \ --title "chore: upgrade Go to <target> (<ticket>)" \ --body "<description>"
Required labels
release/internalrun-e2e
PR description must include
- The Jira ticket (
Jira: <key or URL>) if the user provided one. - Old → new Go version (both modules + Dockerfile
GOLANG_VERSION). - Dockerfile base image + the new
sha256digest. - golang-ci image: updated to
<ref>, or a clear blocker note that it still needs a Go-<target>image before CI can pass. - Breaking changes reviewed from the release notes, and why they do / don't affect us.
- Any code changes made to compile or pass tests on the new version.
- Build result (
okteto build) and test result (okteto test unit). - End the PR body with the Claude Code attribution footer.
IMPORTANT CONSTRAINTS
- Keep
go.mod,tools/go.mod, and the DockerfileGOLANG_VERSIONon the same version. - Always pin the Dockerfile base image by
sha256(the multi-arch manifest-list digest). - Never modify sample or test-fixture Go versions (see CONTEXT).
- Read before edit; keep changes minimal. Any new
.gofile needs the Apache 2.0 header from.copyright-header.tmplwith a year accepted by thegoheaderlinter — match the format of existing files rather than assuming a fixed year range. - Sign every commit (
git commit -s). - If the upgrade goes sideways (build won't pass, unexpected breakage), STOP and re-plan rather than pushing through.