2023/06/09

複数のGoツールをひとつのhomebrewリポジトリで配布する

Goで書かれたCLIツールを homebrew で配布するために goreleaser@goreleaser-action がよく使われている。よくある解説では、ひとつのCLIに対してひとつの homebrew リポジトリを作成して Formula を配布するかたちになっていることが多いが、複数の CLI tool を配布するとなったとき、毎回ツール自体のリポジトリとセットで homebrew 用のリポジトリを作成するのはちょっと面倒くさい。

awshashicorp がひとつの homebrew用リポジトリにある Formula ディレクトリに複数ツールの配布用データセットを置いているのを見つけたので、構成をマネして goreleaser の設定を書いてみた。

なお、githubの公開リポジトリで野良配布する前提で、goreleaserで単発配布まではできているとします。

homebrew用リポジトリ

取り急ぎ、Formula を置くリポジトリをつくる。たぶん任意の名前で良いが、 aws や hashicorp にならって homebrew-tap とする。わかりやすい。

私のを参考までに:bayashi/homebrew-tap

GITHUB Personal access tokens

まず、複数CLIをまとめることには関係ないが、homebrew向けのワークフロー設定に必要なので、githubアカウントで Personal access token を発行しておく。repo権限があればOK。これはリポジトリごとに発行してもいいし、ひとつのトークンを使いまわしても良いと思う。なぜなら同じリポジトリを変更するための token だから(ひとつひとつのツールをセキュアにするなら個別発行の方が望ましいとは思いますが)。

発行した token は、CLI ツールのリポジトリの Actions secrets メニューで HOMEBREW_TAP_GITHUB_TOKEN という名前で secrets に登録しておく。この名前は任意です。後述する goreleaser の設定ファイル .yaml の中で指定します。

goreleaser

releaser.yaml

まず、.github/workflows/releaser.yaml に上で発行した HOMEBREW_TAP_GITHUB_TOKEN の指定を追加しておきます(最終行)。

name: releaser

on:
  push:
    tags:
      - v*
jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: 1.19
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v4
        with:
          version: latest
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}

workflow 自体のファイル名は任意です。

.goreleaser.yaml

つづいて、プロジェクト直下に配置する .goreleaser.yaml には、brew 向けに以下のような項目を書いておきます。irir というツールの例です。

brews:
  - tap:
      owner: bayashi
      name: homebrew-tap
      token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"
    folder: Formula
    homepage: https://github.com/bayashi/irir
    description: A filter to add colors for text lines generically from a YAML configuration file easily
    test: |
      system "#{bin}/irir", '--version'

抽象化した解説を書いておくと、

brews:
  - tap:
      owner: {あなたのgithubアカウント}
      name: {homebrew用リポジトリ名}
      token: "{{ .Env.CLIツールのリポジトリでsecretsに登録したtokenの名前 }}"
    folder: {homebrew用リポジトリでのディレクトリ名。特に変更する必要もないので Formula のまま}
    homepage: {CLIツールを紹介するページURL}
    description: {CLIツールの紹介文}
    test: |
      system "#{bin}/{CLIツールコマンド}", '{必要ならオプション}' # テスト発行するコマンド

brews.tap.name のところを {homebrew用リポジトリ名} として、今回は homebrew-tap と指定している。HOMEBREW_TAP_GITHUB_TOKEN は上で発行したもの。

Workflow permissions

この設定は 複数CLI配布するためというわけではないが、goreleaser を github で動かすために必要な設定。

CLIのリポジトリの settings タブにある、Actions.General のメニューの中に Workflow permissions というのがあるので、これを read and write permissions に変更して保存する。

これをしておかないと、goreleaser のワークフローが 403 でこける。

homebrew 配布コマンド

goreleaser が無事走り切ると、homebrew-tap/Formula 以下に {ツール名}.rb が生成されていると思います。

配布用のコマンドは以下のようになります。

brew tap {あなたのgithubアカウント}/tap
brew install {あなたのgithubアカウント}/tap/{ツール名}

例えば、bayashi の irir というツールの場合、

brew tap bayashi/tap
brew install bayashi/tap/irir

となります。

まとめ

リポジトリを毎回作る手間が省けてハッピー

サイト内検索