Do you use
cobra
andgoreleaser
to package and build your golang CLIs. If not, you should reconsider. They are a fantastic combination and combined with one of my new projects you can add an easy to use and extensible version subcommand which features different outputs
I’ve recently been playing around with building a lot of golang CLI’s, I’ll be
writing more about this at a later date, mostly while experimenting with
Kubernetes kubectl
plugins. One thing I’ve found really useful is to use
cobra
the golang library that helps you
to create powerful CLIs it combined with goreleaser
to help with packaging and distribution. Something I’ve always admired of
kubectl
was the very simple ways you can get the version you’re currently
running and the different ways they can be mutated.
So I spent sometime and created a unified
go-version
package for taking
in ldflags
from the compiler and giving you both a JSON
output and a plain
text output. All you need to do is create a simple command
file for the
version and copy and paste the below code into your version.go
file.
Getting Started
package main
import (
"fmt"
goVersion "github.com/christopherhein/go-version"
"github.com/spf13/cobra"
)
var (
shortened = false
version = "dev"
commit = "none"
date = "unknown"
versionCmd = &cobra.Command{
Use: "version",
Short: "Version will output the current build information",
Long: ``,
Run: func(_ *cobra.Command, _ []string) {
var response string
versionOutput := goVersion.New(version, commit, date)
if shortened {
response = versionOutput.ToShortened()
} else {
response = versionOutput.ToJSON()
}
fmt.Printf("%+v", response)
return
},
}
)
func init() {
versionCmd.Flags().BoolVarP(&shortened, "short", "s", false, "Use shortened output for version information.")
rootCmd.AddCommand(versionCmd)
}
Then when you are compiling your code you can either use goreleaser
which will
automatically add -X main.commit=<SOMEHASH>
and -X main.date=<SOMEDATE>
or
run a command like this to build your CLI.
go build -ldflags "-X main.commit=<SOMEHASH> -X main.date=<SOMEDATE>"
Once you have done this your CLI will have a new version
subcommand. This
subcommand will responde to -s
or --short
to return different variations of
the output.
This is really useful if you plan to use your tool within CI/CD processes where you might need to check the version installed before running the process.
$ ./my-cli version
{"Version":"dev","Commit":"<SOMEHASH>","Date":"<SOMEDATE>"}
Or to make this human readible you could use:
$ ./my-cli -s
Version: dev
Commit: <SOMEHASH>
Date: <SOMEDATE>
Long-Term
Future plans are to make it so that all you have to do is include a the package
and pass the cobra function to a register function in go-version
. Also to add
support for YAML
and potentially jsonpath
output mechanisms.
Conclusion
If you find yourself using cobra
to build out a CLI think about potentially
using my go-version
package to give an easy way to expose proper versioning to
your customers. It will definitely make it easier for others to work with your
tool and allow them to check this while debugging.
Go check out the project and it’s roadmap in the issues. https://github.com/christopherhein/go-version
- Chris