feather の CI 環境を新しくしました

弊社で開発している Twitter クライアント feather for Twitter の CI 環境を新しくしたので記事にしたいと思います。

更新以前の環境

2015年までの変遷は以下の記事にまとまっています(とんでもなく懐かしい...)。

qiita.com

この環境は今年はじめ頃まで運用されていて、いろいろな問題が発生していました。

一番大きいのが CI にかかる時間です。コードベースが増えたり、有料版・無料版のビルドが必要になったことで非常に長い時間がかかるようになっていました。 基本的には1回の CI プロセスに40分かかり、 carthage で管理している依存関係に変更が発生すると再ビルドが必要になるので更に時間がかかりました。

最悪のケースでは一回のビルドに2時間ほどかかっていました...

一時期は feather の開発速度そのものが低かったため顕著な問題にはなっていませんでしたが、最近また開発スピードが加速してきたのでこの状況は良くないと思い刷新することにしました。

また、この CI 環境はオフィスに置いてある mac mini に構築してあり、時々おかしくなった場合にアクセスや再起動を使用にもリモートからだとうまく行かないこともあり、再起動のためにオフィスへ出社する必要があったりして非常に面倒でした...

CI 環境の選定

ローカルに立てた Jenkins ではなく Circle CI, bitrise, Github Actions などクラウド CI 環境で実行したらどうか?という検討を初めに行いました。

いろいろ調べたところ、コスト面から却下することにしました。

feather は結構ギリギリのカツカツのところで開発をしているのでできるだけランニングコストは下げたいのです。

結果として Jenkins で行こうということになりました。

このときに CI 環境用に M1 の mac mini を購入しています。

セットアップ

以前の Jenkins の CI 環境は GitHub Pull Request Builder | Jenkins plugin を軸として組み立てていたため非常に Legacy なものでした。

現代的にするために GitHub Branch Source | Jenkins pluginJenkinsfile を軸とした job にするようにしています。

また M1 の mac mini は消費電力が非常に少ないため僕の家においています。

※ コベリンは基本フルリモートワーク

Jenkins はインターネット上に公開しているため他の人がアクセスしたり、 github の webhook を受け取ったりできます。

Pull Request の open や push の検出は polling と github からの webhook を利用して行っています。

その後の改善

この新しい環境でビルド時間が短縮できたのではないかとワクワクしたのですが、GitHub Branch Source Plugin はビルド毎に新しくディレクトリを作るために carthage bootstrap で毎回再ビルドがかかってしまいあまり時間が短縮できませんでした。

※ 以前の環境で carthage の再ビルドが発生した場合には2時間位かかっていたのが40分にはなったのでめっちゃ短縮されましたが、キャッシュが効かないため必ず40分かかるようになってしまいました。

これはいかんと思いキャッシュする方法を色々調べましたが、キャッシュの store/restore のタイミングの問題など考えることが多く stackover flow でもあまりおすすめされていないようだったのでキャッシュする方向は諦めました。

結果、 Cathage/Build ディレクトリをリポジトリに含める運用にしました。CI 含め全員のビルド環境(Xcode のバージョンなど)が揃える必要などがあるのですが、現在特に問題なく運用できているので問題はなさそうです。

これにより一回のビルド時間は30分ぐらいになりました。 しかしこれでもやや遅い...

さらなる改善

この時点で feather の CI では大きく

  1. テスト実行 (lint, formatter, 有料版、無料版の Test)
  2. 有料版をビルド & Firebase App Distribution に配布
  3. 無料版をビルド & Firebase App Distribution に配布

という3つのタスクを行っていて、それぞれに約10分かかっていて合計30分という感じでした。

社内で聞き取り調査をしたところ、無料版に関連する PR を出すことはそれほど多くないため毎回の PR で無料版のビルドをする必要はないという結論になりました。

そこで PR の本文中に - [x] 無料版もビルドする という文言があった場合にのみ無料版のビルド & 配布を行い、通常は行わないようにしました(コレに関してはまた別途解説したいと思います)。

その結果、通常時は20分程度で CI が完了するようになりました。コレでだいたい満足かなと思っています。

※ 補足: 毎晩ナイトリービルドで有料版、無料版をビルドして AppStore に submit しているので何かビルドに問題があっても直ぐに気がつけるようにはしています。

Github Actions

実は feather では Jenkins 以外でも一部のタスクを Github Actions で行っています。

CI というよりは PR のアサインをしたりなどちょっとした作業を行っています。このあたりもまた別の記事で紹介したいと思います。

まとめ

feather の CI 環境を改善して開発速度が更に出るようになりました。

CI が早くなれば開発のテンポがよくなる、気軽に細かい PR を出せるなど様々なメリットがあると思います。

あと、最近の CI 環境の構築方法などのノウハウも色々溜まるので非常に良いと思います。