Using a Specific Go Version on Azure Pipelines

With Azure Pipelines we can build applications with many different languages, one of which is Go.

If you’re using a Hosted Agent, which is the recommended way (since you don’t need to manage your own machines), you are at the mercy of what software is installed on the agent. But if you’re building an application to target a specific runtime, say Go 1.12.3 (the latest at the time of writing), you might be out of luck as the agent doesn’t have that installed on it.

We’re going to be modifying the standard Go Azure Pipeline, so start with that a template.

Setting up our variables

The first thing we’ll want to do is modify the variables that Go will be expecting, specifically GOPATH and GOROOT. By default, these point to one of the versions of Go on the agent, but we’ll modify them to use our version of Go.

We’ll using one of the Agents pre-defined variables, Agent.BuildDirectory, as it’s somewhere I know I can write to on the Agent, and it’s scoped to my build in particular.

The GOPATH is going to be a new folder we’ll create and GOROOT will be where Go is unpacked to. These will now be environment variables so when Go eventually executes, it’ll be the right version of Go.

Downloading Go

Next, we’ll add a new step to download and unpack the version of Go we want to target:

Since we know my agent is a Linux agent (from the pool defined in the template) we’ll use wget to download the Linux binaries and drop them into the Agent.BuildDirectory. With that done we can unpack it with tar, specifying that we want to unpack to Agent.BuildDirectory, and given the structure of the tar.gz contains a folder named go we’ll end up with a path that matches GOROOT nicely.

Lastly, we need to ensure that the PATH of the agent knows about this version of Go, and we do that by setting output variables:

Conclusion

Version pinning of dependencies is really important to ensure that we have repeatable builds over time. Since we don’t want to end up in a situation where we manually manage our agent pool we want our build definition to prepare the agent to the environment we desire, including setting up the appropriate runtimes.

You can see a full pipeline definition on my GitHub that utilises this approach.

You could also use this approach to prepare multiple different versions of Go to create a build matrix against several runtime releases, but I’ll leave that as an exercise to you, dear reader 😉.