Learning Go by examples: part 9 - Use HomeBrew & GoReleaser for distributing a Golang app
Tags: go, beginners, library, package
Published: 2022-01-20 07:18:22

---
title: Learning Go by examples: part 9 - Use HomeBrew & GoReleaser for distributing a Golang app
published: true
description: Serie of article in order to learn Golang language by concrete applications as example
series: Learning Go by examples
tags: Golang, beginners, library, package
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fjl8sifz5cllr0fbc9ab.png
---

As we have seen in [Learning Go by examples: part 8 - Automatically cross-compile & release your Go app](https://dev.to/aurelievache/learning-go-by-examples-part-8-automatically-cross-compile-release-your-go-app-457a) article, we can create an app and cross-compile automatically. It's cool but I think we can go more deeper.

It's cool to create awesome tools but it's better to provide a way to install them easily.

What do you think if Mac users can install and update our app through HomeBrew?

In this article, you will learn how to allows users to install your apps, hosted in a GitHub repository, through HomeBrew, starting from my GopherSay application.

## HomeBrew

![HomeBrew](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u31j5h3p4fkb194gxgi3.png)

Homebrew is the missing package manager for macOS. It installs packages with a simple command like `brew install curl`. **Homebrew taps** are third-party repositories. By creating a Homebrew tap **formula**, users can install and use your repository.

Taps are external sources of Homebrew formula, casks and/or external commands. They can be created by anyone to provide their own formula, casks and/or external commands to any Homebrew user.

For example, if you want to install **curl** app through HomeBrew, you just need to enter the following command:

```
$ brew install curl
```

Curl app is on the core HomeBrew tap so HomeBrew found the tap and install the tool in your computer.

If you want to install a tool that is in a private tap, you need to add it and then install the tool.

For example:

```
$ brew tap go-task/tap
$ brew install go-task
```

Or you can directly install the tool in a private tap in only one line:

```
$ brew install go-task/tap/go-task
```

## Create a GitHub repository for our HomeBrew Tap

A Tap is usually a Git repository. If hosted on GitHub, it is recommended that the repository’s name start with **homebrew-** in order to use `brew tap` command.

For example:

`scraly/homebrew-tools` repository => `brew tap scraly/tools` command

Note: even if we want to install only our GopherSay app in this tutorial, we will not name our repository **homebrew-gophersay** instead of that we will create a repository that will contains many of different formulas.

First, create our new repository in GitHub: **homebrew-tools**.

For that, I logged in GitHub website, clicked on the repositories link, click on "New" green button and then I created a new repository called `homebrew-tools`.

![homebrew-tools](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ejbuhx75glcczp4irlpr.png)

Our new GitHub repository is created:

{% github scraly/homebrew-tools %}

## Generate automatically HomeBrew Tap Formula through GoReleaser

![Gopher Zelda](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqbae08i5nalsf49ffqu.png)

In the previous article, we created GopherSay golang app, we generated the releases thanks to Go Releaser and we automatized them through GitHub actions.
Everytime we publish a new GitHub release in GopherSay, the GitHub action is runned and our release is created.

It's perfect.

So now we need to ask GoReleaser to generate also a HomeBrew tap formula :).

In order to do that automatically, we need to edit our `goreleaser.yml` file.

If you don't already clone the repository, you need to clone it and go into the **gophersay** folder:

```
$ git clone https://github.com/scraly/gophersay.git
$ cd gophersay
```

Now, add the following step in `.goreleaser.yml` file:

```yaml
brews:
- name: gophersay
  homepage: https://github.com/scraly/homebrew-tools 
  tap:
    owner: scraly
    name: homebrew-tools
```

Let's explain this code block:

- The **brews** section specifies how the formula should be created. 
- **homepage** is for your app's homepage
- **tap** is for defining the GitHub/GitLab repository to push the formula to

Warning: the name of the brew will be the name of the formula, so what you want to install with `brew install <name>` command.

## Generate our formula!

In order to generate the HomeBrew formula automatically, we need to create a new tag in our Git repository and push it. This will create a new release in the GitHub repository.

Let's create and push **v1.0.2** tag:

```
$ git tag v1.0.2
$ git push origin v1.0.2
```

