Publish Go Packages with Goreleaser

| Oct 4, 2022

Goreleaser is awesome. It’s a simple tool that allows you to release your go packages. Recently, my team and I used it with a company wide CLI tool that we built.

In this tutorial, we’ll use goreleaser to automate the release of a simple go package.

Installation

On macOS, to install goreleaser, we can install using:

go install github.com/goreleaser/goreleaser@latest

Or we use the popular homebrew package manager for macOS and Linux with:

brew install goreleaser/tap/goreleaser

On Ubuntu Linux, we can use apt:

echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
sudo apt update
sudo apt install goreleaser

More options can be found here.

Create Package

Create a new folder to house our project. Then initialize the modules with

go mod init main 

Next, we create a file called main.go. In main.go, copy and paste the following code:

package main

func main() {
  println("This is a tutorial about Goreleaser!")
}

Initialize Goreleaser

The next step is to setup goreleaser. To do this, we run:

goreleaser init

This command creates .goreleaser.yaml file in our directory. We’ll take a closer look at this file.

Update .goreleaser.yaml

I have added a few more fields to the generated .goreleaser.yaml file. We’ll go through the important parts.

release:
  github:
    owner: justdamilare
    name: mytool

before:
  hooks:
    - go mod tidy
    - go generate ./...

builds:
  - env:
      - GO_VERSION=1.19
    goos:
      - linux
      - windows
      - darwin

# replaces architecture naming in the archive name
archives:
  - replacements:
      darwin: Darwin
      linux: Linux
      windows: Windows
      386: i386
      amd64: x86_64

    format_overrides:
      - goos: windows
        format: zip

checksum:
  name_template: 'checksums.txt'

snapshot:
  name_template: "{{ incpatch .Version }}-next"

changelog:
  sort: asc
  filters:
    exclude:
      - '^docs:'
      - '^test:'

# upload binaries to gcloud bucket called `mytool`
blobs:
  - provider: gs
    bucket: mytool
    folder: "{{ .Version }}"

# generate homebrew-tap  
brews:
  - name: justdamilare
    tap:
      owner: mytool
      name: homebrew-tap
    folder: Formula
    homepage: https://github.com/justdamilare/mytool
    description: A simple go project
    # use custom download strategy in case the Github repository is private
    download_strategy: GitHubPrivateRepositoryReleaseDownloadStrategy
    custom_require: "../custom_download_strategy"
    test: |
            system "#{bin}/mytool"
    install: |
            bin.install "mytool"

It should be noted that if homebrew-tap and blobs are not needed, the sections can be removed. If homebrew-tap is needed, a Githib repo called homebrew-tap should be created also.

Release Package

Finally, we can release our packages. To do that, we need to create a tag for our release on Git. For example, to create a tag for version 0.1.0, we can run:

git tag v0.1.0

and

git push origin v0.1.0

Then in the directory with main.go, run:

goreleaser release

Goreleaser will build all the binaries. These binaries will be uploaded automatically to Github using the local GitHub credentials. The builds will also be located in a /dist folder in the home directory. If the brew publish method is included, a generated *.rb file will also be in the /dist folder. In case Goreleaser does not copy the generated Formula to the homebrew-tap repo automatically, it can be copied manually. You can see checkout how to publish the build to a private homebrew-tap here

Summary

  • Install goreleaser
  • Create go package
  • Initialize Goreleaser with goreleaser init
  • Update .goreleaser.yaml
  • Release build by creating a tag with git tag vX.X.X and then run goreleaser release