Sansan Builders Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Sansan iOS アプリにおけるリリース作業自動化の仕組みを作り直した話 ~背景編~

こんにちは。 Sansan 技術本部 Mobile Application グループで Sansan の iOS アプリを開発している多鹿です。

私が Sansan の iOS チームにジョインしてから約 1 年半が経とうとしています。(時が経つのは早いですねぇ、、)
弊チームでは、私がジョインした当初から独自に作成した Slack bot*1 を活用したアプリのリリース作業自動化の仕組みが確立されており、とても便利に ChatOps でアプリのリリース作業を行なっていました。
しかし、この度そんな便利な Slack bot を作り直すことになったので、その背景やどういった構成にしたかを(先人に感謝しつつ)記していこうと思います。

また、当記事では背景や全体像の紹介を行いますが、作り直した仕組みを実現した技術的な話については、 Bolt 編, GitHub Actions 編 という風に続編として連載の形式で別の記事として紹介させていただこうと思います。

目次

作り直す前のリリース作業について

まずは、そもそもどのようにして Slack bot を活用したリリース作業を行なっていたのかを紹介します。
※ iOS アプリの話なので、「リリース= App Store への公開」と読み替えていただければと思います。

リリース作業の全体像

Sansan iOS チームでは、毎週*2 週初めの定期リリースを行なっています。
そのため、下図のようにリリース前週の半ばには次回リリースする内容を含んだコードをフリーズさせ、それを元に作成したビルドを審査に提出し、週明けにストア公開を実施しています。

f:id:taji-taji:20220210094341p:plain
週初めの定期リリースサイクルを回している

これらのフローの中で、独自の Slack bot を活用して ChatOps でリリース作業を行なっています。
それぞれのステップについてもう少し細かく見ていきましょう。

1. コードフリーズ

f:id:taji-taji:20220210093854p:plain
週の半ばにコードフリーズを実施

Sansan iOS チームでは、ブランチ戦略として GitLab Flow を採用しているため、 GitLab Flow で言うところの production ブランチをリリース用のブランチとして作成することでコードフリーズしています。
コードフリーズの前提として、次のリリースに含めたい機能のブランチをメインブランチに取り込んでおきます。

そして、ここから Slack bot を活用して下記のような作業を行います。

  • メインブランチからリリース用のブランチを作成
    • Slack 上で独自の Slack bot と対話することで release/vx.x.x という形式のリリース用のブランチが作成されます
    • また、弊チームではアプリのバージョン情報を xcconfig ファイルで管理しているため、このリリース用ブランチ作成の過程で選択したバージョンに xcconfig ファイルを自動更新するようなステップも含まれています

f:id:taji-taji:20220207171018g:plain
Slack bot を利用したリリース用ブランチの作成の様子

  • 前回のリリースタグと今回のリリースブランチの差分を確認
    • Slack bot が Slack 上に差分の URL を投稿するので、それを元に意図しない差分がリリースに含まれていないことを関係者が確認します

f:id:taji-taji:20220207133003p:plain
GitHub 上での最新バージョンと次のバージョンとの差分 URL が投稿される

  • リリースノートの内容が正しいか確認
    • 弊チームでは、 App Store に掲載するリリースノートは fastlane を利用して git 管理しています
    • また、別々のメンバーが担当した複数の新機能が一度のリリースに含まれることもあるため、稀にリリースノートが意図しない内容に変わってしまっていたり、前回のリリース時のリリースノートが残ったままになっているということがありました
    • そういったことを防止するために、 Slack bot が fastlane で管理しているリリースノートを Slack 上にポストして、間違いがないかを複数人の目で確認できるようにしています

f:id:taji-taji:20220210083659p:plain
Slack bot がリリースノートの設定を投稿している様子

  • 段階的リリースの設定が正しいか確認
    • こちらも同様に fastlane で管理しており、リリース作業の中で設定に間違いがないかを確認する目的で、 Slack bot が Slack に投稿するようになっています

f:id:taji-taji:20220210083603p:plain
Slack bot が段階的リリースの設定を投稿している様子

2. App Store Connect への審査提出およびリグレッションテスト実施

f:id:taji-taji:20220210093934p:plain

コードフリーズによりリリースするものが固まったら、リリース用のビルドを作成して App Store Connect へ提出します。
また、弊チームでは、最低限正しく動作しないといけない機能についてはリリース前に必ずリグレッションテストを実施します。
リグレッションテストは App Store Connect へビルドを提出した際に、併せて配信するようにしている TestFlight を利用して本番環境にて実施することになっています。

