Introduction

GoReleaser is a release automation tool for Go projects. The goal is to simplify the build, release and publish steps while providing variant customization options for all steps.

GoReleaser is built for CI tools; you only need to download and execute it in your build script. Of course, you can also install it locally if you wish.

You can also customize your release process through a .goreleaser.yml file.

Several GitHub projects trust their release process to GoReleaser.

Install

You can install the pre-compiled binary (in several different ways), use Docker or compile from source.

Here are the steps for each of them:

Install the pre-compiled binary

homebrew tap (only on macOS for now):

$ brew install goreleaser/tap/goreleaser

homebrew (may not be the latest version):

$ brew install goreleaser

snapcraft:

$ sudo snap install --classic goreleaser

scoop:

$ scoop bucket add goreleaser https://github.com/goreleaser/scoop-bucket.git
$ scoop install goreleaser

deb/rpm:

Download the .deb or .rpm from the releases page and install with dpkg -i and rpm -i respectively.

manually:

Download the pre-compiled binaries from the releases page and copy to the desired location.

Running with Docker

You can also use it within a Docker container. To do that, you’ll need to execute something more-or-less like the following:

$ docker run --rm --privileged \
  -v $PWD:/go/src/github.com/user/repo \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -w /go/src/github.com/user/repo \
  -e GITHUB_TOKEN \
  -e DOCKER_USERNAME \
  -e DOCKER_PASSWORD \
  -e DOCKER_REGISTRY \
  goreleaser/goreleaser release

ATTENTION: Currently, the provided docker image does not support the generation of snapcraft packages.

Note that the image will almost always have the last stable Go version.

The DOCKER_REGISTRY environment variable can be left empty when you are releasing to the public docker registry.

If you need more things, you are encouraged to keep your own image. You can always use GoReleaser’s own Dockerfile as an example though and iterate from that.

Compiling from source

Here you have two options:

  1. If you want to contribute to the project, please follow the steps on our contributing guide.
  2. If just want to build from source for whatever reason, follow the steps bellow:

    # clone it outside GOPATH
    git clone https://github.com/goreleaser/goreleaser
    cd goreleaser
    
    # get dependencies using go modules (needs go 1.11+)
    go get ./...
    
    # build
    go build -o goreleaser .
    
    # check it works
    ./goreleaser --version

Quick Start

In this example we will build, archive and release a sample Go project.

Create a GitHub repository and add a single main package:

// main.go
package main

func main() {
  println("Ba dum, tss!")
}

Run goreleaser init to create an example .goreleaser.yaml file:

$ goreleaser init

   • Generating .goreleaser.yml file
   • config created; please edit accordingly to your needs file=.goreleaser.yml

You can customize the generated .goreleaser.yml or leave it as-is, it’s up to you.

You can test the configuration at any time by running GoReleaser with a few extra parameters to not require a version tag, skip publishing to GitHub, and remove any already-built files:

$ goreleaser --snapshot --skip-publish --rm-dist

If you are not using vgo or Go modules, then you will need to comment out the before hooks in the generated config file or update them to match your setup accordingly.

GoReleaser will build the binaries for your app for Windows, Linux and macOS, both amd64 and i386 architectures. You can customize that by changing the builds section. Check the documentation for more information.

After building the binaries, GoReleaser will create an archive for each OS/Arch pair into a separate file. You can customize several things by changing the archive section, including releasing only the binaries and not creating archives at all. Check the documentation for more information.

You’ll need to export either a GITHUB_TOKEN or GITLAB_TOKEN environment variable, which should contain a valid GitHub token with the repo scope or GitLab token with api scope. It will be used to deploy releases to your GitHub/GitLab repository. You can create a token here for GitHub or here for GitLab.

$ export GITHUB_TOKEN=`YOUR_GH_TOKEN`
# or
$ export GITLAB_TOKEN=`YOUR_GL_TOKEN`

GoReleaser will use the latest Git tag of your repository. Create a tag and push it to GitHub:

$ git tag -a v0.1.0 -m "First release"
$ git push origin v0.1.0

