proposal: cmd/go should output structured version information usable by development tools (and go itself)
Background
Issue #21207 describes an effectively similar problem, but was closed without actually resulting in a structured version output.
Problem
When using CI Tools and pipelines, it is often required to know the major/minor version of Go.
Not least of which for passing into go commands such as go mod tidy which has a -compat argument, which requires just the major.minor version number.
Current Work-Arounds
As best as I can tell, everyone seems to be using some kind of regex against the output of go version.
Proposal
An argument for go version which will output a structured format of some kind, or perhaps just the version elements requested.
CC @bcmills @matloob
You're somewhat there already via go env -json. For example:
$ go1.18.5 version
go version go1.18.5 linux/amd64
$ go1.18.5 env -json GOVERSION GOOS GOARCH
{
"GOARCH": "amd64",
"GOOS": "linux",
"GOVERSION": "go1.18.5"
}
or with tip:
$ go version
go version devel go1.20-1eeb257b88 Tue Sep 20 02:58:09 2022 +0000 linux/amd64
$ go env -json GOVERSION GOOS GOARCH
{
"GOARCH": "amd64",
"GOOS": "linux",
"GOVERSION": "devel go1.20-1eeb257b88 Tue Sep 20 02:58:09 2022 +0000"
}
@mvdan Thanks for pointing out the -json args and options, however GOVERSION still requires parsing out the actual version numbers from the returned text. Perhaps more options could be added for the major, minor and point version (or use whatever terms that Go normally uses)?
Perhaps for tip/non-official releases there could be another option for what git rev it was built from or something like that.
For example, to take your two examples, it would be good to have these values output independently.
$ go1.18.5 env -json GOVERSION GOOS GOARCH GOMAJORVERSION GOMINORVERSION GOPOINTVERSION
{
"GOARCH": "amd64",
"GOOS": "linux",
"GOVERSION": "go1.18.5",
"GOMAJORVERSION": 1,
"GOMINORVERSION": 18,
"GOPOINTVERSION": 5
}
and
$ go env -json GOVERSION GOOS GOARCH GOMAJORVERSION GOMINORVERSION GOPOINTVERSION GOTIPCOMMIT
{
"GOARCH": "amd64",
"GOOS": "linux",
"GOVERSION": "devel go1.20-1eeb257b88 Tue Sep 20 02:58:09 2022 +0000",
"GOMAJORVERSION": 1,
"GOMINORVERSION": 20,
"GOPOINTVERSION": 0,
"GOTIPCOMMIT": "1eeb257b88"
}
For actual releases, it seems to me like you can extract the semver-like numbers with a fairly simple regular expression. I've done that in a couple of places and it doesn't seem particularly difficult.
For "devel" versions, note that they don't need to follow a specific format. A build can end up with any version string placed in the VERSION file when running make.bash. It's true that builds by default end up with a format that includes a commit hash and a timestamp, but - again those feel rather easy to extract via a regular expression or string handling.
Not least of which for passing into go commands such as
go mod tidywhich has a-compatargument, which requires just the major.minor version number.
Note that if this is your use case, you likely don't want to obey go env GOVERSION if it is not a proper stable release. The current master, even though it's 1.20-somecommit, is very different from what the final Go 1.20 will be like.
It sounds to me like you only want to use GOVERSION when it's a stable version - in which case you only need to trim the bugfix release if there is one.
I can use a regex, that's what all the search results for "How to get Go version" do. Some of them are broken in various ways, need maintenance, or assume access to certain tooling or a particular regex implementation.
The point of the proposal is to do away with this. It's information that the Go binary already has, why not make it available in a structured way rather than making everyone re-implement the wheel in various broken ways?
When using CI Tools and pipelines, it is often required to know the major/minor version of Go.
I'm not sure I understand when this would happen at all, certainly not "often".
Not least of which for passing into go commands such as go mod tidy which has a -compat argument, which requires just the major.minor version number.
The -compat argument predates the work on forward compatibility (respecting the go version in the go.mod file) and basically should not be used anymore.
Are there other contexts where this information is needed?
This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — rsc for the proposal review group
Talked to @bcmills and @matloob, and we think probably if this information is anywhere it would be in go list -f context.something, but it's unclear why it's necessary so we should establish a use case first.
With the compatibility work that has landed since this issue was filed in 2022, it seems like this may not be necessary anymore.
Based on the discussion above, this proposal seems like a likely decline. — rsc for the proposal review group
No change in consensus, so declined. — rsc for the proposal review group