自作 CLI を brew と scoop で配る ― GoReleaser でまとめて

シリーズ・第 4 回 — 「個人で出版ツールを作って配るまで」(全 5 回予定)。前回は多言語サイトの設計でした。一覧は シリーズの記事一覧 から。今回のテーマは「brew と scoop で配る実務」です。

CLI ができたら、次は「どう配るか」です。go install でも配れますが、Homebrew や Scoop で入れられた方が、使う人にはずっと楽です。

とはいえ、mac・Windows・Linux 向けに手でビルドして、Homebrew の formula と Scoop の manifest を手書きして…は、リリースのたびにやっていられません。そこを GoReleaser に一括でやらせた話です。ひとつ、macOS で素直に詰まったところ(署名)も含めて。

GoReleaser に一括でやらせる

GoReleaser は、設定ファイル 1 枚から次を全部やってくれます。

リリースは、git tag を切って 1 コマンドです。

git tag v0.1.0
GITHUB_TOKEN=$(gh auth token) goreleaser release --clean

公開前に試すなら、push しない snapshot モードで中身を確認できます。

goreleaser release --snapshot --clean   # dist/ に生成するだけ。公開はしない

バージョンは git tag を単一の出どころに

地味に大事なのが、バージョンの一致です。バイナリが名乗る版・ダウンロード URL・パッケージの版がバラバラだと、事故のもとになります。

GoReleaser では、git tag を ldflags でバイナリに焼き込めます。出どころを tag ひとつにすれば、全部が揃います。

builds:
  - ldflags:
      - -s -w -X your/module/internal/cli.Version={{.Version}}

これで crofty version が表示する版も、配布物の版も、同じ tag から来ます。

macOS の壁:cask をやめて formula に

macOS への配布で素直に詰まりました。最初は Homebrew の cask で配ろうとしたのですが、未署名のバイナリが毎回 Gatekeeper に弾かれるのです(「開発元を確認できません」のポップアップ)。

原因は隔離属性でした。cask は、ダウンロードした配布物に隔離(quarantine)を付けます。未署名だと、それが初回起動で Gatekeeper に引っかかる。警告を消すには Apple Developer ID での署名と notarization が要りますが、個人で配るには重い手続きです。

そこで cask をやめ、formula で配ることにしました。formula はダウンロードに隔離を付けないので、未署名のバイナリでも警告なしで動きます。

cask formula(採用)
ダウンロードの隔離属性 付く 付かない
未署名バイナリの初回起動 Gatekeeper がブロック そのまま動く
警告を消す条件 Apple 署名+notarization 不要

GoReleaser 側は brews: に tap(formula を置くリポジトリ)を指定するだけです。

brews:
  - name: crofty
    repository:
      owner: <your-github>
      name: homebrew-crofty
    dependencies:
      - name: hugo

Windows は Scoop、依存も宣言する

Windows では、Scoop が Homebrew にあたります。GoReleaser が manifest を作って、bucket リポジトリへ push してくれます。

もうひとつ大事なのが、依存の宣言です。crofty は内部で Hugo を使うので、入れたときに Hugo も一緒に入ってほしい。Homebrew は dependencies、Scoop は depends で宣言します。

scoops:
  - name: crofty
    repository:
      owner: <your-github>
      name: scoop-crofty
    depends:
      - main/hugo-extended

これで brew install / scoop install の一発で、ランタイムごと揃います。

まとめ

個人 OSS の配布は、こう落ち着きました。

署名まわりは個人にはまだ重いですが、ここまでで「tag を切れば配れる」状態にはなりました。


← 前の記事:多言語サイトの設計 | 次の記事:AI が動かす前提で CLI を設計する