Engineering

RenovateでCloudflare Workers SDKのパッケージをグルーピングする

  • Renovate
  • Cloudflare Workers
  • CI/CD
  • monorepo

Cloudflare Workers SDKのパッケージ群をRenovateでアップデートする際、packageRulesmatchSourceUrlshttps://github.com/cloudflare/workers-sdk を指定すれば、wrangler@cloudflare/vite-pluginminiflareを1つのPRにまとめられます。

{
  packageRules: [
    {
      groupName: "cloudflare workers-sdk",
      // パッケージ名を個別に指定する方法
      matchPackageNames: ["wrangler", "@cloudflare/vite-plugin", "miniflare"],
      // or ソースリポジトリURLで一括指定する方法
      matchSourceUrls: ["https://github.com/cloudflare/workers-sdk"],
    },
  ],
}

Renovateのmonorepo presetにはまだ含まれていないため、手動でのグルーピング設定が必要です。この記事では、個別PRによるインストール失敗の問題、グルーピング設定の方法、そしてmonorepo presetへの提案で浮上したimmortal PRs問題を紹介します。

Cloudflare Workers SDKのパッケージ構成

Cloudflare Workers SDKは、GitHub上の cloudflare/workers-sdk というモノレポで開発されています。代表的なパッケージは以下の3つです。

  • wrangler — Cloudflare WorkersのCLIツール。ローカル開発、ビルド、デプロイを担います
  • @cloudflare/vite-plugin — ViteベースのフレームワークとCloudflare Workersを統合するプラグイン
  • miniflare — Cloudflare Workersのローカルシミュレーター。wranglerの内部でも使われています

これらのパッケージは密結合です。依存の方向は @cloudflare/vite-plugin → wrangler → miniflare という一方向ですが、monorepo内の依存指定に workspace:* を使っているため、npmにpublishされた時点でexact versionに変換されます。@cloudflare/vite-pluginCHANGELOGを見ると、パッチリリースのたびに「Updated dependencies」として固定バージョンが記載されています。

この仕組みにより、どれか1つだけバージョンを上げると他のパッケージが要求するexact versionと食い違い、パッケージの解決に失敗します。wrangler、@cloudflare/vite-plugin、miniflareは常にセットで更新する必要があります。

ラビー合同会社では、コーポレートサイト(labee.jp)と開発者ツールサイト(labee.dev)の両方をCloudflare Workersにデプロイしています。labee.jpではwranglerを、labee.devではさらに@cloudflare/vite-pluginも使用しており、どちらのリポジトリでもRenovateによる依存パッケージの自動アップデートを運用しています。

個別PRが引き起こす問題

Renovateのデフォルト設定では、パッケージごとに独立したPRが作成されます。cloudflare/workers-sdk モノレポのパッケージも例外ではなく、wranglerと@cloudflare/vite-pluginのアップデートがそれぞれ別のPRになります。

labee.devのリポジトリで実際に起きた事例を紹介します。ある週のRenovateの定期実行で、@cloudflare/vite-pluginのPRとwranglerのPRが別々に作成されました。どちらのPRも pnpm install の時点でエラーになります。

vite-pluginだけを更新すると、新しいvite-pluginが要求するwranglerのexact versionとプロジェクトにインストール済みのバージョンが一致しません。逆にwranglerだけを更新しても、既存のvite-pluginが古いwranglerのexact versionを要求しているため解決できません。個別のPRは単体では pnpm install すら通らない状態です。

すべてのPRをクローズして手動でまとめてアップデートすることになりました。Renovateが自動化のために作ったPRを捨てて手作業に戻るのでは本末転倒です。

