Creating Homebrew taps for private internal tools

Making your fellow developers happy even before using your app

October 8, 2018
Contact Us
Weekly Shorts are topics we discuss in our weekly remote meeting related to recent work we have done with our customers
Creating Homebrew taps for private internal tools

TL;DR: After completing the CLI I wrote for my coworkers to be able to easily release code to production, I had a hard time trying to create my own Homebrew Tap for a private Github repo. I found a mix of information, part outdated and part incorrect. After reading the documentation and some Homebrew-core code, I managed to get it right with a few simple (yet hard to find) additions: one is GitHubPrivateRepositoryDownloadStrategy which was added here, and the other is a binary packaging in a .tar.gz archive.
If you already know Homebrew formulas and taps jump straight to Getting to the point.

TL;DR 2: If you’re using Golang, try the awesome Goreleaser, you won’t be disappointed!

Homebrew, “The missing package manager for macOS” is an awesome tool most advanced mac users know. It allows installation of packages right from the command line by downloading, compiling and placing them in the necessary locations while making sure the environment is configured to run them.

This is done by using “Formulas” — a ruby class that lists a set of required steps to install the package on any machine.
Here’s what a formula looks like:

<p> CODE: https://gist.github.com/Dandevops/826234ee06472d2e634c585ed869b780.js</p>

If you’re an open source tool developer you may want to add your tool to Homebrew by contributing to its core project formulas.
However, if you’re developing an in-house internal tool and you want to make your fellow developers happy about the process of getting and installing it, you’re going to need to use a Homebrew tap.

A “Tap” is basically a git repo that contains a formula. “Tapping” is the process of introducing your local Homebrew to a 3rd party source, that contains tools outside the Homebrew core list and is as simple as brew tap myrepo/mytool. That’s it — your tool is ready to be brew installed.


Getting to the point

If you have a release you’d like to tap in a private repo, you’ll get 404 errors trying to install it as the files are locked for outside tools. In order to let brew fetch the private releases, there’s an addition to brew from 18 months ago that allows the use of GitHubPrivateRepositoryDownloadStrategy like so:

class Fed < Formula
 desc ""
 url "", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
 .
 .
end

The new download strategy allows the download of private repo releases using the environment variable HOMEBREW_GITHUB_API_TOKEN which has to contain a valid Github access token. Homebrew will use the token to fetch the private tarball and install it.

There are numerous ways to get and install a wanted tool, the first, which is known as better practice is to fetch the source code from the repo, match it to the checksum of the tarball containing it to prevent any tampering affects in the way, and then compiling it from its source (while installing required dependencies in the process). While this method is more secure and reliable, we are dealing with private internal tools and prefer speed and conveniency over gaining trust in the open source community…

For that reason, instead of installing the golang binary and environment (in my case) and compiling the tool from its source, I’ve simply wrapped the already compiled binary in a tarball like so:

tar -czvf mytool-darwin-amd64.tar.gz mytool

After that, I’ve created a Github release (using the awesome GHR tool for uploading multiple artifacts to Github in parallel) and made sure the tarball containing my binary is in place.


Formulating

Here’s how the final formula should look like using the above:

<p> CODE: https://gist.github.com/omerxx/b003031ab03efef279387c6e649e2fa1.js</p>

install takes “mytool” binary and ensures it lies with the local machine’s path of executables (usually /usr/local) and bin is how Homebrew addresses that location.

The formula should be a part of a repo called “homebrew-mytool” where mytool is your package name. The mytool.rb which contains the formula should be inside a formula directory. Here’s an example.


Finally, using it!

Once you have https://github.com/somerepo/homebrew-mytool repo available, you should be able to:

# Making sure the environment is set
export HOMEBREW_GITHUB_API_TOKEN=<MY_GITHUB_TOKEN>
# Tapping the repo
brew tap myrepo/mytool
# Installing!
brew install mytool

Let’s recap this process

  1. Make sure to tar your already compiled binary and create a Github release with it
  2. Create a formula like this one for your tool and make sure it’s in a git repo similar to this example
  3. Create a Github access token and export it to the environment from which brew install would run
  4. Tap the tap! brew tap myrepo/mytool
  5. Install with brew install mytool

Last note

My project is written in Golang, and while working on my tap I found “Go Releaser”. GoReleaser takes care of every need, including creating releases based on builds for various platforms, updating a homebrew tap (private ones too!) and many more. If you’re working in Go too, be sure to check it out. It’s easier and more elegant than any other solution or automation.


Creating Homebrew taps for private internal tools
Omer Hamerman
Senior Software Operations Architect
Omer is an experienced software operations engineer and an open source contributor. He is always willing to go the extra mile to help our clients improve their software delivery. He is known for getting the job done very quickly and is clear-cut and very sharp, delivering almost any job on the spot. When he’s not helping our clients achieve scalable and resilient infrastructure, you’ll find him rock climbing and bouldering. He is passionate about beautiful code, cybersecurity and doing things right the first time. He is a keen writer of blog posts and a speaker at meetups.