orangain flavor

じっくりコトコト煮込んだみかん2。知らないことを知りたい。

内部実装から理解するRenovateの処理の流れ

Renovateはアプリケーションで使用している依存ライブラリを更新するためのPull Requestを自動で作成してくれるソフトウェアです。 柔軟な設定が可能で便利な反面、設定項目は150以上と非常に多く、思い通りに設定するのが難しい場合もあります。

意図した通りに設定するためには、それぞれの設定項目が、どのタイミングで適用されるかを知る必要があります。 そのためにはRenovateがどのように実行されるのかを知るのが有用です。

そこで本記事では、Renovateの内部実装を読みながら処理の流れを見ていきます。 対象のバージョンは執筆時点で最新の v36.19.2 です。

なお、筆者はRenovateの開発に関わる人間ではありません。本記事の内容は筆者がドキュメントやソースコード、実行時のデバッグログなどを読んだ上での理解に基づいています。誤りがありましたらご指摘いただけると幸いです。

前提

普段はGitHub Appとして提供されているものを利用することが多いかもしれませんが、Renovateはオープンソースソフトウェアであり、CLIとして実行できます。

GitHub Appを利用する場合、いつの間にかPull Requestができているという体験になり、内部で行われている処理を意識することは少ないかもしれません。処理の流れを考える際は、RenovateをホストしているMend社の立場で考えてみるとわかりやすいと思います。

実行の流れ

結論から言うと、Renovateは次の流れで実行されます。

1. config: 環境変数やコマンドの引数で表現されるグローバルな設定を読み込む 2. discover: 対象のGitリポジトリを探す 3. repository: リポジトリごとに次の処理を行う     1. init: リポジトリをローカルにcloneする     2. extract: リポジトリのファイルから更新可能性があるパッケージを抽出する     3. lookup: 抽出されたすべてのパッケージについて、更新があるかを確認し、更新先のバージョンを決定する     4. onboarding: Renovateが未設定ならオンボーディングのためのPull Requestを作る     5. update: Renovateが設定済みなら更新するためのPull Requestを作る
Renovateの処理の流れ

1〜3の処理を本記事ではそれぞれフェーズと呼び、repositoryフェーズの処理をステップと呼ぶことにします。 これはドキュメントやソースコードで使われている呼称ではなく、本記事内の便宜上のものです。

1〜3のフェーズは、 lib/workers/global/index.tsstart() 関数内で行われています。それぞれのフェーズは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.tsrenovateRepository() 関数内で行われます。

各ステップは、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

該当箇所: https://github.com/renovatebot/renovate/blob/36.19.2/lib/workers/repository/process/index.ts/#L140-L163

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を作ります。 このステップでは、大まかに言えば次の処理が行われます。

  1. packageファイル (package.jsonなど) を更新
  2. lockファイル (package-lock.jsonなど。artifactと呼ばれる) を更新
  3. ブランチを作成
  4. コミットを作成
  5. Pull Requestを作成
  6. 設定されていれば自動マージ

updateステップの後に行われる後処理については、本記事では割愛します。

まとめ

本記事ではRenovateの処理の流れを見てきました。

普段Renovateの設定を書く際は、configフェーズとdiscoverフェーズを意識する必要はほとんどなく、repositoryフェーズのステップを意識すれば十分です。その中でもonboardingステップは初回だけの特殊な処理なので除くと、基本的にはリポジトリごとに以下の順序で実行されることを覚えておくと良いでしょう。

  1. init: リポジトリをローカルにcloneする
  2. extract: リポジトリのファイルから更新可能性があるパッケージを抽出する
  3. lookup: 抽出されたすべてのパッケージについて、更新があるかを確認し、更新先のバージョンを決定する
  4. update: Renovateが設定済みなら更新するためのPull Requestを作る

CLI--dry-run オプションを使う際にも、指定する値ごとに実行される処理がイメージつきやすくなるかと思います。また、それぞれのステップでどの設定が参照されるかは、改めて別の記事を書きたいと考えています。

参考