GitHubActionsでリリースとHomeBrewのformulaレポジトリ更新を一度に行う

個人でHomeBrew通してバイナリを公開する時、formulaを作成してレポジトリを立ち上げる必要があります。
そこにはバージョンやリリースしたいファイルのURL、SHA256 checksumを含めなくてはならないのですが、バイナリをアップデートしたい時にソースコードのレポジトリだけでなくformulaのレポジトリも更新しなくてはならず面倒です。
そこでGitHubActionsで2つのレポジトリを連携してリリースとformulaの更新を一度に行える様にしてみました。

対象レポジトリ

Rustで書いたCLIアプリであるGitHub - QWYNG/harvest: stashes grep tool with rustとそのformulaである GitHub - QWYNG/homebrew-harvestが対象レポジトリです。

workflow

まずリリースする側のレポジトリのworkflowの設定です。長いので中略してます。

 name: Release

on:
  push:
    tags:
      - 'v*.*.*'

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macOS-latest]
        rust: [stable]

    runs-on: ${{ matrix.os }}

    steps:
~~~ snip ~~~
      - name: Set version
        id: set_version
        run: echo ::set-output name=version::${GITHUB_REF/refs\/tags\//}
        env:
          GITHUB_REF:  ${{ github.ref }}
      - name: Build for linux
        if: matrix.os == 'ubuntu-latest'
        run: |
          cargo build --release --target=x86_64-unknown-linux-musl
          zip -j harvest-${VERSION}-x86_64-lnx.zip target/x86_64-unknown-linux-musl/release/harvest
        env:
          VERSION: ${{ steps.set_version.outputs.version }}
      - name: Build for macOS
        if: matrix.os == 'macOS-latest'
        run: |
          cargo build --release --target=x86_64-apple-darwin
          zip -j harvest-${VERSION}-x86_64-mac.zip target/x86_64-apple-darwin/release/harvest
        env:
          VERSION: ${{ steps.set_version.outputs.version }}
      - name: Set SHA256
        if: matrix.os == 'macOS-latest'
        id: sha_256
        run: |
          echo "::set-output name=sha::$(shasum -a 256 harvest-${VERSION}-x86_64-mac.zip |awk '{print $1}')"
        env:
          VERSION: ${{ steps.set_version.outputs.version }}
      - name: Release
        id: release
        uses: softprops/action-gh-release@v1
        with:
          files: '*.zip'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Dispatch homebrew Repo update
        if: matrix.os == 'macOS-latest'
        uses: peter-evans/repository-dispatch@v1
        with:
          token: ${{ secrets.HOMEBREW_REPO_GITHUB_TOKEN }}
          repository: QWYNG/homebrew-harvest
          event-type: update
          client-payload: '{"version": "${{ steps.set_version.outputs.version }}", "sha": "${{ steps.sha_256.outputs.sha }}" }'
 

Build for macOSではビルドとzipへの圧縮を行っています。
GitHubActionsは::set-output name={name}::{value}の形で後のstepでsteps.<step id>.outputs.{name}として値を使用できます。これを利用してSet versionSet SHA256でバージョンとzipファイルのchecksumをセットしています。
最後に取得したバージョンとchecksumをrepository-dispatchをつかってformulaレポジトリに投げます。普通にcurlで発火させることもできますが、今回は

GitHub - peter-evans/repository-dispatch: A GitHub action to create a repository dispatch eventが便利そうだったので使ってみました。

dispatchを受け取るformulaレポジトリ側のworkflowは以下

 name: Release

on: repository_dispatch

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
        with:
          persist-credentials: false
          fetch-depth: 0
      - name: Create local version change
        run: |
          truncate version.rb --size 0
          echo 'VERSION = "${{ github.event.client_payload.version }}"' > version.rb
          echo 'SHA = "${{ github.event.client_payload.sha }}"' >> version.rb
      - name: Commit version change
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          git commit -m "update version" -a
      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }} 

dispatchで受け取ったペイロードを使ってversion.rbを書き直してコミットしてプッシュしてます。 f:id:sasa5740:20200706221128p:plain 無事自動でformulaレポジトリを更新できました。

まとめ

愚直な実装なのでHomeBrewに詳しければもう少しスマートにできるかもしれないです。
harvestをgit diffではなくgit stash show -pの結果で検索するように改良し、更に標準出力にページャを導入しました。大分使いやすくなったので満足。