setup-nim-action を v2 にバージョンアップした
導入
2019年ごろに公開してからほそぼそと更新を続けていて、おそらくGitHubのNimプロジェクトのCIで一番使われている Nim setup アクションなんじゃないかと自負してる
もっとも、ここ数年は特に大きなアップデートもなく、node_modules の依存ライブラリ更新しかしてなかったので、大きな変更がない状態だった
そんな setup-nim-action がとある理由で大改修することになり、生まれ変わってメジャーバージョンアップしたお話
突然のNimのインストールが遅くなった
ある日いきなり CI が急激に遅くなった。今までは10秒もかかっていなかったコンパイラのインストールに6分くらいかかるようになった。Macに至っては30分もかかるようになり、issues が作られた
https://gyazo.com/27faaecd2e06f612e1fd29f018280bc4
特に僕はsetup-nim-actionに手を入れていなかったのにいきなり CI が遅くなったので、原因があるとすれば
GitHub Actions のランナーに変更が入った
のどちらかだろうと思っていた
しかし choosenim も新バージョンは特に公開されていないので、挙動が変わるようには思えなかった
正直、何が原因なのか皆目検討がつかなかったのでお手上げ状態だったのだけれど、とはいえユーザが多いので放置するわけにもいかなかった
そんなわけでとにかくインストールを高速で終わらせるためにあらゆる調査をした
調査と修正
結果としては、choosenim を使ってインストールしようとすると非常に時間がかかることがわかった。それもGitHub Actions上で実行した場合のみ
choosenim を使うと node ランタイムでも composite アクションでもインストールに時間がかかっていた
setup-nim-action v1 はTypeScriptで実装しており、node20 ランタイムで動作していた
その内部では choosenim に依存しており、アクション実行時に choosenim をダウンロードしてきて実行して Nim をインストールするような作りになっている
GitHub Actionsのカスタムランタイムは、node 系と composite の 2 つが選択できる
composite はあとから追加されたランタイムで、簡単にいうとGitHub Actionsのワークフローをかくときの YAML 構文がそのままカスタムアクションになる
今回の問題の調査の結果 node ランタイムから composite に切り替えて、choosenim で実装されていた Nim をインストールする処理をすべてbashで実装しなおすことにした もちろん、choosenim のすべてをシェルスクリプトに移植したわけではない
choosenim は実行プラットフォームを判定して必要な依存ライブラリを整えるような処理も含まれる
setup-nim-action はそこまでやる必要はなく、依存ライブラリ(GCCとか)はすべて GitHub Actions のランナー側でほぼ整っていると判断し、Nimコンパイラのインストール部分のみを実装することにした
この場合、curl でビルド済みのコンパイラを落としてきて配置してPATHを通すだけで良い
bashで実装してもそこまで膨大なコードにはならないだろうと判断した
対応したPRは以下
choosenim にはなくて setup-nim-action で独自に実装していた 1.x とか 1.6.x とかで最新版を取ってくる処理もシェルスクリプトで実装しなおした
上記PRのあとは、要らなくなったファイル削除したり、細々した修正を入れたのみ
この対応により、setup-nim-action は約5年間ずっと依存していた choosenim への依存がなくなった
そしてNimのインストール速度はいぜんと同等の速度でインストールできる状態に戻った
TypeScriptなども不要になったため、リポジトリ上から node.js, typescript のコードがすべて消え、node_modules も不要になった
node ランタイムのカスタムアクションでは、node_modules をリポジトリのコードとして抱えなければならない制約があるので、コード量がめちゃくちゃ多くなる
結果として、setup-nim-action はたかだか130行程度のシェルスクリプトと、少しの action.yml だけで動作する非常にコンパクトなカスタムアクションへと生まれ変わった
たったこれだけ
そんなに難しい処理はしてなくて、非常に単純なシェルスクリプトだと思う
思えば、この程度の処理だったら最初から自分で実装することもできたと思う
まぁ2019年当時は composite アクションなかったんだけどね
やるとしたら今シェルスクリプトでやってる処理を TypeScript で実装することになってたと思う
ただファイル落としてきて圧縮ファイル展開して~って処理はシェルスクリプトのが圧倒的に向いてるので、それをTypeScriptで実装するのは微妙感ある
破壊的変更とマイグレーション
僕はchoosenimの中身に詳しいわけではないため、choosenimの移植をしたわけではない
やったこととしては、GitHub Actions上でNimが使える状態にするのに必要最低限の処理のみをシェルスクリプトで実装した
かなり突貫工事での実装になったし、ランタイムも変更になった。Nimのインストール先も変更せざるを得なかった
ActionsのInputの必須パラメータは変えないように実装したので、使い勝手は今までと変わらないものの、大規模な変更になってしまったため、苦渋の決断でメジャーバージョンアップして v2 バージョンを発行した
今までは v1 を書き換える形で更新し続けていたので v1 を利用している限り自動で最新が使われるようになっていた
今回はそういうわけにいかなかったため、やむを得ず v2 を発行した
破壊的変更をするならマイグレーションガイドが必要だろうと思い、かなり詳細にマイグレーションガイドを README と Release Note に書いた
ついでにNim wikiにかかれてるCI周りも v2 に更新した
やり終えた感想
急な対応だったのでかなり心身ともに疲れた
が、結果としてリポジトリは非常にコンパクトになって、依存パッケージ管理からも開放されて非常に気分が良い
dependabot で node_modules 更新するだけの運用から開放された
コンパイラをインストールするだけの処理のために choosenim に依存しているのも、昔からどうにかしたいと思っていたが、それも解消したので嬉しい
何気に composite アクションを初めて使ったので新鮮だった
シェルスクリプトで十分なカスタムアクション作るとき全部これでいいじゃん
setup-nim-actionはnim-langグループの管理下になってほしい
なんだかんだ setup-nim-action の保守を続けることもう5年だけれど、事実上 Nim プロジェクトで一番使われてる GitHub Actions(のはず)なんだし GitHub の nim-lang グループの管理下になってほしい気持ちがある
これはまぁずっと前からそう思ってるんだが
僕一人で保守しつづけてもまぁいいんだけれど、僕が突然亡くなったりしたら保守できる人いなくなっちゃうし
てかもう 5 年も保守してるのか...なげーな
最近は nim のコードほとんど書いてないのもあって、Nim公式が保守してほしい気持ちがある
ただプロジェクトの移管は、つい最近 Polyfill が売却されてマルウェアが仕込まれた件があるので、どこまで信じていいのかは分からない
まぁさすがに Nim 公式がそういうことするとは思えないけどね
余談
setup-nim-action 以外だと install-nim っていうのもあることを知った
これはchoosenimを使っているらしい
他は setup-nim もある。これは以前から知ってた
4年前から更新されていないので、保守は止まっているのかもしれない
setup-nim-action よりもっと良いカスタムアクションが誕生して、そっちにシェアが置き換わってくれても良いんやで
そうして新陳代謝してこそより良いソフトウェアが生まれるのだ
以上