Reactモノレポ(react、react-dom)やAstroモノレポ(astro、@astrojs/*)ではこの問題は起きません。Renovateのビルトインmonorepo presetに登録されており、デフォルトでグルーピングされるためです。Cloudflare Workers SDKはこのpresetに含まれていないため、ユーザー側でグルーピングを設定する必要があります

packageRulesでグルーピングする

Renovateの packageRules を使えば、特定の条件に合致するパッケージをグルーピングできます。Cloudflare Workers SDKのパッケージをまとめるには、matchSourceUrls でソースリポジトリのURLを指定し、groupName でグループ名を設定します。

{
  packageRules: [
    {
      groupName: "cloudflare workers-sdk",
      matchSourceUrls: ["https://github.com/cloudflare/workers-sdk"],
    },
  ],
}

matchSourceUrls はRenovateがnpmレジストリから取得するパッケージメタデータの repository フィールドを参照します。パッケージ名を個別に列挙する必要はありません。新しいパッケージがモノレポに追加されて依存に加えた場合も、自動的にグルーピング対象になります。

ラビー合同会社では、labee.jpとlabee.devの両方で使う共通のRenovate設定をGitHub Organization配下の .github リポジトリに配置しています。各リポジトリの renovate.json5 は、この共通設定をextendsで参照するだけのシンプルな構成です。

// .github/renovate.json5(共通設定、抜粋)
{
  extends: [
    "config:best-practices",
    ":timezone(Asia/Tokyo)",
    ":prHourlyLimitNone",
    ":prConcurrentLimitNone",
    "schedule:earlyMondays",
    "customManagers:biomeVersions",
  ],
  packageRules: [
    {
      matchUpdateTypes: ["minor", "patch", "pin", "digest"],
      automerge: true,
    },
    {
      groupName: "cloudflare workers-sdk",
      matchSourceUrls: ["https://github.com/cloudflare/workers-sdk"],
    },
  ],
}
// 各リポジトリの renovate.json5
{
  $schema: "https://docs.renovatebot.com/renovate-schema.json",
  extends: [
    "github>LabeeHive/.github:default.json5",
  ],
}
GitHubGitHub - LabeeHive/.githubContribute to LabeeHive/.github development by creating an account on GitHub.

Cloudflare Workers SDKを使うリポジトリが複数あるため、グルーピングを共通設定に入れています。各リポジトリで同じpackageRulesを書くのは冗長ですし、新しいリポジトリを作ったときに設定漏れが起きます。

matchSourceUrlsとmatchPackagePatternsの違い

グルーピングの条件指定には matchSourceUrls のほかに matchPackagePatternsmatchPackageNames も使えます。

matchPackageNames は、パッケージ名を直接列挙する方式です。

{
  groupName: "cloudflare workers-sdk",
  matchPackageNames: [
    "wrangler",
    "@cloudflare/vite-plugin",
    "miniflare",
  ],
}

対象が明確ですが、モノレポに新しいパッケージが追加されて依存に加えた場合、設定の更新が必要です。

matchPackagePatterns は正規表現でパッケージ名をマッチさせます。@cloudflare/ で始まるパッケージをまとめられますが、@cloudflare/ai@cloudflare/d1 など、workers-sdkモノレポに含まれないCloudflareパッケージも巻き込む可能性があります。wranglerやminiflareは @cloudflare/ スコープではないため、別途追加も必要です。

matchSourceUrls はnpmレジストリのメタデータに含まれるソースリポジトリURLでマッチさせます。cloudflare/workers-sdk リポジトリに含まれるパッケージだけが対象になるため、過不足なくグルーピングできます。このモノレポには create-cloudflare など無関係なパッケージも含まれますが、プロジェクトの依存に含まれていなければPRの対象にはなりません。依存に含まれないパッケージが巻き込まれる心配はありません

なお、matchSourceUrls はnpmパッケージの repository フィールドを参照します。このフィールドが未設定のプライベートパッケージでは機能しないため、その場合は matchPackageNames で明示的に列挙してください。

グルーピング後の運用

グルーピング設定を追加した後、次のRenovate実行で効果を確認できます。labee.devでは以前、@cloudflare/vite-pluginとwranglerが別々のPRとして作られていましたが、設定変更後は「chore(deps): update cloudflare workers-sdk」という1つのPRにまとまっています。

@cloudflare/vite-pluginとwranglerが同じPRに含まれることで、exact versionの整合性が保たれた状態で pnpm install が走ります。個別PRをクローズして手動対応する作業は不要になりました。

automergeとの組み合わせも有効です。ラビー合同会社の共通設定では、minor、patch、pin、digestのアップデートタイプに対してautomergeを有効にしています。グルーピングされたPRがCIを通過すると自動マージされるため、Cloudflare Workers SDKのアップデートは完全に自動化されています。

ただし、グルーピングはアップデートのタイミングを揃えるものであり、互換性を保証するものではありません。majorアップデートはautomerge対象外です。特にwranglerのmajorアップデートではデプロイ設定の変更やAPIの非推奨化が伴うことがあるため、CHANGELOGを確認してからマージしてください。

monorepo presetの状況

Renovateのmonorepo presetに登録されれば、ユーザー側のpackageRules設定は不要になります。Cloudflare Workers SDKについてはmonorepo presetへの追加を提案しています。

GitHubAdd cloudflare/workers-sdk to monorepo presets · renovatebot/renovate · Discussion #42605Tell us more. cloudflare/workers-sdk is a monorepo that publishes several tightly coupled packages such as wrangler, @cloudflare/vite-plugin, and miniflare. These packages must be upgraded together...

ただし、repoGroups でリポジトリ全体を登録する方式ではimmortal PRsの問題があります。cloudflare/workers-sdk の各パッケージはバージョン体系が異なるため(wranglerは 4.x、miniflareは 4.YYYYMMDD.x、@cloudflare/vite-pluginは 1.x)、バージョンが揃わずPRが更新され続ける可能性があります。

GitHubci(contributing): `monorepo.json` checklist · Issue #41851 · renovatebot/renovateDescribe the proposed change(s). When contributing to lib/data/monorepo.json there are a few things we should be taken into account entries will be upgraded together entries that have different ver...

この問題を踏まえ、patternGroups で密結合なコアパッケージのみを登録する方向で検討中です。presetへの追加が実現するまでは、ユーザー側でのpackageRules設定が必要です。