1.この記事を書こうと思った背景

今更感満載だけれど、パッケージの依存関係の更新ツールである Renovate について理解が浅いと感じることがあった。とりわけ、PresetsConfig の書き方については見様見真似でやってしまっている感が否めなかった。

そこで、表題のとおり、Renovate を個人リポジトリで小さく始めながら 、Renovate を触っていく上で押さえておきたい点について、この記事に書き留めていきたい。

2.前提と環境情報

Renovate の platformhttps://github.com とし、GitHub App で運用する。Renovate の導入手順は Installing & Onboarding - Renovate Docs を参考にした。

また、Renovate で指定する更新方法のことを Config と書いておく。というのも 設定 と日本語で書いてしまうと一般的な「設定」と、Config のうち、どちらを指して書いているのか、区別することが難しいためである。

3.スタート地点としての [“config:base”]

Renovate の Config は 設定ファイルに書いていくのだが、公開されている Presets(Config Presets) を使うこともできる。

たとえば、Shareable Config Presets - Renovate Docs | Renovate Docs で紹介されている、extends: [“config:base”] を指定するだけでも Renovate を使うことができる。

$ cat renovate.json5
{
  extends: ["config:base"],
  timezone: "Asia/Tokyo"
}

renovate.json5 はコメントが書ける renovate.json のようなもの。詳細は、5-4.Renovate の設定ファイルにコメントを書きたい を参照。

["config:base"] で採用されている Config は以下のとおり。

{
  "extends": [
    ":dependencyDashboard",
    ":semanticPrefixFixDepsChoreOthers",
    ":ignoreModulesAndTests",
    ":autodetectPinVersions",
    ":prHourlyLimit2",
    ":prConcurrentLimit10",
    "group:monorepos",
    "group:recommended",
    "workarounds:all"
  ]
}

出所:config:base | Full Config Presets - Renovate Docs | Renovate Docs

4.Renovate の Config の適用ロジック

ところで Config は以下の3つの方法で適用されている。

  • 自分で Renovate の設定ファイルで指定
  • Preset を使ってRenovate の設定ファイルで指定
  • Renovate の設定ファイルに書かない
$ cat renovate.json5
{
  //Preset から指定
  "extends": ["config:base"],
  //自分で指定
  "timezone": "Asia/Tokyo",
  "dependencyDashboard": false
}

ここで気になるのが、Config の適用ロジックだ。たとえば、PresetConfig が書かれていたら、どちらから適用されるのだろうか? Renovate の設定ファイルに書かれている順に適用されるのだろうか?

Configuration Options - Renovate Docs | Renovate Docs では、Config の適用ロジックについて次のように述べられている。

Renovate will evaluate all packageRules and not stop once it gets a first match. … later rules can override settings from earlier rules if needed.

Renovate はすべての packageRule を評価し、最初にマッチするものがあれば停止しません。(略)必要であれば、後のルールが前のルールの設定を上書きすることができます。(DeepLより)

注意するべき点は、冒頭の evaluate all packageRulesoverride settings from earlier の2点だろう。つまり、Config は Renovate の設定ファイルに書かれている順に適用されるといえる。

4-1.後に書いた Config は前に書いたそれを上書きするのか検証してみた

以下のように dependencyDashboard を2回設定したら、後に設定した "dependencyDashboard": false が適用され、Dependency Dashboard は表示されなかった。エラーにもならない。

$ cat renovate.json5
{
  "timezone": "Asia/Tokyo",
  "dependencyDashboard": true,
  "dependencyDashboard": false 
}

また、次のように後に "dependencyDashboard": true"extends": ["config:base"] を指定すると、Dependency Dashboard は表示された。

$ cat renovate.json5
{
  "timezone": "Asia/Tokyo",
  "dependencyDashboard": false,
  "dependencyDashboard": true,
}
$ cat renovate.json5
{
  "timezone": "Asia/Tokyo",
  "dependencyDashboard": false,
  "extends": ["config:base"]
}

["config:base"]":dependencyDashboard" という Preset を含む点に注意!

Starting from version v26.0.0 the "Dependency Dashboard" is enabled by default as part of the commonly-used config:base preset.

