Getting a --version
flag for Cobra CLIs in Go
In my post Getting a --version
flag for Cobra CLIs in Go, built with GoReleaser I wanted to add a --version
flag to my Go command-line tools.
However, I noted that this solution only works when using GoReleaser, and doesn't work when built from source.
Fortunately this week Carlana Johnson wrote about a project she's built for this exact functionality.
So how do we do this with a Cobra CLI?
The below examples can be found in an example repo on GitLab.com.
Firstly, in our main.go
, we can pass versioninfo
's data to a SetVersionInfo
method:
package main
import (
"time"
"github.com/carlmjohnson/versioninfo"
"gitlab.com/tanna.dev/go-cobra-version-example/cmd"
)
func main() {
cmd.SetVersionInfo(versioninfo.Version, versioninfo.Revision, versioninfo.LastCommit.Format(time.RFC3339))
cmd.Execute()
}
This then calls this snippet to allow us to set the rootCmd
's versioning information:
func SetVersionInfo(version, commit, date string) {
rootCmd.Version = fmt.Sprintf("%s (Built on %s from Git SHA %s)", version, date, commit)
}
If we build it normally with go build
and then invoke it, we'll see the version information:
go build
./go-cobra-version-example --version
go-cobra-version-example version (devel) (Built on 2023-05-27T09:53:47Z from Git SHA 43043f4715f3878b8d13ae73fa6b12dbd1253447)
And if we build it using goreleaser
, we still see the version info:
goreleaser release --snapshot --clean
# where $PLATFORM is the OS platform you're running from
./dist/go-cobra-version-example_$PLATFORM/go-cobra-goreleaser-version-example --version
go-cobra-version-example version (devel) (Built on 2023-05-27T09:53:47Z from Git SHA 43043f4715f3878b8d13ae73fa6b12dbd1253447)
As we can see, this doesn't pick up as well when goreleaser
is performing a release. Following the docs we can tweak the code to pick up the Goreleaser-defined variables, or the data from versioninfo
:
package main
import (
"time"
"github.com/carlmjohnson/versioninfo"
"gitlab.com/tanna.dev/go-cobra-version-example/cmd"
)
// these values are automagically populated by Goreleaser
var (
version = "dev"
commit = "none"
date = "unknown"
)
func main() {
// if installing from source, i.e. not a binary built by `Goreleaser`, this version will not be updated. In that case, use the automagic detection in `versioninfo`
if version == "dev" {
version = versioninfo.Version
commit = versioninfo.Revision
date = versioninfo.LastCommit.Format(time.RFC3339)
} else {
// Goreleaser doesn't prefix with a `v`, which we expect
version = "v" + version
}
cmd.SetVersionInfo(version, commit, date)
cmd.Execute()
}