2019-10-05

GitHub Actionsでpkgを使ったNode.js実行バイナリをWindowsを含めてmatrixビルドする

目的

pkgでNode.jsスクリプトを実行バイナリにする - あーありがち(2019-10-04) において、各プラットフォーム上で pkg を叩けば Node.js スクリプトを Windows, macOS, Linux それぞれで動く単体のバイナリにできることは分かった。

今日はこの pkg を使って各 platform 上で build する処理を GitHub Actions で自動化してみたときのメモ。これが完成すれば基本的には Windows 上のちょっとしたツールを、いつもの macOS で、いつもの JavaScript で書いて git push すればオッケーと言える。便利。

※ 現時点では公開できる完成リポジトリはないので、日本語だけ。

対象

CircleCI など YAML で CI の設定をした経験のある人向け。細かい説明は一切しません。

参考

GitHub ActionsでElectronアプリのクロスプラットフォームバイナリを配布する | Web Scratch

メモ

About GitHub Actions - GitHub Help

matrixビルド

複数の環境を指定していくつもビルドを実行することをmatrixビルドと呼ぶらしい。これは GitHub Actions 独特のものではない。

  • strategy で matrix を指定したうえで runs-on は ${{ matrix.os }} で
  • pkg の target にはこの matrix.os をそのまま使うことはできないので、「matrix.os を加工する action」を加える必要がある

環境の課題

  • step の run に複数行与える書き方は Windows 標準の shell の cmd では正しく動かない1
  • run の中の文字列は shell の世界。bash だったり cmd だったりするので env の展開方法はそれぞれ異なる
  • うっかり yarn <command> と書くと Windows では動かない。しっかり yarn run <command> と書く。

YAMLの中の条件判別などのSyntax大事

Contexts and expression syntax for GitHub Actions - GitHub Help

何が大事って、この部分は shell でも JavaScript でもない独自の文法の世界ってこと。リファレンス見ないと分からないし、オフラインの linter などもまず存在しない世界。

Actionの書き方

  • uses で action を利用する際の書き方は二種類。GitHub上のactionとそのバージョンの指定か、同一repos内のディレクトリのいずれか。外部のリポジトリを指す場合はバージョンを明記しろと言われるが、ローカルのファイルの場合はむしろ書いたらダメ。
    • <owner/repos@version>
    • ./.github/actions/<name>
  • uses で action を利用する場合、inputs / outputs ともに決められた方法でやりとりする
  • action を JavaScript で書く場合、npm install は実行されないので node_modules も含める。Linux / macOS ではなんとなく動く場合もあるけど、Windows だとちゃんとエラーになる。

..github/ ディレクトリの中に直接 action を置いてしまってもよいが、uses の書き方がやや異なるので注意が必要。

共通で使いそうなものは独立させて Creating a JavaScript action - GitHub Help に書いてある通り zeit/ncc を使って node_modules 込みでパッケージにしてしまった方がテストもしやすい(入出力は環境変数っぽい)のでよさそう。

※ 急に zeit さんと親しくなってしまった。

役に立つAction

release にできあがった file を upload する方法に go binary を使っている記事も見かけたけど、action があるのでそっちを使う方が手軽でよさげ。

matrix buildしてるYAMLの例の一部

outputs の読み取り方が結構独特。

run-on: ${{ matrix.os }}

strategy:
  matrix:
    os: [macos-latest, windows-latest, ubuntu-latest]

steps:
  - uses: <owner/repos@version>
    id: <action>
    with:
      os: ${{ matrix.os }}
  - name: package executable
    env:
      <NAME>: ${{ steps.<action>.outputs.<name> }}
    run: command $<NAME>
    if: matrix.os == 'windows-latest'
  - name: package executable
    env:
      <NAME>: ${{ steps.<action>.outputs.<name> }}
    run: command %<NAME>%
    if: matrix.os != 'windows-latest'

ここで env, if の部分は完全に GitHub Actions 独自の Syntax で、if の部分は ${{ }} で囲まなくてもよい。ただし、参照できるオブジェクトは決まっている。

run の中身は shell で実行されるので、shell に応じて環境変数の展開方法などを変える必要がある。

  1. 少なくとも 2019-10-05 時点で 

About

例によって個人のなんちゃらです