Rubyを用いてGoogle Sheetsからリリースノートを取得しGoogle Play Consoleに自動アップロードする取り組み

https://cdn-ak.f.st-hatena.com/images/fotolife/z/zozo-engineer/20230110/20230110164841.png

はじめに

こんにちは、ブランドソリューション開発本部 フロントエンド部 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/の部分を削除し、バージョンのみを取得します。

github.head_ref

まとめ

実際にブランチのトリガー1つでGoogle Play Consoleまでのアップロードを自動化してみたところ手動で行うことが減りました。人為的ミスも起こりにくくなり、導入して恩恵を受けました。ちなみに該当するバージョンのリリースノートが記載されていない場合はCIがエラーを起こして検知してくれるかつ、マージできないので気付けて便利です。GitHub Actions上で完結できるライブラリがあればもっとシンプルなワークフローになるので、改修コストもかからなくて良いと思いました。

最後までご覧いただきありがとうございました。ZOZOでは、各種エンジニアを採用中です。ご興味のある方は以下のリンクからご応募ください。

corp.zozo.com

カテゴリー