GitHub ActionsでElectronアプリのリリースを自動化する

やろうやろうと思っていたけど,できていなかったので,いよいよ自動化した. ここにおけるポイントは,ほぼMacOSをどうするかという話に集約すると思うんだけど,一応Windows/Linuxでもちょっと変更しなきゃいけないことはあったので,書いておく.

リリースのやり方について

ふだん,MAS以外のビルドについてはelectron-builderを使っているんだけど,electron-builderは公式でactionsも出している.

github.com

これを使うと,electron-bulderのconfigにpublish関連の設定を書いたりすることで,ビルドからリリースまで自動でやってくれたりする.が,今回これは使っていない.理由は

  1. リリースフローが違う.Marketplaceのactionsでは,タグ等を起因にしてリリースを自動作成するactionsが非常に多いが,私はリリースを作成した後に,そのリリースのpublishを起因にCDが動いて成果物を,作成したreleaseのassetsにつけてほしい.
  2. .deb.tar.bz2の成果物以外に,そのshasumもアップロードしたい.

というのが大きいところだ.特に1は大事で,リリース時に変更点は毎回書いておきたい.しかし,自動でリリースを作成されると,こういうことが非常にやりにくく,どう考えてもリリース後に手動で本文を書き換える必要がある.リリースに関する手動作業を限りなく少なくしたいのに,CD完了を見計らって本文を書き換えるなど許容できないaction-gh-releaseなどはテンプレート機能も用意してあるが,そうじゃないんだ,毎回ではないけどリリースのときには注意点とかBreaking Changesを書きたいのだ.そうなるとどうしてもこれらは候補から外れる.

というわけで,基本的には自前でビルドし,アップロードも複数のactionsを組み合わせて行うこととする.

MacOS向けのアプリをGitHub Actions内でビルドする

何はともあれビルドだ.MacOSで面倒なのはCodeSignとNotarizeだろう.

今回はここを参考にした.

kent-and-co.com

CodeSignする

これはApple公式のactionsでかなり楽になっている.

github.com

      - name: Apple Codesigning
        uses: apple-actions/import-codesign-certs@v1
        with:
          p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
          p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}

こんなのだけで良い. まず,CERTIFICATES_P12 についてだが,こちらは,Developer ID Application の証明書を使う(Developer ID Installer ではないことに注意).Mac上で,この証明書をp12形式で書き出す.このとき,適当なパスワードを設定してやる. このときに設定したパスワードを CERTIFICATES_P12_PASSWORDとしてactionsのsecretsに入れる. p12形式の証明書の方は

$ base64 -i <CERT_FILE_NAME>.p12

として,出てきた値を CERTIFICATES_P12 としてactionsのsecretsに入れる.基本的にこれでCodeSignは完了する.

Notarizeする

まず,notarize用のスクリプトを用意する.この辺の作業はローカルでnotarizeするときも必要になるので,すでに設定済みの場合は読み飛ばして良い.

const { notarize } = require('electron-notarize')

exports.default = async function notarizing(context) {
  const { electronPlatformName, appOutDir } = context
  if (electronPlatformName !== 'darwin') {
    return
  }

  const appName = context.packager.appInfo.productFilename

  return await notarize({
    tool: 'notarytool',
    appBundleId: 'org.whalebird.desktop',
    ascProvider: process.env.ASC_PROVIDER,
    appPath: `${appOutDir}/${appName}.app`,
    appleId: process.env.APPLE_ID,
    appleIdPassword: process.env.APPLE_PASSWORD,
    teamId: process.env.TEAM_ID
  })
}

こいつをelectron-builderの設定に入れる.

