こんにちは、モバイルクライアントグループの若宮(id:D_R_1009)です。 みなさまお元気でしょうか、私はチェンソーマン9巻購読直後のため気持ちが乱れております。どうしてだよ……。
コードの悪魔は厳しいので、そんな気持ちの乱れをコードに持ち込むわけにはいきません。 そんなわけで、iOSチームで取り組んでいるSwiftLintの自動化について書きます。
SwiftLintに期待すること
多くの現場で取り入れられていると思われるので、ご存知の方は次のセクションまで飛ばしてください。
SwiftLintとは
SwiftLintはeslintやktlintのように、Swiftのコードスタイルを矯正指摘してくれるツールになります。
iOSではおなじみ、Realmによってメンテナンスされています。リリースも活発です。 GitHub Releaseのタイトルもちょっと賑やか。
チーム開発ではSwiftの書き方を揃えてくれるので、書き方の癖によるレビュー時のお悩みを軽減してくれます。 また個人であっても、Swiftのより標準的な書き方を学ぶことができるため助かるツールとなっています。
SwiftLintを動かす
SwiftLintはGitHubのReadmeで紹介されている通り、複数の方法で環境構築することができます。 HomeBrewやCocoaPods以外にも、SwiftPMで動かすなどなどケースに合わせて対応できます。
開発マシンに入れることができれば、あとはXcodeのbuild phaseに追加するだけです。 HomeBrewで入れた場合であれば、Xcodeの項目にある通りスクリプトを追加するだけで、Xcode内でビルドのたびにチェックが走るようになります。
一度ビルドを走らせないといけないのが難点といえば難点(特にビルドに時間がかかるプロジェクトでは)と言えるかもしれません。 ただ、コードを書いて実機の動作チェックを行い、コードに戻ってきた時にSwiftLintが指摘してくれている状態になるため、体験としてはなかなか良いものじゃないかなと感じています。
GitHub ActionsでSwiftLintを動かす
SwiftLintを全ての開発者がローカルで走らせ、全てチェックした上で開発をしていれば、CI上で動かす必要はありません。 しかし、実際は見逃しやGitHub上での修正などがあり、見落としが発生してしまいます。 そんなわけで、PRを作成した時にSwiftLintを走らせ、警告が出たらコメントして欲しくなります。
PRへのコメントといえばDangerです。
Danger自体はRuby、もしくはJSの環境があれば動きます。 そのため、CI上でSwiftLintを動かす際にネックとなるのは Swift です。
もしもCIサービスとしてBitriseを使われている場合には問題にならないのですが、そのほか多くのCIサービスではLinux上で実行させる方が お得 になっています。
Bitriseは無料プランであれば10分までmacOSの環境を利用できるため、ステップとしてSwiftLintを追加するだけです。 Dangerのステップも用意されているので、あとはGitHubのトークンを用意するだけですね。
- https://www.bitrise.io/integrations/steps/swiftlint
- https://www.bitrise.io/integrations/steps/danger
問題は他のCIサービスを利用している場合です。 macOSを利用するとLinuxの8〜10倍のコストがかかるため、PRの度に走らせる処理としてはちょっと厳しいものがあります。
そんなわけで、今回はGitHub Actions + LinuxでSwiftLintとDangerを走らせる方法を紹介したいと思います。
SwiftLintをGitHub Actionsで簡単に実行
一番手軽なのは、GitHub Actionに登録されている Danger Swift
を利用することです。
利用方法は上のページの真ん中あたりに書いてあるので、PRをフックとしたGitHub Actionのymlを作れば完了です。
Danger Swift
はJS版のDangerを利用し、SwiftファイルからDangerを呼び出せるようにしたライブラリです。
なおJS版のDangerを利用しているため、Ruby版のDangerにないバグの影響を受けることがあります。 もしもfastlaneからDangerを利用しているような環境では、一部の振る舞いが変わるためご注意ください。
Docker Imageで高速に実行
Danger SwiftのGitHub Actionに問題があるとすれば、それはActionのセットアップに少し時間がかかることです。 Linuxで動いているためコストとしては気になるほどではありませんが、ささっと実行された方が嬉しいものです。 そんなわけで、Danger Swiftを利用できるDocker Imageを利用しましょう。
なお、SwiftをLinuxで動かすための環境構築が難しいため、Docker Imageを利用すると確実な動作が期待できます。 後述のf-meloniさんがDocker Imageを作ったのは、とあるIssueに一時的に対応するためだったりします。 *1
2020年11月6日現在、Danger Swiftのリポジトリは「Docker Imageの配布準備が完了」しているものの「Dcoker Imageのビルドがされていない」状況となります。 Git Tagが打たれた時にビルドがされる設定になりつつ、まだ新規のGit Tagが打たれていないためです。 この記事をみなさまが読んでいる時にはビルドがされていることと思うので、ぜひ次のページから最新のDocker Imageを確認してみてください。
なお、個人でDocker Imageを作成してくださっているケースもあります。 それぞれSwiftのバージョンなどを確認しつつ、自分のプロジェクトで利用できるかどうかなどを確認してみてください。
Studyplus iOSチームの話
最後にStudyplus iOSチームのSwiftLintに関わる話を少しだけ書きたいと思います。
ローカルのSwiftLintをバージョン管理
私がiOSのアプリの開発に参加した頃は、下記のような整理でした。
- SwiftLintはCocoaPodsでバージョン管理
- CircleCI + macOSで、fastlaneを介して実行
2020年11月現在は下記のようになっています。
- SwiftLintは各自のマシーンではHomeBrewで管理、CI上はDocker Imageのバージョンで管理
- GitHub Actions + LinuxでDocker Imageを介して実行
この「SwiftLintをバージョン管理しなくなった」理由は3つあります。
- CIでSwiftLintのバージョンを管理できるのであれば、開発マシンの上のバージョンを管理する強い理由がない
- CocoaPodsやSwiftPMで管理するのは、アプリの動作に関係のあるライブラリだけにしたい
- リリースビルド時にSwiftLintをスキップできる(実行できないため)
brew update
をする頻度が人によって異なるため、そのズレがプロジェクトに影響を及ぼすほどであればバージョンの管理をするべきかもしません。
Studyplus iOSチームではそのような問題が起きるとは考えられなかったため、今回の判断をすることができました。
CI環境構築の知見を共有
GitHub ActionsやCircleCIなど、利用できれば便利なツールであっても、なかなか最初はとっつきづらいものだと思います。 このため、チームの中で知見を共有できるように2つのことに取り組んでいます。
- CI関連のセルフレビュー時に、参照したドキュメントのURLをコメントする
- ブログとして取り組んだことをまとめ、社内でレビューしてもらう
参考にしたドキュメントやブログなどのURLと一言コメントをPRのセルフレビューで書いておくと、レビューの負荷が下がり、後ほどドキュメントを追いやすくなります。 またCI関連ではよくあることですが、後日ステップの書き方が変わった時、既存の処理をどう書き換えてよいのか判断しやすくなります。 PRレビューで問題があった時に指摘してもらえるようしつつ、知見が偏っている分野では共有する場として利用するようにしています。
ブログは社外への発表であると同時に、社内向けのドキュメントとして書くようにしています。 きっとこのブログも役に立つ……!
終わりに
いかがだったでしょうか?
SwiftLintを導入しているけれどもPRには反映していない、SwiftLintをPR上で動かしているけれどもコストが気になっている、などのお悩みの助けになれば幸いです。 最後までお付き合い頂き、ありがとうございました!