Remove last remnants of ".go-version" file

Before Go 1.21 we relied on third-party and custom tooling to manage which
version of Go we were using for development, testing, and release builds.

However, modern Go toolchains have built-in support for selecting an
appropriate toolchain based on metadata in the go.mod file, and so we had
previously removed most uses of the .go-version file and were maintaining
it just as a remnant of the old state of things.

This replaces our last remaining use of the ".go-version" file with a small
tool that extracts the Go version from the go.mod file, and then removes
the ".go-version" file completely. The "go" and "toolchain" directives in
go.mod are now our single source of truth about which version of Go we're
currently using for OpenTofu.

(It may be possible to rework the Dockerfile for the consul backend to
handle Go version selection in a different way so that we'd no longer need
even this "selected-go-version" tool, but that's beyond the scope of this
commit which aims to leave it unmodified to make sure the effective testing
behavior for that backend is unchanged for now.)

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
Martin Atkins 2026-01-19 08:57:29 -08:00 committed by Christian Mesh
parent 9dbb5fcb9c
commit 9ddd3c1128
6 changed files with 72 additions and 4 deletions

View file

@ -1 +0,0 @@
1.25.6

View file

@ -167,7 +167,7 @@ define infoTestConsul
endef
GO_VER := `cat $(PWD)/.go-version`
GO_VER := `go tool github.com/opentofu/opentofu/tools/selected-go-version`
test-consul: ## Runs tests using in docker container using Consul as the backend.
@ $(info $(infoTestConsul))

View file

@ -15,7 +15,7 @@ Eager to get started on coding? Here's the short version:
### Setting up your development environment
You can develop OpenTofu on any platform you like. However, we recommend either a Linux (including WSL on Windows) or a macOS build environment. You will need [Go](https://golang.org/) and [Git](https://git-scm.com/) installed, and we recommend an IDE to help you with code completion and code quality warnings. (We recommend installing the Go version documented in the [.go-version](../.go-version) file.)
You can develop OpenTofu on any platform you like. However, we recommend either a Linux (including WSL on Windows) or a macOS build environment. You will need [Go](https://golang.org/) and [Git](https://git-scm.com/) installed, and we recommend an IDE to help you with code completion and code quality warnings. We recommend installing the latest available version of Go, and then letting the Go toolchain select suitable language and tool versions automatically based on directives in OpenTofu's `go.mod` file.
Alternatively, if you use Visual Studio Code or Goland/IntelliJ and have Docker or Podman installed, you can also use a [devcontainer](../.devcontainer.json). In Visual Studio Code, you can install the [Remote Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), then reopen the project to get a prompt about activating the devcontainer. In Goland/Intellij, open the `.devcontainers.json` file and click the purple cube icon that appears next to the line numbers to activate the dev container. At this point, you can proceed as if you were [building natively](#building-opentofu) on Linux.

View file

@ -31,7 +31,7 @@ Unicode version for each Go version. The specific Unicode version for a
particular Go version is available in
[`unicode.Version`](https://pkg.go.dev/unicode#Version).
We adopt a new version of Go by editing the `.go-version` file in the root
We adopt a new version of Go by editing the `go.mod` file in the root
of this repository. Although it's typically possible to build OpenTofu with
other versions of Go, that file documents the version we intend to use for
official releases and thus the primary version we use for development and

1
go.mod
View file

@ -328,6 +328,7 @@ tool (
github.com/opentofu/opentofu/tools/find-dep-upgrades
github.com/opentofu/opentofu/tools/loggraphdiff
github.com/opentofu/opentofu/tools/protobuf-compile
github.com/opentofu/opentofu/tools/selected-go-version
go.uber.org/mock/mockgen
golang.org/x/tools/cmd/stringer
google.golang.org/grpc/cmd/protoc-gen-go-grpc

View file

@ -0,0 +1,68 @@
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
// selected-go-version determines which version of Go is currently selected
// in the go.mod file.
//
// Note that running this requires that there already be some reasonable
// Go toolchain version (Go 1.21 or newer) installed on the system. The modern
// Go toolchain is able to manage its own versions automatically so it shouldn't
// typically matter which toolchain is used to run this command, and this
// command should only be used in situations where something other than the
// Go toolchain itself needs to make a decision about what to use, such as
// when building container images for testing purposes.
package main
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
// Despite the name of this command, this is just printing a JSON
// representation of the go.mod file and not actually editing it.
cmd := exec.Command("go", "mod", "edit", "-json")
raw, err := cmd.Output()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to get Go module metadata: %s\n", err)
os.Exit(1)
}
var meta GoModJSON
err = json.Unmarshal(raw, &meta)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to parse Go module metadata from JSON: %s\n", err)
os.Exit(1)
}
// If the Toolchain field is present then we prefer to use that because
// that matches what would be used when running "go" commands directly,
// but we do need to trim of the "go" prefix to make it consistent with
// how the "Go" field is formatted.
//
// Toolchain is described in https://go.dev/doc/toolchain .
if toolchain, ok := strings.CutPrefix(meta.Toolchain, "go"); ok {
// Note that this doesn't do any special handling of "custom toolchains"
// because the OpenTofu project does not currently use those. If we
// do decide to use custom toolchains in future then we'll need to
// decide what that means for this program: should it return the base
// version of the custom toolchain, or the full custom toolchain name?
fmt.Println(toolchain)
return
}
// Otherwise we use the "Go" field, since that's the only one present
// when the toolchain directive isn't specified, and "go mod tidy" will
// automatically remove the toolchain directive if the go directive matches.
fmt.Println(meta.Go)
}
type GoModJSON struct {
Go string `json:"Go"`
Toolchain string `json:"Toolchain"`
}