To disable the Dependency Dashboard, add the preset :disableDependencyDashboard or set dependencyDashboard to false.

出所: dependencyDashboard | Configuration Options - Renovate Docs

このようにルールを複数書いたとしてもエラー扱いとはならないが、読みにくい。ルールをダブらせて指定することはできるだけ避けたほうがよいのではないか?と思う。

4-2.Preset と個別に指定したい Config どちらを先に書くか

最初に Preset を書いていき、続いて個別に指定したい Config を都度書いていくべきだろう。

先に個別に指定したい Config を書いてしまうと、個別に指定したい Config は、Preset でセットされている Config に上書きされてしまう。

$ cat renovate.json5
{
  "timezone": "Asia/Tokyo",
  "dependencyDashboard": false,
  "extends": ["config:base"]
}

5.逆引き

5-1.ドキュメントに沿って設定をしたけどPRがこない

"rangeStrategy" とバージョンの指定方法を確認する。とくに、"rangeStrategy": "replace" となっており、かつ、バージョンの指定方法として キャレット(^) を使っていた場合、更新対象とはならないという。"rangeStrategy": "bump" を使うようにとのこと。

For example, if your package.json specifies a value for left-pad of ^1.0.0 and the latest version on npmjs is 1.2.0, then Renovate won’t change anything because 1.2.0 satisfies the range. If instead you’d prefer to be updated to ^1.2.0 in cases like this, then configure rangeStrategy to bump in your Renovate config.

出所:rangeStrategy | Configuration Options - Renovate Docs | Renovate Docs

5-2.Schedule の書き方を知りたい

schedule | Configuration Options - Renovate Docs | Renovate Docs で紹介されている。

詳細はドキュメントを参照してほしいが、要点は以下2点。

  • Cron 表記で指定するには、cheap-glitch/mi-cron を使う必要があり、また、時間ピッタリでの指定はできない
  • Schedule Presets を使うとカンタンに Schedule の設定ができるというが、以下のようにそのまま書いてしまってもいいと思う。
{
  "schedule": ["after 10pm and before 5am every weekday", "every weekend"]
}

5-3.ローカルで実行したい

npm でインストールするか、コンテナイメージを使うことで、ローカルでも実行できる。以下はコンテナイメージを使った様子。

$ docker run --rm \
> -e RENOVATE_TOKEN=<ghp_personal_acecess_token> \
> -e LOG_LEVEL=debug \
> renovate/renovate:32.72.0 \
> --platform github \
> --dry-run=true \
> gkzz/echo-server-typescript 

 WARN: cli config dryRun property has been changed to full
 INFO: Repository started (repository=gkzz/echo-server-typescript)
       "renovateVersion": "32.72.0"
 INFO: Dependency extraction complete (repository=gkzz/echo-server-typescript)
       "baseBranch": "main",
       "stats": {
         "managers": {
           "dockerfile": {"fileCount": 1, "depCount": 2},
           "npm": {"fileCount": 1, "depCount": 11}
         },
         "total": {"fileCount": 2, "depCount": 13}
       }

認証トークンを RENOVATE_TOKEN という環境変数に渡す必要がある。--platform github の場合、認証トークンは Personal Access Token(PAT)

参考:

5-4.Renovate の設定ファイルにコメントを書きたい

Renovate の設定ファイルは renovate.json 以外にもいくつかの名前やフォーマットに対応している。

  • renovate.json
  • renovate.json5
  • .github/renovate.json
  • .github/renovate.json5
  • .gitlab/renovate.json
  • .gitlab/renovate.json5
  • .renovaterc
  • .renovaterc.json
  • package.json (within a “renovate” section)

出所:Configuration Options - Renovate Docs | Renovate Docs

そのなかで renovate.json5renovate.json と違い、コメントが書ける

さて、コメントが書けるというのはどういうことか? JSON5 | JSON for Humans によると、JSON5 は ECMAScript 5.1からのいくつかの Production を含むように構文を拡張 したものとあり、そういった構文のひとつが、コメントを許容するという記法だという。

The JSON5 Data Interchange Format (JSON5) is a superset of JSON that aims to alleviate some of the limitations of JSON by expanding its syntax to include some productions from ECMAScript 5.1. …

