Gitlab has a very configurable CI/CD system. Everything is specified in the .gitlab-ci.yml
file in the root of your project.
Getting some CI and automated testing up and running for a Go project is pretty straight forward. The official Gitlab post is comprehensive, but complicated as it involves building a docker image and using Makefiles as an additional level of abstraction.
Let’s see how we would build a very simple Go project. In this example, we only have main
package files, rather than building libraries.
├── src
│ ├── alpha.go
│ ├── alpha_test.go
│ └── beta
│ ├── beta.go
│ └── beta_test.go
├── .gitignore
├── .gitlab-ci.yml
└── README.md
Here both alpha.go
and beta.go
are standalone main
packages intended to be run with go run
(or have a binary built with go build
).
Base image
First, the Gitlab runner will need to grab a docker image with Golang tools installed. We use the official Golang image. The default tags 1.12.6, 1.12, 1, latest
will get you an image based on Debian (version 9 aka Stretch at time of writing), but you could try the Alpine Linux tags (suffix alpine
) if you want a more lightweight image.
We’ll lock in a version rather than use latest
so that future changes to Go don’t break things. The semantic versioning should mean that all 1.x versions of Go will be backwards compatible, but it’s good to be sure.
image: golang:1.12.6
Stages
We only want to run tests, not build a binary or deploy, so we will have just one stage in our CI pipeline.
stages:
- test
Dependencies
Now we need to pull in any dependencies that our Go files have. To be able to use go get
, we need to put the repository in the $GOPATH, which defaults to /go
. Furthermore, our projects need to be under the /src/<git domain>/<namespace>/<project>
directory
before_script:
- mkdir -p /go/src/gitlab.com/flying_kiwi /go/src/_/builds
- cp -r $CI_PROJECT_DIR /go/src/gitlab.com/flying_kiwi/go-ci-demo
- ln -s /go/src/gitlab.com/flying_kiwi /go/src/_/builds/flying_kiwi
- go get -v -d ./...
Tests
To run the tests on all the .go
files in your project, you can run go test ./...
from the root folder.
unit_tests:
stage: test
script:
- go test -v ./...
Coverage
At this stage all our tests are running. What about test coverage? We can use the -coverprofile
flag to get coverage data for our tests.
script:
- go test -v ./... -coverprofile .testCoverage.txt
To let Gitlab parse the coverage output of go test
, we add the following regular expression under Settings > CI/CD > General pipelines > Test coverage parsing
total:\s+\(statements\)\s+(\d+.\d+\%)
You can now add badges to your README so you can see pipeline status and coverage right from the repository page! Look under Settings > CI/CD > General pipelines
and scroll down to find the Pipeline status
and Coverage report
sections. Grab the markdown snippet, pop it in your README.md
, and there you go!
Caching
The official Gitlab tutorial for running CI/CD with Golang suggests the following:
cache:
paths:
- /apt-cache
- /go/src/github.com
- /go/src/golang.org
- /go/src/google.golang.org
- /go/src/gopkg.in
But that doesn’t work. Why? Gitlab only allows caching of files inside of your repository. So the above paths resolve to e.g. /home/user/flying_kiwi/demo-go-ci/go/src/github.com
.
This subdirectory caching works great for Node projects, for example, where node_modules
will be a subdirectory of your project. But for Go, all the dependencies are stored on the gopath /go
. And obviously /apt-cache
is completely out.
Variables
Lastly we’re going to refactor this script with some variables so it’s more easily portable to other projects. We will also use the $GOPATH variable in case the default path for our base image changes from /go/
.
The final .gitlab-ci.yml
file looks like:
image: golang:1.12.6
variables:
REPO: gitlab.com
GROUP: flying_kiwi
PROJECT: go-ci-demo
stages:
- test
before_script:
- mkdir -p $GOPATH/src/$REPO/$GROUP $GOPATH/src/_/builds
- cp -r $CI_PROJECT_DIR $GOPATH/src/$REPO/$GROUP/$PROJECT
- ln -s $GOPATH/src/$REPO/$GROUP $GOPATH/src/_/builds/$GROUP
- go get -v -d ./...
unit_tests:
stage: test
script:
- go test -v ./... -coverprofile .testCoverage.txt
You can see this project and grab all the files in it at https://gitlab.com/flying_kiwi/go-ci-demo