Attention: Check if your tag adheres to semantic versioning.

If you don’t want to create a tag yet, you can also create a release based on the latest commit by using the --snapshot flag. (Note: only GitHub supports snapshots)

Now you can run GoReleaser at the root of your repository:

$ goreleaser

That’s all! Check your GitHub project’s release page. The release should look like this:

Or check your GitLab project’s release page. The release should also look like this:

Note: Releasing to a private-hosted GitLab CE will only work for version v11.7+, because the release feature was introduced in this version.

Dry run

If you want to test everything before doing a release “for real”, you can use the --skip-publish flag, which will only build and package things:

$ goreleaser release --skip-publish

You can check the other options by running:

$ goreleaser --help

and

$ goreleaser release --help

Semantic Versioning

GoReleaser enforces semantic versioning and will error on non compliant tags.

Your tag should be a valid semantic version. If it is not, GoReleaser will error.

The v prefix is not mandatory. You can check the templating documentation to see how to use the tag or each part of the semantic version in name templates.

CGO

Unfortunately, GoReleaser does not support CGO.

You can see the discussion about this in this issue.

You can see the comments on the issue referenced for workarounds on it.

Environment

API Tokens

GoReleaser requires either a GitHub API token with the repo scope selected to deploy the artifacts to GitHub or a GitLab API token with api scope or a Gitea API token. You can create one here for GitHub or here for GitLab or in Settings | Applications | Generate New Token page of your Gitea instance.

This token should be added to the environment variables as GITHUB_TOKEN or GITLAB_TOKEN or GITEA_TOKEN respecively. Here is how to do it with Travis CI: Defining Variables in Repository Settings.

Alternatively, you can provide the GitHub/GitLab token in a file. GoReleaser will check ~/.config/goreleaser/github_token, ~/.config/goreleaser/gitlab_token and ~/.config/goreleaser/gitea_token by default, you can change that in the .goreleaser.yml file:

# .goreleaser.yml
env_files:
  # use only one or release will fail!
  github_token: ~/.path/to/my/gh_token
  gitlab_token: ~/.path/to/my/gl_token
  gitea_token: ~/.path/to/my/gitea_token

IMPORTANT: you can define multiple env files, but the release process will fail because multiple tokens are defined. Use only one.

GitHub Enterprise

You can use GoReleaser with GitHub Enterprise by providing its URLs in the .goreleaser.yml configuration file:

# .goreleaser.yml
github_urls:
  api: https://git.company.com/api/v3/
  upload: https://git.company.com/api/uploads/
  download: https://git.company.com/
  # set to true if you use a self-signed certificate
  skip_tls_verify: false

If none are set, they default to GitHub’s public URLs.

GitLab Enterprise or private hosted

You can use GoReleaser with GitLab Enterprise by providing its URLs in the .goreleaser.yml configuration file:

# .goreleaser.yml
gitlab_urls:
  api: https://gitlab.mycompany.com/api/v4/
  download: https://gitlab.company.com
  # set to true if you use a self-signed certificate
  skip_tls_verify: false

If none are set, they default to GitLab’s public URLs.

Gitea

You can use GoReleaser with Gitea by providing its URLs in the .goreleaser.yml configuration file:

# .goreleaser.yml
gitea_urls:
  api: https://gitea.myinstance.com/api/v1/
  # set to true if you use a self-signed certificate
  skip_tls_verify: false

The dist folder

By default, GoReleaser will create its artifacts in the ./dist folder. If you must, you can change it by setting it in the .goreleaser.yml file:

# .goreleaser.yml
dist: another-folder-that-is-not-dist

Using the main.version

Default wise GoReleaser sets three ldflags:

  • main.version: Current Git tag (the v prefix is stripped) or the name of the snapshot, if you’re using the --snapshot flag
  • main.commit: Current git commit SHA
  • main.date: Date according RFC3339

You can use it in your main.go file:

package main

import "fmt"

var (
	version = "dev"
	commit  = "none"
	date    = "unknown"
)

