Homebrew and Private GitHub Repositories

This page summarizes the projects mentioned and recommended in the original post on dev.to

Our great sponsors
  • InfluxDB - Power Real-Time Data Analytics at Scale
  • WorkOS - The modern identity platform for B2B SaaS
  • SaaSHub - Software Alternatives and Reviews
  • mytool

    # typed: false # frozen_string_literal: true # This file was generated by GoReleaser. DO NOT EDIT. require_relative "lib/custom_download_strategy" class Mytool < Formula desc "" homepage "" version "1.1.5" on_macos do if Hardware::CPU.arm? url "https://github.com/myorg/mytool/releases/download/v1.1.5/mytool_1.1.5_Darwin_arm64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "abc123..." def install bin.install "mytool" end end if Hardware::CPU.intel? url "https://github.com/myorg/mytool/releases/download/v1.1.5/mytool_1.1.5_Darwin_x86_64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "qwerty987..." def install bin.install "mytool" end end end on_linux do if Hardware::CPU.arm? && Hardware::CPU.is_64_bit? url "https://github.com/myorg/mytool/releases/download/v1.1.5/mytool_1.1.5_Linux_arm64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "f00bar..." def install bin.install "mytool" end end if Hardware::CPU.intel? url "https://github.com/myorg/mytool/releases/download/v1.1.5/mytool_1.1.5_Linux_x86_64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "xyz543..." def install bin.install "mytool" end end end end

  • semver

    Semantic Versioning Specification

    The tool I wrote is a little CLI tool written in go. When I tag a commit on main with a version semver, our CI tool uses GoReleaser to build binaries for various architectures, create a GitHub release, and update the Homebrew formula. GoReleaser is definitely not necessary, but makes things incredibly easy. Here's my .goreleaser.yaml for reference:

  • InfluxDB

    Power Real-Time Data Analytics at Scale. Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.

  • goreleaser

    Deliver Go binaries as fast and easily as possible

    The tool I wrote is a little CLI tool written in go. When I tag a commit on main with a version semver, our CI tool uses GoReleaser to build binaries for various architectures, create a GitHub release, and update the Homebrew formula. GoReleaser is definitely not necessary, but makes things incredibly easy. Here's my .goreleaser.yaml for reference:

  • Puts Debuggerer

    Ruby library for improved puts debugging, automatically displaying bonus useful information such as source line number and source code.

    require "download_strategy" # S3DownloadStrategy downloads tarballs from AWS S3. # To use it, add `:using => :s3` to the URL section of your # formula. This download strategy uses AWS access tokens (in the # environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`) # to sign the request. This strategy is good in a corporate setting, # because it lets you use a private S3 bucket as a repo for internal # distribution. (It will work for public buckets as well.) class S3DownloadStrategy < CurlDownloadStrategy def initialize(url, name, version, **meta) super end def _fetch(url:, resolved_url:, timeout:) if url !~ %r{^https?://([^.].*)\.s3\.amazonaws\.com/(.+)$} && url !~ %r{^s3://([^.].*?)/(.+)$} raise "Bad S3 URL: " + url end bucket = Regexp.last_match(1) key = Regexp.last_match(2) ENV["AWS_ACCESS_KEY_ID"] = ENV["HOMEBREW_AWS_ACCESS_KEY_ID"] ENV["AWS_SECRET_ACCESS_KEY"] = ENV["HOMEBREW_AWS_SECRET_ACCESS_KEY"] begin signer = Aws::S3::Presigner.new s3url = signer.presigned_url :get_object, bucket: bucket, key: key rescue Aws::Sigv4::Errors::MissingCredentialsError ohai "AWS credentials missing, trying public URL instead." s3url = url end curl_download s3url, to: temporary_path end end # GitHubPrivateRepositoryDownloadStrategy downloads contents from GitHub # Private Repository. To use it, add # `:using => :github_private_repo` to the URL section of # your formula. This download strategy uses GitHub access tokens (in the # environment variables `HOMEBREW_GITHUB_API_TOKEN`) to sign the request. This # strategy is suitable for corporate use just like S3DownloadStrategy, because # it lets you use a private GitHub repository for internal distribution. It # works with public one, but in that case simply use CurlDownloadStrategy. class GitHubPrivateRepositoryDownloadStrategy < CurlDownloadStrategy require "utils/formatter" require "utils/github" def initialize(url, name, version, **meta) super parse_url_pattern set_github_token end def parse_url_pattern unless match = url.match(%r{https://github.com/([^/]+)/([^/]+)/(\S+)}) raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Repository." end _, @owner, @repo, @filepath = *match end def download_url "https://#{@github_token}@github.com/#{@owner}/#{@repo}/#{@filepath}" end private def _fetch(url:, resolved_url:, timeout:) curl_download download_url, to: temporary_path end def set_github_token @github_token = ENV["HOMEBREW_GITHUB_API_TOKEN"] unless @github_token raise CurlDownloadStrategyError, "Environmental variable HOMEBREW_GITHUB_API_TOKEN is required." end validate_github_repository_access! end def validate_github_repository_access! # Test access to the repository GitHub.repository(@owner, @repo) rescue GitHub::HTTPNotFoundError # We only handle HTTPNotFoundError here, # becase AuthenticationFailedError is handled within util/github. message = <<~EOS HOMEBREW_GITHUB_API_TOKEN can not access the repository: #{@owner}/#{@repo} This token may not have permission to access the repository or the url of formula may be incorrect. EOS raise CurlDownloadStrategyError, message end end # GitHubPrivateRepositoryReleaseDownloadStrategy downloads tarballs from GitHub # Release assets. To use it, add `:using => :github_private_release` to the URL section # of your formula. This download strategy uses GitHub access tokens (in the # environment variables HOMEBREW_GITHUB_API_TOKEN) to sign the request. class GitHubPrivateRepositoryReleaseDownloadStrategy < GitHubPrivateRepositoryDownloadStrategy def initialize(url, name, version, **meta) super end def parse_url_pattern url_pattern = %r{https://github.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(\S+)} unless @url =~ url_pattern raise CurlDownloadStrategyError, "Invalid url pattern for GitHub Release." end _, @owner, @repo, @tag, @filename = *@url.match(url_pattern) end def download_url "https://api.github.com/repos/#{@owner}/#{@repo}/releases/assets/#{asset_id}" end private def _fetch(url:, resolved_url:, timeout:) # HTTP request header `Accept: application/octet-stream` is required. # Without this, the GitHub API will respond with metadata, not binary. curl_download download_url, "--header", "Accept: application/octet-stream", "--header", "Authorization: token #{@github_token}", to: temporary_path end def asset_id @asset_id ||= resolve_asset_id end def resolve_asset_id release_metadata = fetch_release_metadata assets = release_metadata["assets"].select { |a| a["name"] == @filename } raise CurlDownloadStrategyError, "Asset file not found." if assets.empty? assets.first["id"] end def fetch_release_metadata release_url = "https://api.github.com/repos/#{@owner}/#{@repo}/releases/tags/#{@tag}" GitHub::API.open_rest(release_url) end end # ScpDownloadStrategy downloads files using ssh via scp. To use it, add # `:using => :scp` to the URL section of your formula or # provide a URL starting with scp://. This strategy uses ssh credentials for # authentication. If a public/private keypair is configured, it will not # prompt for a password. # # @example # class Abc < Formula # url "scp://example.com/src/abc.1.0.tar.gz" # ... class ScpDownloadStrategy < AbstractFileDownloadStrategy def initialize(url, name, version, **meta) super parse_url_pattern end def parse_url_pattern url_pattern = %r{scp://([^@]+@)?([^@:/]+)(:\d+)?/(\S+)} if @url !~ url_pattern raise ScpDownloadStrategyError, "Invalid URL for scp: #{@url}" end _, @user, @host, @port, @path = *@url.match(url_pattern) end def fetch ohai "Downloading #{@url}" if cached_location.exist? puts "Already downloaded: #{cached_location}" else system_command! "scp", args: [scp_source, temporary_path.to_s] ignore_interrupts { temporary_path.rename(cached_location) } end end def clear_cache super rm_rf(temporary_path) end private def scp_source path_prefix = "/" unless @path.start_with?("~") port_arg = "-P #{@port[1..-1]} " if @port "#{port_arg}#{@user}#{@host}:#{path_prefix}#{@path}" end end class DownloadStrategyDetector class << self module Compat def detect(url, using = nil) strategy = super require_aws_sdk if strategy == S3DownloadStrategy strategy end def detect_from_url(url) case url when %r{^s3://} S3DownloadStrategy when %r{^scp://} ScpDownloadStrategy else super(url) end end def detect_from_symbol(symbol) case symbol when :github_private_repo GitHubPrivateRepositoryDownloadStrategy when :github_private_release GitHubPrivateRepositoryReleaseDownloadStrategy when :s3 S3DownloadStrategy when :scp ScpDownloadStrategy else super(symbol) end end end prepend Compat end end

  • HomeBrew

    🍺 The missing package manager for macOS (or Linux)

    I recently developed an internal CLI tool for my organization to use and, of course, wanted to make it easy for the other devs to install. That means I wanted to make it installable from Homebrew, since most, if not all, of my colleagues use it to manage their installed applications. I was able to tap a private repo by setting the HOMEBREW_GITHUB_API_TOKEN environment variable with a GitHub access token, but I was getting 404 errors from curl when installing. The documentation and information I could find by searching was either non-existent or outdated, so I figured I would get what worked for me out there for others to use.

  • WorkOS

    The modern identity platform for B2B SaaS. The APIs are flexible and easy-to-use, supporting authentication, user identity, and complex enterprise features like SSO and SCIM provisioning.

NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts