Trendyol Tech
Published in

Trendyol Tech

Photo by Diana Parkhouse on Unsplash

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, goreleaseruploads release files as “attachments,” which may have administrative limits. Notably, hosted 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
use_package_registry: true

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

⭐️Bonus: What if I host my project on GitHub then what would be the solution to the same problem?




Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store


I do mostly Go, Kubernetes, and cloud-native stuff ⛵️🐰🐳