さて、ここでは次のような作業が発生します。

  • リリース用ブランチからリリース用ビルドを作成
    • こちらは CI の設定としてリリース用のブランチが作成された時点で CI の workflow が周り、ビルドの生成が自動で行われるようになっています
  • リリース用ビルドを App Store Connect へ提出
    • こちらも同じく CI 上で fastlane が走り、 App Store Connect への提出まで自動で行われるようになっています
    • また、同時に TestFlight へも配信されます
  • TestFlight に配信されたアプリでリグレッションテストを実施
    • Sansan iOS チームでは QA チームと協業しながら TestRail というツールを用いてリグレッションテストのテスト項目を管理しています。そのため、 Slack bot から TestRail の API を叩いてリリースするバージョン用のテストプランを自動生成するようにしています

f:id:taji-taji:20220207171606p:plain
自動生成されたテストプランの URL が Slack bot によって投稿される

3. ストア公開

f:id:taji-taji:20220210094027p:plain
週明けにストア公開

ここまでで審査が通り、リグレッションテストも通過すれば、週明けにいよいよストア公開となります。
ストアへの公開は自動では行わず、必ずダブルチェックの上、 App Store Connect の公開ボタンを手動で押す運用になっています。

4. 後片付け

f:id:taji-taji:20220210094137p:plain
ストア公開後の作業

さて、無事ストアへの公開が完了したら、最後に後片付けとして下記のような作業を行い、リリース作業を終えます。
これらも Slack bot を使用して対話的に行なっていきます。

  • GitHub の Sansan iOS リポジトリにリリースを作成
    • GitHub 上にリリースタグを打ちます
  • TestRail のリグレッションテストのテストプランをクローズする
    • Slack bot から対象のテストプランをクローズするための TestRail API を叩きます
  • リリース用のブランチを削除する

f:id:taji-taji:20220207172212p:plain
リリースの作成やテストプランのクローズが行われた様子が投稿される

以上が Sansan iOS チームが実施していたリリース作業の概要となります。

リリース作業自動化の仕組みについて

さて、ここまでで Slack bot を活用したリリース作業の概要を見てきました。
ここからは作り直す前の Slack bot の構成とそれらの課題について説明していきます。

bot の構成 / 役割

基本的には Slack App の Event Subscriptions を使用して特定のポストに反応して動作するような bot アプリケーションを作成しています。

  • Slack bot アプリのホスト先
  • Slack bot アプリの実装言語
    • Go 言語
  • Slack bot アプリの役割
    • Slack 上にて iOS チームメンバーとインタラクティブにやりとりをするインターフェースの役割
    • リリース作業にて行う各ステップを実行する役割

上記の通り、bot 自体は Go 言語で作成し Netlify Functions を活用して動かすことで Slack 上で対話的にやりとりを行うことができるようにしています。

シーケンス図

当初、私がこの Slack bot の仕組みを理解するために、リリース作業を行う iOS チームメンバーと Slack bot の処理をシーケンス図でまとめたものがあるので掲載しておきます。

f:id:taji-taji:20220210091303p:plain

課題

この Slack bot が作られた当初は、iOS チーム内に所属していた一人の有志によってチームの生産性向上のために作られ、メンテナンスされていました。
お陰様でかなりの生産性向上の効果があったかと思いますが、一方で Slack bot の知見の大部分がその有志メンバーに属人化する形になっており、 Slack bot のメンテナンスをするにあたって次第に下記のような問題が発生してきました。

  1. 他の iOS チームメンバーの技術スタック的に Go 言語でのメンテナンスに学習コストがかかる
  2. 開発環境が整備されておらず、機能追加や修正の動作確認がやりづらい
  3. 依存関係のないリリース作業のステップも全て Slack bot 内に実装されていたので、特定のステップを修正するのにも Slack bot 自体に手を入れる必要があり、修正スコープが大きくなりがちだった

自動化の仕組み作り直しの計画

上記の課題を踏まえて、自動化を実現している Slack bot の作り直しを計画しました。
闇雲に作り直すのではなく、計画するにあたっては下記の点を考慮しながら計画を立てました。

  • 前述の課題を解決する
    • 課題 1. iOS チームのメンバーがメンテナンスできる技術の選定
    • 課題 2. 開発環境の整備
    • 課題 3. 自動化の仕組みにおける責務の分割
  • 既存の運用方法は大きく変えない
    • 作り直しによって運用に混乱が生じないように ChatOps で行なっている Slack bot との対話インターフェースは大きく変化させない

