初めてのOSSへの貢献を果たした話【homebrew-cask】

3年ほど前、初めてLinuxに触れてからOSSという文化にとても感銘をうけ、常々貢献したいと思っていた。
と言いつつ結局特に行動していないワナビだったのだが、この度晴れてプルリクを作成し、マージされるに至ったので共有

## 更新履歴
2021/11/02 `brew bump-cask-pr`について追記

## やったこと

最近M1 MacBook Airを買ったので、Macで定番のパッケージマネージャ[^packagemanager]である[homebrew(cask)](https://brew.sh/)[^homebrew]を使って[GnuCash](https://gnucash.org/index.phtml?lang=ja_JP)[^gnucash]をインストールしようとしたらバージョンが古くエラーになったので更新した。

## 状況の確認

### 問題の発生

Homebrewでgnucashをインストールしようとしたら以下のエラーが発生した。

```
$ brew install --cask gnucash
==> Downloading https://github.com/Gnucash/gnucash/releases/download/4.8/Gnucash-Intel-4.8-1.dmg

curl: (22) The requested URL returned error: 404
Error: Download failed on Cask 'gnucash' with message: Download failed: https://github.com/Gnucash/gnucash/releases/download/4.8/Gnucash-Intel-4.8-1.dmg
```

### Gnucashの確認

エラーを見るに[github上のGnucashのリリース](https://github.com/Gnucash/gnucash/releases/)から直接ダウンロードをしている模様。
確認してみたところ、Mac向けのパッケージが`Gnucash-Intel-4.8-1.dmg` から`Gnucash-Intel-4.8-2.dmg`に差し替わっていた。
単に使うだけならここから手動でダウンロードしてインストールすればいい。とはいえ、せっかくパーケージマネージャが対応しているのに手動で入れるのも何なので[^manual]、こちらの設定変更とかでなんとかできないか、今度はhomebrewの方のリポジトリを確認してみた。

### Homebrew-caskの確認

homebrewはGUIアプリケーションはhomebrew-caskという別のリポジトリになっている。


ということでhomebrew-caskのリポジトリを確認し、以下のことが分かった。

- ダウンロードするファイル自体はgithubの公式リポジトリのリリースページなどにあり、homebrew-caskで直接扱うのは設定ファイルのみ
  - そのため設定ファイルの修正だけで更新できる  
    最低限URLやHash値、バージョンの3か所書き換えれば更新できるので簡単そう。（実際はそうはいかなかった、後述）
- homebrew-caskはそれ自体が内部でgitを利用している
    - 修正からプルリクの作成までの手順がシンプルでわかりやすい
- （バージョンの更新だけなら）プルリクはテンプレート文のみでよく、Issueも不要
    - コミュ障でもなんとかなりそう
- 更新者は毎回違っており、とくに担当などはなく気が付いた各々が更新している模様
    - 一見さんでも大丈夫そう


ということで、作業的にもコミュ力的にも何とかなりそうな気がしたので、さっそく修正にとりかかった。

## 作業


基本的には[公式のコントリビューションガイド](https://github.com/Homebrew/homebrew-cask/blob/master/CONTRIBUTING.md)の通り。これが本当に親切にできていたのでコントリビューションの入門としてはちょうどよかった。

なお、以降の例ではgithubのユーザー名として実際に筆者のgithubのユーザー名である`fluo10`を使っている。

### ※この手順は推奨されているものではありません（2021/11/02追記）
既存のファイルの更新では`brew bump-cask-pr`での作成が推奨されています。
今回はbrewのパッケージの更新もプルリクも今回が初めてでうまくできる自信がなかったため、一度ローカルで試しに修正し、動くのを確認してからプルリクをするという流れだったため使っていなかったのですが、この手順は非推奨でした。真似しないでください。

### homebrew-caskのディレクトリに移動

```
$ cd "$(brew --repository)"/Library/Taps/homebrew/homebrew-cask
```

このディレクトリ、[Homebrew-caskのgitリポジトリ](https://github.com/Homebrew/homebrew-cask)そのものらしく、ここでブランチを切って修正し、自分のフォークしたリポジトリにプッシュしたりができる。これは手軽！

### ブランチの作成

```
git checkout -b gnucash-4.8-2
```

ブランチ名は過去の例に倣ってアプリ名とバージョンを使った。

### gnucash.rbの修正
gnucashの設定は`Casks/gnucash.rb`にあるので、これを修正する

（この段階では）修正したのは`version`、`sha256`、`url`の3箇所。

まずはバージョン。

```diff
-  version "4.8"
+  version "4.8-2"
```

見ての通り、バージョンの表記が1桁（？）増えている[^version]ので、これに伴ってURLも修正した。


```diff
-  url "https://github.com/Gnucash/gnucash/releases/download/#{version}/Gnucash-Intel-#{version}-1.dmg",
+  url "https://github.com/Gnucash/gnucash/releases/download/#{version.hyphens_to_dots.major_minor}/Gnucash-Intel-#{version}.dmg",
```

最後にファイルの検証用のハッシュ値を[公式のリリース](https://github.com/Gnucash/gnucash/releases/)からコピペして更新する[^hash]。

```diff
-  sha256 "abb6a0bc433207c1f31fee33aa7f0c63774217b2675e5fab78062c4cd862f975"
+  sha256 "20af888f1d1293a036b595145ad9e5338b3a92f868b6e4fca021d4cc7d9df36b"
```


### チェック

公式のプルリクエストに2つのチェック用のコマンドを実行するように指示があるのでそのとおりに実行


```
$ brew style --fix gnucash

1 file inspected, no offenses detected
```

```
$ brew audit --cask gnucash
audit for gnucash: passed
```

これでテストも問題ないことが確認できた[^selfcheck]

### 試しにインストールしてみる

```
$ brew install --cask gnucash
==> Downloading https://github.com/Gnucash/gnucash/releases/download/4.8/Gnucash
==> Installing Cask gnucash
==> Moving App 'Gnucash.app' to '/Applications/Gnucash.app'
🍺  gnucash was successfully installed!
```

これでインストールができることは確認できた。

## プルリクエストの準備

### githubでフォークの作成

githubでフォークを作成する
https://github.com/fluo10/homebrew-cask

### リモートに自分のフォークを追加

```
$ git remote add fluo10 "https://github.com/fluo10/homebrew-cask"
$ git push -u fluo10 gnucash-4.8-2
```

### プルリクを作成

実際に作成したプルリクが[こちら](https://github.com/Homebrew/homebrew-cask/pull/112790)
本文は過去の例を参考に、テンプレほぼそのままで作成した。

作成が完了すると早速自動チェックが始まり、便利だなー、これが自動テストかーと眺めていたらエラーが出た。

### Livecheckの更新

発生したエラーは以下の通り。

```
Run brew audit --cask --appcast --online './Casks/gnucash.rb'
==> Downloading https://github.com/Gnucash/gnucash/releases/download/4.8/Gnucash-Intel-4.8-2.dmg
Already downloaded: /Users/runner/Library/Caches/Homebrew/downloads/bf1f5963742fc400194d7a6613884eeae23387a727947cf86c6465af9c54b80b--Gnucash-Intel-4.8-2.dmg
audit for gnucash: failed
 - Version '4.8-2' differs from '4.8' retrieved by livecheck.
Error: 1 problem in 1 cask detected
Error: Version '4.8-2' differs from '4.8' retrieved by livecheck.
Error: Process completed with exit code 1.
```

調べたところ、どうやら上流の新しいバージョンを確認するためにlivecheckという機能があり、今回の例ではGitHubのリリースのバージョンである`4.8`をそのまま最新のバージョンとして取得した結果、今回更新した`4.8-2`と矛盾しているぞということらしい。

[公式のLivecheckに関する箇所](https://docs.brew.sh/Cask-Cookbook#stanza-livecheck)を読んでなんとかちゃんと取得できるようにする。

```diff
   livecheck do
-    url :url
-    strategy :github_latest
+    url "https://github.com/Gnucash/gnucash/releases/latest"
+    regex(%r{href=.*/Gnucash-Intel-v?(\d+\.\d+-\d+)\.dmg}i)
   end
```

ローカルでlivecheckを試し、`4.8-2`が取得できることを確認した。

```
$ brew livecheck --debug --cask gnucash
Cask:             gnucash
Livecheckable?:   Yes

URL:              https://github.com/Gnucash/gnucash/releases/latest
Strategy:         PageMatch
Regex:            /href=.*\/Gnucash-Intel-v?(\d+\.\d+-\d+)\.dmg/i
URL (final):      https://github.com/Gnucash/gnucash/releases/tag/4.8

Matched Versions:
4.8-2
gnucash : 4.8-2 ==> 4.8-2
```

これで改めてプッシュすると、プルリクエストにもそのまま更新が反映され、再度自動テストが動いた。今回はちゃんとテストも突破できた。

## その後

livecheckに以下の修正があったものの、無事にマージされていた

```diff
   livecheck do
-    url "https://github.com/Gnucash/gnucash/releases/latest"
+    url :url
+    strategy :github_latest
   end
```

## 感想

- 初めて貢献出来て嬉しい（小並感）。
- livecheckの更新は完全に想定外だったため、焦ってちゃんと理解は出来ていないが動くからいいか精神で提出してしまい、結果として修正の手間をかけさせてしまったあったのは心残り。
- 機会を見逃さずに立ち向かうというのは大事だなと思った。単純に当初の目的だったGnuCashのインストールだけであればここまでする必要はなかったが、結果的には「初めてOSSに貢献する」という、かけた時間以上の成果が得られたので。
- Mac買ってよかった。Linuxに慣れた今だからこそわかることがあって色々と楽しい。



[^packagemanager]: 色んなアプリケーションを簡単にインストールしたりできる便利なツール。非常に便利でLinuxだと標準装備なのだが、どういうわけかWindowsにもMacにも純正のものは無い。

[^homebrew]: Macの定番のパッケージマネージャ。Linuxですっかりパッケージマネージャの便利さを知ってしまった自分としては必須だった。

[^gnucash]: 複式簿記の家計簿アプリ

[^manual]: とくにLinuxではパッケージマネージャーはややこしい依存関係も管理してくれるので、基本的にはパッケージマネージャ経由でインストールするのが推奨されている模様。といってもGnucashのようなMacのGUIのアプリケーションに限ればパッケージ一つで動くので手動で入れても特に問題ないと思われる。

[^version]: ファイル自体はもともと"4.8-1"だったが、リリースのバージョンは`4.8`となっており、homebrew-caskは後者に合わせていた模様。

[^hash]: なお、最初はリリースページにあるのに気づかなかったので、ローカルでテストしてる段階では`shasum`で自力で計算していたものを使っていた。流石にプルリクを作成する前に公式で掲載しているものを確認し、一致していたので問題なかったのだが、一歩間違ったらやらかしていた可能性がある。反省。

[^selfcheck]: 実際はなんどかエラーがでてその都度修正した。