Pin Go Installed Package Version
You may already have encountered the version issues when working with executable binaries installed by Go (using go install command), specially if you’re working in a team, where other team members are using a different version of the same package that you’ve installed on your machine, and as a result, they get different outputs/results than what you get. In this post, I’m going to share a solution that I’m using. You can skip to the Solution section if you’re already familiar with this issue.
Problem
As you may know, Go command line provides the install command, which as its documentation states:
Install compiles and installs the packages named by the import paths.
There are also many packages available by the Go community that needs to be installed to be used. Here are some of these packages that I usually use:
swag: Generates Swagger/OAS documentation from code commentsmock: Generates mock code that can be used for testingjet: Generates type-safe models from existing SQL database schemas alongside provided utilities for writing SQL queries in Goeasyjson: Generates code forstructs that does JSON serialization, and deserialization
Let’s take mock package as an example, and have a simple Make target similar to the following to make command execution easier:
.PHONY: gen
gen:
mockgen -source=foo.go
This has a couple of issues in general:
- It assumes the user has
mockalready installed on their machine, and it’s available in executables$PATH, which is, in general, a bold assumption for a developer who joined recently for example. Or they do not want to include$GOBINdirectory in their$PATH, maybe because there is an executables in their$GOBINthat might mess up with the ones installed system-wide. - How would a developer know what is that
mockexecutable, and where to install it from? Specially for some packages where their executable name differs from the package name, likemock. It seems we need some sort of documentation here, right? - What if there is another executable named
mockinstalled on your machine that gets executed instead of the one you installed usinggo install? How would you resolve this? - What if the version resolved to the
latesttag at the time of installation on my machine isv1.1.0, for example, but versionv1.2.0gets installed on CI environment tomorrow that causes some sort of misbehavior internally without any explicit errors on production?
Solution
The solution that I’m using recently is simply updating the command to the following:
.PHONY: gen
gen:
go run github.com/golang/mock/[email protected] -source=foo.go
It does the same thing without installing the executable in the $GOBIN directory. Look at how explicit this version is, and we’d always want explicitness, don’t we?
How this works is it retrieves the specified version once, and builds it. Any subsequent execution of the same command will result in a cache-hit, and doesn’t require any downloads unless you change the version tag.