Making your fellow developers happy even before using your app
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:
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.
Here’s how the final formula should look like using the above:
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
Make sure to tar your already compiled binary and create a Github release with it
Create a Github access token and export it to the environment from which brew install would run
Tap the tap! brew tap myrepo/mytool
Install with brew install mytool
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.
My name is Omer, and I am an engineer at ProdOps — a global consultancy that delivers software in a Reliable, Secure and Simple way by adopting the Devops culture. Let me know your thoughts in the comments below, or connect with me directly on Twitter @omergsr.