In my previous post I converted httpstat to use Go 1.11’s upcoming module support. In this post I continue to explore integrating Go modules into a continuous integration workflow via Travis CI.
Life in mixed mode
The first scenario is probably the most likely for existing Go projects, a library or application targeting Go 1.10 and Go 1.11. httpstat has an existing CI story–I’m using Travis CI for my examples, if you use something else, please blog about your experience–and I wanted to test against the current and development versions of Go.
GO111MODULE
The straddling of two worlds is best accomplished via the GO111MODULE
environment variable. GO111MODULE
dictates when the Go module behaviour will be preferred over the Go 1.5-1.10’s vendor/
directory behaviour. In Go 1.11 the Go module behaviour is disabled by default for packages within $GOPATH
(this also includes the default $GOPATH
introduced in Go1.8). Thus, without additional configuration, Go1.11 inside Travis CI will behave like Go 1.10.
In my previous post I chose the working directory ~/devel/httpstat
to ensure I was not working within a $GOPATH
workspace. However CI vendors have worked hard to make sure that their CI bots always check out of the branch under test inside a working $GOPATH
.
Fortunately there is a simple workaround for this, add env GO111MODULE=on
before any go build
or test
invocations in your .travis.yml
to force Go module behaviour and ignore any vendor/
directories that may be present inside your repo.
language: go
go:
- 1.10.x
- master
os:
- linux
- osx
dist: trusty
sudo: false
install: true
script:
- env GO111MODULE=on go build
- env GO111MODULE=on go test
Creating a go.mod on the fly
You’ll note that I didn’t check in the go.mod
module manifest I created in my previous post. This was initially an accident on my part, but one that turned out to be beneficial. By not checking in the go.mod
file, the source of truth for dependencies remained httpstat’s Gopkg.toml
file. When the call to env GO111MODULE=on go build
executes on the Travis CI builder, the go
tool converts my Gopkg.toml
on the fly, then uses it to fetch dependencies before building.
$ env GO111MODULE=on go build
go: creating new go.mod: module github.com/davecheney/httpstat
go: copying requirements from Gopkg.lock
go: finding github.com/fatih/color v1.5.0
go: finding golang.org/x/sys v0.0.0-20170922123423-429f518978ab
go: finding golang.org/x/net v0.0.0-20170922011244-0744d001aa84
go: finding golang.org/x/text v0.0.0-20170915090833-1cbadb444a80
go: finding github.com/mattn/go-colorable v0.0.9
go: finding github.com/mattn/go-isatty v0.0.3
go: downloading github.com/fatih/color v1.5.0
go: downloading github.com/mattn/go-colorable v0.0.9
go: downloading github.com/mattn/go-isatty v0.0.3
go: downloading golang.org/x/net v0.0.0-20170922011244-0744d001aa84
go: downloading golang.org/x/text v0.0.0-20170915090833-1cbadb444a80
If you’re not using a dependency management tool that go mod
knows how to convert from this advice may not work for you and you may have to maintain a go.mod
manifest in parallel with you previous dependency management solution.
A clean slate
The second option I investigated, but ultimately did not pursue, was to treat the Travis CI builder, like my fresh Ubuntu 18.04 install, as a blank canvas. Rather than working around Travis CI’s attempts to check the branch out inside a working $GOPATH
I experimented with treating the build as a C project
then invoking gimme
directly. This also required me to check in my go.mod
file as without Travis’ language: go
support, the checkout was not moved into a $GOPATH
folder. The latter seems like a reasonable approach if your project doesn’t intend to be compatible with Go 1.10 or earlier.
language: c
os:
- linux
- osx
dist: trusty
sudo: false
install:
- eval "$(curl -sL https://raw.githubusercontent.com/travis-ci/gimme/master/gimme | GIMME_GO_VERSION=master bash)"
script:
- go build
- go test
You can see the output from this branch here.
Sadly when run in this mode gimme
is unable to take advantage of the caching provided by the language: go
environment and must build Go 1.11 from source, adding three to four minutes delay to the install phase of the build. Once Go 1.11 is released and gimme
can source a binary distribution this will hopefully address the setup latency.
Ultimately this option may end up being redundant if GO111MODULE=on
becomes the default behaviour in Go 1.12 and the location Travis places the checkout becomes immaterial.