モノレポで大量に作成されるRenovateのPRに負けないための施策

こんにちは、Platformチームのほしいです。この記事は HRBrain Advent Calendar 2021 3日目の記事です。

qiita.com

突然ですが、ソフトウェアの依存関係のアップデートはどうやってますか? 弊社では2020年頃にRenovateを導入しました。しかし、botが作成するPRが溜まりがちでした。(だってマージしてもどんどんPRが作成されるんだもの...!)
さらに、モノレポに移行して、各リポジトリのRenovateのPRが集約されると、もう数百件ものPRが作成されるため、PRの一覧を眺めるだけでも疲れてしまう感じになっています。

問題となっていること

社内でGitHub Discussionsを使ってヒアリングしてみたところ、以下のような意見が出てきました。

  • モノレポで横断的なPRが作成されるため、プロダクトチームが分かれている体制だとマージしづらい
  • プロダクトによっては、時間をとって複数のPRを確認してマージする動きもあるが、マージ後にブラウザによってはデグレすることもあり、運用が手間になっている

そもそも、依存関係のアップデートをRenovateのようなPRを作成するツールでやるのに限界があるのではないかという意見もあります*1が、設定を工夫することでいい感じに依存関係をアップデートできるような気もするので、少しやり方を考えてみたいと思います。

施策1. モノレポのサービスごとにPRを作成する

弊社のモノレポのディレクトリは以下のような構成になっています。

apps/
  foo/
    backend/
    frontend/
  bar/
    backend/
    frontend/
  ...

Renovateのモノレポ用の設定で、additionalBranchPrefixというのがあります。モノレポ移行時に、一括で"additionalBranchPrefix": "{{parentDir}}-"に設定していました。
GoやDockerfileの依存関係のアップデートのPRはこの設定により、同じ依存関係のアップデートのPRがディレクトリごとに複数作成されるようになりました。一方、フロントエンドの依存関係はapps以下で1つのPRが作成されるため、サービスごとのチームだとマージしにくいというデメリットがありました。

フロントエンドもバックエンドもディレクトリで分けたPRを作成する

そこで、このような設定に変更しました。どうやらフロントエンドは{{parentDir}}だと、apps以下でまとめて作成されるようですが、逆に{{baseDir}}に一括で設定すると、バックエンドのPRが作成されないようでした。なので苦肉の策で以下のような設定にしました。

  "packageRules": [
    {
      "managers": ["gomod"],
      "additionalBranchPrefix": "{{parentDir}}-",
      "packagePatterns": [".*"]
    },
    {
      "managers": ["dockerfile"],
      "additionalBranchPrefix": "{{parentDir}}-",
      "packagePatterns": [".*"]
    }
  ]
  "additionalBranchPrefix": "{{baseDir}}-",

ちなみに参考にしたのはこちらのissueです。 github.com

課題

上記の設定によって、サービスごとにPRをマージできるようにはなったのですが、依存関係のPRって本当に大量に作成されます。1つ1つ手作業でマージしていくのもしんどいし、現実的ではないので、次の施策と組み合わせて使うのが良さそうです。また、まだ試せていないのですが、サービスごとに複数の依存関係のPRを1つにまとめると、確認してマージしやすいのかもと思っていたりします。

施策2. マイナー、パッチバージョンの自動マージをサービスごとに設定できるようにする

Renovateについて調べていたところ、自動マージを使って上手に運用している会社が多いようでした。

developer.hatenastaff.com

blog.studysapuri.jp

renovate-approveを使って自動で approveを設定する場合、下記の設定をすれば、各サービスでマイナー、パッチバージョンの自動マージの設定ができます。

  "packageRules": [
    {
      "paths": ["apps/foo/backend/**"],
      "matchUpdateTypes": ["minor","patch"],
      "automerge": true
    },
    {
      "paths": ["apps/foo/front/**"],
      "matchUpdateTypes": ["minor","patch"],
      "automerge": true
    }
  ]

テスト環境が整っているサービスは、この自動マージの設定を入れて、テストがこけたら、チームでPRをRevertして、必要な修正を入れてからマージするみたいな運用にしたら良さそうです。

最後に

ソフトウェアの依存関係のアップデートは手間がかかるので、これを効率化したい気持ちがあります。Renovateが最高なソリューションかというと、そうではない気もするのですが、なんかいい感じに設定したら使えなくはなさそうです。あと、自動マージの設定はテスト環境の整備も同時に必要だと思います。
今後もぼちぼちrenovate.jsonをいじってみて、これなら使えそうっていうのがあれば追記していく予定です。何か良いプラクティスを知っている方がいたら、ぜひ教えてください!

*1:こちらの論文によると、依存関係のアップデートのPRのうち、実際にマージされている数は1/3程度だそうです。