AndroidのCIとテストアプリ配信をサービスアカウントを使ったGithubActions+AppDistributionに載せ替える

##載せ替えた理由
###CI
・BitriseにiOSとAndroidの両方を載せて回していたが、プロジェクト数も多くなり始め契約していたMAX2レーンのプランだとタイミングによって待つ必要が出てきていた。
・それぞれのプロジェクトで使っているBitriseのStepにばらつきが出ていたので、統一するタイミングが欲しかった。
・サーバーサイドがすでに一部載せ替えており、使いやすいし無料枠が余っていると言われていた。
・とりあえず新しい技術には触っておきたかった。

###テストアプリ配信
・FabricのFirebase統合に伴い、Betaが利用できなくなる。
https://docs.fabric.io/apple/beta/overview.html

##完成形
とりあえずGithubActions用のYAMLファイルを載せておきます

```yaml
name: CI

on:
  push:
    branches:
      - develop

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Ruby 2.6
        uses: actions/setup-ruby@v1
        with:
          ruby-version: 2.6.5
      - name: install bundler
        run: gem install bundler:2.0.2
      - uses: actions/setup-node@v1
        with:
          node-version: '10.x'
      - name: install firebase tools
        run: npm install -g firebase-tools
      - name: Set Google GOOGLE_APPLICATION_CREDENTIALS
        run: |
          cat << "EOF" > google_service_account_key.json
          ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
          EOF
      - name: exec fastlane
        run: |
          bundle install --path vendor/bundle
          bundle exec fastlane beta
        env:
          GOOGLE_APPLICATION_CREDENTIALS: ./google_service_account_key.json
```

##解説
当初はFirebaseTokenを使って実装していたのですが、各プロジェクトの担当者がそれぞれtokenの認証通すのか？退社した場合どうするのか？みたいな問題があったため、サービスアカウントを使って実装する運びとなりました。
結構詰まりポイントがあったので、解説していきます。
（ほぼ社内のエンジニアの方に助けてもらってできたので、私はまとめているだけです。皆さんありがとうございました…）

###AppDistributionサービスアカウント情報の格納
まず、サービスアカウントの情報はYAMLから秘匿された状態でGithubActionsから参照できるようにしなければなりません。
これを実現するためにはGithubのSecretsを利用すれば可能ですが、Secretsは以下の通りjson形式のファイル保存をさけるように言及しています。
https://help.github.com/ja/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets

```シークレットの名前には、空白を含めることはできません。 GitHubがログのシークレットを確実に削除するよう、構造化データをシークレットの値として使用することは避けてください。 たとえば、JSONやエンコードされたGit blobを含むシークレットは作成しないでください。```

何度か検証した結果、Secretに改行が含まれているものをYAMLで読み込むと、シェルスクリプトに改行を書いたと解釈されてしまうようです。
なので、Secretに格納する前に、サービスアカウントのjsonから改行を全て取り除きました。
また、サービスアカウントjson内の`""`などもシェルスクリプトの記法として解釈されるため、YAML上でヒアドキュメントを使って文字リテラルとして解釈させます。

加工したjsonをSecret内に格納した上で、以下のスクリプトでgoogle_service_account_key.jsonとして出力します。

```yaml
- name: Set Google GOOGLE_APPLICATION_CREDENTIALS
  run: |
    cat << "EOF" > google_service_account_key.json
    ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
    EOF
```

###AppDistributionの実行
実際にAppDistributionに配信させる部分は、fastlaneから実行します。
fastlaneから実行できるように、PluginFileに以下を記述します。
参考
https://github.com/fastlane/fastlane-plugin-firebase_app_distribution

```
gem 'fastlane-plugin-firebase_app_distribution'
```

fastlaneに先ほど生成したjsonのPathを渡します。
環境変数名`GOOGLE_APPLICATION_CREDENTIALS`にパスを入れて渡してやると、あとは勝手に解釈してくれるようです。
参考
https://firebase.google.com/docs/app-distribution/android/distribute-gradle

```yaml
- name: exec fastlane
    run: |
      bundle install --path vendor/bundle
      bundle exec fastlane beta
    env:
      GOOGLE_APPLICATION_CREDENTIALS: ./google_service_account_key.json
```

既存のlaneのBeta配信だった部分を以下に置き換えます。
hogehogeの部分はFirebaseに登録しているアプリIDに差し替えてください。

```
firebase_app_distribution(
  app: "****************hogehoge****************",
  apk_path: apk_path,
  release_notes: "",
  groups: "GROUP"
)
```

これで準備は完了です。
あとはCIに設定したトリガに引っ掛けて動作させるだけです。

##まとめ
結構Secret周りにクセがあって、Androidエンジニアとしての知識だけだと辛かったです。
いつもGit周りはSourceTreeを利用しているので、CUI周りの知識が乏しく、ヒアドキュメントとか聞いたこともない単語でした:innocent: 
どこかで困っているAndroidエンジニアの助けになればと思います…