> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/continuous-integration/3.0/troubleshooting-and-resources/tutorials-and-code-samples/ci-golang.md).

# Go

You can build and test a [Go](https://go.dev/) application using a Linux platform on [Harness Cloud](/continuous-integration/3.0/use-harness-ci/use-harness-ci/set-up-build-infrastructure/use-harness-cloud-build-infrastructure.md) or a [self-managed Kubernetes cluster](/continuous-integration/3.0/use-harness-ci/use-harness-ci/set-up-build-infrastructure/k8s-build-infrastructure.md) build infrastructure.

This guide assumes you've [created a Harness CI pipeline](/continuous-integration/3.0/use-harness-ci/use-harness-ci/prep-ci-pipeline-components.md).

### Install dependencies <a href="#install-dependencies" id="install-dependencies"></a>

If necessary, add a [Run step](/continuous-integration/3.0/use-harness-ci/use-harness-ci/run-step-settings.md) to install any dependencies.

{% tabs %}
{% tab title="Harness Cloud" %}

```yaml
- step:
    type: Run
    identifier: dependencies
    name: Dependencies
    spec:
      shell: Sh
      command: |-
        go get example.com/my-go-module
```

{% endtab %}

{% tab title="Self-managed" %}

```yaml
- step:
    type: Run
    identifier: dependencies
    name: Dependencies
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: golang:latest
      command: |-
        go get example.com/my-go-module
```

{% endtab %}
{% endtabs %}

### Cache dependencies <a href="#cache-dependencies" id="cache-dependencies"></a>

Add caching to your stage.

{% tabs %}
{% tab title="Cache Intelligence" %}
Cache your Go module dependencies with [Cache Intelligence](/continuous-integration/3.0/use-harness-ci/use-harness-ci/caching-ci-data/cache-intelligence.md).

Add `caching.enabled.true` to your `stage.spec`:

```yaml
- stage:
    spec:
      caching:
        enabled: true
```

{% endtab %}

{% tab title="Save and Restore Cache steps" %}
You can use built-in steps to:

* [Save and Restore Cache from S3](/continuous-integration/3.0/use-harness-ci/use-harness-ci/caching-ci-data/saving-cache.md)
* [Save and Restore Cache from GCS](/continuous-integration/3.0/use-harness-ci/use-harness-ci/caching-ci-data/save-cache-in-gcs.md)

{% hint style="info" %}
**GO CACHE KEY AND PATH REQUIREMENTS**

Go pipelines must reference `go.sum` for `spec.key` in **Save Cache** and **Restore Cache** steps, for example:

```yaml
spec:
  key: cache-{{ checksum "go.sum" }}
```

Additionally, `spec.sourcePaths` must include `/go/pkg/mod` and `/root/.cache/go-build` in the **Save Cache** step, for example:

```yaml
spec:
  sourcePaths:
    - /go/pkg/mod
    - /root/.cache/go-build
```

{% endhint %}

<details>

<summary>YAML example: Save and restore cache steps</summary>

Here's an example of a pipeline with **Save Cache to S3** and **Restore Cache from S3** steps.

```yaml
            steps:
              - step:
                  type: RestoreCacheS3
                  name: Restore Cache From S3
                  identifier: Restore_Cache_From_S3
                  spec:
                    connectorRef: AWS_Connector
                    region: us-east-1
                    bucket: your-s3-bucket
                    key: cache-{{ checksum "go.sum" }}
                    archiveFormat: Tar
              - step:
                  type: Run
                  ...
              - step:
                  type: BuildAndPushDockerRegistry
                  ...
              - step:
                  type: SaveCacheS3
                  name: Save Cache to S3
                  identifier: Save_Cache_to_S3
                  spec:
                    connectorRef: AWS_Connector
                    region: us-east-1
                    bucket: your-s3-bucket
                    key: cache-{{ checksum "go.sum" }}
                    sourcePaths:
                      - /go/pkg/mod
                      - /root/.cache/go-build
                    archiveFormat: Tar
```

</details>
{% endtab %}
{% endtabs %}

### Build and run tests <a href="#build-and-run-tests" id="build-and-run-tests"></a>

Add [**Run**](/continuous-integration/3.0/use-harness-ci/use-harness-ci/run-step-settings.md) steps to build and run your tests.

{% tabs %}
{% tab title="Harness Cloud" %}

```yaml
- step:
    type: Run
    identifier: build
    name: Build
    spec:
      shell: Sh
      command: |-
        go build
- step:
    type: Run
    identifier: test
    name: Test
    spec:
      shell: Sh
      command: |-
        go test -v ./...
```

{% endtab %}

{% tab title="Self-managed" %}

```yaml
- step:
    type: Run
    identifier: build
    name: Build
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: golang:latest
      command: |-
        go build
- step:
    type: Run
    identifier: test
    name: Test
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: golang:latest
      command: |-
        go test -v ./...
```

{% endtab %}
{% endtabs %}

#### Visualize test results <a href="#visualize-test-results" id="visualize-test-results"></a>

You can [view test results](/continuous-integration/3.0/use-harness-ci/use-harness-ci/run-tests/viewing-tests.md) on the **Tests** tab of your pipeline executions. Test results must be in JUnit XML format.

You can use [go-junit-report](https://github.com/jstemmer/go-junit-report) to output compatible JUnit XML reports.

For your pipeline to produce test reports, you need to modify the **Run** step that runs your tests. Make sure the `command` generates JUnit XML reports and add the `reports` specification.

{% tabs %}
{% tab title="Harness Cloud" %}

```yaml
- step:
    type: Run
    identifier: test
    name: Test
    spec:
      shell: Sh
      command: |-
        export PATH=$(go env GOPATH)/bin:$PATH
        go install github.com/jstemmer/go-junit-report/v2@latest
        go test -v ./... | tee report.out
        cat report.out | go-junit-report -set-exit-code > report.xml
      reports:
        type: JUnit
        spec:
          paths:
            - report.xml
```

{% endtab %}

{% tab title="Self-managed" %}

```yaml
- step:
    type: Run
    identifier: test
    name: Test
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: golang
      command: |-
        go install github.com/jstemmer/go-junit-report/v2@latest
        go test -v ./... | tee report.out
        cat report.out | go-junit-report -set-exit-code > report.xml
      reports:
        type: JUnit
        spec:
          paths:
            - report.xml
```

{% endtab %}
{% endtabs %}

#### Test splitting <a href="#test-splitting" id="test-splitting"></a>

You can use [test splitting (parallelism)](/continuous-integration/3.0/use-harness-ci/use-harness-ci/run-tests/speed-up-ci-test-pipelines-using-parallelism.md) to improve test times.

### Specify version <a href="#specify-version" id="specify-version"></a>

{% tabs %}
{% tab title="Harness Cloud" %}
Go is pre-installed on Hosted Cloud runners. For details about all available tools and versions, go to [Platforms and image specifications](/continuous-integration/3.0/use-harness-ci/use-harness-ci/set-up-build-infrastructure/use-harness-cloud-build-infrastructure.md#platforms-and-image-specifications).

If your application requires a specific version of Go, add a **Run** step to install it.

<details>

<summary>Install a specific version of Go</summary>

```yaml
- step:
    type: Run
    identifier: installgo
    name: Install Go
    spec:
      shell: Sh
      # install version 1.20 of Go
      command: |-
        export PATH=$(go env GOPATH)/bin:$PATH
        go install golang.org/dl/go1.20@latest
        go1.20 download
```

</details>

<details>

<summary>Install multiple versions of Go</summary>

1. Add the [matrix looping strategy](/harness-ai/use-harness-platform/pipelines/looping-strategies/looping-strategies-matrix-repeat-and-parallelism.md) configuration to your stage.

```yaml
strategy:
  matrix:
    # matrix strategy with Go versions 1.19 and 1.20
    goVersion:
      - "1.19"
      - "1.20"
```

2. Reference the matrix variable in your steps.

```yaml
- step:
    type: Run
    identifier: installgo
    name: Install Go
    spec:
      shell: Sh
      command: |-
        export PATH=$(go env GOPATH)/bin:$PATH
        go install golang.org/dl/go<+matrix.goVersion>@latest
        go<+matrix.goVersion> download
```

</details>
{% endtab %}

{% tab title="Self-managed" %}
Specify the desired [Golang Docker image](https://hub.docker.com/_/golang) tag in your steps. There is no need for a separate install step when using Docker.

<details>

<summary>Build using a specific version of Go</summary>

```yaml
- step:
    type: Run
    identifier: build
    name: Build
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      # use version 1.20 of Go
      image: golang:1.20
      command: |-
        go build
```

</details>

<details>

<summary>Build using multiple versions of Go</summary>

1. Add the [matrix looping strategy](/harness-ai/use-harness-platform/pipelines/looping-strategies/looping-strategies-matrix-repeat-and-parallelism.md) configuration to your stage.

```yaml
strategy:
  matrix:
    # matrix strategy with Go versions 1.19 and 1.20
    goVersion:
      - "1.19"
      - "1.20"
```

2. Reference the matrix variable in the `image` field of your steps.

```yaml
- step:
    type: Run
    identifier: build
    name: Build
    spec:
      connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
      image: golang:<+matrix.goVersion>
      command: |-
        go build
```

</details>
{% endtab %}
{% endtabs %}

### Full pipeline examples <a href="#full-pipeline-examples" id="full-pipeline-examples"></a>

The following full pipeline examples are based on the partial examples above.

{% tabs %}
{% tab title="Harness Cloud" %}
If you copy this example, replace the placeholder values with appropriate values for your [code repo connector](/continuous-integration/3.0/use-harness-ci/use-harness-ci/codebase-configuration/create-and-configure-a-codebase.md#code-repo-connectors) and repository name. Depending on your project and organization, you may also need to replace `projectIdentifier` and `orgIdentifier`.

<details>

<summary>Pipeline with one specific Go version</summary>

Here is a single-stage pipeline using Cache Intelligence with steps to install Go 1.20, build, and test.

```yaml
pipeline:
  name: Build and test Go app
  identifier: Build_and_test_Go_app
  projectIdentifier: default
  orgIdentifier: default
  stages:
    - stage:
        name: Build
        identifier: Build
        type: CI
        spec:
          caching:
            enabled: true
          cloneCodebase: true
          execution:
            steps:
              - step:
                  type: Run
                  identifier: installgo
                  name: Install Go
                  spec:
                    shell: Sh
                    command: |-
                      export PATH=$(go env GOPATH)/bin:$PATH
                      go install golang.org/dl/go1.20@latest
                      go1.20 download
              - step:
                  type: Run
                  identifier: build
                  name: Build
                  spec:
                    shell: Sh
                    command: |-
                      export PATH=$(go env GOPATH)/bin:$PATH
                      go1.20 build
              - step:
                  type: Run
                  identifier: test
                  name: Test
                  spec:
                    shell: Sh
                    command: |-
                      export PATH=$(go env GOPATH)/bin:$PATH
                      go1.20 install github.com/jstemmer/go-junit-report/v2@latest
                      go1.20 test -v | tee report.out
                      cat report.out | go-junit-report -set-exit-code > report.xml
                    reports:
                      type: JUnit
                      spec:
                        paths:
                          - report.xml
          platform:
            os: Linux
            arch: Amd64
          runtime:
            type: Cloud
            spec: {}
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
```

</details>

<details>

<summary>Pipeline with multiple Go versions</summary>

Here is a single-stage pipeline using Cache Intelligence with a matrix looping strategy for Go versions 1.19 and 1.20.

```yaml
pipeline:
  name: Build and test Go app
  identifier: Build_and_test_Go_app
  projectIdentifier: default
  orgIdentifier: default
  stages:
    - stage:
        name: Build
        identifier: Build
        type: CI
        strategy:
          matrix:
            goVersion:
              - "1.19"
              - "1.20"
        spec:
          caching:
            enabled: true
          cloneCodebase: true
          execution:
            steps:
              - step:
                  type: Run
                  identifier: installgo
                  name: Install Go
                  spec:
                    shell: Sh
                    command: |-
                      export PATH=$(go env GOPATH)/bin:$PATH
                      go install golang.org/dl/go<+matrix.goVersion>@latest
                      go<+matrix.goVersion> download
              - step:
                  type: Run
                  identifier: build
                  name: Build
                  spec:
                    shell: Sh
                    command: |-
                      export PATH=$(go env GOPATH)/bin:$PATH
                      go<+matrix.goVersion> build
              - step:
                  type: Run
                  name: Test
                  identifier: test
                  spec:
                    shell: Sh
                    command: |-
                      export PATH=$(go env GOPATH)/bin:$PATH
                      go<+matrix.goVersion> install github.com/jstemmer/go-junit-report/v2@latest
                      go<+matrix.goVersion> test -v ./... | tee report_<+matrix.goVersion>.out
                      cat report_<+matrix.goVersion>.out | go-junit-report -set-exit-code > report_<+matrix.goVersion>.xml
                    reports:
                      type: JUnit
                      spec:
                        paths:
                          - report_*.xml
          platform:
            os: Linux
            arch: Amd64
          runtime:
            type: Cloud
            spec: {}
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
```

</details>
{% endtab %}

{% tab title="Self-managed" %}
If you copy this example, replace the placeholder values with appropriate values for your [code repo connector](/continuous-integration/3.0/use-harness-ci/use-harness-ci/codebase-configuration/create-and-configure-a-codebase.md#code-repo-connectors), [Kubernetes cluster connector](/harness-ai/use-harness-platform/connectors/cloud-providers/add-a-kubernetes-cluster-connector.md), Kubernetes namespace, and repository name. Depending on your project and organization, you may also need to replace `projectIdentifier` and `orgIdentifier`.

<details>

<summary>Pipeline with one specific Go version</summary>

Here is a single-stage pipeline, with steps to install Go 1.20, build and test.

```yaml
pipeline:
  name: Build and test Go app
  identifier: Build_and_test_Go_app
  projectIdentifier: default
  orgIdentifier: default
  stages:
    - stage:
        name: Build
        identifier: Build
        type: CI
        spec:
          cloneCodebase: true
          execution:
            steps:
              - step:
                  type: Run
                  identifier: build
                  name: Build
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: golang:1.20
                    command: |-
                      go build
              - step:
                  type: Run
                  identifier: test
                  name: Test
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: golang:1.20
                    command: |-
                      go install github.com/jstemmer/go-junit-report/v2@latest
                      go test -v ./... | tee report.out
                      cat report.out | go-junit-report -set-exit-code > report.xml
                    reports:
                      type: JUnit
                      spec:
                        paths:
                          - report.xml
          infrastructure:
            spec:
              connectorRef: YOUR_KUBERNETES_CONNECTOR_ID
              namespace: YOUR_KUBERNETES_NAMESPACE
            type: KubernetesDirect
          platform:
            arch: Amd64
            os: Linux
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
```

</details>

<details>

<summary>Pipeline with multiple Go versions</summary>

Here is a single-stage pipeline, with a matrix looping strategy for Go versions 1.19 and 1.20.

```yaml
pipeline:
  name: Build and test Go app
  identifier: Build_and_test_Go_app
  projectIdentifier: default
  orgIdentifier: default
  stages:
    - stage:
        name: Build
        identifier: Build
        type: CI
        strategy:
          matrix:
            goVersion:
              - "1.19"
              - "1.20"
        spec:
          cloneCodebase: true
          execution:
            steps:
              - step:
                  type: Run
                  identifier: build
                  name: Build
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: golang:<+matrix.goVersion>
                    command: |-
                      go build
              - step:
                  type: Run
                  name: Test
                  identifier: test
                  spec:
                    connectorRef: YOUR_IMAGE_REGISTRY_CONNECTOR
                    image: golang:<+matrix.goVersion>
                    command: |-
                      go install github.com/jstemmer/go-junit-report/v2@latest
                      go test -v ./... | tee report_<+matrix.goVersion>.out
                      cat report_<+matrix.goVersion>.out | go-junit-report -set-exit-code > report_<+matrix.goVersion>.xml
                    reports:
                      type: JUnit
                      spec:
                        paths:
                          - report_*.xml
          infrastructure:
            spec:
              connectorRef: YOUR_KUBERNETES_CLUSTER_CONNECTOR_ID
              namespace: YOUR_KUBERNETES_NAMESPACE
            type: KubernetesDirect
          platform:
            arch: Amd64
            os: Linux
  properties:
    ci:
      codebase:
        connectorRef: YOUR_CODE_REPO_CONNECTOR_ID
        repoName: YOUR_REPO_NAME
        build: <+input>
```

</details>
{% endtab %}
{% endtabs %}

### Next steps <a href="#next-steps" id="next-steps"></a>

Now that you have created a pipeline that builds and tests a Go app, you could:

* Create [triggers](/harness-ai/use-harness-platform/triggers.md) to automatically run your pipeline.
* Add steps to [build and upload artifacts](/continuous-integration/3.0/use-harness-ci/use-harness-ci/build-and-upload-artifacts.md).
* Add a step to [build and push an image to a Docker registry](/continuous-integration/3.0/use-harness-ci/use-harness-ci/build-and-upload-artifacts/build-and-push/build-and-push-to-docker-registry.md).
