Renovateとpnpmで公開から7日経ったバージョンだけPRを作成する
Renovateには、公開されてから一定期間が経ったバージョンだけを対象にするminimumReleaseAgeという設定があります。公開直後のバージョンには、不具合のあるものや、乗っ取られたアカウントから公開された悪意のあるものが紛れていることがあるので、少し待ってから取り込むための設定です。 業務で使っているリポジトリでは、これを7日にしていました。ところが、7日経っていないバージョンのPRが作られたり、いつまでも待機中のままのPRが残ったりして、マージできないPRが溜まっていました。 今回はその原因を調べ、7日経ってそのままマージできるPRだけが作られるようにしたので、その備忘録になります。
INFO
記事内の設定は、説明のために簡略化しており、実際の設定とは異なります。 Renovate v44、pnpm v12で確認した内容です。どちらも変化の早いツールなので、最新のドキュメントもあわせて確認してください。
もともとの設定
renovate.jsonは下記のようになっていました。
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:best-practices"],
"minimumReleaseAge": "7 days"
}minimumReleaseAgeに満たないバージョンのPRには、renovate/stability-daysというステータスチェックが付き、期間が経つまで待機中になります。
パッケージマネージャーはpnpmです。少し前にyarnから移行しました。
原因
調べたところ、原因は下記の2つでした。
config:best-practicesに含まれる設定で、npmのパッケージだけ3日になっていた- lock file maintenanceには公開日時がないので、7日の判定がずっと待機中のままになっていた
どちらもpnpmとは関係なく、yarnやnpmでも起きます。pnpmの機能は、解決するときに使います。
npmのパッケージだけ3日になっていた
config:best-practicesは、Renovateがおすすめする設定をまとめたプリセットです。この中にsecurity:minimumReleaseAgeNpmというプリセットが含まれています。
{
"packageRules": [
{
"matchDatasources": ["npm"],
"minimumReleaseAge": "3 days"
}
]
}matchDatasourcesは、パッケージをどこから取ってくるかで絞り込む条件です。npmはnpmレジストリのことで、パッケージマネージャーのnpmではありません。pnpmやyarnで入れるパッケージも、npmレジストリから取ってくるので対象になります。
packageRulesは、トップレベルの設定より優先されます。そのため、自分で書いた"minimumReleaseAge": "7 days"は、npmレジストリのパッケージには効いていませんでした。設定ファイルを見ても3日はどこにも書かれていないので、気付きにくいです。
lock file maintenanceが待機中のままになる
もう1つは、lock file maintenanceのPRです。lock file maintenanceは、ロックファイルを消してパッケージマネージャーに作り直させ、package.jsonの範囲内で依存を最新にする機能です。間接的な依存もここで更新されます。config:best-practicesでは毎週動きます。
このPRのrenovate/stability-daysが、何日経っても待機中のままでした。
原因は、lock file maintenanceには公開日時がないことです。普通の更新は「このパッケージのこのバージョン」なので公開日時がありますが、lock file maintenanceはロックファイル全体の作り直しなので、1つに決まる公開日時がありません。 そして、minimumReleaseAgeBehaviourという設定の既定値はtimestamp-requiredです。公開日時がないものは、期間を満たしていないとみなされます。つまり、何日待っても待機中のままです。
解決方法
npmのパッケージも7日にする
自分のpackageRulesは、プリセットのpackageRulesより後に適用されます。同じ条件で7日を指定すれば上書きできます。
{
"matchDatasources": ["npm"],
"minimumReleaseAge": "7 days"
}lock file maintenanceは公開日時がなくても待機中にしない
lock file maintenanceだけ、minimumReleaseAgeBehaviourをtimestamp-optionalにします。こうすると、公開日時がないものは期間を満たしているとみなされます。
{
"matchUpdateTypes": ["lockFileMaintenance"],
"minimumReleaseAgeBehaviour": "timestamp-optional"
}ただし、これだけでは不十分です。待機中にならなくなるだけで、ロックファイルには公開されたばかりのバージョンもそのまま入ってしまいます。
pnpmのminimumReleaseAgeで7日経ったバージョンだけを選ぶ
ここでpnpmの機能を使います。pnpmにもminimumReleaseAgeという設定があり、公開から指定した時間が経っていないバージョンは選ばなくなります。 Renovateはlock file maintenanceのとき、pnpmにロックファイルを作り直させます。そのため、pnpm側で設定しておけば、7日経ったバージョンだけでロックファイルが作られます。
# 公開から7日経っていないものは選ばない。Renovateのlock file maintenanceもこの設定に従う
minimumReleaseAge: 10080単位は分なので、7日は10080(7 × 24 × 60)です。 Renovateだけでなく、手元でpnpm installやpnpm updateをしたときにも効きます。
最終的なrenovate.jsonは下記のようになりました。
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:best-practices"],
"minimumReleaseAge": "7 days",
"packageRules": [
{
"matchDatasources": ["npm"],
"minimumReleaseAge": "7 days",
"description": "config:best-practicesに含まれるsecurity:minimumReleaseAgeNpmが3日なので7日に戻す"
},
{
"matchUpdateTypes": ["lockFileMaintenance"],
"minimumReleaseAgeBehaviour": "timestamp-optional",
"description": "lock file maintenanceには公開日時がなく、stability-daysが常に待機中になるため。7日の判定はpnpm-workspace.yamlのminimumReleaseAgeで行う"
}
]
}INFO
Renovate v44.236で、minimumReleaseAgePackageManagerSyncという試験的な設定が追加されました。trueにすると、パッケージマネージャー側で公開からの経過日数の制限をかけている場合に限り、lock file maintenanceを待機中にしなくなります。 まだ試験的な設定なので、今回は使っていません。詳しくはRenovateのドキュメントを確認してください。
dry-runで確認する
Renovateでは、dry-run(実際にはPRを作らずに結果だけ出す)を実行できます。まだ試験的な機能ですが、localプラットフォームを使うと、手元のファイルに対して実行できます。 前後の比較まではしてくれないので、設定を変える前と後でそれぞれ実行し、どのバージョンが選ばれるかを比べました。
RENOVATE_GITHUB_COM_TOKEN=$(gh auth token) LOG_LEVEL=debug LOG_FORMAT=json \
npx --yes --package renovate@44 -- renovate --platform=local > /tmp/renovate-dryrun.log 2>&1--platform=localで、今いるディレクトリのファイルを対象にできます。このときは最初からdryRun=lookup(更新できるバージョンを調べるところまで)で動くので、dry-runの指定は不要です。リリースノートなどをGitHubから取るため、トークンを渡しています。 ログはかなり長いので、パッケージごとに必要な項目だけを抜き出しました。
newVersion:上げようとしているバージョンreleaseTimestamp:その公開日時pendingVersions:期間を満たしていないため対象外にしたバージョン
変更前は、公開から3日以上経ったバージョンが選ばれていました。
{"logTime":"2026-11-10T03:36:22.436Z","depName":"next","updates":[{"newVersion":"16.4.5","releaseTimestamp":"2026-11-03T18:01:54.667Z","pendingVersions":["16.4.6"]}]}
{"logTime":"2026-11-10T03:36:22.436Z","depName":"oxfmt","updates":[{"newVersion":"0.77.0","releaseTimestamp":"2026-11-06T12:43:46.688Z","pendingVersions":["0.78.0"]}]}
{"logTime":"2026-11-10T03:36:22.436Z","depName":"pnpm","updates":[{"newVersion":"12.18.0","releaseTimestamp":"2026-11-05T00:56:16.339Z","pendingVersions":null}]}変更後は、7日以上経ったバージョンだけが選ばれ、それより新しいものはpendingVersionsに入っています。
{"logTime":"2026-11-10T04:36:44.477Z","depName":"next","updates":[{"newVersion":"16.4.4","releaseTimestamp":"2026-11-02T10:49:48.611Z","pendingVersions":["16.4.5","16.4.6"]}]}
{"logTime":"2026-11-10T04:36:44.477Z","depName":"oxfmt","updates":[{"newVersion":"0.75.0","releaseTimestamp":"2026-10-27T05:48:04.648Z","pendingVersions":["0.76.0","0.77.0","0.78.0"]}]}
{"logTime":"2026-11-10T04:36:44.477Z","depName":"pnpm","updates":[{"newVersion":"12.17.0","releaseTimestamp":"2026-10-30T14:23:51.302Z","pendingVersions":["12.18.0"]}]}lock file maintenanceのステータスチェックは、ローカルでは確認できません。マージ後にRenovateが作り直したPRを見ると、renovate/stability-daysが成功になっていました。 ロックファイルに追加されたバージョンの公開日時も調べたところ、一番新しいものでも公開から7日と約21時間経っており、7日未満のものはありませんでした。
セキュリティ修正は待たずに入る
7日待つ設定にすると、気になるのがセキュリティ修正です。脆弱性が見つかったときに、修正版を7日も待ちたくはありません。
Renovateのセキュリティ修正のPRは、Renovate側のminimumReleaseAgeの対象外です。さらにpnpmを使っている場合は、修正するパッケージをパッケージ名@バージョンの形でpnpmのminimumReleaseAgeExcludeに自動で追加してくれます(renovatebot/renovate#40020)。
minimumReleaseAge: 10080
minimumReleaseAgeExclude:
# Renovate security update: [email protected]
- [email protected]minimumReleaseAgeExcludeは、minimumReleaseAgeの対象外にするパッケージの一覧です。これで、pnpmもそのバージョンを7日待たずに選べます。どのセキュリティ修正で追加したかが分かるように、Renovateはコメントも一緒に書き込みます。
既知の制限
ただし、まだ解決していない問題があります。自動で追加されるのは、修正するパッケージ本体だけです。そのパッケージが依存しているパッケージは、同時に公開されたものであっても追加されません。
たとえばNext.jsは、@next/envや@next/swc-*などの依存も同じタイミングで公開されます。nextだけが例外になっても、依存のほうが7日経っていないので、pnpmがロックファイルを作れずに失敗します。 この問題はRenovateのIssueで報告されていますが、記事執筆時点では未解決です。
対応されるまでは、失敗したPRのエラーに出てくる依存を、パッケージ名@バージョンでminimumReleaseAgeExcludeに手で追加してマージします。payloadcms/payloadなど、pnpmのminimumReleaseAgeを使っている多くのリポジトリが、Next.jsの依存を同じように追加しています。
minimumReleaseAgeExclude:
# Renovate security update: [email protected]
- [email protected]
- '@next/[email protected]'
- '@next/[email protected]'頻発するようなら、'@next/*'のようにパターンでまとめて例外にする方法もあります。ただし、そのパターンに当てはまるパッケージは、どのバージョンも7日待たずに入るようになるので、手で追加する手間と見比べて決めるのが良さそうです。
いかがだったでしょうか。minimumReleaseAgeは1行で設定できますが、config:best-practicesの中で上書きされていたり、lock file maintenanceでは公開日時がなかったりと、そのままでは思ったとおりに動きませんでした。 Renovate側の判定とpnpm側のminimumReleaseAgeを組み合わせることで、7日経ってそのままマージできるPRだけが作られるようになりました。セキュリティ修正まわりには未解決の問題が残っていますが、今のところは手動で例外を追加すれば対応できます。ご参考になれば幸いです。