はじめに
こんにちは、ブランドソリューション開発本部 フロントエンド部 WEAR Androidブロックの武永です。普段はファッションコーディネートアプリWEARのAndroidアプリを開発しています。
リリースノートを手動で毎回入力するのが面倒
WEARは多言語対応をしています。Google Play Consoleへアップロード後、Google Sheetsからテキストを4言語分コピーしたのち、申請画面でテキストを貼り付ける作業が面倒でした。誤って違う言語のリリース文言を記述してしまうリスクもあったので、検討した結果リリースノートもアプリと同じタイミングでアップロードすることにしました。
導入方法
今回はGitHub ActionsでRubyをセットアップし、Rubyのファイルを実行してリリースノートのテキストを取得します。それをテキストファイルとしてダウンロードします。使用するライブラリは2つあります。
1つ目はGoogle Sheetsからテキストを取得するRubyライブラリの「google-drive-ruby」です。Google Sheetsを操作できるライブラリはいくつかあったのですが、スター数もそれなりにあり信頼できると思い選定しました。
2つ目はGoogle Play Consoleにアプリのパッケージをアップロードするライブラリの「gradle-play-publisher」です。非公式ではありますが、できることの柔軟さが魅力的で選定に至りました。それでは実際に見ていきましょう。
Rubyファイルのセットアップ
プロジェクト直下にGoogle Sheetsからテキストを取得する下記のGemfileとRubyファイルを追加します。
- Gemfile
source "https://rubygems.org" gem 'google_drive'
- download_release_note_text.rb
require 'google_drive' def fetch_google_sheets service_acount_key_json = { type: 'service_account', project_id: ENV["SERVICE_ACCOUNT_PROJECT_ID"], private_key_id: ENV["SERVICE_ACCOUNT_PRIVATE_KEY_ID"], private_key: ENV["SERVICE_ACCOUNT_PRIVATE_KEY"].gsub(/\\n/, "\n"), client_email: ENV["SERVICE_ACCOUNT_CLIENT_EMAIL"], client_id: "CLIENT_ID", auth_uri: 'https://accounts.google.com/o/oauth2/auth', token_uri: 'https://oauth2.googleapis.com/token', auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs', client_x509_cert_url: ENV["SERVICE_ACCOUNT_CLIENT_X509_CERT_URL"] }.to_json service_acount_key_io = StringIO.new(service_acount_key_json) session = GoogleDrive::Session.from_service_account_key(service_acount_key_io) spreadsheet = session.spreadsheet_by_key(ENV["GOOGLE_SPREAD_SHEET_ID"]) return spreadsheet end def save_metadata(spreadsheet) branchName = ENV["GITHUB_BRANCH_NAME"].dup versionName = branchName.delete("qa/") LANGUAGES.each do |key, value| row = spreadsheet.worksheet_by_title(key).rows.find { |row| row[0] == versionName } path = "./app/src/main/play/release-notes/#{value}/default.txt" File.open(path, mode = 'wb') do |f| f.write(row[RELEASE_NOTES_COLUMN]) end end end LANGUAGES = {'ja'=>'ja-JP', 'zh-Hans'=>'zh-CN', 'zh-Hant'=>'zh-TW', 'en-US'=>'en-US'} RELEASE_NOTES_COLUMN = 7 spreadsheet = fetch_google_sheets save_metadata(spreadsheet)
Rubyファイル上でGoogle Sheetsを認証します。その後リリースノートファイル作成の関数を呼び出しテキストファイルとして保存しています。LANGUAGESのdictionary型はGoogle Play ConsoleにアップロードできるようにGoogle Sheetsのシート名を置き換えています。ちなみにサービスアカウントで.gsub(/\\n/, "\n"),
の処理を行なっている理由は、環境変数から改行コードを読み込んだ場合\\n
になるので置換しています。詳しい説明は後ほど行ないます。
次にGitHub Actions上で上記のRubyファイルを実行できるようにセットアップします。
- download_release_note.yml
build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3.2.0 with: ref: ${{ github.head_ref }} - uses: actions/setup-ruby@v1 with: ruby-version: 3.1 - name: Prepare bundler run: | gem install bundler bundle install --jobs 4 --retry 3 - name: Deploy Metadata run: bundle exec ruby get_release_note_text.rb env: GITHUB_BRANCH_NAME: ${{ github.head_ref }} GOOGLE_SPREAD_SHEET_ID: ${{ secrets.GOOGLE_SPREAD_SHEET_ID }} SERVICE_ACCOUNT_PROJECT_ID: ${{ secrets.SERVICE_ACCOUNT_PROJECT_ID }} SERVICE_ACCOUNT_PRIVATE_KEY_ID: ${{ secrets.SERVICE_ACCOUNT_PRIVATE_KEY_ID }} SERVICE_ACCOUNT_PRIVATE_KEY: ${{ secrets.SERVICE_ACCOUNT_PRIVATE_KEY }} SERVICE_ACCOUNT_CLIENT_EMAIL: ${{ secrets.SERVICE_ACCOUNT_CLIENT_EMAIL }} SERVICE_ACCOUNT_CLIENT_ID: ${{ secrets.SERVICE_ACCOUNT_CLIENT_ID }} SERVICE_ACCOUNT_CLIENT_X509_CERT_URL: ${{ secrets.SERVICE_ACCOUNT_CLIENT_X509_CERT_URL }} - name: Commit and Push run: | git add ./app/src/main/play/* git diff --name-only set -x git config user.name github-actions[bot] git config user.email github-actions[bot]@users.noreply.github.com git add . git commit --author=. -m 'add release note text' git push
こちらはプルリクエストが作成されたタイミングで実行されるワークフローです。リリースノートを取得した後にその変更をコミットし、originにプッシュします。セキュアな情報が多いのでシークレットに変数を追加することを推奨します。
上記のプルリクエストがクローズされたらGoogle Play Consoleにパッケージをアップロードします。
- internal_test_deploy.yml
on: pull_request: branches: - main types: [closed] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: set up JDK 11 uses: actions/setup-java@v3 with: distribution: "zulu" java-version: 11 - name: Create Empty local.properties for ci run: echo > local.properties - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties - name: Create Credential File run: echo '${{secrets.SERVICE_ACCOUNT_JSON}}' > ./app/service_account.json - name: Upload to Play Console run: ./gradlew publishReleaseBundle
- app/build.gradle
//細かい導入方法は割愛しています import com.github.triplet.gradle.androidpublisher.ReleaseStatus play { serviceAccountCredentials.set(file('service_account.json')) track.set("internal") releaseStatus.set(ReleaseStatus.COMPLETED) }
gradle-play-publisherはbuild.gradleに記述しアップロードをします。GitHub Actionsの実行ファイルはシンプルになります。internalは内部テスト配布です。内部テスト配布にしている理由は審査が入らないトラックなので即時にGoogle Play Consoleへ反映され確認がしやすいからです。alpha,betaは審査が入るので注意が必要です。
困ったこと
Google Sheetsでリリースノートのバージョン管理を行なっているのですが、そのバージョンとトリガーになるブランチ名を一致させないといけませんでした。そこでGitHub Actionsでブランチ名を取得できる変数を使う方法を採用しました。実際に見ていきましょう。
- download_release_note_text.rb
def save_metadata(spreadsheet) branchName = ENV["GITHUB_BRANCH_NAME"].dup versionName = branchName.delete("qa/") LANGUAGES.each do |key, value| row = spreadsheet.worksheet_by_title(key).rows.find { |row| row[0] == versionName } path = "./app/src/main/play/release-notes/#{value}/default.txt" File.open(path, mode = 'wb') do |f| f.write(row[RELEASE_NOTES_COLUMN]) end end end LANGUAGES = {'ja'=>'ja-JP', 'zh-Hans'=>'zh-CN', 'zh-Hant'=>'zh-TW', 'en-US'=>'en-US'} RELEASE_NOTES_COLUMN = 7
今回はgithub.head_ref
を使用しています。運用としてはQA期間があり、テストが完了したらmainブランチへのマージを行ないます。そしてプルリクエストがオープンされたタイミングでワークフローが発火します。github.head_ref
を指定するとqa/1.0.0
のテキストが出力されます。そのテキストをRubyファイルに渡し、環境変数から値を取り出した後にqa/
の部分を削除し、バージョンのみを取得します。
まとめ
実際にブランチのトリガー1つでGoogle Play Consoleまでのアップロードを自動化してみたところ手動で行うことが減りました。人為的ミスも起こりにくくなり、導入して恩恵を受けました。ちなみに該当するバージョンのリリースノートが記載されていない場合はCIがエラーを起こして検知してくれるかつ、マージできないので気付けて便利です。GitHub Actions上で完結できるライブラリがあればもっとシンプルなワークフローになるので、改修コストもかからなくて良いと思いました。
最後までご覧いただきありがとうございました。ZOZOでは、各種エンジニアを採用中です。ご興味のある方は以下のリンクからご応募ください。