func main() {
  fmt.Printf("%v, commit %v, built at %v", version, commit, date)
}

You can override this by changing the ldflags option in the build section.

Customization

GoReleaser provides multiple customizations via the .goreleaser.yml file.

You can generate it by running goreleaser init or start from scratch. The defaults are sensible and fit for most projects.

Continuous Integration

GoReleaser was built from the very first commit with the idea of running it as part of the CI pipeline in mind.

Let’s see how we can get it working on popular CI software.

Travis CI

You may want to setup your project to auto-deploy your new tags on Travis, for example:

# .travis.yml
language: go

addons:
  apt:
    packages:
    # needed for the nfpm pipe:
    - rpm
    # needed for the snap pipe:
    - snapd

env:
# needed for the snap pipe:
- PATH=/snap/bin:$PATH

install:
# needed for the snap pipe:
- sudo snap install snapcraft --classic

# needed for the docker pipe
services:
- docker

after_success:
# docker login is required if you want to push docker images.
# DOCKER_PASSWORD should be a secret in your .travis.yml configuration.
- test -n "$TRAVIS_TAG" && docker login -u=myuser -p="$DOCKER_PASSWORD"
# snapcraft login is required if you want to push snapcraft packages to the
# store.
# You'll need to run `snapcraft export-login snap.login` and
# `travis encrypt-file snap.login --add` to add the key to the travis
# environment.
- test -n "$TRAVIS_TAG" && snapcraft login --with snap.login

# calls goreleaser
deploy:
- provider: script
  skip_cleanup: true
  script: curl -sL https://git.io/goreleaser | bash
  on:
    tags: true
    condition: $TRAVIS_OS_NAME = linux

Note the last line (condition: $TRAVIS_OS_NAME = linux): it is important if you run a build matrix with multiple Go versions and/or multiple OSes. If that’s the case you will want to make sure GoReleaser is run just once.

CircleCI

Here is how to do it with CircleCI 2.0:

# .circleci/config.yml
version: 2
jobs:
  release:
    docker:
      - image: circleci/golang:1.10
    steps:
      - checkout
      - run: curl -sL https://git.io/goreleaser | bash
workflows:
  version: 2
  release:
    jobs:
      - release:
          filters:
            branches:
              ignore: /.*/
            tags:
              only: /v[0-9]+(\.[0-9]+)*(-.*)*/

Drone

By default, drone does not fetch tags. plugins/git is used with default values, in most cases we’ll need overwrite the clone step enabling tags in order to make goreleaser work correctly.

In this example we’re creating a new release every time a new tag is pushed. Note that you’ll need to enable tags in repo settings and add github_token secret.

1.x

# .drone.yml

kind: pipeline
name: default

steps:
  - name: fetch
    image: docker:git
    commands:
      - git fetch --tags

  - name: test
    image: golang
    volumes:
      - name: deps
        path: /go
    commands:
      - go test -race -v ./... -cover

  - name: release
    image: golang
    environment:
      GITHUB_TOKEN:
        from_secret: github_token
    volumes:
      - name: deps
        path: /go
    commands:
      - curl -sL https://git.io/goreleaser | bash
    when:
      event: tag

volumes:
  - name: deps
    temp: {}

0.8

pipeline:
  clone:
    image: plugins/git
    tags: true

  test:
    image: golang:1.10
    commands:
      - go test ./... -race

  release:
    image: golang:1.10
    secrets: [github_token]
    commands:
      curl -sL https://git.io/goreleaser | bash
    when:
      event: tag

Google CloudBuild

CloudBuild works off a different clone than your github repo: it seems that your changes are pulled to a repo like source.developers.google.com/p/YourProjectId/r/github-YourGithubUser-YourGithubRepo, and that’s what you’re building off.

This repo has the wrong name, so to prevent Goreleaser from publishing to the wrong github repo, add to your .goreleaser.yml file’s release section:

release:
  github:
    owner: YourGithubUser
    name: YourGithubRepo

Create two build triggers:

  • a “push to any branch” trigger for your regular CI (doesn’t invoke goreleaser)
  • a “push to tag” trigger which invokes goreleaser

