Renovateはアプリケーションで使用している依存ライブラリを更新するためのPull Requestを自動で作成してくれるソフトウェアです。 柔軟な設定が可能で便利な反面、設定項目は150以上と非常に多く、思い通りに設定するのが難しい場合もあります。
意図した通りに設定するためには、それぞれの設定項目が、どのタイミングで適用されるかを知る必要があります。 そのためにはRenovateがどのように実行されるのかを知るのが有用です。
そこで本記事では、Renovateの内部実装を読みながら処理の流れを見ていきます。 対象のバージョンは執筆時点で最新の v36.19.2 です。
なお、筆者はRenovateの開発に関わる人間ではありません。本記事の内容は筆者がドキュメントやソースコード、実行時のデバッグログなどを読んだ上での理解に基づいています。誤りがありましたらご指摘いただけると幸いです。
前提
普段はGitHub Appとして提供されているものを利用することが多いかもしれませんが、Renovateはオープンソースソフトウェアであり、CLIとして実行できます。
GitHub Appを利用する場合、いつの間にかPull Requestができているという体験になり、内部で行われている処理を意識することは少ないかもしれません。処理の流れを考える際は、RenovateをホストしているMend社の立場で考えてみるとわかりやすいと思います。
実行の流れ
結論から言うと、Renovateは次の流れで実行されます。
1〜3の処理を本記事ではそれぞれフェーズと呼び、repositoryフェーズの処理をステップと呼ぶことにします。 これはドキュメントやソースコードで使われている呼称ではなく、本記事内の便宜上のものです。
1〜3のフェーズは、 lib/workers/global/index.ts
の start() 関数内で行われています。それぞれのフェーズはOpen Telemetryで計装されており、 instrument()
関数でラップされています。
以降では、それぞれのフェーズ・ステップを詳しく見ていきます。
1. config
該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/global/index.ts#L123-L148
configフェーズでは、設定ファイルや環境変数、コマンド引数で表現される Global config を読み込みます。
ここでの設定ファイルは config.js
などであり、一般にRenovateの設定としてイメージする renovate.json
などとは異なることに注意が必要です。
この時点で、対象のPlatformが決まります。PlatformはGitリポジトリをホストするサービス (GitHubなど)を表します。
なお local
はテスト用途の特別なPlatformで、ローカルファイルシステムを参照するのみで、Pull Requestの作成などは行いません。
なお、ここで登場する mergeChildConfig() 関数 は設定をマージするために繰り返し登場するので、覚えておくとコードが読みやすいでしょう。
2. discover
該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/global/index.ts#L150-L153
discoverフェーズでは、Platformから対象のGitリポジトリを探します。--autodiscoverオプション を指定した場合は、 --tokenオプション などで指定した権限でアクセス可能なリポジトリを取得します。
3. repository
該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/global/index.ts#L169-L195
repositoryフェーズでは、discoverされたリポジトリごとに下記の処理を行います。
repositoryフェーズ内の各ステップの処理は、 workers/repository/index.ts の renovateRepository()
関数内で行われます。
各ステップは、Splitという単位で実行時間を計測されています。 addSplit(<Split名>)
がそのSplitが終了することを表します。
3-1. init
該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/repository/index.ts#L40-L55
initステップでは、Gitリポジトリをローカルにcloneします。
さらに、リポジトリ内の設定ファイル(renovate.json
など)を読み込みます。
この時点で extends で表現された Preset を解決したり、暗号化された設定を復号したりします。
3-2. extract
該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/repository/index.ts#L56-L62 https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/repository/process/index.ts/#L114-L139
lib/workers/repository/index.ts で呼び出している extractDependencies()
関数内で、extractステップと次のloopkupステップが実行されます。
extractステップでは、リポジトリのファイルから更新可能性があるパッケージ(いわゆるライブラリ)を抽出します。 更新対象となるベースブランチが複数ある場合は、すべてのベースブランチについて実行されます。
パッケージの抽出にあたっては、さまざまな言語のパッケージマネジャーが Manager として定義されており、有効なManager(デフォルトはすべて)の設定ファイルから更新可能性があるパッケージを抽出します。
regexManagers
で正規表現によるカスタムManagerを定義することも可能です。
3-3. lookup
lookupステップでは、extractステップで抽出されたすべてのパッケージについて、更新があるかを確認し、更新先のバージョンを決定します。osvVulnerabilityAlerts が有効な場合は、最初に脆弱性情報も確認します。
パッケージの更新があるかを確認する先であるパッケージレジストリは DataSource として定義されています。
また、更新の種類(Major/Minorなど)を判断するためのバージョンニングポリシーは Versioning として定義されています。
3-4. onboarding
該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/repository/index.ts#L63-L73
onboardingステップでは、Renovateが未設定の場合に、オンボーディング(Renovateの導入)のためのPull Requestを作ります。
3-5. update
該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/repository/index.ts#L75-L79
updateステップでは、Renovateが設定済みの場合に、パッケージを更新するためのPull Requestを作ります。 このステップでは、大まかに言えば次の処理が行われます。
- packageファイル (
package.json
など) を更新 - lockファイル (
package-lock.json
など。artifactと呼ばれる) を更新 - ブランチを作成
- コミットを作成
- Pull Requestを作成
- 設定されていれば自動マージ
updateステップの後に行われる後処理については、本記事では割愛します。
まとめ
本記事ではRenovateの処理の流れを見てきました。
普段Renovateの設定を書く際は、configフェーズとdiscoverフェーズを意識する必要はほとんどなく、repositoryフェーズのステップを意識すれば十分です。その中でもonboardingステップは初回だけの特殊な処理なので除くと、基本的にはリポジトリごとに以下の順序で実行されることを覚えておくと良いでしょう。
- init: リポジトリをローカルにcloneする
- extract: リポジトリのファイルから更新可能性があるパッケージを抽出する
- lookup: 抽出されたすべてのパッケージについて、更新があるかを確認し、更新先のバージョンを決定する
- update: Renovateが設定済みなら更新するためのPull Requestを作る
CLIの--dry-run オプションを使う際にも、指定する値ごとに実行される処理がイメージつきやすくなるかと思います。また、それぞれのステップでどの設定が参照されるかは、改めて別の記事を書きたいと考えています。