Skip to content

Instantly share code, notes, and snippets.

@brownhash
Created March 5, 2022 10:29
Show Gist options
  • Save brownhash/05ce5fb14493986c275b42e7c394c820 to your computer and use it in GitHub Desktop.
Save brownhash/05ce5fb14493986c275b42e7c394c820 to your computer and use it in GitHub Desktop.
Private HomeBrew tap formula
# formula/lib/private.rb
require "download_strategy"
# 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
class DownloadStrategyDetector
class << self
module Compat
def detect_from_symbol(symbol)
case symbol
when :github_private_repo
GitHubPrivateRepositoryDownloadStrategy
when :github_private_release
GitHubPrivateRepositoryReleaseDownloadStrategy
else
super(symbol)
end
end
end
prepend Compat
end
end
# formula/tool.rb
require_relative "lib/private"
class ToolName < Formula
desc "Tap for a private Github repository"
homepage "https://github.com/owner/repository"
version "1.0.0"
# For MacOs Intel based systems
if OS.mac? && Hardware::CPU.intel?
url "https://github.com/owner/repository/releases/download/v1.0.0/tool_darwin_amd64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
sha256 "ba833d556af4a47923fcb1234ca31492369808eea2165c733f5b5fd25c3885a7"
end
# For MacOs M1 based systems
if OS.mac? && Hardware::CPU.arm?
url "https://github.com/owner/repository/releases/download/v1.0.0/tool_darwin_arm64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
sha256 "4c5d45c7ad41cd217aa9f1bc7654921161a2554cb3e5084f3188ffd347ccc7b9"
end
# For Linux X64 based systems
if OS.linux? && Hardware::CPU.intel?
url "https://github.com/owner/repository/releases/download/v1.0.0/tool_linux_amd64.tar.gz", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
sha256 "801e95a44248765a111qab0d650321f286cd6bf506c88ae571db3d0624dac37e"
end
def install
bin.install "tool"
end
test do
system "#{bin}/tool --version && #{bin}/tool --help"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment