No commit activity in last 3 years
No release in over 3 years
There's a lot of open issues
Build Bottles and update Formulae. Please see README on Github for details.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
~> 3.7
>= 0

Runtime

~> 2.4
~> 0.20
~> 0.2
 Project Readme

Build Bottles and update Formulae

Build Status Gem Version

This is a Ruby library, with a small CLI, to help you publish new versions of your software through Mac Homebrew.

Motivation

Earlier, I was working on a project, hack-assembler, which was an assignment as part of a MOOC. It was a fun piece of code, so after I finished the assignment, I wanted to show it to my friends in a convenient way. I aimed for publishing it using Mac Homebrew, mostly due to familiarity; I also want to provide pre-built binaries so my friends won't have to compile my Haskell code on their system.

It turns out that was't super straightforward! I had to juggle between this repo, a second Github repo as the Tap repo, Bintray, brew commands, Travis CI, and API calls here and there. In particular, Travis CI was the real pain point. I started with some shell scripts for my automation, but tiny mistakes often cost me hour-long Travis builds to debug (because Travis is slow, and compiling my Haskell code is even slower). The long debug cycles were crushing. Yes, I'm aware of Travis debug builds, but for some reason they weren't working at the time. The build servers at Travis were also pretty buggy, and I was in frequent contact with their lovely support staff.

At some point I thought, enough with the shell scripts, let me package these scripts as their own tool, decoupled from my Haskell project. I've had enough of the shell scripts and the errors on Travis, and besides, it would actually be a useful tool on its own for publishing other software on Homebrew, especially in CI/CD setups. That was the beginning of this Gem.

If you're not yet familiar with any of the beer-themed Homebrew terms (e.g. Formula, Tap, Bottle), you should read the Homebrew docs first.

Scope of functionality

This Gem isn't trying to automate away the entire process of publishing a Homebrew Formula, but rather only the incremental steps. That is, this Gem helps you with what you have to do each time you want to publish a new version, but not the initial setup when you create a new Formula. This means before you can benefit from this Gem, you'll first have to manually:

Functionality that this Gem provides include:

  • Editing Formula files programmatically;
  • Building Bottles for an existing Formula;
  • Uploading Bottle tarballs to Bintray;
  • Searching for and gathering Bottle tarballs from Bintray; and
  • Publishing a new version of a Formula to a Tap, optionally including Bottles from Bintray.

Installation

To use the Gem either as a library or as a CLI, install it via Gem:

$ gem install homebrew_automation
... ( RubyGems busy at work ) ...

$ homebrew_automation.rb version 2> /dev/null
0.1.18

$ homebrew_automation.rb version
warning: parser/current is loading parser/ruby26, which recognizes
warning: 2.6.6-compliant syntax, but you are running 2.6.5.
warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
0.1.18

Don't worry about the errors on stderr; I just can't find a way to silence them. They don't cause issues because Formula files only use very simple Ruby language features.

Note: Since I don't plan to put in any effort to keep the API nor CLI stable, please take note of which version of this Gem you are depending on, and stick to it. gem install homebrew_automation -v some-version.

About the Ruby API:

  • require 'homebrew_automation'
  • Top-level Ruby module: HomebrewAutomation; see rubydoc.
  • API docs are available via rake docs.

Example

Suppose I've made some changes to my app, hello-homebrew-packaging, and pushed the commits to Github under the tag v0.0.3. At this point, the Tap repo would not have been updated with the new version (v0.0.3) of the app yet. Let's say we want to publish v0.0.3 of our app to the world, and include pre-built binaries. We can run homebrew_automation.rb from our local development machine to do so.

First, let's build the Bottles and upload them to Bintray, so we can use them in the next step:

$ gem install homebrew_automation
... ( RubyGems doing its thing ) ...

$ homebrew_automation.rb bottle build-and-upload \
    --source-repo       hello-homebrew-packaging \
    --source-tag        v0.0.3 \
    --source-user       easoncxz \
      \
    --formula-name      hello-homebrew-packaging \
    --formula-version   0.0.3 \
      \
    --tap-user          easoncxz \
    --tap-repo          homebrew-tap \
    --tap-token         $EASONCXZ_GITHUB_OAUTH_TOKEN \
      \
    --bintray-user      easoncxz \
    --bintray-token     $EASONCXZ_BINTRAY_API_KEY \

