[iOS] GitHub Actionsでfastlaneのmatchを使わずにAdHoc書き出しをしてからFirebase App Distributionにアップロードする

こんにちは!きんくまです。

今回は「GitHub Actionsでfastlaneのmatchを使わずにAdHoc書き出しをしてからFirebase App Distributionにアップロードする」です!(長いっ)

作ったGitHub Acitonsのワークフロー

  1. GitHubでプルリクを作ってから、マージされたイベントをトリガーにする
  2. macOSを立ち上げる
  3. fastlaneを使う
  4. テストする。失敗したらSlackに通知
  5. AdHocビルドする。
    その際、証明書とプロビジョニングファイルはGitHubのsecretsに登録したものを使用する
    登録するファイルはbase64化したもの
  6. Firebase App Distributionにアップロードする
  7. Slackに通知

参考にした神情報のみなさま

先に申し上げますと、さきほど「作った」と書いてしまったのですが、先人のみなさまの情報を元に組み合わせて作成しました。
ありがとうございます!

Gemfile

fastlaneだけ書いてます。

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "fastlane", "2.139.0"

plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

fastalneにFirebase App Distributionのプラグイン追加

fastlane add_plugin firebase_app_distribution

参考

このコマンドを打つと fastalne/Pluginfile が追加されます。これもGitにコミットしてください。

ワークフローファイル

2020/02/11修正 Carthageのif文追加しました。

adhoc.yml

name: AdHoc Distribution

on: 
   pull_request:
     branches: [master]
     types: [closed]

jobs:
  build:

    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v2

    # Firebaseのため
    - uses: actions/setup-node@v1
      with:
        node-version: '10.x'
    - name: Bundle Install
      run: bundle install

    # Xcode 11.2.1 を使う
    - name: Select Xcode version 
      run: sudo xcode-select -s '/Applications/Xcode_11.2.1.app'

    - name: Show Xcode version
      run: xcodebuild -version

    - name: Keychain.p12
      run: |
        echo "${{ secrets.P12_BASE64 }}" > ios_distribution.p12.txt
        base64 --decode ios_distribution.p12.txt > ios_distribution.p12

    - name: ProvisioningProfile
      run: |
        echo "${{ secrets.PROVISIONING_BASE64 }}" > adhoc.mobileprovision.txt
        base64 --decode adhoc.mobileprovision.txt > adhoc.mobileprovision

    - name: list files
      run: ls -l

    - name: Cache Carthage
      uses: actions/cache@v1.1.2
      id: cache-carthage
      with:
        path: Carthage
        key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
        restore-keys: |
          ${{ runner.os }}-carthage-

    - name: Carthage
      if: steps.cache-carthage.outputs.cache-hit != 'true'
      run: carthage bootstrap --platform iOS --no-use-binaries --cache-builds

    - name: Tests
      env:
        SLACK_URL: ${{ secrets.SLACK_URL }}
      run: |
        bundle exec fastlane tests

    - name: Upload Tests Result
      uses: actions/upload-artifact@v1
      with:
        name: test-results
        path: fastlane/test_output/report.html

    - name: Adhoc
      env:
        KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}  
        SLACK_URL: ${{ secrets.SLACK_URL }}
        CERT_PASSWORD: ${{ secrets.CERT_PASSWORD }}
        FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
      run: |
        npm install -g firebase-tools
        bundle exec fastlane adhoc

Cacheについて

2020/02/11追記

Carthageのキャッシュ設定を上のyamlでは入れているのですが、この設定だと残念ながらできません。

[warning]No scopes with read permission were found on the request.

というメッセージが実行時に出力されます。

調べてみると、Cacheが使えるのはpushとpull_requestのみです。
ただしpull_requestにtypesを指定すると使えなくなりました、、、。
上のyamlでは、typesにclosedを指定しています。これはプルリクをマージしたときのイベントです。
pull_requestのデフォルトのtypeは opened, synchronize, reopenedとなっていて、何も指定しないとこのイベントでワークフローが走ります。ですが、今現在はこれ以外を指定するとダメだというだと思います。

