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
beta.go are standalone
main packages intended to be run with
go run (or have a binary built with
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.
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
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 ./...
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 ./...
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
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!
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.
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.
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
.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