By

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.


Want to learn more about Atatus? Learn More

With Atatus, Get to know exactly how your users are experiencing your app.

Start your free 14-day trial