GitHub ActionsでUnityのAndroid, iOSビルドをやってみる(運用編)

この記事は [Akatsuki Advent Calendar 2020](https://adventar.org/calendars/5174) 21日目の記事です。
前日は [Ruby on Rails 6.1 の水平シャーディング対応 & Octopusからの移行事例](https://hackerslab.aktsk.jp/2020/12/20/040504) でした。
[アカツキ人事がハートドリブンに書く Advent Calendar 2020](https://adventar.org/calendars/5563) もあるのでそちらもぜひ。

はじめに
---
去年の Advent Calendar で [GitHub ActionsでUnityのAndroid, iOSビルドをやってみる](https://qiita.com/johro/items/0a846bebfe3899410164) という記事を書きました。
あれから1年が経ち、自分が所属しているプロジェクトで実際に GitHub Actions を使った CI 環境を構築し運用しているので、その事について書いていきたいと思います。

GitHub Actions ってなに？という方や GitHub Actions の細かい導入方法を知らない方は前回の記事を読んでもらえると嬉しいです！！


全体の流れ
---
初めに全体の流れを図示した画像をお見せします。

![CIworkflow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153196/6fbf8859-ad66-5374-cbff-a8c3ee17d615.png)


大まかに説明をすると
1. GitHub Actions がイベントを検知して `.github/workflows` にある ワークフローファイルに記述されている処理を `self-hosted` で登録している PC で実行
2. ワークフローファイルでリポジトリの更新や環境変数の定義し `build.sh` を実行
3. `build.sh` で Unity から iOS, Android 向けのビルドを行い、 `fastlane` で `xcodeproj` → `ipa` へのビルドや `DeployGate` へのアップロードを行なっています

ワークフローファイルについて
---

まずはワークフローファイルの内容は以下のような内容です（一部書き換えを行ったりしています）

```yml
name: Build

on:
  schedule:
     - cron: "0 3 * * 1-5"
  workflow_dispatch:
    inputs:
      clean:
        description: 'Clean build.'
        required: true
        default: 'false'
      delete_output:
        description: 'Delete output file.'
        required: true
        default: 'true'
      upload:
        description: 'Upload to deploygate.'
        required: true
        default: 'false'
  pull_request:
    branches: [ development ]

env:
  UNITY_VERSION: 2019.4.0f1
  SLACK_URL: ${{secrets.SLACK_URL}}
  CLEAN: ${{github.event.inputs.clean}}
  DELETE_OUTPUT: ${{github.event.inputs.delete_output}}
  UPLOAD: ${{github.event.inputs.upload}}

jobs:
  buildAndroid:
    # The type of runner that the job will run on
    runs-on: [self-hosted, macOS, for-Android]

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
    # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
    - name: Checkout client
      uses: actions/checkout@v2
      with:
        path: client
        clean: 'false'
        lfs: 'true'
        submodules: 'true'
        token: ${{secrets.PERSONAL_ACCESS_TOKEN_FOR_GITHUB}}

    - name: Checkout resource
      uses: actions/checkout@v2
      with:
        repository: resource
        path: resource
        lfs: 'true'
        token: ${{secrets.PERSONAL_ACCESS_TOKEN_FOR_GITHUB}}

    # Runs a single command using the runners shell
    - name: Build Android
      run: |
        if [ ${{github.event_name}} == "pull_request" ]; then
          sh client/CI/build.sh -p Android -c false -d true -u false
        fi
        if [ ${{github.event_name}} == "schedule" ]; then
          sh client/CI/build.sh -p Android -c false -d true -u true
        fi
        if [ ${{github.event_name}} == "workflow_dispatch" ]; then
          sh client/CI/build.sh -p Android -c ${CLEAN} -d ${DELETE_OUTPUT} -u ${UPLOAD}
        fi
      env:
        # fastlane 向けのパスワードや Apple のアカウント情報など渡したい機密情報を環境変数として渡す

  buildIOS:
    runs-on: [self-hosted, macOS, for-iOS]

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
    # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
    - name: Checkout client
      uses: actions/checkout@v2
      with:
        path: client
        clean: 'false'
        lfs: 'true'
        submodules: 'true'
        token: ${{secrets.PERSONAL_ACCESS_TOKEN_FOR_GITHUB}}

    - name: Checkout resource
      uses: actions/checkout@v2
      with:
        repository: resource
        path: resource
        lfs: 'true'
        token: ${{secrets.PERSONAL_ACCESS_TOKEN_FOR_GITHUB}}

    - name: Build iOS
      run: |
        if [ ${{github.event_name}} == "pull_request" ]; then
          sh client/CI/build.sh -p iOS -c false -d true -u false
        fi
        if [ ${{github.event_name}} == "schedule" ]; then
          sh client/CI/build.sh -p iOS -c false -d true -u true
        fi
        if [ ${{github.event_name}} == "workflow_dispatch" ]; then
          sh client/CI/build.sh -p iOS -c ${CLEAN} -d ${DELETE_OUTPUT} -u ${UPLOAD}
        fi
      env:
        # fastlane 向けのパスワードや Apple のアカウント情報など渡したい機密情報を環境変数として渡す

``` 

ではそれぞれ解説をしていきます。
全部は解説しないので漏れてしまったものはドキュメントを読んでください。
なお、解説の内容は 2020/12 時点の内容となっています。

#### on
`on:` はワークフローをトリガーするGitHubイベントの名前です。
プロジェクトの状況に合わせて適宜変えてください。
ここでは `schedule（定期実行）`, `workflow_dispatch(手動実行)`, `pull_request(PRが作成、更新された時に実行)`の3種類を使っています。
`workflow_dispatch` では入力を定義できるので、任意のパラメータを設定することが可能です。
また、デフォルト値の設定も可能なので入力がなければデフォルト値を使う、ということがもできます。

#### env
それぞれの `Job` で共通で使う環境変数を定義します。
なお、機密情報は Secrets を利用しワークフローファイルに直接書かないようにしましょう。

#### runs-on
`iOS` と `Android` で実行する Runner を分けたい場合もあると思います。
その際には `iOS`, `Android` それぞれのラベルを用意することでジョブを実行するマシンを選択することができます。
ラベルは `Self-hosted runners` のページから設定できます。
![スクリーンショット 2020-12-18 22.18.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153196/20c3ce5c-4df8-a87c-dcd8-8d08c5a73383.png)

#### actions/checkout@v2
リポジトリを取得、更新します。
複数のブランチを取得することもできます。詳細は[こちら](https://github.com/actions/checkout)で確認してください。

#### Build
`build.sh` にパラメータを渡して実行しています。
ここは説明する必要はないと思うので飛ばします。

大まかにですが、以上でワークフローファイルの説明を終わりにします。

その他 Tips
---
### Unity のバージョンをワークフローファイルに直接記述する
Unity のバージョンはワークフローファイルに直接書きます。
こうすることでバージョンアップ対応の際にそのブランチだけ Unity のバージョンを変更する、ということができるためです。

### GitHub から手動で実行する
`workflow_dispatch` を定義すると
このように `GitHub` の `Actions` から実行できるようになります。もちろんパラメータの設定も可能です。
これで手動実行もできるようになります！便利ですね！~~(最近まで知らなかった)~~
![スクリーンショット 2020-12-18 23.08.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153196/a72c5315-c6f7-5d9e-4be7-2d28835ffc86.png)

### GitHub Actions の Runner を複数登録する
自分が所属しているプロジェクトでは self-hosted として動かしている PC が一台あり、この PC から Runner として4つ登録しています。
そして Runner にラベルを付けることで、 iOS, Android のビルド処理を分けて実行させています。
こうすることでプラットフォーム切替を発生させずに高速化しています。

まとめ
---
去年の記事を書いてからプロジェクトに導入する機会があったため、実際に導入して運用しそこで行なった工夫を書いてみました。
GitHub Actions で Unity のビルドを行おうとしている方の参考になれば幸いです。
今年は [AWS の Mac インスタンス](https://aws.amazon.com/jp/about-aws/whats-new/2020/12/aws-announces-mac-instances-amazon-ec2/) も発表され、Unity の ビルド環境 がまた一歩進みましたね。移行したい。