DEV Community

Cover image for Learning Go by examples: part 9 - Use HomeBrew & GoReleaser for distributing a Golang app
Aurélie Vache
Aurélie Vache

Posted on

Learning Go by examples: part 9 - Use HomeBrew & GoReleaser for distributing a Golang app

As we have seen in Learning Go by examples: part 8 - Automatically cross-compile & release your Go app 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

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

$ brew install go-task/tap/go-task
Enter fullscreen mode Exit fullscreen mode

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

Our new GitHub repository is created:

homebrew-tools

Homebrew formula for installing Scraly's apps & tools.

How To Use

Add repository:

brew tap scraly/tools

Install GopherSay:

brew install gophersay

Upgrade the GopherSay CLI to the latest version:

brew upgrade gophersay

Generate automatically HomeBrew Tap Formula through GoReleaser

Gopher Zelda

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
Enter fullscreen mode Exit fullscreen mode

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

brews:
- name: gophersay
  homepage: https://github.com/scraly/homebrew-tools 
  tap:
    owner: scraly
    name: homebrew-tools
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Check if the new tag have been correctly added, go to GopherSay Releases page.

GopherSay Releases

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

Everything is green, it's a good sign! 🙂

Let's check if our formula have been added

Go in our HomeBrew Tap repository.

The GopherSay formula have been automatically updated:

GopherSay formula

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

# 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
Enter fullscreen mode Exit fullscreen mode

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).
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

$ brew install scraly/tools/gophersay
Enter fullscreen mode Exit fullscreen mode

Test our app

Run the following command:

$ gophersay test

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

       (%%.                             .
     @***,*********@           &****************&             .&%(********%#
       ,(((((((@*******@   .*************///***********#  @****(#((((((((((@
         &(((((((((@*****@***********************************((((((((((,
           .((((((((((%((((((((&****************************((((((((((@
             &((((((((@.    .@#((@***************************@((((((@
                /@(@     @@@     (*************************&(((/(((((%
                   @     @@      /************************            @
                 (**            /************************&    (@@@    *
                /*****%       @**************************@            @
               ,*******************************************&         ,
               ***************************************************
              @***********************((((((((&*******************
             *************************((((((&((&*****************&
             ***********************((((((((((((%****************
            (****.......@......#***&((((((#((((%***..........@**,@,
          ****,/ .......#.......,******,  (  ******.. ....@..*******@
          @*@.... @.....#..(.....#*****@@@@/(*****..(...../...&. ****&
             ............ ......../************&.........&..&*,  (((#
             ..............@........@********/.......... .....   &(((
              ...............%........&**#............/......(    %((.
             *..................,.......#...........#.......@    .((((
             *....................(.......%.....#..........(     (((((
              ......................@........%.............      #((((
               .......................&......@............(       ((((
                ........................@................*        #(((
                 /....................... ......(.......%        #(((
                   (.......................,.....#....****@     (#((
                  .******.@.................,.....@*   ****/   &((((/
                 /****.                                         ##.
Enter fullscreen mode Exit fullscreen mode

Awesome!

Upgrade our app

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

$ brew upgrade gophersay
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (5)

Collapse
 
streamdp profile image
Alexandr Primak

Hi, many thanks for your great work!

I want to add one case not considered here:

If you got 403 error while run goreleaser action script, you should use a Personal Access Token (PAT) instead a GITHUB_TOKEN (resource-not-accessible-by-integra...) and add it to settings -> secrets and variables -> actions of app repository (repository, where you run goreleaser action workflow)

Collapse
 
hiteshhedwig profile image
Hitesh Kumar

Hi, Thanks for the series. While it works great for MacOS. I was wondering, how would i make the app available incase of ubuntu? anywhere anytime.

Collapse
 
aurelievache profile image
Aurélie Vache

Hi,
You can build a go app for Linux platform so the binary file will works in a Ubuntu 🙂.

Collapse
 
noush012 profile image
Noushad Ibrahim

Hi @Aurélie Vache

What if the github.com/scraly/gophersay repo is private ?

Collapse
 
aurelievache profile image
Aurélie Vache

Strange because on my side, the repo is public :)