Single and multi-line comments are allowed.

5-5.Dockerfile で使っているコンテナイメージのバージョンを Renovate で管理したい

docker:enableMajor | Docker Presets - Renovate Docs | Renovate Docs を使うとカンタンにできる。また、multi-stage builds でも問題なくできた。

{
  "extends": [
    "config:base",
    // https://docs.renovatebot.com/presets-docker/
    "docker:enableMajor"
  ]
//略
}

一例として、以下のような Dockerfile で使っている node:16.15.0-slim のバージョンを管理したいとする。

FROM node:16.15.0-slim AS base

#略

FROM node:16.15.0-slim AS dev
#略

無事、更新できている。

Image from Gyazo

以下は --dry-run=true でドライランをしたときに表示されたログの抜粋である。

       "config": {
         "dockerfile": [
           {
             "packageFile": "Dockerfile",
             "deps": [
               {
                 "depName": "node",
                 "currentValue": "16.15.0-slim",
                 "currentDigest": "sha256:df27e7dd385d35b7cc48d77d37bfd2e784bb4e2bc56da8ee8818a2a862d555ec",
                 "replaceString": "node:16.15.0-slim@sha256:df27e7dd385d35b7cc48d77d37bfd2e784bb4e2bc56da8ee8818a2a862d555ec",
                 "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
                 "datasource": "docker",
                 "depType": "stage",
                 "depIndex": 0,
                 "updates": [
                   {
                     "bucket": "non-major",
                     "newVersion": "16.15.1",
                     "newValue": "16.15.1-slim",
                     "newMajor": 16,
                     "newMinor": 15,
                     "updateType": "patch",
                     "newDigest": "sha256:3c8acd4934617f60dad7e4cc941faa064aa5a14da437dc156bdcad9d4a67bc4e",
                     "branchName": "renovate/node-16.x"
                   },
                   {
                     "bucket": "major",
                     "newVersion": "18.3.0",
                     "newValue": "18.3.0-slim",
                     "newMajor": 18,
                     "newMinor": 3,
                     "updateType": "major",
                     "newDigest": "sha256:0739e03851228cc1380f60e9dc14c192bd9d22d02eab364de609b6b8efb94174",
                     "branchName": "renovate/node-18.x"
                   },

上記で作成された PR をマージし、改めて Renovate を CLI から実行してみると、先ほどの non-major アップデートと違い、major アップデートとなっている。このことから、アップデート先のイメージは currentValue の書式、node:[0-9]+\.[0-9]+\.[0-9]-slim を参考に、 該当する non-major のバージョンがなければ、major のそれを選定するように伺える。 Image from Gyazo

ドライランでは、以下のように表示された。

       "config": {
         "dockerfile": [
           {
             "packageFile": "Dockerfile",
             "deps": [
               {
                 "depName": "node",
                 "currentValue": "16.15.1-slim",
                 "replaceString": "node:16.15.1-slim",
                 "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
                 "datasource": "docker",
                 "depType": "stage",
                 "depIndex": 0,
                 "updates": [
                   {
                     "bucket": "major",
                     "newVersion": "18.3.0",
                     "newValue": "18.3.0-slim",
                     "newMajor": 18,
                     "newMinor": 3,
                     "updateType": "major",
                     "branchName": "renovate/node-18.x"
                   }
                 ],

5-6.Presets で指定されているルールの確認場所

だいたい、以下で列挙されている。

https://docs.renovatebot.com/presets-config/

5-7.terraform の required_version と .terraform-version の更新を一つのグループにまとめたい

ポイントは、groupName を同じにするということ。matchManagers はそれぞれのパッケージやツールの Renovate の該当ページを参照して指定する。


// renovate.json5 一部抜粋

  packageRules: [
    {
      groupName: "terraform-version",
      // https://docs.renovatebot.com/modules/manager/terraform
      matchManagers: ["terraform"],
      matchDepTypes: ["required_version"],
    },
    {
      groupName: "terraform-version",
      // https://docs.renovatebot.com/modules/manager/terraform-version
      matchManagers: ["terraform-version"]
    }
  ]

x.困ったときに参照したいリンク集とひとことメモ