Language Guide: Go

CircleCI supports building Go projects using any version of Go that can be installed in a Docker image.

Quickstart: Demo Go Reference Project

We maintain a reference Go project to show how to build on CircleCI 2.0:

In the project you will find a commented CircleCI configuration file .circleci/config.yml. This file shows best practice for using CircleCI 2.0 with Go projects.

Pre-Built CircleCI Docker Images

We recommend using a CircleCI pre-built image that comes pre-installed with tools that are useful in a CI environment. You can select the version you need from Docker Hub: The demo project uses an official CircleCI image.

Build the Demo Project Yourself

A good way to start using CircleCI is to build a project yourself. Here’s how to build the demo project with your own account:

  1. Fork the project on GitHub to your own account
  2. Go to the Add Projects page in CircleCI and click the Build Project button next to the project you just forked
  3. To make changes you can edit the .circleci/config.yml file and make a commit. When you push a commit to GitHub, CircleCI will build and test the project.

If you want to test your changes locally, use our CLI tool and run circleci build.

Config Walkthrough

This section explains the commands in .circleci/config.yml

We always start with the version.

version: 2

Next, we have a jobs key. Every config file must have a ‘build’ job. This is the only job that will be automatically picked up and run by CircleCI.

In the job, we specify a working_directory. Go is very strict about the structure of the Go Workspace, so we’ll need to specify a path that satisfies those requirements.

version: 2
    working_directory: /go/src/

This path will be used as the default working directory for the rest of the job unless otherwise specified.

Directly beneath working_directory, we’ll specify primary container images for this job under docker.

      - image: circleci/golang:1.8

We’ll use a custom image which is based on golang:1.8.0 and includes also netcat (we’ll need it later).

We’re also using an image for PostgreSQL, along with 2 environment variables for initializing the database.

      - image: circleci/postgres:9.4.12-alpine
          POSTGRES_USER: root
          POSTGRES_DB: circle_test

Now we need to add several steps within the build job.

The checkout step will default to the working_directory we have already defined.

      - checkout

Next we create a directory for collecting test results

      - run: mkdir -p $TEST_RESULTS

Then we pull down the cache (if present). If this is your first run, this won’t do anything.

      - restore_cache:
            - v1-pkg-cache

And install the Go implementation of the JUnit reporting tool and other dependencies for our application. These are good candidates to be pre-installed in primary container.

      - run: go get
      - run: go get
      - run: go get

Both containers (primary and postgres) start simultaneously, however Postgres may require some time to get ready and if our tests start before that the job will fail. So it’s good practice to wait until dependent services are ready. Here we have only Postgres, so we add this step:

      - run:
          name: Waiting for Postgres to be ready
          command: |
            for i in `seq 1 10`;
              nc -z localhost 5432 && echo Success && exit 0
              echo -n .
              sleep 1
            echo Failed waiting for Postgres && exit 1

This is why netcat installed on the CircleCI Go image. We use it to validate that the port is open.

Now we run our tests. To do that, we need to set an environment variable for our database’s URL and path to the DB migrations files. This step has some additional commands, we’ll explain them below.

      - run:
          name: Run unit tests
            CONTACTS_DB_URL: "postgres://rot@localhost:5432/circle_test?sslmode=disable"
            CONTACTS_DB_MIGRATIONS: /go/src/
          command: |
            trap "go-junit-report <${TEST_RESULTS}/go-test.out > ${TEST_RESULTS}/go-test-report.xml" EXIT
            make test | tee ${TEST_RESULTS}/go-test.out

Our project uses make for building and testing (you can see Makefile here), so we can just run make test. In order to collect test results and upload them later (read more about test results in the Project Tutorial) we’re using go-junit-report:

make test | go-junit-report > ${TEST_RESULTS}/go-test-report.xml

In this case all output from make test will go straight into go-junit-report without appearing in stdout. We can solve this by using two standard Unix commands tee and trap. The first one allows us to duplicate output into stdout and somewhere else (read more). The second one allows us to specify some command to be executed on script exit (read more). So we can do:

trap "go-junit-report <${TEST_RESULTS}/go-test.out > ${TEST_RESULTS}/go-test-report.xml" EXIT
make test | tee ${TEST_RESULTS}/go-test.out

Now we know that our unit tests succeeded we can start our service and validate it’s running.

      - run: make

      - save_cache:
          key: v1-pkg-cache
            - ~/.cache/go-build

      - run:
          name: Start service
            CONTACTS_DB_URL: "postgres://root@localhost:5432/circle_test?sslmode=disable"
            CONTACTS_DB_MIGRATIONS: /go/src/
          command: ./workdir/contacts
          background: true

      - run:
          name: Validate service is working
          command: curl --retry 10 --retry-delay 1 --retry-connrefused http://localhost:8080/contacts/test

After we pull and build the project’s dependencies using make, we store any built packages in the cache. This is the recommended way to cache dependencies for your Go project.

To start the service we need to build it first. After that we use the same environment variables as we did in the testing step for the service to start. We’re using background: true to keep the service running and proceed to the next step where we use curl to validate it successfully started and is responding to our request.

Finally, let’s specify a path to store the results of the tests.

      - store_test_results:
          path: /tmp/test-results

Success! You just set up CircleCI 2.0 for a Go app. Check out our Job page to see how this looks when building on CircleCI.

See Also

See the Deploy document for example deploy target configurations.

Refer to the Caching Dependencies document for more caching strategies.