Skip to content
Snippets Groups Projects
README.md 15.7 KiB
Newer Older
Pierre Smeyers's avatar
Pierre Smeyers committed
# GitLab CI template for Go

This project implements a GitLab CI/CD template to build, test and analyse your [Go](https://golang.org/) projects.
Pierre Smeyers's avatar
Pierre Smeyers committed

## Usage

This template can be used both as a [CI/CD component](https://docs.gitlab.com/ee/ci/components/#use-a-component-in-a-cicd-configuration) 
or using the legacy [`include:project`](https://docs.gitlab.com/ee/ci/yaml/index.html#includeproject) syntax.

### Use as a CI/CD component

Add the following to your `gitlab-ci.yml`:

```yaml
include:
  # 1: include the component
  - component: gitlab.com/to-be-continuous/golang/gitlab-ci-golang@4.9.0
    # 2: set/override component inputs
    inputs:
      image: "registry.hub.docker.com/library/golang:buster" # ⚠ this is only an example
```

### Use as a CI/CD template (legacy)

Add the following to your `gitlab-ci.yml`:
Pierre Smeyers's avatar
Pierre Smeyers committed

```yaml
include:
  # 1: include the template
Pierre Smeyers's avatar
Pierre Smeyers committed
  - project: 'to-be-continuous/golang'
    ref: '4.9.0'
Pierre Smeyers's avatar
Pierre Smeyers committed
    file: '/templates/gitlab-ci-golang.yml'

variables:
  # 2: set/override template variables
  GO_IMAGE: "registry.hub.docker.com/library/golang:buster" # ⚠ this is only an example
Pierre Smeyers's avatar
Pierre Smeyers committed
```

## Global configuration

The Go template uses some global configuration used throughout all jobs.

| Input / Variable | Description                                                                                                | Default value   |
|------------------|------------------------------------------------------------------------------------------------------------|-----------------|
| `image` / `GO_IMAGE` | The Docker image used to run Go for `go-build` <br/>:warning: **set the version required by your project** | `registry.hub.docker.com/library/golang:bookworm` |
| `test-image` / `GO_TEST_IMAGE` | The Docker image used to run Go for `go-test` <br/>:warning: **set the version required by your project**  | _none_          |
| `project-dir` / `GO_PROJECT_DIR` | Go project root directory                                                                                  | `.`             |
| `goproxy` / `GOPROXY` | URL of Go module proxy                                                                                     | _none_          |
### go generate job

The Go template supports code generation with [go generate](https://go.dev/blog/generate).
It is disable by default and can be enabled by setting the `GO_GENERATE_MODULES` variable.

| Input / Variable | Description                                                                                                | Default value   |
|------------------|------------------------------------------------------------------------------------------------------------|-----------------|
| `generate-modules` / `GO_GENERATE_MODULES` | Space separated list of Go code generator modules (ex: `stringer mockery`) | _none_ (disabled) |

#### Capture generated files as job artifacts

Using [go generate](https://go.dev/blog/generate) actually generates source files, that have to be captured and promoted all the way down to the build & test jobs.

In its default configuration, the template captures the following:

* any folder named `mock/` wherever in the file tree (entire content),
* any folder named `mocks/` wherever in the file tree (entire content),
* any file matching `*mock*.go` pattern wherever in the file tree.

If this default doesn't suit your needs, you'll have to override the artifact path patterns (YAML).
An example of this is given in the next chapter.

#### Example

```yaml
variables:
  # list all required generate modules (including mockery)
  GO_GENERATE_MODULES: >
    github.com/vektra/mockery/v2@v2.38.0 
    github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest 
    mockery

# override the artifact path patterns
go-generate:
  artifacts:
    paths:
      # list all the matchers to capture generated code
      - "**/*mockery.go"
      - "myapi/client/"
```

Pierre Smeyers's avatar
Pierre Smeyers committed
### build & test jobs

You can specify if you want the template to build an `application` or `modules` with the `GO_BUILD_MODE` variable. It may have the following values: 
 * `application` will make the build output the binaries (use `-o` build option, won't work if there is no `main.go` file)
 * `modules` won't output the binaries (no use of the `-o` option)
 * `auto` the template will rely on the presence of a `main.go` file to detect if it should output the binaries.

The build target platform is the one defined by the docker image but it can be overriden using the `GO_TARGET_OS` and `GO_TARGET_ARCH` variables.

```yaml
variables:
  GO_TARGET_OS: "windows"
  GO_TARGET_ARCH: "amd64"
```

Pierre Smeyers's avatar
Pierre Smeyers committed
Build and tests can be done in separate jobs.
If `GO_TEST_IMAGE` is not set (default), the `go-build-test` job will run build and tests at once.
If `GO_TEST_IMAGE` is set, separate `go-build` and `go-test` jobs will be run in the `build` phase in parallel.

Separating `build` and `test` jobs can be useful to use different images (and hence different tools) or if you want to build muli-platform binaries.

Here is a `.gitlab-ci.yml` example that triggers a build on 3 target platforms using the [parallel matrix jobs](https://docs.gitlab.com/ee/ci/yaml/#parallel-matrix-jobs) pattern:

```yaml
variables:
  GO_IMAGE: "registry.hub.docker.com/library/golang:1.17-buster"
  GO_TEST_IMAGE: "registry.hub.docker.com/library/golang:1.17-buster"

go-build:
  parallel:
    matrix:
      - GO_TARGET_OS: "windows"
        GO_TARGET_ARCH: "amd64"
      - GO_TARGET_OS: "linux"
        GO_TARGET_ARCH: "amd64"
      - GO_TARGET_OS: "linux"
        GO_TARGET_ARCH: "arm"
```

Pierre Smeyers's avatar
Pierre Smeyers committed
These jobs use the following variable:

| Input / Variable | Description                                                                                                             | Default value                                 |
|-------------------------|-------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|
| `build-mode` / `GO_BUILD_MODE` | The template build mode (accepted values are `application`, `modules` and `auto`)                                       | `auto`                                        |
| `build-flags` / `GO_BUILD_FLAGS` | Flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies)                   | `-mod=readonly`                               |
| `build-linker-flags` / `GO_BUILD_LINKER_FLAGS` | Linker flags used by the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies) `-ldflags` | `-s -w`                                       |
| `build-packages` / `GO_BUILD_PACKAGES` | Packages to build with the [go build command](https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies)          | `./...`                                       |
| `test-flags` / `GO_TEST_FLAGS` | Flags used by the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages)                                        | `-mod=readonly -v -race`                      |
| `test-packages` / `GO_TEST_PACKAGES` | Packages to test with the [go test command](https://pkg.go.dev/cmd/go#hdr-Test_packages)                                | `./...`                                       |
| `list-args` / `GO_LIST_ARGS` | Arguments used by the list command                                                                                      | `list -u -m -mod=readonly -json all`          |
| `target-os` / `GO_TARGET_OS` | The `GOOS` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63)           | _none_ (fallback to go docker image `GOOS`)   |
| `target-arch` / `GO_TARGET_ARCH` | The `GOARCH` target [see available values](https://gist.github.com/asukakenji/f15ba7e588ac42795f421b48b8aede63)         | _none_ (fallback to go docker image `GOARCH`) |
| `cobertura-flags` / `GO_COBERTURA_FLAGS` | The `GOFLAGS` to use with `gocover-cobertura` if needed                                                                 | _none_                                        |
Pierre Smeyers's avatar
Pierre Smeyers committed
In addition to a textual report in the console, the test jobs produce the following reports, kept for one day:

| Report                                              | Format                                                                             | Usage                                                                                                                 |
|-----------------------------------------------------|------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| `$GO_PROJECT_DIR/reports/go-test.native.txt`        | native Go test report (text)                                                       | N/A                                                                                                                   |
| `$GO_PROJECT_DIR/reports/go-test.native.json`       | native Go test report (json)                                                       | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/test-coverage/test-execution-parameters/#header-8) |
| `$GO_PROJECT_DIR/reports/go-test.xunit.xml`         | [xUnit](https://en.wikipedia.org/wiki/XUnit) test report(s)                        | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsjunit)                 |
| `$GO_PROJECT_DIR/reports/go-coverage.native.out`    | native Go coverage                                                                 | N/A                                                                                                                   |
| `$GO_PROJECT_DIR/reports/go-coverage.cobertura.xml` | [Cobertura XML](https://gcovr.com/en/stable/output/cobertura.html) coverage report | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report)       |
Pierre Smeyers's avatar
Pierre Smeyers committed

### `go-ci-lint` job

This job enables a manual [GolangCI-Lint](https://github.com/golangci/golangci-lint) analysis.

It is bound to the `build` stage, and uses the following variables:

| Input / Variable | Description                                                                                              | Default value                          |
|-----------------------|----------------------------------------------------------------------------------------------------------|----------------------------------------|
| `ci-lint-image` / `GO_CI_LINT_IMAGE` | The Docker image used to run `golangci-lint`                                                             | `registry.hub.docker.com/golangci/golangci-lint:latest-alpine` |
| `ci-lint-args` / `GO_CI_LINT_ARGS` | `golangci-lint` [command line arguments](https://github.com/golangci/golangci-lint#command-line-options) | `-E gosec,goimports ./...`             |
| `ci-lint-disabled` / `GO_CI_LINT_DISABLED` | Set to `true` to disable this job                                                                        | _none_ (enabled)                        |
Pierre Smeyers's avatar
Pierre Smeyers committed
In addition to a textual report in the console, this job produces the following reports, kept for one day:

| Report                                                | Format                                                   | Usage                                                                                                       |
|-------------------------------------------------------|----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
Pierre Smeyers's avatar
Pierre Smeyers committed
| `$GO_PROJECT_DIR/reports/go-ci-lint.codeclimate.json` | [Code Climate](https://docs.codeclimate.com/docs/pylint) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscodequality) |
| `$GO_PROJECT_DIR/reports/go-ci-lint.checkstyle.xml`   | Checkstyle                                               | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/external-issues/)                        |
Pierre Smeyers's avatar
Pierre Smeyers committed

### `go-mod-outdated` job

This job enables a manual [Go-mod-outdated](https://github.com/psampaz/go-mod-outdated) analysis.

It is bound to the `test` stage, and uses the following variables:

| Input / Variable | Description                                                                                   | Default value     |
|------------------------|-----------------------------------------------------------------------------------------------|-------------------|
| `mod-outdated-args` / `GO_MOD_OUTDATED_ARGS` | `god-mod-outdated` [command line arguments](https://github.com/psampaz/go-mod-outdated#usage) | `-update -direct` |
Pierre Smeyers's avatar
Pierre Smeyers committed

Checking outdated modules can be a long operation and therefore the job is configured to be ran **manually** by default (overridable).

## SonarQube analysis

If you're using the SonarQube template to analyse your Go code, here is a sample `sonar-project.properties` file:

```properties
# see: https://docs.sonarqube.org/latest/analyzing-source-code/test-coverage/test-execution-parameters/#go
Pierre Smeyers's avatar
Pierre Smeyers committed
# set your source directory(ies) here (relative to the sonar-project.properties file)
sonar.sources=.
# exclude unwanted directories and files from being analysed
sonar.exclusions=bin/**,**/*_test.go,**/vendor/**

# set your tests directory(ies) here (relative to the sonar-project.properties file)
sonar.tests=.
sonar.test.inclusions=**/*_test.go
sonar.test.exclusions=**/vendor/**

Pierre Smeyers's avatar
Pierre Smeyers committed
# tests report: JSON native format
sonar.go.tests.reportPaths=reports/go-test.native.json
# coverage report: native format
sonar.go.coverage.reportPaths=reports/go-coverage.native.out
# golanci-lint: checkstyle report (if enabled)
sonar.go.golangci-lint.reportPaths=reports/go-ci-lint.checkstyle.xml
* [Go language support](https://docs.sonarqube.org/latest/analyzing-source-code/test-coverage/test-execution-parameters/#go)
Pierre Smeyers's avatar
Pierre Smeyers committed
* [test coverage & execution parameters](https://docs.sonarqube.org/latest/analysis/coverage/)
* [third-party issues](https://docs.sonarqube.org/latest/analysis/external-issues/)

:warning: an [unsolved issue](https://jira.sonarsource.com/browse/SONARSLANG-450) may prevent SonarQube Go plugin from
importing your test reports.
### `go-sbom` job

This job generates a [SBOM](https://cyclonedx.org/) file listing installed packages using [@cyclonedx/cyclonedx-gomod](https://github.com/CycloneDX/cyclonedx-gomod).

It is bound to the `test` stage, and uses the following variables:

| Input / Variable | Description                            | Default value     |
| --------------------- | -------------------------------------- | ----------------- |
| `sbom-disabled` / `GO_SBOM_DISABLED` | Set to `true` to disable this job | _none_ |
| `sbom-image` / `GO_SBOM_IMAGE` | Image of cyclonedx-gomod used for SBOM analysis | `registry.hub.docker.com/cyclonedx/cyclonedx-gomod:latest` |
| `sbom-opts` / `GO_SBOM_OPTS` | [@cyclonedx/cyclonedx-gomod options](https://github.com/CycloneDX/cyclonedx-gomod#usage) used for SBOM analysis | `-main .` |
:warning: if you don't have your main class located at the root of your `GO_PROJECT_DIR`, then you will need to override the `-main` option in `GO_SBOM_OPTS` and define your real main class location.

Example:

```yaml
variables:
  GO_SBOM_OPTS: "-main cmd/my_app"
```

### `go-govulncheck` job

This job enables Vulnerability Management with [Govulncheck](https://go.dev/blog/vuln).

It is bound to the `test` stage, and uses the following variables:

| Input / Variable | Description                            | Default value     |
| --------------------- | -------------------------------------- | ----------------- |
| `vulncheck-disabled` / `GO_VULNCHECK_DISABLED` | Set to `true` to disable this job | _none_ 
| `vulncheck-args` / `GO_VULNCHECK_ARGS` | `govulncheck` [command line arguments](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck#hdr-Flags) | `./...` |