For Resultra, I recently migrated the project from Go’s dep dependency management to Go modules. The primary motivations for transitioning to modules were to allow the project to be built outside the $GOPATH and work with GitHub’s fork and pull request model.
The project is currently using Go version 1.12. In version 1.12, module support is only triggered when a repository is not below the $GOPATH directory. To override this, the project’s Makefiles currently set the GO111MODULE
environment variable to on
. This transition went very smoothly in my local development environment.
Fixing Travis CI Builds to Work with Modules
When changes to incorporate Go modules were first pushed to GitHub, the Travis CI builds began to fail. By default, Travis CI is configured with the environment variable GO111MODULE
environment variable set to auto
, which disables modules when the build occurs inside $GOPATH.
My first attempt was to change GO111MODULE to on
in the environment section of the .travis.yml
config file. This potentially could have worked, except there was a conflict with a go get
from inside the project’s build script; an error message like the following was generated:
The command "eval go get -v -t ./... " failed. Retrying, 3 of 3.
go get: -t flag is a no-op when using modules
The project does use go get
to install the yacc tools for an equation compiler. However, the command is not invoked with the -v
or -t
option; perhaps Travis CI’s Go environment is overriding how go get
is invoked? At any rate, without this being part of the project’s build, I suspect Travis CI likely would have worked right away. Before spending too much time investigating this specific build failure, I decided to try other potential solutions.
Further researching possible solutions to this, I found a couple of good blog posts on the topic:
- “Using Go modules with Travis CI” by Dave Cheney
- “Using Go modules with vendor support on Travis CI by Fatih Arslan
These posts discuss a number of solutions, but the 2nd solution I tried and succeeded with was a variation of Dave Cheney’s “A clean slate” option; in particular:
- In the
.travis.yml
config file, remove the configuration for default Golang language support; i.e., removelanguage: go
. - Replace
language: go
withlanguage: minimal
. The minimal option tells Travis to start with an image that is not tailored to any specific programming language. - During the
install
phase, configure Travis to directly install Go. - Before launching the build, configure the
$PATH
environment variable to reference the correct version of Go.
It only takes a few lines in the Travis config file to directly install and configure Go tools. The resulting Travis config file allowed the project to build successfully while using Go’s module support.
Minimal Language Configuration for Travis CI Builds
The major change to fix the Travis CI builds was to abandon Travis CI’s language:go
configuration option in favor of starting with a minimal image without Go support.
When I initially integrating the project with Travis CI, I wondered how much value Travis CI’s Go language option really added. While there is likely a performance gain for Travis to cache the environment needed for their default Go environment, it is also very straightforward to directly install the Go tools.
Secondly, even though Resultra’s back-end is implemented in Go, the project as a whole is built with a number of languages, including Python and Javascript; therefore, specifying a single language option in the Travis CI config file is arguably not the best option for the project as a whole.
Moreover, starting with a minimal configuration, the environment can be setup using a command sequence which is very similar to Resultra’s development environment. In terms of maximizing parity between the development and production builds, a case can be made for the Travis CI configuration to:
- start with a minimal image; then
- install and configure Go tools directly, using the same commands used to setup the development environment.
Next Steps
In Go version 1.13, module support will purportedly be enabled by default. When Go 1.13 is release, it may be worth re-testing the language:go
configuration option. In my case, the initial build failure was potentially due to a conflict with the project’s own build environment; nonetheless, directly installing the Go tools fixed the build.
In terms of maximizing parity with the development environment and considering how straightforward it is to install the Go tools directly, a viable alternative is to continue using the language:minimal
configuration option; this is the most important lesson learned from this experience.