The push to any branch trigger could use a Dockerfile or a cloudbuild.yaml, whichever you prefer.

You should have a dedicated cloudbuild.release.yaml that is only used by the “push to tag” trigger.

In this example we’re creating a new release every time a new tag is pushed. See Using Encrypted Resources for how to encrypt and base64-encode your github token.

The clone that the build uses has no tags, which is why we must explicitly run git tag $TAG_NAME (note that $TAG_NAME is only set when your build is triggered by a “push to tag”.) This will allow goreleaser to create a release with that version, but it won’t be able to build a proper changelog containing just the messages from the commits since the prior tag. Note that the build performs a shallow clone of git repositories and will only contain tags that reference the latest commit.

steps:
# Setup the workspace so we have a viable place to point GOPATH at.
- name: gcr.io/cloud-builders/go
  env: ['PROJECT_ROOT=github.com/YourGithubUser/YourGithubRepo']
  args: ['env']

# Create github release.
- name: goreleaser/goreleaser
  entrypoint: /bin/sh
  dir: gopath/src/github.com
  env: ['GOPATH=/workspace/gopath']
  args: ['-c', 'cd YourGithubUser/YourGithubRepo && git tag $TAG_NAME && /goreleaser' ]
  secretEnv: ['GITHUB_TOKEN']

  secrets:
  - kmsKeyName: projects/YourProjectId/locations/global/keyRings/YourKeyRing/cryptoKeys/YourKey
    secretEnv:
      GITHUB_TOKEN: |
        ICAgICAgICBDaVFBZUhVdUVoRUtBdmZJSGxVWnJDZ0hOU2NtMG1ES0k4WjF3L04zT3pEazhRbDZr
        QVVTVVFEM3dVYXU3cVJjK0g3T25UVW82YjJaCiAgICAgICAgREtBMWVNS0hOZzcyOUtmSGoyWk1x
        ICAgICAgIEgwYndIaGUxR1E9PQo=

Semaphore

In Sempahore 2.0 each project starts with the default pipeline specified in .semaphore/semaphore.yml.

# .semaphore/semaphore.yml.
version: v1.0
name: Build
agent:
  machine:
    type: e1-standard-2
    os_image: ubuntu1804

blocks:
  - name: "Test"
    task:
      prologue:
        commands:
          # set go version
          - sem-version go 1.11
          - "export GOPATH=~/go"
          - "export PATH=/home/semaphore/go/bin:$PATH"
          - checkout

      jobs:
        - name: "Lint"
          commands:
            - go get ./...
            - go test ./...

# On Semaphore 2.0 deployment and delivery is managed with promotions,
# which may be automatic or manual and optionally depend on conditions.
promotions:
    - name: Release
       pipeline_file: goreleaser.yml
       auto_promote_on:
         - result: passed
           branch:
             - "^refs/tags/v*"

Pipeline file in .semaphore/goreleaser.yml:

version: "v1.0"
name: GoReleaser
agent:
  machine:
    type: e1-standard-2
    os_image: ubuntu1804
blocks:
  - name: "Release"
    task:
      secrets:
        - name: goreleaser
      prologue:
        commands:
          - sem-version go 1.11
          - "export GOPATH=~/go"
          - "export PATH=/home/semaphore/go/bin:$PATH"
          - checkout
      jobs:
      - name: goreleaser
        commands:
          - curl -sL https://git.io/goreleaser | bash

The following YAML file, createSecret.yml creates a new secret item that is called goreleaser with one environment variable, named GITHUB_TOKEN:

apiVersion: v1alpha
kind: Secret
metadata:
  name: goreleaser
data:
  env_vars:
    - name: GITHUB_TOKEN
      value: "4afk4388304hfhei34950dg43245"

Check Managing Secrets for more detailed documentation.

GitLab CI

To push releases to both GitHub and the official Docker registry, add a file .gitlab-ci.yml in the Go project directory:

image: docker:stable
services:
- docker:dind

stages:
- build

