GitHub Actions の Matrix build で各 OS 向けの Electron アプリをビルドする

Scrapbox の野良 Electron アプリ sbe をリリースするときは、macOS / Windows のバイナリをそれぞれ MacBook Pro や Windows ラップトップでビルドし GitHub の Release Draft にアップロードして公開しています。ビルドが1箇所でできないのは結構めんどくさいものです。

GitHub Actions の Matrix build を使うと複数の OS・複数のランタイム環境 (複数バージョンの Node.js 環境など) の組合せのビルドやテストを1つの Workflow で一気に実行できます。これを使って面倒な各 OS 向けのビルドを CI 化しようと思いました。

GitHub Actionsのワークフロー構文 - GitHub ヘルプ

Matrix build の Matrix パラメータには Ubuntu / Windows / macOS などを仮想環境として指定可能です。

LinuxおよびWindowsのGitHub Actions仮想環境は、GitHub Actions runnerがインストールされたMicrosoft AzureのStandard_DS2_v2仮想マシン上にホストされています。 GitHub Actions runner は、Azure Pipelines Agent のフォークです。 Standard_DS2_v2マシンリソースに関する詳しい情報については、Microsoft Azureドキュメンテーションの「DSv2-series」を参照してください。 GitHubは、macOS仮想環境のホストにMacStadiumを使用しています。

GitHub Actionsの仮想環境 - GitHub ヘルプ

GitHub が Microsoft に買収されたことで Azure の Windows Server 環境を Action の実行環境として使えるみたいですね。MacStadium は iOS / macOS アプリの CI/CD サービスのようです。

www.macstadium.com

今回は Matrix build により macOS と Windows 環境で下記ステップを実行します。

  • リポジトリへの tag push をトリガーとして開始する
  • Node.js 環境を構築する (最新の v12 系のみ)
  • OS に応じた npm script (electron-packager) を実行する
  • 生成されたバイナリーを zip 圧縮する
  • 圧縮されたバイナリーを成果物として保存する

実際の Workflow 定義です。

name: Build sbe binaries

on:
  push:
    branches:
      - "!*"
    tags:
      - "v*"

jobs:
  build:

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

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

    steps:
    - uses: actions/checkout@v1
    - name: setup nodejs
      uses: actions/setup-node@v1
      with:
        node-version: 12.x
    - name: install dependencies
      run: npm install

    - name: package for macOS
      if: matrix.os == 'macos-latest'
      run: |
        echo ${GITHUB_REF}
        npm run package-macos
        zip -ry sbe-darwin-x64/sbe-macos.zip sbe-darwin-x64/sbe.app
    - name: archive package for macOS
      if: matrix.os == 'macos-latest'
      uses: actions/upload-artifact@master
      with:
        name: sbe-v-macos
        path: ./sbe-darwin-x64/sbe-macos.zip

    - name: show ref tags
      if: matrix.os == 'windows-latest'
      run: echo %GITHUB_REF%
    - name: package for Windows
      if: matrix.os == 'windows-latest'
      run: npm run package-win32
    - name: zip package for Windows
      if: matrix.os == 'windows-latest'
      run: powershell Compress-Archive -Path sbe-win32-x64 -DestinationPath sbe-windows.zip
    - name: archive package for Windows
      if: matrix.os == 'windows-latest'
      uses: actions/upload-artifact@master
      with:
        name: sbe-v-windows
        path: sbe-windows.zip

v で始まる名前の tag が push された場合に起動するようにトリガーを設定しています。

Job の Matrix パラメータ に windows-latestmacos-latest を指定して Matrix build を実行しています。

step 毎に if expression を使って Matrix パラメータ (os) を判定し実行するコマンドを使い分けています。macos では bash を、Windows では cmd.exe ( と PowerShell) で動作するコマンドを記述しています。

GitHub Actions (beta) の Windows 仮想環境では、run: で複数コマンドを実行できないようでしたので step を分割し1コマンドずつ実行するようにしました。

push された tag の名前はビルトインの環境変数 GITHUB_REF に格納されます。artifact のファイル名に tag 名を使いたいのですが、GITHUB_REF に設定される値は refs/tags/v1.0.2 のような形式なのでそのままファイル名に使用することができません。GitHub Actions の関数には文字列の join はあるのに split がないという状況です。

GitHub Actions のコンテキストおよび式の構文 - GitHub ヘルプ

ということで tag 名を upload-artifat の path に指定するのは断念し、echo で出力するのみとしています。

Workflow を実行すると OS 毎にジョブがパラレル実行され、ビルド済みのバイナリーが Artifact として保存されます。

f:id:kondoumh:20190915211234p:plain

GitHub Actions で各 OS 向けのバイナリのビルドを 1つの Workflow で実現できました。今後は、GitHub API で Release Draft にアップロードする Job や UI テストを実行する Job を追加していきたいと思っています。

追記) electron-packager -> electron-builder に移行することで OS 固有の処理がなくなり if expression はなくすことができました。

blog.kondoumh.com

参考記事:

www.kaizenprogrammer.com