{
  "productName": "Whalebird",
  "appId": "org.whalebird.desktop",
  "artifactName": "${productName}-${version}-${os}-${arch}.${ext}",
  "afterSign": "build/notarize.js",

ここからactionsの設定になる.

  release-darwin:
    name: Release for MacOS

    runs-on: macos-11
    # ...
      - name: Package
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
          ASC_PROVIDER: ${{ secrets.ASC_PROVIDER }}
          TEAM_ID: ${{ secrets.TEAM_ID }}
        run: |
          yarn run build:mac

で,あとは環境変数を与えてやれば良い.

  • APPLE_ID は,そのままAppleのログイン時に使うIDで良い.
  • APPLE_PASSWORDは,App用パスワードを用意し,それを入れれば良い.参考にした記事では,altoolを使ってactionsのVM上のkeychainにパスワードを入れているが,notarizeにnotarytoolを使う場合は不要である.legacyを使う場合は,このままでは認証できなかったので,keychainが必要なのかもしれない.
  • ASC_PROVIDERTEAM_IDは同じ値でいけた.どちらもTeam Shortnameで問題なかった.

notarizeにnotarytoolを使う場合は,osはmacos-latestではダメだった.notarytoolはXCode13で入ったツールであり,Big Sure以降でないと使えない.ちなみに2022年1月4日現在,GitHub Actionsのmaxos-latestはBig SureではなくCatalinaである.なので,maxos-latestではnotarytoolが使えず,maxos-11とする必要がある.

docs.github.com

なお,shasumを計算するにあたり,MacOSでは

$ shasum -a 256 file_path

を使った.

Linux向けアプリをビルドする

基本的にubuntu-latestでだいたいビルドできるが,一つ問題だったのはpacmanである.pacmanだけはビルドエラーになった.

⨯ cannot execute  cause=exit status 1
                    out={:timestamp=>"2022-01-03T14:13:17.667212+0000", :message=>"Process failed: /bin/sh failed (exit code 127). Full command was:[\"/bin/sh\", \"-c\", \"LANG=C bsdtar -czf .MTREE --format=mtree --options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' opt .INSTALL usr .PKGINFO\"]", :level=>:error}

                    command=/home/runner/.cache/electron-builder/fpm/fpm-1.9.3-2.3.1-linux-x86_64/fpm -s dir --force -t pacman -d c-ares -d ffmpeg -d gtk3 -d http-parser -d libevent -d libvpx -d libxslt -d libxss -d minizip -d nss -d re2 -d snappy -d libnotify -d libappindicator-gtk3 --pacman-compression xz --architecture i686 --after-install /tmp/t-MalZPa/4-after-install --after-remove /tmp/t-MalZPa/5-after-remove --description '
     An Electron based Mastodon client for Windows, Mac and Linux' --version 4.5.0 --package /home/runner/work/whalebird-desktop/whalebird-desktop/build/Whalebird-4.5.0-linux-i686.pacman --name Whalebird --maintainer 'AkiraFukushima <h3.poteto@gmail.com>' --url 'https://github.com/h3poteto/whalebird-desktop#readme' --vendor 'AkiraFukushima <h3.poteto@gmail.com>' --license MIT /home/runner/work/whalebird-desktop/whalebird-desktop/build/linux-ia32-unpacked/=/opt/Whalebird /home/runner/work/whalebird-desktop/whalebird-desktop/build/icons/256x256.png=/usr/share/icons/hicolor/256x256/apps/whalebird.png /tmp/t-MalZPa/e-Whalebird.desktop=/usr/share/applications/whalebird.desktop
                    workingDir=

これについては未解決である.

おそらくubuntupacmanをビルドするにはなにか足らないものがある気がするのだが,ローカルはManjaroなので再現できなかった.また,そもそもGitHubのreleaseにpacmanを入れる必要性が今の所ないので,pacmanをスキップすることにした.AURを用意してあれば,ほぼそれで問題ないだろうしね.

Windows向けアプリをビルドする

Windowswindows-latest(初めて使った)で無事ビルドできた.ia32もx64も両方とも同じOSでビルドできたし,特に問題はなかった.

なお,shasumを計算するにあたり,Windowsでは

$ sha256sum file_path

を使った.Windowsにはshasumコマンドが存在しなかった.

Publishについて

github.com

こちらを使っている.

triggerは

on:
  release:
    types: [published]

こう.createdでもいいんだけど,createdだと,releaseをdraft -> publishしたときにtriggerしてくれない.

基本的にはこれで成果物をreleaseにあげている.asset_pathに上げたいもののパスを指定すれば良い.

      - uses: shogo82148/actions-upload-release-asset@v1
        with:
          upload_url: ${{ github.event.release.upload_url }}
          asset_path: "build/Whalebird-*.dmg"
      - uses: shogo82148/actions-upload-release-asset@v1
        with:
          upload_url: ${{ github.event.release.upload_url }}
          asset_path: "build/Whalebird-*.shasum"

とかしておけば,成果物もshasumもアップロードできる.

snapについて

生成されたもののうち,github releaseではないところにアップロードしたいものもある.一つはsnapだ.

これについては

github.com

を使っている.

      - uses: snapcore/action-publish@v1
        with:
          store_login: ${{ secrets.STORE_LOGIN }}
          snap: "build/Whalebird-${{ github.event.release.name }}-linux-amd64.snap"
          release: beta

とかしておけば良い.