variables:
  GORELEASER_IMAGE: goreleaser/goreleaser:latest
  DOCKER_REGISTRY: https://index.docker.io/v1/

build:
  stage: build
  script:
    - docker pull $GORELEASER_IMAGE
    - docker run --rm --privileged -v $PWD:/go/src/github.com/YourGithubUser/YourGithubRepo -v /var/run/docker.sock:/var/run/docker.sock -w /go/src/github.com/YourGithubUser/YourGithubRepo -e GITHUB_TOKEN -e DOCKER_USERNAME -e DOCKER_PASSWORD -e DOCKER_REGISTRY $GORELEASER_IMAGE release --rm-dist

Next, in the GitLab sidebar add the variables DOCKER_USERNAME, DOCKER_PASSWORD and GITHUB_TOKEN through Project –> Settings –> CI / CD –> Variables.
Make sure they are set to Masked (Protection is not needed).

To push to some other Docker registry (e.g. to a GitLab registry), set different variables in the file above:

CI_REGISTRY: gitlab.example.com:4567
DOCKER_REGISTRY: $CI_REGISTRY
DOCKER_USERNAME: gitlab-ci-token
DOCKER_PASSWORD: $CI_JOB_TOKEN

Make sure the image_templates in the file .goreleaser.yml reflect that custom registry!

Example:

dockers:
-
  goos: linux
  goarch: amd64
  binaries:
  - program
  image_templates:
  - 'gitlab.example.com:4567/Group/Project:{{ .Tag }}'
  - 'gitlab.example.com:4567/Group/Project:latest'

Codefresh

Codefresh uses Docker based pipelines where all steps must be Docker containers. Using Goreleaser is very easy via the existing Docker image.

Here is an example pipeline that builds a Go application and then uses Goreleaser.

version: '1.0'
stages:
  - prepare
  - build
  - release
steps:
  main_clone:
    title: 'Cloning main repository...'
    type: git-clone
    repo: '${{CF_REPO_OWNER}}/${{CF_REPO_NAME}}'
    revision: '${{CF_REVISION}}'
    stage: prepare
  BuildMyApp:
    title: Compiling go code
    stage: build
    image: 'golang:1.13'
    commands:
      - go build
  ReleaseMyApp:
    title: Creating packages
    stage: release
    image: 'goreleaser/goreleaser'
    commands:
      - goreleaser --rm-dist

You need to pass the variable GITHUB_TOKEN in the Codefresh UI that contains credentials to your Github account or load it from shared configuration. You should also restrict this pipeline to run only on tags when you add git triggers on it.

More details can be found in the goreleaser example page.

GitHub Actions

GoReleaser can also be used within our official GoReleaser Action through GitHub Actions.

You can create a workflow for pushing your releases by putting YAML configuration to .github/workflows/release.yml.

Below is a simple snippet to use this action in your workflow:

name: goreleaser

on:
  pull_request:
  push:

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/[email protected]
      -
        name: Set up Go
        uses: actions/[email protected]
      -
        name: Run GoReleaser
        uses: goreleaser/[email protected]
        with:
          version: latest
          args: release

For detailed intructions please follow GitHub Actions workflow syntax.

Customizing

Inputs

Following inputs can be used as step.with keys

Name Type Default Description
version String latest GoReleaser version. Example: v0.117.0
args String Arguments to pass to GoReleaser
key String Private key to import

Signing

If signing is enabled in your GoReleaser configuration, populate the key input with your private key and reference the key in your signing configuration, e.g.

signs:
  - artifacts: checksum
    args: ["--batch", "-u", "<key id, fingerprint, email, ...>", "--output", "${signature}", "--detach-sign", "${artifact}"]

This feature is currently only compatible when using the default gpg command and a private key without a passphrase.

Sponsors

Does your company use goreleaser? Help keep the project bug-free and feature rich by sponsoring the project.

Backers

Love our work and community? Become a backer.

Contributing

This page will eventually have information for those who want to contribute to the project.

Also check the CONTRIBUTING.md file on the root of our repository.