homebrew_automation.rb [info] (2020-04-23T04:37:03+12:00): Hello, this is HomebrewAutomation! I will now build your Formula and upload the bottles to Bintray.
homebrew_automation.rb [info] (2020-04-23T04:37:03+12:00): First let's clone your Tap repo to see the Formula.
Cloning into 'homebrew-tap'...
...
... ( some git stuff ) ...
...
homebrew_automation.rb [info] (2020-04-23T04:37:07+12:00): I've updated the Formula file in our local Tap clone, and we're ready to start building the Bottle. This could take a long time if your Formula is slow to compile.
Updating Homebrew...
...
... ( Homebrew gets really busy ) ...
...
==> Summary
🍺  /usr/local/Cellar/hello-homebrew-packaging/0.0.3: 5 files, 13.2KB, built in 5 seconds
...
... ( more stuff ) ...
...
homebrew_automation.rb [info] (2020-04-23T04:37:37+12:00): Bottle built! Let me now upload the Bottle tarball to Bintray.
...
homebrew_automation.rb [info] (2020-04-23T04:37:41+12:00): All done!

There should now be a new tarball sitting on Bintray, holding the Bottle we've just built, which should look like this: hello-homebrew-packaging-0.0.3.high_sierra.bottle.tar.gz. However, our users don't notice this yet. Let's now update the Tap to tell our users that a new version of our app is available, complete with the Bottles we built in the previous step. We may have built and uploaded Bottles for multiple macOS versions; all Bottles will be "gathered" from Bintray and "published" in the Tap.

$ homebrew_automation.rb bottle gather-and-publish \
    --source-repo       hello-homebrew-packaging \
    --source-tag        v0.0.3 \
    --source-user       easoncxz \
      \
    --formula-name      hello-homebrew-packaging \
    --formula-version   0.0.3 \
      \
    --tap-user          easoncxz \
    --tap-repo          homebrew-tap \
    --tap-token         $EASONCXZ_GITHUB_OAUTH_TOKEN \
      \
    --bintray-user      easoncxz \
    --bintray-token     $EASONCXZ_BINTRAY_API_KEY \

homebrew_automation.rb [info] (2020-04-23T04:50:00+12:00): Hello, this is HomebrewAutomation! I will browse through your Bintray to see if there may be Bottles built earlier for your Formula, and update your Tap to refer to them.
homebrew_automation.rb [info] (2020-04-23T04:50:00+12:00): I will also update the source tarball of your Formula in your Tap, effectively releasing a new version of your Formula.
Cloning into 'homebrew-tap'...
...
... ( git stuff ) ...
...
homebrew_automation.rb [info] (2020-04-23T04:50:03+12:00): Let's see if any files on your Bintray look like Bottles.
homebrew_automation.rb [info] (2020-04-23T04:50:04+12:00): All files in Bintray Version: [{"name"=>"hello-homebrew-packaging-0.0.3.mojave.bottle.tar.gz", ... }]
homebrew_automation.rb [info] (2020-04-23T04:50:04+12:00): Found bottles: {"mojave"=>"e92cc9ac8db371e20e21c99b1b14c8f463f739d5f6bb5a7893766840bddec90a", "high_sierra"=>"257aa2e4317addf83260b970e13eef4426f2792acfab945c52ccb7658eec3b2d", "catalina"=>"040d71d9874b038d6bedfd9c490b32dbc93f41013cc505a270a6e22f735e1e91"}
...
homebrew_automation.rb [info] (2020-04-23T04:50:05+12:00): I've refered to the Bottles I found in this new commit. Let's push to your Tap!
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 212 bytes | 212.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/easoncxz/homebrew-tap.git
   552fa9a..cba653d  master -> master
homebrew_automation.rb [info] (2020-04-23T04:50:10+12:00): All done!

Now our Tap knows about the new version of the app, including the Bottles. If our user now ran brew install easoncxz/tap/hello-homebrew-packaging, they would be installing the new version, in this case v0.0.3. Hopefully, the user will be running a macOS version for which we've built a Bottle, otherwise Homebrew will build the hello-homebrew-packaging Formula from source on our user's system, installing the necessary build-time dependencies automatically. This can be a lengthy process.

Further details

You can use hello-homebrew-packaging as an end-to-end example, and examine for yourself how everything fits together. In the Github Wiki of hello-homebrew-packaging, I also share my journey of figuring out how to put all these pieces together when I was developing this Gem. Go read it if you're interested; it's quite a lengthy couple of articles!