Golang Auto Build Versioning
Atatus’s backend consumer and server are written in Go, and earlier we were just deploying our applications without tracking any version number or build number. The reason we never hit upon the idea to version the code was, coming from node.js
world, where the source was always present, there was never a need for version numbering.
Then we hit upon an issue, where we needed a version number to find whether the binary was from yesterday or today’s source. Then we decided that for all our golang applications we should have a way to find out the version number, so that we can always query and find out which version it is, there by which source is running.
We early on pondered if we want to hard code a version number inside the app
var (
Version = "1.0.0"
BuildTime = "2015-08-01 UTC"
)
However, the issue here is, we have to update and commit this source file, which defeats the purpose of having a version number itself. We wanted the build system itself to automatically put in a version, when it builds.
Then we found out that golang
has an elegent way of doing so. Using the linker option -X we can set a value for a symbol that can be accessed from within the binary.
This was awesome. Using this, we thought we can write a unique version number every time. Something like -X main.Version 1.5
Let’s take a simple example myapp.go
. By default, if you want, you can key in a version string.
$ cat myapp.go
package main
import "fmt"
var Version = "No Version Provided"
func main() {
fmt.Printf("App Version: %s\n", Version)
}
When you go build
/go run
/go install
the program, you can modify the Version
variable using the -ldflags -X
option.
$ go run myapp.go
App Version: No Version Provided
$ go run -ldflags "-X main.Version 1.5" myapp.go
App Version: 1.5
Now we had a question of whether we should pass the version number everytime we build. Also would it make sense to pass more than one variable to identify specific builds. We decided based on the following thoughts:
- Our version numbers are not exposed to end users, so we are free to choose a complex version number, as long as it is unique
- We wanted to capture the exact build time, so that we can identify exactly when the build was done.
Based on this, what we decided was to use the git hash
- which can be used to uniquely identify our source and the build time
.
So, we use the below ldflag for our applications
go build -ldflags "-X main.buildstamp `date -u '+%Y-%m-%d_%I:%M:%S%p'` -X main.githash `git rev-parse HEAD`" myapp.go
We have a code to handle --version
flag in our app. When the flag --version
is passed, we print the buildstamp
and githash
variables, and exit the application. Hence, you will get the below output when we run all our applications with the version flag.
$ ./myapp --version
Git Commit Hash: c553786277bf05c0aa0320b7c7fc8249c73a27c0
UTC Build Time : 2015-07-26_07:07:11AM
This is how we handle auto versioning in golang binaries. If you have any other tips, share it in comments.