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. You can customize your release process by creating a .goreleaser.yml file.

The idea started with a simple shell script, but it quickly became more complex and I also wanted to publish binaries via Homebrew taps, which would have made the script even more hacky, so I let go of that and rewrote the whole thing in Go.

Installing Goreleaser

There are three ways to get going install GoReleaser:

Using homebrew

brew install goreleaser/tap/goreleaser

Using Scoop

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

Check the tap source for more details.

Manually

Download your preferred flavor from the releases page and install manually.

Using go get

Note: this method requires Go 1.10+.

$ go get -d github.com/goreleaser/goreleaser
$ cd $GOPATH/src/github.com/goreleaser/goreleaser
$ dep ensure -vendor-only
$ make setup build

It is recommended to also run dep ensure to make sure that the dependencies are in the correct versions.

Quick Start

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

Create a GitHub repository and add a single main package:

// main.go
package main

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

By default GoReleaser will build the current directory, but you can change the package path in the GoReleaser configuration file:

# .goreleaser.yml
# Build customization
builds:
  - binary: drum-roll
    goos:
      - windows
      - darwin
      - linux
    goarch:
      - amd64

GoReleaser skips invalid GOOS/GOARCH combinations.

With the above configuration the name of all created binaries will be drum-roll and GoReleaser will build one binary in 64bit architecture for each of the operating systems Windows, Linux and MacOS.

GoReleaser will then archive the resulting binaries of each OS/Arch pair into a separate file. The default format is {{.ProjectName}}_{{.Os}}_{{.Arch}}. You can change the archive’s name and format. You can also replace the OS and the Architecture with your own.

Another useful feature is to add additional files to the created archives:

# .goreleaser.yml
# Build customization
builds:
  - main: main.go
    binary: drum-roll
    goos:
      - windows
      - darwin
      - linux
    goarch:
      - amd64
# Archive customization
archive:
  format: tar.gz
  replacements:
    amd64: 64-bit
    darwin: macOS
    linux: Tux
  files:
    - drum-roll.licence.txt

This configuration will generate tar archives, each containing an additional file called drum-roll.licence.txt. The archives will be located in the dist folder:

  • ./dist/drum-roll_windows_64-bit.tar.gz
  • ./dist/drum-roll_macOS_64-bit.tar.gz
  • ./dist/drum-roll_Tux_64-bit.tar.gz

Next, you need to export a GITHUB_TOKEN environment variable, which should contain a GitHub token with the repo scope selected. It will be used to deploy releases to your GitHub repository. Create a token here.

$ export GITHUB_TOKEN=`YOUR_TOKEN`

GoReleaser uses 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

Note: We recommend the use of semantic versioning. We are not enforcing it though. We do remove the v prefix and then enforce that the next character is a number. So, v0.1.0 and 0.1.0 are virtually the same and both are accepted, while version0.1.0 is not.

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.

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:

Environment

GitHub Token

GoReleaser requires a GitHub API token with the repo scope selected to deploy the artifacts to GitHub. You can create one here.

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

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

# .goreleaser.yml
env_files:
  github_token: ~/.path/to/my/token

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/

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

IMPORTANT: be careful with the URLs, they may change from one instalation to another. If they are wrong, goreleaser will fail at some point, so, make sure they’re right before opening an issue. See for example #472.

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.

Customizing Git

By default, GoReleaser uses full length commit hashes when setting a main.commit ldflag or creating filenames in --snapshot mode.

You can use short, 7 character long commit hashes by setting it in the .goreleaser.yml:

# .goreleaser.yml
git:
  short_hash: true

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 softwares.

Travis

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:
    - snapcraft

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"

# 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.

Circle

Here is how to do it with CircleCI:

# circle.yml
deployment:
  tag:
    tag: /v[0-9]+(\.[0-9]+)*(-.*)*/
    owner: user
    commands:
      - curl -sL https://git.io/goreleaser | bash

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.

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

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.