GitHub Actions を使って Android の CI 環境を整えてみようと思います。
今回は PR が master にマージされたら、ビルドして Firebase App Distribution に apk をデプロイ (+ Slack でデプロイ完了を通知) するまでを目指します。
Firebase の準備
まずは Firebase のアカウントを準備しましょう。
Firebase のプロジェクトを作成
Firebase にプロジェクトを作成し、Android アプリを追加します。
追加できたら、サイドメニューから 品質 -> App Distibution を選びます。
App Distribution を開始してテスターを追加してください。
アプリを配布するだけなら google-services.json は必要ありません。
FCM とか使う場合は組み込んでおきましょう。
ただし、google-services.json をパブリックリポジトリで使う場合は少し工夫がいるので後ほど説明します。
これで Firebase App Distribution で apk を配布する準備ができました。
作成したプロジェクトから アプリ ID を取得
GitHub Actions から App Distribution で配布するために、該当のアプリ ID を控えておきます。
Firebase のトークンを取得
以下のリファレンスを参考に CI サーバ用のアクセストークンを取得します。
まず、Firebase CLI をインストールします。
Mac の方は brew でインストールできます。
$ brew install firebase-cli
次に、ci サーバにログインするコマンドを入力します。
$ firebase login:ci
するとブラウザに連携されるので、Firebase Console にログインするアカウントを選択します。
以下の様な表示がされていればログイン成功です。Woohoo!😄
コンソールに戻ってアクセストークンを控えておきましょう。
Firebase 側の設定は以上になります。
Actions で自動ビルドと apk の配布
続いて GitHub 上で自動ビルド -> App Distribution に配布する設定をします。
GitHub の環境を設定
Settings -> Secrets
から先程控えたアプリ ID とアクセストークンをアカウントに登録します。
後ほど説明しますが、セキュアな情報はここに登録して使います。
workflow を追加
最後に Actions の workflow を定義します。
マーケットプレイスに色々 Action がリリースされており、
App Distibution へのデプロイ用 Action があるので今回はそれを使います。
ただしサンプルにはグループの指定が書いてあるので設定していない場合は、削除するかコンソールからグループを作成しておきましょう。
Firebase App Distribution · Actions · GitHub Marketplace · GitHub
今回は PR が master にマージされたら apk を配布する設定にしています。
name: Build & upload to Firebase App Distribution
on:
pull_request:
types: [closed]
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: build release
run: ./gradlew assembleRelease
- name: upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{secrets.FIREBASE_APP_ID}}
token: ${{secrets.FIREBASE_TOKEN}}
file: app/build/outputs/apk/release/app-release-unsigned.apk
これで PR が master にマージされる度に App Distribution に apk がデプロイされます。
Console を確認すると以下の様にリリースされています。
workflow 内の各プロパティ
name
その Actions や各実行される処理の Description です。
on
workflow が実行されるトリガーを指定します。
types や branches で更に条件を絞ることができます。
今回は master に対する PR が close された時にトリガーされる様な指定になっています。
jobs
workflow で実行される処理です。
今回は build と言う ID のジョブが登録されています。
runs-on
必須パラメータ。ジョブを実行するマシンの種類。
GitHub にホストされているマシンや自分でホストしているマシン等が選べます。
if
処理を実行するための条件を指定します。
今回はマージされずにクローズされた PR でもトリガーされて配布されるのを防ぐために、マージされた時だけ処理される様にしています。
steps
ジョブが実行する処理の集まりです。
各ステップはプロセスが別です。
with
action で定義されているパラメータを指定します。
Firebase-Distribution-Github-Action ではアプリID、アクセストークン、 apk ファイルを指定して実行します。
gradle-wrapper.jar が見つからない
ワクワクしながら一度 Actions を走らせてみたらビルドに失敗していました😂
失意の中さまよっていると下記の様な記事を見つけました。
gradlewが謎のエラーで動かない件について - Qiita
何も考えずに Gibo で kotlin プロジェクトを gitignore にダンプすると jar ファイルが ignore されます。
それに引っかかって GitHub のリポジトリ上に gradle/wrapper/gradle-wrapper.jar
が存在しないせいでビルドができなくなっていました。
.gitignore に以下を追加して gradle-wrapper.jar だけ ignore から除外する様にしておかないといけません。
!gradle/wrapper/gradle-wrapper.jar
後は gradle-wrapper.jar を作成してコミットしましょう。
jar ファイルの作成は以下のコマンドでできます。
$ gradle wrap
Secrets でセキュアな情報を管理
既存のプロジェクトに GitHub Actions を導入した時の話です。
SDK の認証情報を外部ファイルに切り出して管理し ignore していたため、
上の workflow のままだとこれまたリポジトリにファイルがないのでビルドに失敗します。
以下の様にファイルの内容を Base64 でエンコードして Secrets に保存し、
ビルドのステップの前にデコードして追加してあげるとビルドが通る様になりました。
GithubActionsでgitignoreしたgoogle-services.jsonを読み込む - Qiita
追加の仕方が悪いのか平文で Secrets に登録すると改行とかがあると上手くいかなかったりしたので、エンコード -> デコードの手順が必要なのかなと思います。
ワンラインの内容なら特に問題はないかと。
google-services.json 等セキュアな情報を抱き込む必要がある場合は Secrests に登録すると安全に CI できます。
ついでにデプロイされたら Slack に通知する様にしてみた
Firebase App Distribution は apk が新しく登録されたらテスターにメールが飛ぶのでそれでいいのかもしれませんが、
できれば Slack で通知されると見落としが減っていいなぁと思ってやってみました。
PR の URL も一緒に流せたらもっと素敵。
過去に Slack の Incoming Webhook をセットアップした事があるんですが、もう一度調べてみたところアップデートされており、
ペイロードの attachments はいつ消えてもおかしくないから blocks 使いなよって事らしいです。
ただ、左側のカラー付きサイドバーで引用っぽく表示するやり方 (color の指定) は今のところ attachments にしか無いみたいなのでどちらを使うかはメッセージのレイアウトによりますね。
Slack にポストする Actions もマーケットプレイスにたくさんありましたが、今回は
- 新しい Incoming Webhook に対応している
- レイアウトを自由に決めれる様に attachments, blocks 等 Slack のメッセージペイロード に対応している
を元にこちらの Actions を使わせていただきました。
ありがとうございます。
Slack Incoming Webhook · Actions · GitHub Marketplace · GitHub
Webhook のセットアップの仕方は今回は割愛します。
Webhook URL を secrets に登録しておきましょう。
name: Build & upload to Firebase App Distribution
on:
pull_request:
types: [closed]
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: build release
run: ./gradlew assembleRelease
- name: upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{secrets.FIREBASE_APP_ID}}
token: ${{secrets.FIREBASE_TOKEN}}
file: app/build/outputs/apk/release/app-release-unsigned.apk
- name: post message to Slack
if: success()
uses: tokorom/action-slack-incoming-webhook@master
env:
INCOMING_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
with:
text: "New app was deployed!!"
blocks: |
[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "New app was deployed!! :clap:"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*${{ github.event.pull_request.title }}*\nPushed by ${{ github.event.pull_request.user.login }}\n\n*URL*\n${{ github.event.pull_request.url }}"
},
"accessory": {
"type": "image",
"image_url": "${{ github.event.pull_request.user.avatar_url }}",
"alt_text": "User Icon"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Join Test"
},
"url": "${{ secrets.APP_DISTRIBUTION_URL }}"
}
]
},
{
"type": "divider"
}
]
これで workflow が成功すると Slack にデプロイされた通知が飛んでくる様になります。
色々とパラメータが使えるみたいで好きな様にレイアウトやテキストがカスタマイズできそうでいいですね。
もっと素敵なメッセージにしたかった。デザイン力をください。。。
どういったパラメータが使えるかはドキュメントに記載してあります。
GitHub Actions のコンテキストおよび式の構文 - GitHub Docs
他のパラメータも知りたい場合は workflow の途中とかでダンプすると出てきます。
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
Conclusion
こういう設定周りのファイルを弄るのは、手間暇かけた分楽できるのがダイレクトに感じられて楽しいです。
触ってみるととても分かりやすく、ドキュメントもしっかりしていました。
Enterprise でリリースされたらぜひプロジェクトで使ってみたいですね😄
今後は aab にシフトしていくらしいですけど、その時は DeployGate に流したほうがいいんでしょうかね🤔
参考
GitHub Actionsのワークフロー構文 - GitHub Docs