Renovate で Go の依存ライブラリを自動更新する
概要
- Renovate とは何か、なぜ必要なのか
- Renovate のインストール方法
-
go.mod
内の依存ライブラリを Renovate で自動更新する方法
を紹介します。
Renovate とは何か
依存関係を自動更新するツール。
Renovate が実行されると Renovate は依存関係の参照を検索し、新しいバージョンが利用可能な場合は Pull Request を作成し、バージョンを自動的に更新してくれます。
なぜ必要なのか
依存ライブラリが多いとそれらのアップデートに追随して更新していくのはなかなか大変な作業です。
アップデートが頻繁なライブラリ(Google Cloud SDK, AWS SDK など)があれば尚更で、更新作業は後回しにされやすくなります。
Renovate を使って自動化することで作業負荷を軽減することができます。
つまり、少ない作業工数でアプリケーションを安全に利用できる状態を維持しやすくできます。
前提
次のようなファイルを持つリポジトリを事前に用意します。
.
├── go.mod
└── main.go
module renovate-golang-tutorial
go 1.23.3
require (
cloud.google.com/go/firestore v1.14.0
cloud.google.com/go/storage v1.36.0
go.opentelemetry.io/otel v1.33.0
go.opentelemetry.io/otel/sdk v1.33.0
)
package main
import (
"cloud.google.com/go/firestore"
"cloud.google.com/go/storage"
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/sdk/trace"
)
func main() {
// 依存ライブラリを使用していることを示すためのコードです。特に意味はありません。
firestore.NewClientWithDatabase(context.Background(), "", "")
storage.NewClient(context.Background(), storage.WithJSONReads())
trace.NewTracerProvider()
otel.Tracer("example.com/basic")
}
go mod tidy
を実行して go.sum
を生成します。
使用する Renovate のバージョンは 39.107.0
です。
Renovate のインストール
GitHub App を使って Renovate をインストールする方法を記載します。
このアプリはパブリックリポジトリとプライベートリポジトリのどちらでも無料でインストールできます。
まず Renovate の Github App ページ に移動し、[Configure] ボタンを選択します。
私の場合、ユーザアカウントか組織アカウントかを選択する画面が表示されました。
Configure
とあるのはアカウントに紐づくどこかのリポジトリで既に Renovate をインストールしているものです。
ここでは Configure
が付いていない sample-account
を選択し、リポジトリ選択画面が表示されました。
Renovate を実行したいリポジトリを選択して install ボタンを押します。
そうすると、次のような renovate.json
をリポジトリルートに追加するPRが自動生成されます。
renovate.json
の config:recommended は使用する言語によらず多くのユーザに推奨される設定が施されているpresetsです。
presetsとは簡単に言うと、extends
配列に加えることで使用できるビルトインの設定です。
Dependency Dashboard:依存関係の可視化
先程のPRをマージすると Renovate が動き出します。
そして早速、依存ライブラリを更新するPRを3つ作成してくれました。
1つのPRで1つのライブラリを更新するものになっています。
また、リポジトリの issue に「Dependency Dashboard」というものが作られました。
このダッシュボードはプロジェクトの依存関係やアップデート対象を一目で把握することができる代物です。
Open
には Renovate が自動生成した更新PRのリンクがあり、Detected dependencies
には go.mod
内の依存ライブラリが記載されています。
enabledManagers:パッケージマネージャーの制限
Renovate はパッケージマネージャーという概念に基づいて依存関係を検出・更新しています。
パッケージマネージャーは File Matching や DataSource という機能を持っていて、前者は設定した正規表現に合致する依存関係設定ファイルを見つけて依存関係を検出し、後者は抽出した依存関係に対して新しいバージョンを検索します。
具体的なパッケージマネージャーには gomod や npm, composer など様々なものがあり、ユーザはこれらを必要に応じて設定して Renovate が依存関係を適切に把握できるようにします。
先程PRが作成されたのは、gomod マネージャーがリポジトリ内で go.mod
ファイルを見つけて依存関係を検出し、ライブラリの更新も見つかったため更新PRが作成されました。
デフォルトでは他のマネージャーも有効化されており、例えば次のような Dockerfile が含まれている場合、dockerfile マネージャーによって golang イメージのタグを最新版に更新するPRが作成されます。
FROM golang:1.23.3
WORKDIR /go/src
COPY go .
RUN GOOS=linux GOARCH=amd64 go build -o /go/main main.go
ENTRYPOINT ["/go/main"]
今回は go.mod のライブラリに限定して自動更新をかけたいため、enabledManagers に gomod
を指定することで、使用するパッケージマネージャーを限定します。
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
// 追加
"enabledManagers": [
"gomod"
]
}
go mod tidy
の実行
postUpdateOptions:私がライブラリの更新作業を行うとき、まず go get <package>@version
を実行してgo.mod
とgo.sum
を更新し、その後で go mod tidy
を実行して不要になった依存関係を削除していました。
gomod マネージャーのデフォルトの挙動では go mod tidy
が実行されず、go.mod
や go.sum
に不要な依存関係が残ったままになってしまいます。
go mod tidy
を実行するには、postUpdateOptions に gomodTidy
を指定します。
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"enabledManagers": [
"gomod"
],
// 追加
"postUpdateOptions": [
"gomodTidy"
]
}
ここまでの作業によって、手動で行っていた Go ライブラリの更新作業が Renovate によって自動化されました。
packageRules:マイナー・パッチ更新PRを集約
ここまでの設定では依存するライブラリ単位でPRが生成されます。
PR数が多くなると、CIリソースを多く消費してしまうことや、PRを人間がレビュー・マージする場合にヒューマンリソースがかかってしまうことなどが懸念されます。
セマンティックバージョニングに則っていれば、マイナー・パッチ更新は後方互換性が保たれていることを踏まえて、PRをまとめても良さそうです。
go.mod
の依存ライブラリでマイナー・パッチ更新PRを集約するには、packageRules を次のように記述します。
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"enabledManagers": [
"gomod"
],
"postUpdateOptions": [
"gomodTidy"
],
// 追加
"packageRules": [
{
// ①
"matchManagers": [
"gomod"
],
// ②
"matchDatasources": [
"go"
],
// ③
"matchUpdateTypes": [
"patch",
"minor"
],
// ④
"groupName": "golang-modules-minor-patch-updates"
}
]
}
packageRules
はライブラリの更新PRをグループ化するためのルールです。このルールが一致するライブラリ更新は同一のPRにまとめられます。今回のルールは次の3つで構成されています。
- パッケージマネージャーが gomod マネージャーであること(
①
) - DataSource が go であること(
②
)- gomod マネージャーが扱う Datasource には
golang-version
とgo
があり、前者はgo.mod
のgo
ディレクティブの更新を管理するものなので今回は対象外とし、後者を指定しています。
- gomod マネージャーが扱う Datasource には
- マイナー又はパッチアップデートであること(
③
)
上記が一致するPRはグループ化され、そのグループの名前が groupName で指定した値になります(④
)。groupName はPRタイトルの一部として使われます。
ちなみに、メジャーバージョンの更新は上記ルールに当てはまらないため、ライブラリ単位でPRが作成されます。
上記設定を行うと、3つのPRに分かれていたものが1つのPRに集約されました。
よく使いそうな設定
頻出の設定をいくつか簡単に説明をします。
必要に応じて取り入れて、快適な Renovate Life を送りましょう。
prHourlyLimit
1時間あたりに作成されるPRの最大数を制限します。
デフォルトは2
。0
にすると制限は無しとなります。
Renovate がPRを一度に大量に作ると、CI リソースを滞留させてしまって困る場合などに、これを設定してPRの作成速度を落とすことができます。
{
"prHourlyLimit": 10
}
label
PRにラベルを付与します。
{
"labels": ["renovate"]
}
presetsを使って書くこともできます。
{
"extends": [
":label(renovate)"
]
}
reviewers
PRのレビュワーを設定します。
{
"reviewers": [
"some-account"
]
}
shcedule
Renovate にブランチの作成(≒ PRの作成)を許可する時間帯を cron 書式で定義します。
スケジュールのデフォルト値は「いつでも」で、cron で* * * * *
を宣言するのと同じになります。
設定する際の注意点がいくつかあります。
- Renovate は分単位の精度をサポートしていないため、分の値に
*
を使用する必要がある - また、定義する時間帯が短すぎると Renovate が実行されない可能性があるため、少なくとも3~4時間の時間枠を設けることが推奨
- schedule を想定通り動かすには timezone の設定を行う(timezone, timezone preset)。
次のように設定すると、タイムゾーンが Asia/Tokyo で11時から15時の間にPRが作成されました。
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":timezone(Asia/Tokyo)"
],
"schedule": ["* 11-15 * * *"]
}
参考
Automated Dependency Updates for Go Modules
Discussion