フロントエンド開発でパッケージのアップデートを継続的におこなう - Renovate

フロントエンド開発でパッケージのアップデートを継続的におこなう

これは [Classi Advent Calendar 2018](https://qiita.com/advent-calendar/2018/classi) 1 日目の記事です。
フロントエンドエンジニアの @kasaharu です。

# はじめに
- 昨今のフロントエンド開発はフレームワークと呼ばれるものから便利なライブラリまで幅広いパッケージを使って行われている
- しかし、これらは導入したときのままであることが多く、バージョンアップすることを怠ると後々問題の原因になったりする
    - バージョンを上げないとセキュリティ問題に対応できなくなったり、パッケージそのものがサポートされなくなったりする
- また、逆にバージョンを上げることでパフォーマンス改善などの恩恵を受けられる場合もあるが、その機会を損失していたりする
- 今回は、できるだけ負荷にならずに継続的なパッケージアップデートを習慣化するために Renovate というサービスを使用しているのでそのまとめをする

# [Renovate](https://renovatebot.com/) とは
<img width="1277" alt="renovate.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/b6db228c-4f1d-0841-db04-119812a33cca.png">

- Automated Dependency Updates と謳っている
- 対象リポジトリの package.json を監視し、パッケージに更新があった場合に Pull Request(PR) を作成してくれる
    - package.json の他に .circleci/config.yml や Dockerfile なども監視対象になる
- GitHub, GitLab に対応しており BitBucket にも対応予定
- GitHub の public リポジトリなら無料で使える

# 導入
- [Marketplace](https://github.com/marketplace/renovate) から "Open Source" プランを選択しインストールをする
<img width="941" alt="renovate_install.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/812d9969-55c8-9fa8-1492-c43906ceeeeb.png">
- インストールすると [GitHub - settings - Applications](https://github.com/settings/installations) にアプリが表示される
- Renovate の Configure ボタンを押して "Repository access" から Renovate を使いたいリポジトリを選択し、保存する
- 対象のリポジトリに Renovate から "Configure Renovate" というタイトルの PR が届くのでそれをマージして設定完了
    - renovate.json が追加される
- 設定が完了すると "Pin dependencies" というタイトルの PR が届くので問題なければマージする
    - 今の package.json に記載されている各パッケージのバージョンを固定
    - バージョンアップを Renovate にゆだねるので固定してしまって問題ない

# 特徴
- package.json の他に Dockerfile, .circleci/config.yml も監視する
    - Docker image で使っている Node.js のバージョンアップなどにも使える
- アップデートするパッケージの PR が open の状態で次のバージョンが出た場合、古い PR を自動でクローズして次の PR が作られる
    - PR が無駄にたまらない
- まとめてアップデートしたほうがいいパッケージを Monorepo としてグルーピングして PR を作る仕組みがある
    - デフォルトで Monorepo となっているのは [presets-monorepo](https://renovatebot.com/docs/presets-monorepo/) 参照(Storybook などがある)
    - 最新の情報は [renovate-config-monorepo/package.json](https://github.com/renovatebot/presets/blob/master/packages/renovate-config-monorepo/package.json) を見ると確認できる
    - PR は下記のようになる
<img width="939" alt="storybook.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/a94a3285-34a5-ea1b-1fd8-8d44ee7adee3.png">
- コンフリクトした場合は自動で rebase してコンフリクトを解消する
- PR を手動でマージした後にブランチを消し忘れても Renovate が自動で削除する
<img width="667" alt="delete_branch.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/9bdf21a7-0a1d-0690-bb2c-003266e88f0f.png">


# 便利なオプション

オプション | 説明
----- | -----
[schedule](https://renovatebot.com/docs/configuration-options/#schedule) | Renovate が PR を作成する時間帯を指定できる
[labels](https://renovatebot.com/docs/configuration-options/#labels) | PR にラベルが設定でき Renovate から来た PR かどうかを一覧ですぐに判別できる
[automerge](https://renovatebot.com/docs/configuration-options/#automerge) | 「patch バージョンは auto merge」や「devDependencies は auto merge」などの設定が柔軟にできる
[rebaseLabel](https://renovatebot.com/docs/configuration-options/#rebaselabel) | GitHub の PR に該当のラベルをつけると即時 rebase が行われる<br>デフォルトは "rebase"
[enabled](https://renovatebot.com/docs/configuration-options/#enabled) | 特定のパッケージはバージョンアップの対象外にすることが可能
[lockFileMaintenance](https://renovatebot.com/docs/configuration-options/#lockfilemaintenance) | lock file のメンテナンスが可能

- その他設定は [Configuration Options](https://renovatebot.com/docs/configuration-options/) を参照

# Classi での使い方
```json:renovate.json
{
  "extends": [
    "config:base"
  ],
  "timezone": "Asia/Tokyo",
  "schedule": ["every weekend"],
  "labels": ["renovate"],
  "patch": { "automerge": true },
  "lockFileMaintenance": {
    "enabled": true,
    "schedule": [
      "before 3am on the first day of the month"
    ]
  },
  "packageRules": [
    {
      "groupName": "Unit test package",
      "packagePatterns": ["^jasmine", "^karma"]
    },
    {
      "groupName": "Angular DevKit",
      "packagePatterns": ["^@angular-devkit/"]
    },
    {
      "packagePatterns": ["^mysql"],
      "enabled": false
    }
  ]
}
```

- assignees, reviewers にはチームメンバーを指定
- スケジューリング : 毎週末
    - これにより月曜日にはアップデートが必要なパッケージの PR が作られている
- patch バージョンアップは auto merge
    - PR を作成して、マージするまでを Renovate が自動でやるのでパッケージアップデートにかける時間を削減できる
<img width="681" alt="auto_merge.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/84f6a497-1bc6-748a-8a34-94db6317748c.png">

- PR に "rebase" ラベルをつけることで即時 rebase するように設定
<img width="691" alt="rebase.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/8b5783f7-6085-1f27-ebcc-16ef3c603fab.png">
- グルーピング機能を使って `angular-devkit` などのパッケージを 1 つの PR で作成する
    - グルーピング設定するとそれぞれ作成されていた PR は自動でクローズされ、新規でグルーピングされた PR が作られる

angular-devkit/build-angular 単体 | angular-devkit/build-ng-packagr 単体 | Grouping　後
--- | --- | ---
<img width="722" alt="a.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/d5501b04-2e71-8203-0198-1a633b1c37c2.png"> | <img width="712" alt="b.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/ba3ad985-1af0-7108-482f-33bc2bef4c57.png"> | <img width="710" alt="c.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/3721d5d3-a38c-39ad-664c-2c5f9a67b105.png">
- Docker image で使用している MySQL のバージョンは Renovate で変更したくないので `"enabled": false` にしている
- 毎月 1 日 3 時に lock file(yarn.lock) のメンテナンスをするように設定
    - package.json に記載されているパッケージのアップデートをやっていても、依存しているパッケージのバージョンでハマったことがあったので lock file も定期的にメンテナンスするように設定

# まとめ
実際に仕事で使い始めて 2 ヶ月以上経過しましたが、毎週月曜日の定期作業として習慣化してきました。
テストが通ることで動作保証するため、単体テストのコードカバレッジ 100% をルール化し、テストを書くモチベーションの一つにもなっています。
<img width="689" alt="code_coverage.png" src="https://qiita-image-store.s3.amazonaws.com/0/28573/be0ad4fe-5b13-cb03-e143-80b88dfa4748.png">

また、こまめに上げることで major バージョンアップ時もあまり時間がかからないのを実感しています。
これを読んだ人も是非試してみてください。

明日は @tetsuroito さんです。

## 参考
- [Renovate - Docs](https://renovatebot.com/docs/)
* [Automated Dependency Updates with Renovate](https://www.slideshare.net/teppeis/automated-dependency-updates-with-renovate-102769685)