1. この記事を書こうと思った背景
パッケージのバージョン管理をするとなったときに真っ先に思い浮かぶツールは Renovate だが、なんと .tool-versions のマネージャーが提供されていなかった。
Managers - Renovate Docs で挙げられている dockerfile などはマネージャーが提供されており、たとえば、Dockerfile の場合、デフォルトで以下の書式の Dockerfile に書かれたコンテナイメージのバージョン管理が major を除いてできる。1
(^|/|.)Dockerfile$
(^|/)Dockerfile[^/]*$
さて、マネージャーが提供されていない .tool-versions に書かれた言語やツールのバージョン管理をどうすればよいだろうか?
結論から言うと、Regex Manager で .tool-versions から更新管理したいものを指定(キャプチャ)すればよかった。
この記事では、具体的にどうやったか?その設定をするためにどう調べたか?書いていきたい。
2. 前提
2-1. 2022/08/01 時点でのワークアラウンドな方法であること
以下の issue で議論されているように、以前から .tool-versions をサポートしてほしいという声はあがっている。そのため、この記事で書かれていることは、あくまでも 2022/08/01 時点でのワークアラウンドな方法であることとしたい。
Upgrade versions in .tool-versions #4051
2-2. .tool-versions で管理しているもの
.tool-versionsで管理しているものは、TerraformとNode.js
$ cat .tool-versions
terraform 1.0.0
nodejs 16.15.0
3. 環境情報
Renovateの実行環境はGitHub App
4. renovate.json5 の設定内容抜粋
regexManagers で .tool-versions に書かれた Terraform や Node.js の現バージョンをキャプチャする。
$ cat renovate.json5
{
//抜粋
regexManagers: [
{
// Terraform
fileMatch: ["^.tool-versions$"],
matchStrings: ["terraform (?<currentValue>\\d+\\.\\d+\\.\\d+)"],
datasourceTemplate: "github-releases",
depNameTemplate: "hashicorp/terraform",
extractVersionTemplate: "^v(?<version>.*)$"
},
{
// Node.js
fileMatch: ["^.tool-versions$"],
matchStrings: ["nodejs (?<currentValue>\\d+\\.\\d+\\.\\d+)"],
datasourceTemplate: "github-tags",
depNameTemplate: "nodejs/node",
extractVersionTemplate: "^v(?<version>\\d+\\.\\d+\\.\\d+)$"
}
]
}
4-1. regexManagers の設定項目の解説
必須項目は [必須] 、そうではないものは [任意] としている。
- [必須]fileMatch
- キャプチャする対象が書かれているファイルを指定する。
- [必須]matchStrings
- キャプチャする対象
(currentValue)を適宜正規表現も使って指定する。 \(バックスラッシュ) はそれ自体もエススケープする必要がある。たとえば、\nを書く場合、\\nとなる。
- キャプチャする対象
- [必須]matchStrings に depName を書くか、depNameTemplate を指定する。
- [必須]matchStrings に datasource を書くか、datasourceTemplate を指定する。
datasourceTemplateには以下のページで書かれているSupported Datasourcesのいずれかを指定する。
- [任意]extractVersionTemplate
datasourceやdatasourceTemplateで指定した更新バージョンの情報を整形する- 例: 頭についている
vを取り除いた任意の文字列を取得する場合は、"^v(?<version>.*)$"
4-2.datasourceTemplate の値の選定方法
datasourceTemplate の値を決めるのに試行錯誤したので、調べたことを書いていく。
- 基本的な考え方
- 更新対象のパッケージのマネージャーを Renovate が提供していないか、以下の Renovate のマネージャーのページの Supported Managers から探す。
- 提供している場合、更新対象のパッケージを取り扱うのマネージャーはどの
Datasourceをサポートしているか?調べる。 - 提供されていない場合、 Renovate のドキュメントの
Datasourceのページの Supported Datasources から、更新したいものがないか?探す。
例1. .tool-versions に書かれた Terraform の datasourceTemplate の場合
datasourceTemplate: "github-releases"
例2. .tool-versions に書かれた Node.js の datasourceTemplate の場合
datasourceTemplate: "github-tags"
例3. .tool-versions に書かれた Golang の datasourceTemplate の場合
datasourceTemplate: "golang-version"- ※ Renovate から
Golangのマネージャーが提供されていないので、これまでのやりかたと異なり、Renovate のドキュメントの Datasource のページの Supported Datasources からgolang-versionをみつける。 - 参考: golang-version の Datasource のドキュメント
- ※ Renovate から
- cf. Golang の Datasource を
golang-versionとした経緯が書かれた issue - cf. Go Modules のマネージャーは Renovate から提供されている。
5. 小ネタを一問一答形式で書く
5-1. .tool-versions に書かれた Terraform のバージョンと tf ファイルの required_version のバージョンの更新 PR をひとつにまとめたい
そもそもどうして別々の PR になっているか?というと、.tool-versions に書かれた Terraform のバージョンと tf ファイルの required_version のバージョンはそれぞれ異なる packageRules で設定しているためである。
このように、複数の packageRules で設定している更新をひとつにまとめたい場合、groupName で同じ値を指定することでまとめられる。
regexManagers: [
//略
],
packageRules: [
{
// .tool-versions
groupName: "terraform",
matchManagers: ["regex"],
},
{
// tf ファイルの required_version
groupName: "terraform",
matchManagers: ["terraform"],
matchDepTypes: ["required_version"]
}
]
以下は .tool-versions に書かれた Terraform のバージョンと tf ファイルの required_version の更新PRの CHANGELOG だが、無事、 .tool-versions に書かれた Terraform のバージョンと tf ファイルの required_version のバージョンの更新 PR をひとつにまとめることができた。
5-2. .tool-versions に書かれた Node.js のバージョンと Dockerfile に書かれた Node.js のコンテナイメージのバージョン更新 PR にまとめたい
Node.js の場合も同様に、groupName を使うことでまとめられる。
regexManagers: [
//略
],
packageRules: [
{
// .tool-versions
groupName: "nodejs",
matchManagers: ["regex"],
matchPackageNames: ["nodejs/node"]
},
{
groupName: "nodejs",
matchDatasources: ["docker"],
matchPackageNames: ["node"]
}
]
参考: group:nodeJs | Group Presets - Renovate Docs
以下は .tool-versions に書かれた Node.js のバージョンと Dockerfile に書かれた Node.js のコンテナイメージのバージョン更新 PR の CHANGELOG だが、こちらも同様にひとつにグルーピングすることができた。
5-3. terraform-version マネージャーを使ってもいい?
ところで、Renovate には、terraform-version というマネージャーがある。わざわざ、Regex Manager を使わなくても terraform-version マネージャーを使えばいいのではないか?
、、と思って調べてみたが、実は terraform-version マネージャーでは、.tool-versions に書かれた Terraform のバージョン管理はできない。
terraform-version マネージャーは、あくまでも .terraform-version に書かれた Terraform のバージョンの更新管理をするためのマネージャー であり、Terraform のバージョン管理をするためのマネージャーではなかった。
もし、Terraform のバージョン管理役を .tool-versions ではなく、.terraform-version が担っているのであれば、Renovate の設定せずとも .terraform-version に書かれた Terraform のバージョン管理ができる。
By default, Renovate will check any files matching the following regular expression: (^|/).terraform-version$.
参考: Automated Dependency Updates for Terraform Version - Renovate Docs
nodeenv マネージャーも同様で、nodeenv マネージャーで .tool-versions に書かれた Node.js のバージョン管理はできない。nodeenv マネージャーは、あくまでも .node-version に書かれた Node.js のバージョンを更新管理をするためのマネージャーである。
参考: Automated Dependency Updates for nodenv - Renovate Docs
5-4. depName と packageName の違いや使い分けは?
packageNameが未指定である場合、depNameの値が適用される。- 両方値が指定されている場合、
depNameは ログやコミットメッセージ、 PR で使われ、packageNameはパッケージレジストリから更新対象をルックアップするのに使われる。
参考: Difference between depName and packageName? · Discussion #14885 · renovatebot/renovate
6. 参考資料
Regex Managerについて調べるにあたり参考にしたドキュメントdepNameとpackageNameの違いや使い分け
major を除いて、Dockerfile に書かれたコンテナイメージの更新の検知が出来るようになっている理由は、
Default Presetの docker ルールが有効になっている一方で、Docker Presetの docker:enableMajor のデフォルト値が disabled であるためである。 ↩︎

