macOSX 向け dotfiles を Github Actions でテストする
macOS 環境が無料で CI が回せる時代になりましたね。16インチ MacBook Pro を買ったこともあって GitHub Actions で macOS 向け dotfiles をテスト&見直ししてみました。 案の定動かない処理もあったりして、やはりテストを定常的に回すのは効くなと思い知らされましたが、それにもいくつかハマりどころがあったので書いておこうと思います。
環境構築スクリプトを育てていると、どうしても今のPCの環境には適用できるけれど実は新規PCには適用できなくなっているということは起きてしまいます。まっさらな状態からセットアップすることはめったにありませんからね。具体的にはディレクトリのないところにsymlinkを貼るとか、セットアップの前の方で入れているツールを後の方で使っているのだけどPATHが通っていないとか、そういうケースです。
そこでCIを回しましょうという話です。最近、GitHub Actionsのmacos-latestでCIを回すようになりました。実際にCIを回したら、必要なディレクトリを作るのを忘れていたり、諸々通らないことが発覚しました。
現状の設定ファイルを先に貼っておくと、こうなりました。
リポジトリと作業の様子はこちらです。
- https://github.com/tamakiii/dotfiles/tree/6fd099b57646a69fb0ffb44fba541b9464b1c1ec
- https://github.com/tamakiii/dotfiles/pull/9
1. GitHub 上で YAML ファイルを initialize する
画面上から YAML ファイルが作れて PR も作れます。とりあえず PR を作ればテンションが上がるのでとりあえず作るといいと思います。
自分は Set up a workflow yourself
から始めました。
2. デフォルトで HomeBrew やいくつかのパッケージがインストールされている
これは dotfiles をテストする目的ではあまり嬉しくないことですが、デフォルトで HomeBrew や git, node などがインストールされていました。
ちょっと困ったのが、Brewfile で brew node
をインストールさせたい場合、brew node@12
と brew @node13
が衝突してコケてしまいました。
これはメインのスクリプトを動かす前にデフォルトでインストールされている node をアンインストールすることで回避しました。(brew uninstall node@12
)
==> Downloading https://homebrew.bintray.com/bottles/node-13.1.0.catalina.bottle.tar.gz ==> Downloading from https://akamai.bintray.com/58/5863d08b039c44d35a8343179cf93d495e1288efe2c669ccb77704a236e0e17b?__gda__=exp=1574272109~hmac=9967f775a1b5093bc37183b749e04921790fe0894fdec9d213efacd13b9c6ac8&response-content-disposition=attachment%3Bfilename%3D%22node-13.1.0.catalina.bottle.tar.gz%22&response-content-type=application%2Fgzip&requestInfo=U2FsdGVkX1-HgyW49y3C7roMUH2e6Ay__vYCfMAjNkaXbnNPwYSBlYuywDo6KSDP77-xzhgl2poWSbWyOqlhQXdPRm-Heaa85s3o5DAWzDspCV12Yu3lCCUO08p1ocfNZMtoImL1AsiYZ7xjt1rbgQ&response-X-Checksum-Sha1=7352019f912696f10f9cf7feaaad9c0e2666894f&response-X-Checksum-Sha2=5863d08b039c44d35a8343179cf93d495e1288efe2c669ccb77704a236e0e17b ==> Pouring node-13.1.0.catalina.bottle.tar.gz Error: The `brew link` step did not complete successfully The formula built, but is not symlinked into /usr/local Could not symlink bin/node Target /usr/local/bin/node is a symlink belonging to node@12. You can unlink it: brew unlink node@12 To force the link and overwrite all conflicting files: brew link --overwrite node To list all files that would be deleted: brew link --overwrite --dry-run node Possible conflicting files are: /usr/local/bin/node -> /usr/local/Cellar/node@12/12.13.0/bin/node
3. キャッシュの有効サイズは 400MB
ライフサイクルはこのようになっているので、Workflow が成功するまではキャッシュが有効になりません。
- ロックファイルからキャッシュキーを生成する(今回は
${{ hashFiles('Brewfile') }}
) - キャッシュキーからキャッシュの有無を探す
- Workflow が成功したらポストプロセスが動いてキャッシュを圧縮して保存する
またキャッシュされる最大サイズは 400MB で、これを超えるとポストプロセスでキャッシュが保存されなくなります。
/usr/bin/tar -cz -f /Users/runner/runners/2.160.2/work/_temp/430ca3b6-c547-4cda-ae16-a5e6e998894c/cache.tgz -C /usr/local/Cellar . ##[warning]Cache size of ~722 MB (757155145 B) is over the 400MB limit, not saving cache.
HomeBrew の場合、キャッシュ対象はざっと見た感じ2つあり、ひとつが $(brew --cache)/downloads
= ~/Library/Caches/Homebrew/downloads
、もうひとつが /usr/local/Cellar
です。
前者は install プロセスはスキップできませんが、download プロセスがスキップできます。ただし、40行ほどの内容でも 900MB 近くなってしまったため、post プロセスで保存される前にファイルサイズの大きいものから10件ほど削除することでキャッシュを効かせました。
後者の /usr/local/Cellar
なら 400MB を下回ってくれるのでは、と思いましたがこれも 700MB 超えでそのままではキャッシュに乗りませんでした。
キャッシュを効かせても Workflow ごとに5分ほどの実行時間を要しているので、あまりキャッシュは有効に使えなそうな雰囲気があります。
4. brew install が Host key verification failed.
で死ぬ
main.yml
から make -f brew.mk
を叩き、brew.mk
内で brew install
している場合は問題なく動くのですが、main.yml
と make -f brew.mk
の間にひとつシェルスクリプトや Makefile を挟むだけで Host key verification failed.
fatal: Could not read from remote repository.
で死ぬようになりました。
具体的なドキュメントは出てきませんでしたが、おそらくセキュリティ上の都合だと思われます。
解決策はなかったので諦めて間に何も挟まない形にしました。ci.mk
と実機で叩くセットアップスクリプトを近い形にしておきたかったんですが、まぁ致し方ないです。