なので、types設定を削除すれば、上のyamlでもCacheが使えるようになります!
そのうちclosedでも使えるようになれるといいなー

Fastfile

Fastfile

default_platform(:ios)

platform :ios do

  desc "Unit Tests"
  lane :tests do
    scan(
        scheme: "スキーム名",
        device: "iPhone 11",
        clean: true,
        slack_message: "テストが完了しました!",
        slack_url: ENV["SLACK_URL"],
        slack_only_on_failure: true
    )
  end

  desc "Import Certificates and Provisioning Profile"
  private_lane :import_certificates_and_provisioning_profile do
    create_keychain(
        name: "mykeychain",
        password: ENV["KEYCHAIN_PASSWORD"],
        timeout: 1800
    )
    import_certificate(
      certificate_path: "ios_distribution.p12",
      certificate_password: ENV["CERT_PASSWORD"],
      keychain_name: "mykeychain",
      keychain_password: ENV["KEYCHAIN_PASSWORD"]
    )
    install_provisioning_profile(path: "adhoc.mobileprovision")
  end

  desc "Archive AdHoc and send to Firebase"
  lane :adhoc do
    import_certificates_and_provisioning_profile
    build_app(project: "プロジェクト名.xcodeproj",
              scheme: "スキーム名",
              configuration: "Configuration名",
              clean: true,
              export_options: {
                  method: "ad-hoc"
              })
    firebase_app_distribution(
              app: "Firebaseプロジェクトから取得したApp ID (AppleのBundle IDではない)",
              groups: "developer",
              release_notes: "ベータ版配信",
              firebase_cli_path: `which firebase`.strip()
          )
    slack(
        message: "ベータ版が配信されました\nhttps://appdistribution.firebase.dev/app_distro/projects",
        slack_url: ENV["SLACK_URL"]
        )
  end

end

CocoaPods使っているときは、projectじゃなくて、workspace指定してくださいまし。

firebase_app_distributionのappのところだけ補足

設定ページのここです

<a href="https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2020/01/github_actions200125_fig1.png"><img src="https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2020/01/github_actions200125_fig1-640x585.png" alt="" width="640" height="585" class="alignnone size-medium wp-image-525914" /></a>

GitHubのSecretsに登録するもの

Secretsは、GitHubの画面上のSettingsタブ > 画面左のSecretsメニュー から見れます。<br> ただし、権限がないと見れないかも

キー 何するもの?
P12_BASE64 base64化されたAcHoc用のp12証明書
PROVISIONING_BASE64 base64化されたプロビジョニングプロファイル
SLACK_URL 投稿したいチャンネル情報のWebhook URL
KEYCHAIN_PASSWORD 適当なキーチェーン用パスワード(一時的なものなのでわからなそうなやつであればなんでも)
CERT_PASSWORD キーチェーンから証明書を書き出した際に使用したパスワード
FIREBASE_TOKEN firebaseをCIから利用するときのトークン

ファイルをbase64化する

キーチェーンからp12ファイル形式で書き出したAdHoc用証明書と、プロビジョニングファイルはbase64化します。

コマンド例

openssl base64 -in cert.p12 -out cert_base64.txt

base64化すれば、バイナリファイルがテキストファイルに変換できるのでsecrets内に登録することができます。<br> それをワークフロー内でbase64デコードしてバイナリファイルに戻してあげて使用します。

FIREBASE_TOKEN

firebase login:ci

を実行すると、こんな感じになります。

Waiting for authentication...

✔  Success! Use this token to login on a CI server:

ここにトークンが書いてあります

fastalneから書き出されたテスト結果ファイル

ここにあります。

まとめ

ここではfastlaneを使いました。ですが、yaml内のrunにコマンドを書けば、xcodebuildコマンドでもいけるみたいです。
あと、acitions/checkoutは@v2が出ていたので、そちらにしました。

あと、チームのみんなと料金表見ていたのですが、macランナーはLinuxランナーに対して10倍のポイント分(と呼べばよいのか?)を消費するみたいなので、少し気をつけた方が良いかもしれないです。

ただ、普段使っているGitHubでCI/CDが使えるというのはとても便利だと思いました!
ではでは。