メンテナンス性の課題はあるものの、 ChatOps のインターフェース自体に課題がある訳ではなかったので、既存の運用方法が大きく変わらないことも念頭に考えました。
それでは、次にそれぞれの課題に対してどのように解決策を考えていったのかを説明します。

課題 1. iOS チームのメンバーがメンテナンスできる技術の選定

結論から述べると、 Slack App の公式フレームワークである Bolt for JavaScript を採用しました。
選定理由としては以下になります。

  • iOS チームメンバーの技術スタックとして、 JavaScript であれば比較的メンテナンス可能そうだった
  • 公式フレームワークということもあり、ドキュメントが充実していた

JavaScript に馴染みないメンバーももちろんいますが、公式のドキュメントが充実していることもあり、 JavaScript そのものの知識が豊富でなくてもメンテナンスは可能そうという点もポジティブな要因となりました。
また、「すでにある Go 言語のアプリケーションを使い回しつつ、開発環境を整備しては?」という議論も行いましたが、やはり公式ドキュメントの充実やメンバーの Go 言語の学習コストなどを考慮すると Bolt の使用が好ましいという結論に至りました。

課題 2. 開発環境の整備

こちらは、すでに Netlify 環境を利用していたこともあり、 netlify-cli の機能と合わせてローカルで開発できる環境を整備することにしました。
詳しい方法は連載の Bolt 編をお楽しみください!

課題 3. 自動化の仕組みにおける責務の分割

作り直す前の仕組みは、全ての役割が Slack bot 上に集約されていました。
それによって局所的な修正であっても Slack bot 自体に修正を入れる必要があり、影響範囲が大きくなるという課題が存在していました。
それを解決するために、下記のように GitHub Actions も導入しつつ、リリース作業自動化の責務を分けることを考えました。

  • Bolt 製の 新 Slack bot アプリの役割
    • Slack 上にて iOS チームメンバーとインタラクティブにやりとりをするインターフェースの役割
      • 対話的にiOS チームメンバーからの入力を受け付ける
    • iOS チームメンバーの入力をもとに、後述する GitHub Actions をトリガーする役割
      • あくまでリリース作業の各ステップを実行するのは GitHub Actions の役割として、新 Slack bot アプリからはトリガーするのみとする
  • GitHub Actions の役割
    • リリース作業にて行う各ステップを実行する役割
      • 必要に応じて、実行結果を Slack にポストする

このように責務分割をすることで、リリース作業の中のあるステップだけ改修したいという時に特定の GitHub Actions の workflow のみに修正を入れてテスト実行すれば良かったりと、メンテナンス性が向上することを期待しました。
もちろん、今回新しく GitHub Actions という登場人物が出てくることで、管理する対象が増えるという点はデメリットになり得ると思います。それでも、それ以上に改修のスコープが小さくできるメリットの方が大きいと踏んでこのように分けることにしました。

作り直し後の構成案

それでは、一旦ここまでで考えた構成案をまとめてみます。

  • 新 Slack bot アプリのホスト先
  • 新 Slack bot アプリの実装言語 / フレームワーク
    • Bolt for JavaScript
  • Bolt 製の 新 Slack bot アプリの役割
    • Slack 上にて iOS チームメンバーとインタラクティブにやりとりをするインターフェースの役割
  • GitHub Actions の役割
    • リリース作業にて行う各ステップを実行する役割

シーケンス図

この構成案を提案した際に作成したシーケンス図も掲載しておきます。

f:id:taji-taji:20220210091337p:plain

作り直し前に比べて、 iOS チームメンバーと対話を行う Slack bot の部分と実際にリリース作業のステップを実行する GitHub Actions の部分で役割が分かれていることが分かると思います。

before after

おわりに

本記事では、 Sansan iOS チームで運用しているリリース作業の全体像および、それらを自動化する仕組みとそれを作り直した経緯について記載していきました。
Go 言語製の Slack bot は Bolt に置き換えることになり、新しく GitHub Actions も導入することになりました。
今回は技術的な内容ではありませんでしたが、連載記事の 2本目, 3本目では、 Bolt フレームワークでの Slack bot アプリ作成にフォーカスした内容、 GitHub Actions によるリリース作業の実装にフォーカスした内容をそれぞれお届けできればと思います。


buildersbox.corp-sansan.com

*1:岸川さん作のdeliverbotを参考にしたものだそうです

*2:アップデート内容がない場合はスキップされる週もあります

© Sansan, Inc.