Go Version for Cobra Projects

Do you use cobra and goreleaser 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

Example

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


comments powered by Disqus