🌊
プライベートなツールをGitHub Releaseで配布してbrewでインストールする - brew 4 版
背景
独自のhomebrew tapを用意して、そこから認証の必要なGitHub RepositoryのReleaseからバイナリを配布していた。
昔はbrew公式の機能でインストールができていたができなくなってしまった。
その対応方法として下記があった。
しかし、
これを解決したい。
解決方法
選択肢
- GitHub Packges や Amazon S3などから配布する
- GitHub Release用のDownloadStrategyを用意する
本記事では DownloadStrategy をbrew version 4対応方法について記述する。
これは上記ブログ記事と同じ手段で、formulaeを変更なしで利用できる利点があります。
長期的にはGitHub Packagesを使うほうがよさそうだがそれは今後検討する。
DownloadStrategyの実装例
# privateなGitHub ReppositoryのReleaseからダウンロードするためのdownload strategy
# @see https://docs.brew.sh/Formula-Cookbook#specifying-the-download-strategy-explicitly
class GitHubPrivateRepositoryReleaseDownloadStrategy < CurlDownloadStrategy
def initialize(url, name, version, **meta)
meta[:headers] ||= []
token = GitHub::API.credentials
meta[:headers] += ["--header", "Authorization: token #{token}"]
meta[:headers] += ["--header", "Accept: application/octet-stream"]
parse_url_pattern(url)
super(download_url, name, version, **meta)
end
def parse_url_pattern(url)
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)
@tag = URI.decode(@tag)
end
def download_url
"https://api.github.com/repos/#{@owner}/#{@repo}/releases/assets/#{asset_id}"
end
private
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
GitHub.get_release(@owner, @repo, @tag)
end
end
これを定義したファイルを読み込みし、formulaeで指定すればよい。
例
require_relative '../lib/download_strategy'
class XXX < Formula
desc "xxx"
homepage "https://example.com/xxx/xxx"
url "https://example.com/xxx/xxx", :using => GitHubPrivateRepositoryReleaseDownloadStrategy
end
もうちょっと詳しく
brew 4の CurlDownloadStrategy では _fetchが呼ばれる前に 認証の必要urlへのアクセスが発生してしまって失敗していた。そのため、それよりも早く認証情報の付与と実際のダウンロードurlを生成することで解決している。
これらの処理をinitializeメソッドで行うことで、この問題が解決される。
参考情報
DownloadStrategyについて
DownloadStrategyの実装
Discussion