Publish Go Packages with Goreleaser
Published: 2022-10-04 22:48:46

[Goreleaser](https://goreleaser.com/) 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_](https://brew.sh/) 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](https://goreleaser.com/install/).

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

```go
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.

```yaml
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](https://blog.devgenius.io/create-homebrew-taps-for-private-github-repos-44daf2f4cff8)

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