Go v1.11 was released August 24th, 2018. There were quite a few changes! While there are several changes that I really enjoy, such as the ability to assign nested variables, there are also changes that affect your CircleCI build.

Enabling module support in a build

A typical Go project on CircleCI will have a config that starts like this:

version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.10
    working_directory: /go/src/github.com/my-org/my-repo
    steps:
      - checkout

Simply changing the Docker image to circleci/golang:1.11 will not enable module support. Instead, there are two different ways for you to do it:

  1. Move your code out of GOPATH
  2. Set the GO111MODULE environment variable to "ON"

Method 1 - Move code out of GOPATH

Using a Go v1.11 Docker image, enable module support by moving your code to a path outside of GOPATH. For example:

version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.11
    working_directory: /my-app
    steps:
      - checkout

Better yet, unless you absolutely need to specify a working_directory, I would leave it out of the config altogether. When you leave it out, CircleCI defaults to ~/project and it’s one less line in your config. This is my recommended approach for enabling module support:

version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.11
    steps:
      - checkout

Method 2 - Use GO111MODULE

If you prefer to keep your project’s code in GOPATH, module support can be enabled via an environment variable. Here is an example:

version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.11
        environment:
          GO111MODULE: "ON"
    working_directory: /go/src/github.com/my-org/my-repo
    steps:
      - checkout

Take note of the double quotes used to wrap "ON". For many people, not using the quotes causes YAML to interpret the value as true, which Go doesn’t accept as a valid value.

Enabling module support in the repository

For the CircleCI builds to work, your repository also has to be built to support Go modules. There’s a lot to say about this, and you can read in detail about it on the Go Wiki. I suggest a thorough reading of it if your project is any larger than a side project. The short version is below.

To prepare your code:

go mod init

If you’re coming from another popular Go vendoring method such as Dep, the next step can be skipped. If not, the following step needs to be done to create a full go.mod file:

go mod tidy

Now, adding the mod management files to Git is the last step:

git add go.mod go.sum
git commit -m "Add Go module support."
git push

If you were not using a dependency manager before and were simply using go get to pull in packages, you can remove that from your CircleCI config now.

Testing

There are two forms of go test for you to consider:

go test ./...  # Tests only the code in your current module, typically your repo.
go test all    # This will test your code as well as direct and in-direct dependancies.

Caching

When using Go modules, the cache location changes. Here’s how you would restore and save the cache:

      - restore_cache:
          keys:
            - go-mod-v1-{{ checksum "go.sum" }}

# ...

      - save_cache:
          key: go-mod-v1-{{ checksum "go.sum" }}
          paths:
            - "/go/pkg/mod"

Good luck, Gophers. :)

More resources