Check if the new tag have been correctly added, go to [GopherSay Releases](https://github.com/scraly/gophersay/releases/) page.

![GopherSay Releases](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/reqktr4g3n75ls2d25xz.png)

Fine, release v1.0.2 exists.
 
Now, go in **Actions** tab in the GitHub repository in order to check if GitHub action runned:

![GitHub Actions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0geajhny62miu29iuxl.png)
 
Everything is green, it's a good sign! 🙂

## Let's check if our formula have been added

Go in our [HomeBrew Tap repository](https://github.com/scraly/homebrew-tools).

The GopherSay formula have been automatically updated:

![GopherSay formula](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/awlysnv794sf83y7j6sc.png)

Let's have a look to our `gophersay.rb` formula file:

```ruby
# typed: false
# frozen_string_literal: true

# This file was generated by GoReleaser. DO NOT EDIT.
class Gophersay < Formula
  desc ""
  homepage "https://github.com/scraly/homebrew-tools"
  version "1.0.2"

  on_macos do
    if Hardware::CPU.intel?
      url "https://github.com/scraly/gophersay/releases/download/v1.0.2/gophersay_1.0.2_Darwin_x86_64.tar.gz"
      sha256 "084b60f89b442cc66159a495421d3e9fb48b3861b324a2ac1062d4491c342f27"

      def install
        bin.install "gophersay"
      end
    end
    if Hardware::CPU.arm?
      url "https://github.com/scraly/gophersay/releases/download/v1.0.2/gophersay_1.0.2_Darwin_arm64.tar.gz"
      sha256 "0e98ff426817075492f3e61569c28d5bfd7a69ab7264f6cf03dd99e007277ae1"

      def install
        bin.install "gophersay"
      end
    end
  end

  on_linux do
    if Hardware::CPU.intel?
      url "https://github.com/scraly/gophersay/releases/download/v1.0.2/gophersay_1.0.2_Linux_x86_64.tar.gz"
      sha256 "bd3af60d4e9f5deb63dfd675cc5c2aa515d4897fb056b3170d316d9a9e466998"

      def install
        bin.install "gophersay"
      end
    end
    if Hardware::CPU.arm? && Hardware::CPU.is_64_bit?
      url "https://github.com/scraly/gophersay/releases/download/v1.0.2/gophersay_1.0.2_Linux_arm64.tar.gz"
      sha256 "b8e8113b90efcd8dce4a38d648000cd5f1d8830bba039a585ca2d5067eb17740"

      def install
        bin.install "gophersay"
      end
    end
  end
end
```

GoReleaser create and update this formula every time you will push a new tag is your app with release information like: version, executable binary archive depending on the OS, sha256...

## Install our app through HomeBrew

Now your HomeBrew tap is ready and the formula is created, so we can install our app.

Add our tap:

```
$ brew tap scraly/tools
==> Tapping scraly/tools
Cloning into '/usr/local/Homebrew/Library/Taps/scraly/homebrew-tools'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 9 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (9/9), done.
Tapped 1 formula (13 files, 7.7KB).
```

Install our app:

```
$ brew install gophersay
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (scraly/tools).
==> New Formulae
scraly/tools/gophersay

==> Installing gophersay from scraly/tools
==> Downloading https://github.com/scraly/gophersay/releases/download/v1.0.1/gophersay_1.0.1_Darwin_x86_64.tar.gz
==> Downloading from https://github-releases.githubusercontent.com/398637863/968c588e-71e2-4300-b62a-33aa9b245ada?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20210830%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20210830T100137
######################################################################## 100.0%
Error: The `brew link` step did not complete successfully
The formula built, but is not symlinked into /usr/local
Could not symlink bin/gophersay
Target /usr/local/bin/gophersay
already exists. You may want to remove it:
  rm '/usr/local/bin/gophersay'

To force the link and overwrite all conflicting files:
  brew link --overwrite gophersay

To list all files that would be deleted:
  brew link --overwrite --dry-run gophersay

Possible conflicting files are:
/usr/local/bin/gophersay
==> Summary
🍺  /usr/local/Cellar/gophersay/1.0.1: 5 files, 1.5MB, built in 8 seconds
```

Or you can directly install the app in oneline installation command:

```
$ brew install scraly/tools/gophersay
```

## Test our app

Run the following command:

```
$ gophersay test

  ----
< test >
  ----
        \
         \

       (%%.                             .
     @***,*********@           &****************&             .&%(********%#
       ,(((((((@*******@   .*************///***********#  @****(#((((((((((@
         &(((((((((@*****@***********************************((((((((((,
           .((((((((((%((((((((&****************************((((((((((@
             &((((((((@.    .@#((@***************************@((((((@
                /@(@     @@@     (*************************&(((/(((((%
                   @     @@      /************************            @
                 (**            /************************&    (@@@    *
                /*****%       @**************************@            @
               ,*******************************************&         ,
               ***************************************************
              @***********************((((((((&*******************
             *************************((((((&((&*****************&
             ***********************((((((((((((%****************
            (****.......@......#***&((((((#((((%***..........@**,@,
          ****,/ .......#.......,******,  (  ******.. ....@..*******@
          @*@.... @.....#..(.....#*****@@@@/(*****..(...../...&. ****&
             ............ ......../************&.........&..&*,  (((#
             ..............@........@********/.......... .....   &(((
              ...............%........&**#............/......(    %((.
             *..................,.......#...........#.......@    .((((
             *....................(.......%.....#..........(     (((((
              ......................@........%.............      #((((
               .......................&......@............(       ((((
                ........................@................*        #(((
                 /....................... ......(.......%        #(((
                   (.......................,.....#....****@     (#((
                  .******.@.................,.....@*   ****/   &((((/
                 /****.                                         ##.
```

Awesome!

## Upgrade our app

Through HomeBrew, you can now upgrade our GopherSay application to the latest version:

```
$ brew upgrade gophersay
```

## Conclusion

As you have seen in this article and previous articles, it's possible to create multiple different applications in Go,  and automatize build and cross-compilation and even provides an easy way to install our app for Mac users.

All the code of our GopherSay app in Go is available in: https://github.com/scraly/gophersay

In the following articles we will create others kind/types of applications in Go.

Hope you'll like it.