Skip to main content

Hosting Private Go Modules on GitLab

·2 mins

There are a few hoops to jump through to host private go modules on GitLab. Firstly, we have to include .git in the module path, otherwise go get has trouble finding a repository in a nested subgroup.

For example, say we have a repository hosted at gitlab.com/ray1729/dev/hello; to create a go module in this repository, we need to do:

go mod init gitlab.com/ray1729/dev/hello.git

In the consumer, we need to import it as:

import "gitlab.com/ray1729/dev/hello.git"

To consume a subpackage in the module, we simply do:

import "gitlab.com/ray1729/dev/hello.git/pkg/foo"

Secondly, we have to define the GOPRIVATE environment variable to prevent go get from trying to download the module from a public proxy:

export GOPRIVATE=gitlab.com/ray1729/*

Finally, we need to configure authentication. For local development, create a personal access token with read_repository permission, and add the following to ~/.netrc:

machine gitlab.com
login oauth2
password ${TOKEN}

We can now run go get to fetch modules from our private repositories.

For GitLab CI/CD, every job has an automatic variable called $CI_JOB_TOKEN that we can write to a .netrc file in a before_script. Here's a minimal working .gitlab-ci.yml:

variables:
  GOPRIVATE: gitlab.com/ray1729/*

go-build:
  image: golang:1.15-buster
  before_script:
    - echo -e "machine gitlab.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc
  script:
    - go build ./...

Note: if you define a group-level GOPRIVATE variable in GitLab there is no need to include the variable in the CI config.