Swift Package Manager で作った Command Line Tool を Homebrew で配布する
応用編でCommand Line Toolが作れるようになったと思うので、Homebrewで配布してみましょう。
1. SPM製のCommand Line ToolのリポジトリでTagを打ってReleaseノートを公開する
git tag 1.0.0
git push origin 1.0.0

公開すると、Assetsに自動的にリポジトリのスナップショットがアーカイブされます。特にtar.gzの方が重要です。このリンクは https://github.com/org/repo/archive/refs/tags/1.0.0.tar.gz のようになっています。

2. Homebrewで配布する時に参照されるFormulaファイルを設置する専用のリポジトリを作る
作ったCommand Line Toolのリポジトリとは別に、HomebrewのFormulaファイルを設置するためのリポジトリを作ります。これは自作のツールをHomebrewで公開する時に毎回使うものになります。
リポジトリ名は homebrew- というプレフィックスで始まる必要があります。よくあるパターンだと homebrew-tap にするっぽいです。
3. Formulaファイルを作ってReleaseノートのアーカイブと紐づける
2で作ったリポジトリをcloneして作業を進めます。
ここで、1のtar.gzのリンクが必要です。
git clone git@github.com:org/repo.git
cd repo
echo ".DS_Store" > .gitignore
mkdir Formula
brew create https://github.com/org/repo/archive/refs/tags/1.0.0.tar.gz
コンソールでFormula名を聞かれるので入力します。(ここではrepoとします。)
そうするとデフォルトのエディタでrepo.rbが開かれるので編集します。
class Repo < Formula
desc "A command line tool to do something."
homepage "https://github.com/org/repo"
url "https://github.com/org/repo/archive/refs/tags/1.0.0.tar.gz"
sha256 "d0df02c78a4d406a4574feba074f3da886f6f05a1f77f14887233005457cf04b"
license "MIT"
head "https://github.com/org/repo.git", branch: "main"
depends_on xcode: ["26.0", :build]
uses_from_macos "swift" => :build
def install
args = if OS.mac?
["--disable-sandbox"]
else
["--static-swift-stdlib"]
end
system "swift", "build", *args, "--configuration", "release"
bin.install ".build/release/repo"
end
test do
system "false"
end
end
- desc: リポジトリにDescriptionが指定されていれば自動で入力される
- head: デフォルトブランチを指定
- depends_on xcode: ビルドに使用するXcodeの下限バージョンを指定
- uses_from_macos "swift": swiftコマンドを使うことを宣言
- def install: インストール方法を記述
要はtar.gzを解凍してswift buildした成果物をコピーしている - test do: インストールしたツールがちゃんと動いていることを確認するシェルスクリプトを書く
system "false"のままでも配布自体はできる
これで出来上がったrepo.rbをFormulaディレクトリの中にコピーしてプッシュします。
ここまでで上手くいっていればHomebrew経由でインストールできるようになります。
brew tap org/tap
brew install org/tap/repo
同名のツールがHomebrew/Coreになければbrew install repoでもいけます。
内容を修正してプッシュしなおした場合はbrew untap org/tapしてからタップし直してください。
4. 【任意】Bottle向けのアーカイブを作ってインストールのコストを下げる
1~3の方法だとインストールする時にそれぞれの手元でツールをビルドすることになります。するとインストールに時間がかかってしまうので、アーカイブ済みのバイナリを配った方がコストが下がります。HomebrewにはBottleという仕組みがあって、アーカイブ済みのバイナリを紐づけられます。
brew uninstall org/tap/repo
brew install --build-bottle org/tap/repo
brew bottle --root-url https://github.com/org/reop/releases/download/1.0.0 org/tap/repo
==> Determining org/tap/repo bottle rebuild...
==> Bottling repo--1.0.0.arm64_tahoe.bottle.1.tar.gz...
./repo--1.0.0.arm64_tahoe.bottle.1.tar.gz
bottle do
root_url "https://github.com/org/reop/releases/download/1.0.0"
rebuild 1
sha256 cellar: :any_skip_relocation, arm64_tahoe: "4a237e30a4c8463d36d6aa766b00dbb87e69ccd731102ba2fc0a0e3a87690a91"
end
上記を実行すると、コマンドを実行したディレクトリに repo--1.0.0.arm64_tahoe.bottle.1.tar.gz のようなファイルが出力されているのでこれをツールのリポジトリのリリースノートにAssetとしてアップロードします。ただ、不具合なのかわからないのですが、そのままの名前ではフェッチできないのでリネームします。
ハイフンが2つ連なっていたら一つにして、bottleの後ろにrebuild番号が不要なら消します。
Before: repo--1.0.0.arm64_tahoe.bottle.1.tar.gz
After: repo-1.0.0.arm64_tahoe.bottle.tar.gz
そして、brew bottleコマンドを実行した時に出力されていたDSLをrepo.rbに追記します。
このとき、rebuild番号が不要なら消してOKです。
class Repo < Formula
desc "A command line tool to do something."
homepage "https://github.com/org/repo"
url "https://github.com/org/repo/archive/refs/tags/1.0.0.tar.gz"
sha256 "d0df02c78a4d406a4574feba074f3da886f6f05a1f77f14887233005457cf04b"
license "MIT"
head "https://github.com/org/repo.git", branch: "main"
+ bottle do
+ root_url: "https://github.com/org/reop/releases/download/1.0.0"
+ sha256 cellar: :any_skip_relocation, arm64_tahoe: "4a237e30a4c8463d36d6aa766b00dbb87e69ccd731102ba2fc0a0e3a87690a91"
+ end
depends_on xcode: ["26.0", :build]
uses_from_macos "swift" => :build
def install
args = if OS.mac?
["--disable-sandbox"]
else
["--static-swift-stdlib"]
end
system "swift", "build", *args, "--configuration", "release"
bin.install ".build/release/repo"
end
test do
system "false"
end
end
追記したら改めてプッシュして、タップし直せばBottleからインストールができるようになると思います。
Discussion
バージョンアップする方法
tar.gzのリンクをコピーsha256を計算して取得urlとsha256を更新してコミット