[GitHub] モノリポ(npm workspaces)環境でサブプロジェクトごとに Grouped version updates for Dependabot を構成する際の注意点

サブプロジェクトを更新する Pull Request にロックファイルの変更が含まれなる挙動となりました
2023.12.24

こんにちは、CX 事業本部 Delivery 部の若槻です。

GitHub でコードの依存関係の管理を効率化できる Dependabot は、npm workspaces により構成されたモノレポ環境でも利用が可能です。

次のように構成ファイルでルートディレクトリを対象とすると、すべてのサブプロジェクトをアップデートの対象とすることができます。

.github/dependabot.yml

version: 2
updates:
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: daily

また、次のようにサブプロジェクトごとにアップデートを構成することもできます。サブプロジェクトごとにコードオーナーが異なっている場合にも便利です。

.github/dependabot.yml

version: 2
updates:
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: daily
  - package-ecosystem: npm
    directory: /sub1
    schedule:
      interval: daily
  - package-ecosystem: npm
    directory: /sub2
    schedule:
      interval: daily

さて今回は、上記のようなモノリポ(npm workspaces)環境でサブプロジェクトごとにアップデートする構成を Grouped version updates と組み合わせた際の注意点についてです。

サブプロジェクトごとのアップデートと、Grouped version updates を組み合わせた場合、期待動作とならない

Grouped version updates を使用すると、依存関係をアップデートする Pull Request をアップデートごとにまとめることができます。使用しなければ、依存関係ごとに Pull Request が作成されてノイズとなるため、Dependabot を利用する上では実質必須の機能と言えます。

サブプロジェクトごとにアップデートを構成している場合は、次のようにアップデートごとにグループを設定します。

.github/dependabot.yml

version: 2
updates:
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: daily
    groups:
      rootDpendencies:
        patterns:
          - "*"
  - package-ecosystem: npm
    directory: /sub1
    schedule:
      interval: daily
    groups:
      sub1Dependencies:
        patterns:
          - "*"
  - package-ecosystem: npm
    directory: /sub2
    schedule:
      interval: daily
    groups:
      sub2Dependencies:
        patterns:
          - "*"

上記構成を実際に動かしてみます。ルートおよびそれぞれのサブプロジェクトの package.json に古いバージョンの依存関係を追加しておきます。

すると、プロジェクトごとに Pull Request が作成されました。

しかしルートの Pull Request にはロックファイル(package-lock.json)に加えて、ルートだけでない各プロジェクトのマニフェストファイル(package.json)の変更が含まれています。

一方でサブプロジェクトの Pull Request には、マニフェストファイルの変更のみが含まれています。

Grouped version updates を構成しない場合のように、プロジェクトごとにロックファイルおよび定義ファイルの変更が含まれることが期待動作 でしたが、残念ながらそうはなりませんでした。

この場合、ルートプロジェクトを更新する Pull Request の更新をマージするまでロックファイルの変更が反映されないため、ロックファイルの更新をもとに依存関係のインストールを CI で行っている場合などに、依存関係アップデート後のソースコードを CI がチェックできなくなってしまいます。(すべての Pull Request をマージ後に初めてチェックできるようになる)

versioning-strategy を increase にしても解決しない

この問題は Dependabot の Issue にも上がっていましたが、そこには「versioning-strategyincrease を指定すれば良い」とありました。

versioning-strategy は、Dependabot による依存関係アップデート時のバージョン管理方法を指定するオプションです。

versioning-strategy のオプションには次の 6 つがあります。npm の場合は auto がデフォルトです。

Strategy Description(自動翻訳)
auto アプリケーションとライブラリを区別しようとします。アプリケーションの場合は increase、ライブラリの場合は widen を使用します。
increase 常に最小バージョン要件を新しいバージョンに合わせて増やします。範囲がすでに存在する場合、通常は下限のみが増加します。
increase-if-necessary 元の制約が新しいバージョンを許可する場合は、制約をそのままにして、そうでない場合は制約を増やします。
lockfile-only ロックファイルのみを更新するためのプルリクエストのみを作成します。パッケージマニフェストの変更が必要な新しいバージョンは無視します。
widen 可能な場合は、新しいバージョンと古いバージョンの両方を含めるように許可されるバージョン要件を広げます。通常、これは最大許可バージョン要件のみを増やします。
N/A 一部のパッケージマネージャは、versioning-strategy パラメータを設定することをサポートしていません。

サブプロジェクトの Dependabot のジョブログを見ると、プロジェクトがライブラリだと判断されて widen が使用されている様子です。

では、versioning-strategyincrease に指定してみます。

.github/dependabot.yml

version: 2
updates:
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: daily
    groups:
      rootDpendencies:
        patterns:
          - "*"
  - package-ecosystem: npm
    directory: /sub1
    schedule:
      interval: daily
    groups:
      sub1Dependencies:
        patterns:
          - "*"
  - package-ecosystem: npm
    directory: /sub2
    schedule:
      interval: daily
    groups:
      sub2Dependencies:
        patterns:
          - "*"

しかし上記変更を適用しても、サブプロジェクトの Pull Request には引き続きロックファイルの変更が含まれず、マニフェストファイルの変更のみが含まれる挙動となりました。

ジョブログを見ると、更新時のストラテジーは widen ではなく bump になっており、increase が適用されていない様子です。

考えられる対処方法

対処方法としては、次のようなものが考えられますが、それぞれデメリットがあります。

No 対処方法 デメリット
1 手動で package-lock.json を更新する。 PR のブランチをローカルにプルして更新するなどの対応が必要。
2 自動で package-lock.json を更新する。 GitHub Actions ワークフローを別途構成する必要。
3 対象ディレクトリをルートのみとする。 すべてのプロジェクトの依存関係の更新が一つの PR にまとまってしまう。
4 Grouped version updates を使わない。 依存関係ごとに PR が作成されてしまう。

個人的には、サブプロジェクトごとに更新を適切にグルーピングする管理を自動化できる 2 番目の方法が良いと思います。

おわりに

モノリポ(npm workspaces)環境でサブプロジェクトごとに Grouped version updates for Dependabot を構成する際の注意点についてご紹介しました。

良かれと思ってプロジェクトごとにアップデートを分けたらまさかの挙動となってしまいました。余裕があれば Issue を出したいと思います。

以上