renovate-config レポジトリを作成して renovate の設定を共通化する

## はじめに

NPM パッケージの更新管理といえば renovate か dependabot かの二択な近頃。dependabot はクリティカルなセキュリティイシューだけ管理したら良いものに、renovate は全部クリーンにしておきたいものに適用している人も多いかと思います。

そのシチュエーションにおいて困ってくるのが renovate の柔軟な設定を以下に楽にまとめて管理するか。大量のパッケージを管理している場合、renovate設定を一つ変えるために全部書き換えていくのはそれなりに手間のかかる作業になってきます。

例えば、 renovate からの PR に特定のラベルをつけたい、パッケージのメンテナが変わったからデフォルトのレビュー assignee を変更したい……などのたびに、20や30のレポジトリの設定を手動でやるのはあまり良いやり方とは言えません。

そんなときは、 renovate の設定をレポジトリに切り出して共通化しておくと便利です。

## renovate の設定共通化について

renovate には、 tsconfig.json や jest.config.js や .eslintrc などの NPM ベースのエコシステムの設定ファイルと同じように、 extends が存在します。

renovate をとりあえず導入するとデフォルトで作られる renovate.json でも、 extends が利用されていますね。

```json
{
  "extends": [
    "config:base"
  ]
}
```

この設定、他の設定ファイルの感覚でいると `yarn add` して設定して……という手順を踏まないといけないように見えて少し煩雑に映るのですが、実は renovate.json は、自身の dependencies にいない設定をフェッチしてくるように作られています。

フェッチのルールは[公式サイト](https://docs.renovatebot.com/config-presets/#preset-hosting) に書かれていますが、特に頻出する設定は以下でしょうか。

- `abc`: `renovate-config-abc` パッケージの `default` 設定を取得
- `@abc`: `@abc/renovate-config` パッケージの `default` 設定を取得
- `abc:xyz`: `renovate-config-abc`  パッケージの `xyz` 設定を取得
- `@abc:xyz`: `@abc/renovate-config`  パッケージの `xyz` 設定を取得

つまりはデフォルトで出てくる `config:base` は、 [renovate-config-config](https://github.com/renovatebot/presets/tree/master/packages/renovate-config-config) の base 設定を取得してきているという意味です。

つまりは、適当なパッケージを作成してやったあと、ここを書き換えるだけで、 deps の更新なしに、一つのパッケージの publish 状況に応じて連携する全てのレポジトリの renovate 設定を書き換えることができるようになります。

## 実際にレポジトリを作成して呼び出す

適当に名前空間を持った renovate-config 用のレポジトリを作成します。
私の場合は [https://github.com/elevenback/renovate-config](https://github.com/elevenback/renovate-config) を作成し、 `@elevenback/renovate-config` としました。

多くの場合、個人や組織用の renovate 設定となるはずですので、 `renovate-config-xxx` よりは `@xxx/renovate-config` のほうが行儀が良いかなと思います。

作った後は package.json 内に `renovate-config` というプロパティを追加、更にその下に `default` を用意し、普段のように記述するだけです。例えば renovate のデフォルト設定を引き継ぐだけの場合、以下のような設定になります。

```json:package.json
{
  "name": "@name/renovate-config",
  "version" "0.0.1",
  "renovate-config": {
    "default": {
      "extends": [
        "config:base"
      ]
    }
  }
}
```

これでパッケージ自体は作成完了。`npm publish` してやると設定は公開されます。

公開されたら、次は利用する側の設定に移ります。今回は default を利用してやるだけなので、 `renovate.json` に以下のように記述するだけで OK です。

```json:renovate.json
{
  "extends": ["@name"] // 私の場合だと "@elevenback"
}
```

先述の通り、 **`@abc` が `@abc/renovate-config:default` に対応している** ことを覚えておいてください。
`@abc/renovate-config` でも `@abc/renovate-config:default` でもなければ、 `@abc/default` でもありません。ただの `@abc` で OK です。

これの設定が終わってしまえば、あとは renovate が動き出すまで放置で OK です。

お疲れさまでした。

## CI による設定の自動テストを行う

ついでに、せっかく設定を記述したなら CI 環境も整えておくと便利です。renovate は、公式に renovate-config-validator というツールを提供しているので、これを共通化したレポジトリに導入しておきましょう。

renovate-config-validator は、renovate パッケージに付随してきます。NPM あるいは Yarn でインストールしてしまいます。

```bash
$ yarn add -D renovate
```

どのみち renovate の設定で Jest なりの出番はないはずなので、`npm test` の枠をもらってしまいましょう。

```json:package.json
{
  // ...
  "scripts": {
    "test": "renovate-config-validator"
  }
  // ... 
}
```

この状態で、間違った設定で実行すると、きちんと exit code 1 を出力してくれます。試しに午前13時という現実的でない時間を設定するとこうなります。

<img width="646" alt="スクリーンショット 2019-11-09 14.22.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75633/ddac4c7c-619d-5b37-e855-ea9c660b4846.png">

ここまでできたら CI 環境を整えて終わりです。最近だと GitHub Actions がファイルを配置するだけで手軽で高速なので、ここでは GitHub Actions のサンプルコードを置いておきます。

`.github/workflows/test.yml` に以下を配置すると OK です。

```yaml:test.yml
name: Renovate Validate

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [10.x, 12.x]

    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - name: yarn install and test
      run: |
        yarn 
        yarn test
```

あとは GitHub に載せてしまうと、自動でテストが走るようになってくれます。

<img width="1457" alt="スクリーンショット 2019-11-09 14.25.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75633/f08c54e8-ddf2-5b89-97cc-2620325e4973.png">

## おわりに

renovate の設定を共通化すると、レポジトリの環境に依存せず管理できたり、 CI を回す手間が省けたりと、非常に多くのメリットがあります。

一方で、実際に共通化してみると Organization の renovate 設定はまだ共通化しやすくても、fork される頻度が比較的多いレポジトリまで共通化することは個人的にまだ抵抗があります。

どのみち私が関係することは無いとはいえ、fork先にまで assignee の設定が私になっている config が生まれるのはあまり気持ちの良いものではないかなと思ったり。結果として、現状共通化先は最低限の設定のみになっていたりします。

個人用設定と Organization 設定を分けてみたり、default 以外にも複数の config を利用し始めてみたり。私自身共通化をはじめたところなので、何か学びがあれば随時共有しようと思います。