Renovateを半年運用して得た知見

「[Ateam Finergy Inc. Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ateam-finergy)」7日目は @okonomi が担当します。

# はじめに

「[Renovate](https://www.whitesourcesoftware.com/free-developer-tools/renovate)」は依存ライブラリの自動更新ツールです。

私が担当しているサービスでもRenovateを導入していて、半年ほど運用してみてそれなりに軌道に乗ってきたので、一度振り返ってみようと思います。

前提として、下記のような環境・アプリで運用しています。

- self-hosted Gitlab
- フロントエンドのコードを含んだRailsアプリ

# Renovateはローカルでも試せる

Renovateに対する私の理解不足だったんですが、RenovateはWebサービスとしての提供のほかにOSSとしても公開されており、ローカル環境で動かすことができます。

- https://docs.renovatebot.com/self-hosting/#installing-renovate-oss-cli

CLIをnpmでインストールすればとりあえずRenovateを使ってみることができます:

```
$ npm install -g renovate
```

プロジェクトへの初期セットアップはこんなかんじです:

```
$ renovate --token xxxx --onboarding=true okonomi/renovate-sandbox
```

上記コマンドで`renovate.json`を作成するMerge Requestが作成されます:

- https://github.com/okonomi/renovate-sandbox/pull/1

`--token`はAPIトークンです。デフォルトだとGithubのAPIトークンで、`--platform`で別のプラットフォームを指定した場合はそれに合わせてAPIトークンを取得・設定します（指定できるプラットフォームはドキュメント参照）:

- https://docs.renovatebot.com/self-hosted-configuration/#platform

あと`--log-level debug`や`--dry-run true`を付けておくとうまくいかないときの原因調査が早いです。
その他のオプションはこちらにまとまっています:

- https://docs.renovatebot.com/self-hosted-configuration/

導入時にありがちですが、APIトークンのパーミッションが足りなかったりAPIエンドポイントがズレてたり、本質的ではないところでハマりがちなので、試行錯誤のループが早くなってよかったです。

あとRenovateの運用環境が整うまでは、`renovate`コマンドを週一とかで人力で叩くようにするだけでもとりあえず使い始めることができたりします。

# Merge Requestのランダムアサイン

Renovateがライブラリ更新のMerge Requestを作ってくれるのですが、そのままだと放置されたり一部の人に対応が集中したりしそうだなと思ったので、チームのエンジニアにランダムでアサインするようにしました。

- https://docs.renovatebot.com/configuration-options/#assignees

設定はこんなかんじです:

```json
  "assignees": [
    "user1",
    "user2",
    "user3"
  ],
  "assigneesSampleSize": 1,
```
  
`assignees`にアサイン候補のユーザーIDを列挙して、`assigneesSampleSize`でひとつのMerge Requestに何人アサインするかを指定します。

結果、みんなに均等に作業分担されるようになったのと、どういうライブラリを使ってるとか、アップデートで動かなくなったときにどこで使ってるかを確認したりで、アプリに対するナレッジがそれなりに平準化する効果もあった気がします。

# `group:allNonMajor`の有効化

Renovateは設定項目が膨大なので、よくあるユースケース向けにプリセットを用意してくれています。
その中の`group:allNonMajor`を有効にしておくと、メジャーアップデートは個別のMerge Requestに、それ以外のマイナー/パッチアップデートはひとつのMerge Requestにまとめてくれます。

- https://docs.renovatebot.com/presets-group/#groupallnonmajor

こんなかんじです:

```json
  "extends": [
    "group:allNonMajor"
  ],
```

メジャーアップデートのMerge Requestは破壊的変更がないかChangelogやDiffをしっかり確認、それ以外はCIがとおってればOKというふうにレビューの負荷を下げることができます。

# gemの更新はしていない

gemの更新はRenovateではやっていません。Renovateは`Gemfile`にバージョン指定があるgemしか更新してくれないためです。

gemの更新は別途[gitlabci-bundle-update-mr](https://rubygems.org/gems/gitlabci-bundle-update-mr)を導入しています。
gitlabci-bundle-update-mrもRenovateと同様にMerge Requestへのランダムアサインが可能です。

- https://gitlab.com/sue445/gitlabci-bundle-update-mr#randomly-assign-one-person-to-mergerequest

ただ、gitlabci-bundle-update-mrは逆にバージョン指定があるgemは更新してくれないので、Renovateと併用してもいいかも、と思っています。​​

# Auto Mergeはしていない

Merge RequestのCIが通ったら自動的にマージするようにも設定できるのですが、今のところはやっていません。

- https://docs.renovatebot.com/automerge-configuration/

自動テストを完璧に書けている自信がないのと、環境によって動く動かないがあったりするので（IE11とか…）、コードレビューを通すようにしています。

# `@types`はグループ化したほうがいいかも

前述のようにマイナー/パッチアップデートはグループ化してるのですが、TypeScriptの型定義の更新は差分を見ても「なるほど」としか言えないことが多く、レビュー時のノイズになりがちなので、別のMerge Requestにまとめると良さそうかもと思っています。
都合のいいことに`group:definitelyTyped`というプリセットが用意されています。

- https://docs.renovatebot.com/presets-group/#groupdefinitelytyped

# 設定ファイルはJSON5型式がいいかも

Renovateの設定ファイルはいくつかの名前や型式に対応しています。

- https://docs.renovatebot.com/configuration-options/

その中に`json5`という見慣れない拡張子があります。これはJSON5という形式で、ざっくりいうとコメントが書けるJSONと思っておけばよさそうです（正確にはECMAScript 5.1の記法が使えるJSONの拡張フォーマット）。

- https://json5.org/

Renovateの設定は追い込んでいくと複雑になりがちでコメントを残しておきたくなるので、JSON5型式はメリットがありそうです。

# まとめ

Renovateを半年運用して得られた知見を振り返ってみました。
Renovate導入前は手動でアップデートしていたことを考えるとだいぶ楽になったと思う反面、レビューがそれなりに大変なので、Auto Mergeを有効化するなど引き続き改善していきたいと思います。