Mobile Factory Tech Blog

技術好きな方へ!モバイルファクトリーのエンジニアたちが楽しい技術話をお届けします!

GitHub Actions で nodenv を扱う方法

こんにちは。ブロックチェーンチームのソフトウェアエンジニアの id:odan3240 です。

下記の記事で紹介した通り、ブロックチェーンチームではバックエンドでも Node.js を使用しています。 tech.mobilefactory.jp

フロントエンドとバックエンドのソースコードは同一リポジトリで管理するモノレポを採用しています。

使用しているライブラリやプラットフォームの違いもあり、フロントエンドとバックエンドでは異なる Node.js のバージョンを使用しています。複数のバージョンを使い分けるために開発環境では nodenv を導入しています。

この記事ではチームで実践している GitHub Actions で nodenv を使用して複数の Node.js のバージョンを使い分ける方法を紹介します。

公式の Actions はあるが Node.js のインストールは行われない

nodenv の Organization が Actions を公開しています。

github.com

これを使えばバージョンの使い分けができるように見えます。しかしこの Actions は nodenv コマンドをインストールするだけで、その先の環境の設定や指定したバージョンの Node.js のインストールは自分で行う必要があります。

setup-node だと Node.js のバージョンの切り替えができない

GitHub Actions で Node.js のインストールというと setup-node を思い浮かべる人が多いでしょう。

しかしこの Actions は一時的に PATH に含まれる node コマンドを置き換えるだけです。nodenv の機能にある、都度ローカルの .node-version ファイルを読んでバージョンの違う node コマンドを実行できるようにはなりません。

そのため今回のようなディレクトリごとに Node.js のバージョンを切り替えたい要求には使用することができません。

解決策

今回は次の Actions を書いて問題を解決しました。今回のサンプルコードは GitHub に置いてあります。

重要なステップを1つずつ説明していきます。

name: CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - uses: nodenv/actions/setup-nodenv@v2

      - name: Install node-build
        run: |
          mkdir -p "$(nodenv root)"/plugins
          git clone https://github.com/nodenv/node-build.git "$(nodenv root)"/plugins/node-build

      - name: Install node
        run: nodenv install -s

      - name: Run nodenv init
        run: |
          echo "$(nodenv root)"/shims >> $GITHUB_PATH
          echo "NODENV_SHELL=bash" >> $GITHUB_ENV
          nodenv rehash

      - name: Check node version
        run: node -v

Install node-build について

nodenv だけでは Node.js のインストールができないため node-build を別途インストールする必要があります。

node-build の README で説明されている通り nodenv のプラグインとしてインストールしています。

github.com

Run nodenv init について

nodenv init 相当のセットアップを行っています。

開発環境に nodenv をインストールする場合、eval "$(nodenv init -)" を実行するか .bashrc.zshrceval "$(nodenv init -)" を追記する必要があります。self-hosted not using bashrc · Discussion #25407 · community を参考に .bashrc に追記する方法も試してみましたが環境変数が設定されませんでした。

これは、GitHub Actions では変数を export しても環境変数として扱われないことが原因だと予想して、手動で設定する方針にしました。

dev.classmethod.jp

GitHub Actions 上で nodenv init を実行したときの出力内容は次の通りです。

export PATH="/home/runner/.nodenv/shims:${PATH}"
export NODENV_SHELL=bash
source '/opt/hostedtoolcache/nodenv/1.3.1/x64/libexec/../completions/nodenv.bash'
command nodenv rehash 2>/dev/null
nodenv() {
  local command
  command="${1:-}"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  rehash|shell)
    eval "$(nodenv "sh-$command" "$@")";;
  *)
    command nodenv "$command" "$@";;
  esac
}

これに相当することを GitHub Actions 流の設定方法で step に記述しています。

これらの対応を行うことで、GitHub Actions でも cd すると自動的に .node-version の Node.js が実行されるようになります。

まとめ

  • ブロックチェーンチームではモノレポでディレクトリごとに異なる Node.js のバージョンを使用している
  • 開発環境と同様に GitHub Actions でも nodenv で Node.js を使い分けたくなった
  • nodenv/actions/setup-nodenvactions/setup-node では目的を達成できない
  • nodenv init の内容に相当する処理を step に書くと、自動的に Node.js のバージョンが切り替わるようになる