Distribute your Binaries hosted on a private GitLab repository with HomeBrew using GoReleaser šš«£
A while ago, we wrote a blog about GoReleaser, āThe fanciest way of releasing Go binaries with GoReleaser,ā and yes, Iām still thinking the same š In that blog post, we gave a higher-level introduction to GoReleaser. In addition, we explored a bunch of features supported in it. So I recommend you take a look at it if you are not familiar enough with the GoReleaser project because in this blog post, Iāll introduce you to another feature that GoReleaser shines on, and thatās the automation of creating formulas to facilitate the process of distributing binaries through HomeBrew, which is as known as The Missing Package Manager for macOS (or Linux). HomeBrew provides a cookbook for us to give an overview of how to create formulas. Still, it can be challenging for most of us as we arenāt already familiar with building formulas. However, I believe you will be surprised when you notice how it can quickly be done with GoReleaser without much effort.
Today, on the one hand, Iāll give you an overview of how you can start creating formulas using GoReleaser; on the other hand, weāll be demoing that on a private repository hosted in GitLab.
Homebrew has a core repository of packages but also supports providing your tap for hosting your formulas, which we will be using in this guide. Thanks to HomeBrew, they created excellent documentation about how to develop and maintain our tap.
TL;DR A tap is a separate Git repository with a unique naming that only contains instructions for HomeBrew (so it knows how to install your stuff). They recommend that the repositoryās name start with homebrew-
so the short brew tap
command can be used. For example, letās assume that we give a name to the Git repository as ā<my-org>homebrew-tools,ā then we should use the tap name as ā<my-org>/toolsā while we are adding the tap.
According to the documentation, first, we need to create a Git repository but donāt forget itāll be a private one. Therefore, I wonāt dive into all the details in GoReleaser and focus only on the brew part. As the next step, we need to tell GoReleaser where it should create formulas and how. Finally, we need to add another section for the brew to ā.goreleaser.ymlā, a configuration file for GoReleaser. You can reach out to all the options available in the brew section here. Most probably, once you configure it, you will end up something like the following:
Iām not going to every detail in the example above; however, there are some points Iād like to highlight, especially the completions, token, url_template, and private_token parts. Special thanks to Carlos A. Becker; I can hand over the completions part to his blog for a more pleasing experience because he already did excellent work there.
As we mentioned, we should create a Git repository, and here we created a Git repository named āhomebrew-tools.ā As we kept it private, we should provide a token granted to write this repository and give that token to the ātokenā field of the ātapā section. You can reach out to the list of available options in the tap section.
As a next step, Iād like to introduce you to one of the great features in GitLab named āPackage Registriesā to explain why we have the ā../packages/genericā part in the āurl_template.ā We have to make it reachable thus (donāt forget the Git repository is private); the brew will be using this URL while downloading the package.
The GitLab Package Registry is a private or public registry for various familiar package managers. You can publish and share packages, which can be easily consumed as a dependency in downstream projects, which weāll use in this guide. There is support for various packages in the Package Registry, and you can reach out to the list here. One is āGeneric,ā which weāll also use in this guide to release our binaries. Also, there is good news that GoReleaser has first-class support for the āGeneric Package Registry,ā
Normally, goreleaser
uploads release files as āattachments,ā which may have administrative limits. Notably, hosted gitlab.com instances have a 10MB attachment limit, which cannot be changed. Uploading to the Generic Package Registry does not have this restriction. To use it instead,v set use_package_registry
it to true
.
# .goreleaser.yml
gitlab_urls:
use_package_registry: true> https://goreleaser.com/scm/gitlab/#gitlab-enterprise-or-private-hosted
Last but not least, as the documentation says, we need a token with read_package_registry
and/or write_package_registry
scope permissions.
?private_token={{ .Env.DOWNLOADER_TOKEN }}
Thanks to Adam Meech for giving this idea of using āprivate_tokenā as a request parameter, you can reach out to his blog post here, where I found the real solution.
This is how we pass environment variables to GoReleaser. Although, as you may notice, because of the work that needs to be done, we use two different tokens, one GITLAB_TOKEN and the other DOWNLOADER_TOKEN, there are various types of permissions in it.
Once everything is completed, you will end up having something like the followings:
Everything seems so relaxed at this point š
But how do you download packages from one tap we provide as a separate private Git repository? š°
Donāt panic! Of course, there is already a solution for this, like everything else šŗš»
The only thing that you have to do is that provide the private Git repository URL to the command, just like the following:
brew tap pe-container/tools <private-gitlab-url>
Now, everything is ready for downloading the package from GitLabās Generic Package Registry through the brew š
brew install kcfgctl
Thatās the story, all you need to do to distribute your package stored in a private Git repository is include a bunch of tokens with necessary permissions. šŖ
I hope you like it, see you next time, please stay tuned š»
āļøBonus: What did you do if your local package is not upgraded even if the new version of your project gets released?
If the ābrew upgradeā command doesnāt work for you, you can do the following trick:
# cd into the local repo
cd "$(brew --repo sjbonner/tap)"
# find out the latest commit locally
git log -s -1
# compare the commit with your remote repo
# if the repo is outdated, run
brew update
https://stackoverflow.com/questions/58279117/homebrew-not-updating-the-version-of-my-package