GitHubでのCIはActions | GitHubを使うようになりましたが、GitHub Actionのsetup-nodeにはLTSのような相対的な値を指定する方法がありません。

そのため、GitHub ActionsでNode.jsのテストを書くには、次のようにnode-versionにそれぞれのバージョンを指定する必要があります。

Travis CIではnvmが使われていたので lts/* などをLTSを指定できたので、 node_js: stable とだけ書いていることが多かったです。

バージョンを書くのは問題ないのですが、バージョンを更新するのが面倒です。 また、ローカルでは古いバージョンで実行しないので、リポジトリをメジャーアップデートするコミットをpushしてから、Node.js 10では動かないパッケージが入ってきてテストが落ちてから気づくみたいな現象が起きやすいです。

この更新を楽にするためのgithub-actions-node-versionsというツールを書きました

github-actions-node-versions

github-actions-node-versionsは、.github/workflow/*.{yml,yaml}matrix にかかれている node-version を自動的にLTSとActiveなバージョンに更新します。

Node.jsでは、LTSとしてMaintenanceとActive LTSの2種類があり、2021-05-28時点では、Node.js 12と14が該当します。 また、LTSではないがActiveに開発するCurrentバージョンがあり、2021-05-28時点では、Node.js 16が該当します。

次のコマンドを実行すると node-version: [Maintenance LTS、Active LTS, Current] に更新してくれるシンプルなツールです。 2021-05-28時点では node-version: [12, 14, 16] と更新してくれます。

$ npx github-actions-node-versions

実行結果の例

node-version-aliasを使っているので、https://nodejs.org/dist/の状態によって自動的に結果が変わります。

Node.js 17が出たときは、まだUnstableなので入ってほしくなくて奇数バージョンは除外しています。 なので、node-version: [14, 16] となる気がします。(テストしてないので、テストと修正のPR待ってます!)

内部的な仕組み

コメントを維持しながらYAMLを変換したかったためjs-yamlが使えませんでした。 eemeli/yaml: JavaScript parser and stringifier for YAMLを使って、Yamlをパースしてtraverseしながら、位置情報を取得しています。

この位置情報を元に node-version だけを書き換えることで、コメントを維持しながらYAMLのマイグレーションをしています。

おわりに

管理しているリポジトリが大量にあるので、こういうちょっとした変更も手作業じゃなくてツール化していることが多いです。

何度実行しても同じ結果になるマイグレーションツールを作っておくと何も考えなくて良いので楽だと思います。