🌙

GitHub ActionsでNode.js Nightly版でもテストする

2023/01/16に公開

はじめに

GitHub Actionsのmatrix機能で複数のNode.jsバージョンを対象にビルド・テストなどする場合に、Node.jsのNightly版も加える方法です。

対象Node.jsバージョンにNightly版を入れれば、将来のNode.jsバージョンでうまく動かなくなる事象が早めに発覚して対処がしやすくなります。
一方で、Node.js側のバグを踏む可能性もありますので、あくまでも参考としてエラーを出してもらい、パイプライン全体には影響しないようにします。

やり方

  • ジョブにcontinue-on-error設定を追加
  • マトリックスに、continue-on-error用の変数を追加
  • マトリックスのincludeを使って、Node.jsのバージョンがNightlyの場合はcontinue-on-errortrueに設定する

最終的なワークフロー定義は以下のとおり。

.github/workflows/run.yaml
name: Node.js Nightly Demo

on:
  push:

jobs:
  nightly-demo:
    runs-on: ubuntu-latest
    strategy:
      # node-version と experimental という2つの変数からなるマトリックスを定義
      matrix:
        node-version:
          - 16
          - 18
        experimental:
          - false
        # { node-version: "20-nightly", experimental: true } を追加
        include:
          - node-version: 20-nightly
            experimental: true

    name: Runs on Node.js ${{ matrix.node-version }}
    # trueの場合、このジョブが失敗しても、ワークフローは継続する(失敗にしない)
    continue-on-error: ${{ matrix.experimental }}
    steps:
      - uses: actions/checkout@v3

      # setup-nodeはv3.6.0以降でNightly版のインストールに対応した
      - uses: actions/setup-node@v3.6.0
        with:
          node-version: ${{ matrix.node-version }}

      # ここから後は、好きなステップを実施する(ビルドでもLintでもテストでも)
      - run: node index.js

この記事を書こうと思った背景

GitHub Actionsで好きなバージョンのNode.jsをインストールするactions/setup-nodev3.6.0がリリースされました。このバージョンではNightly版、RC版などをインストールすることに対応し、気軽にNightly版を使えるようになりました。

ステップごとの説明

準備

当記事の説明用に、まずGitHubにリポジトリーを用意し、以下の2ファイルを追加しました。
今回は、Node.js LTS版では正常に動くがNightly版では異常終了するスクリプトを用意してみました。
本来ここは単にスクリプトを動かすのではなくビルドやテストをするところです。

index.mjs
import { version } from "node:process";
import { setTimeout } from "timers/promises";

// Node.jsのバージョンを表示する
console.log(`node version is: ${version}`);

if (version.indexOf("nightly") > 0) {
  // バージョンにnightlyが含まれていたらエラーにする
  throw new Error("This script runs on Node.js Nightly");
}

// 問題無ければ、5秒待ってから終了する
await setTimeout(5000);
.github/workflows/run.yaml
name: Node.js Nightly Demo

on:
  push:

jobs:
  nightly-demo:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version:
          # 一通りLTSバージョンで動かす
          - 16
          - 18

    name: Runs on Node.js ${{ matrix.node-version }}
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.6.0
        with:
          node-version: ${{ matrix.node-version }}
      # 当記事用のスクリプトを実行する
      - run: node index.mjs

とりあえず上記の状態でプッシュすると、こうなりました。

普通にNode.jsのバージョン16と18で動かして成功しただけです。

単純にNightlyを加えてみる 👎

単純にmatrix(この例ならnode-version)に20-nightlyを加えてみます。
index.mjsはNode.jsのバージョンが20で始まっている場合はエラーをthrowしますので…

.github/workflows/run.yaml
name: Node.js Nightly Demo

on:
  push:

jobs:
  nightly-demo:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version:
-         # 一通りLTSバージョンで動かす
          - 16
          - 18
+         # Nightlyでも実行してみる
+         - 20-nightly

    name: Runs on Node.js ${{ matrix.node-version }}
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.6.0
        with:
          node-version: ${{ matrix.node-version }}
      # 当記事用のスクリプトを実行する
      - run: node index.mjs

このようにワークフロー全体がエラーになり、他のNode.jsバージョンのジョブは途中でキャンセルされました。
NightlyではNode.js側の理由でジョブ失敗のリスクが高いため、Node.js自体を開発する人以外で採用するのは止めた方が良いです。

Nightlyは失敗しても影響ないようにする 👍

そこでNightly版の場合は失敗してもスルーするようにします。

.github/workflows/run.yaml
name: Node.js Nightly Demo

on:
  push:

jobs:
  nightly-demo:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version:
          - 16
          - 18
-         # Nightlyでも実行してみる
-         - 20-nightly
+       experimental:
+         - false
+       include:
+         - node-version: 20-nightly
+           experimental: true

    name: Runs on Node.js ${{ matrix.node-version }}
+   continue-on-error: ${{ matrix.experimental }}
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3.6.0
        with:
          node-version: ${{ matrix.node-version }}
      # 当記事用のスクリプトを実行する
      - run: node index.mjs

まず適当な変数(ここではexperimental)をマトリックスに定義し、それをジョブのcontinue-on-errorに渡します。
continue-on-error: trueにすると、そのジョブが失敗してもワークフロー全体を継続します。
continue-on-errorのリファレンスはここちらです。
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idcontinue-on-error

そして、マトリックスでincludeを使うと、特定の変数値の組み合わせをマトリックスに追加できます。
includeのリファレンスはこちらです。
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrixinclude

上記のマトリックスの場合、以下の組み合わせで実行されます。

node-version experimental
16 false
18 false
20-nightly true

pushしてみたら以下のようになりました。

Nightlyが7秒でジョブに失敗していますが、バージョン16や18のジョブがキャンセルされることもなく、ワークフロー全体が成功になっています。

終わりに

上記の通り、これまでの運用に悪い影響を与えずに、Nightly版でのジョブ実行を加えることができました。
GitHub Actionsはpublicリポジトリーであれば基本的にいくら使っても無料です。少しだけワークフロー定義は複雑になりますが、せっかくならNode.jsのNightlyバージョンを先取りして継続的インテグレーション(CI)に加えてみてはいかがでしょうか。

当記事を書くために参考にしたマニュアルなど

Using a matrix for your jobs - Handling failures
https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#handling-failures

setup-node/advanced-usage.md - Nightly versions
https://github.com/actions/setup-node/blob/v3.6.0/docs/advanced-usage.md#nightly-versions

Discussion