Skip to content

e2e ジョブの host Node を 24 に上げ、キャッシュキーをジョブ単位に絞る - #74

Open
kogai wants to merge 1 commit into
mainfrom
claude/e2e-ci-node
Open

kogai wants to merge 1 commit into
mainfrom
claude/e2e-ci-node

Conversation

@kogai

@kogai kogai commented Sep 14, 2026

Copy link
Copy Markdown
Owner

base は main.github/workflows/test.yml の e2e ジョブだけを触ります(Haskell ジョブは #65 が触っているので、ハンクは重なりません)。

訂正あり。 初版の本文には事実誤認が 2 件ありました(npm ci と lockfile の書き換えについて)。レビューで指摘を受け、このコメントで訂正したうえで、本文も直しています。

1. host の Node 12.x → 24.x

e2e ジョブは node-version: 12.x のままでした。Node 12 は 2022 年 4 月に EOL です。setup-node がまだバイナリを取ってこられるので CI は通っていましたが、4 年前にサポートが切れたランタイムで npm installnpx bazelisk を回し続ける理由はありません。Node 24 は現在 Active LTS です。

この PR が変えるのは「host の node」だけです。 //e2e/go:snapshot_test は rules_nodejs 3.1.0 の generated_file_test なので、テスト本体は rules_nodejs が持つ hermetic な Node で走り、それはこの変更では変わりません。 そこまで含めて現代化するのは #61generated_file_test を素の sh_test に置き換えて rules_nodejs を落とす)の仕事です。

Renovate の #69 も同じ 1 行を含みますが、あちらは @types/node 22 → 24 と package-lock.json の書き換えを巻き込んでおり、package-lock.json を触る #59 / #62 と衝突します。この PR はワークフローの 1 行だけに絞っています。

2. e2e ジョブのキャッシュキーを絞る

key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
  ${{ runner.os }}-          # ← これ

restore-keysLinux- だけなので、Haskell ジョブのキャッシュにも前方一致します。そちらは ~/.stack./.stack-work/ を含んでいて、直近の run では 実測 519 MBCache Size: ~519 MB (544375301 B))ありました。e2e ジョブには使い道のない中身です。

#65 で Haskell 側を Linux-ghc9.8.4-stack3.11.1- に絞ったのと同じ対処を、こちら側にも入れます。両方入って初めて、2 つのジョブのキャッシュが混ざらなくなります。

key: ${{ runner.os }}-e2e-node24-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
  ${{ runner.os }}-e2e-node24-

マージ後の初回は必ずキャッシュミスになりますLinux- にぶら下がっていた既存キャッシュにもう前方一致しないため)。ただし e2e キャッシュは実測 20 MB、依存は 4 つ、ジョブ全体で 31 秒なので実害はありません。

lockfile について

package-lock.jsonlockfileVersion: 1 のままです。.npmrclockfile-version=1 がそれを固定しているので、modern な npm で npm install しても v3 に書き換わりません(検証: .npmrc あり → 1 のまま / なし → 3 になる)。

この .npmrc#57 で意図的に入れたもので、コミットメッセージが根拠を 2 つ挙げています。

rules_nodejs 3.1.0 runs npm_install with its own bundled npm, and the CI job still runs Node 12.x; neither reads a v3 lockfile's packages key … The lockfile version can move once the Node toolchain and rules_nodejs are updated.

この PR は 2 つのうち片方(CI の Node 12.x)を解消します。 もう片方(rules_nodejs 3.1.0 の同梱 npm)は #61 が解消するので、#61#74 が両方入った時点で v3 移行の前提が揃います。 移行そのものは、package-lock.json を触る #59 / #62 と衝突するため別 PR に回します。

確認したこと

  • .github/workflows/test.ymlyaml.safe_load でパースし、jobs.e2e.steps[1].with{'node-version': '24.x'} になることを確認
  • Move to lts-23.25 (GHC 9.8.4) and stop pinning dependency versions #65test.yml への差分と照合し、ハンクが重ならないことを確認(あちらは 9〜27 行目、こちらは 31〜48 行目)
  • 519 MB と 20 MB はどちらも Actions のログに出ている実測値
  • CI で確認済み: run 34817481336//e2e/go:snapshot_test PASSED.bazelversion3.7.0 のままですが、bazelisk と Bazel 3.7.0 は Node 24 で問題なく動きました

🤖 Generated with Claude Code

https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z


Generated by Claude Code

Node 12 は 2022 年 4 月に EOL になっている。setup-node がまだ取ってこられる
ので CI は通っていたが、4 年前に上流のサポートが切れたランタイムで
npm install と bazelisk を動かし続ける理由はない。24.x に上げる。

ローカル (npm 10.9.7) で現在の package-lock.json のまま npm install が
通ることを確認した。lockfileVersion 1 なので npm が「one-time fix-up」の
警告を出してメタデータをレジストリから取り直すが、インストール自体は成功し、
終了コードは 0 になる。

あわせて e2e ジョブのキャッシュキーを絞る。restore-keys が
`${{ runner.os }}-` だけだったので、Haskell ジョブのキャッシュにも前方一致
する。そちらは ~/.stack と .stack-work を含んでいて実測 519 MB あり、
e2e ジョブには一切使い道がない。#65 で Haskell 側を
`${{ runner.os }}-ghc9.8.4-stack3.11.1-` に絞ったのと同じ対処を、
こちら側にも入れる。

lockfile を v3 に上げる変更はここには入れない。package-lock.json は #59#62 が触っており、衝突するため。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P8rZakwAiz1jpViUX34x1Z

kogai commented Sep 14, 2026

Copy link
Copy Markdown
Owner Author

CI が通りました(run 34817481336)。本文で「この PR の CI が最終確認」と書いた点の結果です。

npx bazelisk は Node 24 で問題なく動きました。 .bazelversion3.7.0 のままなので、そこが一番の懸念でしたが、e2e ジョブのログは次のとおりです。

INFO: Found 1 test target...
Target //e2e/go:snapshot_test up-to-date:
INFO: Elapsed time: 21.148s, Critical Path: 3.15s
//e2e/go:snapshot_test                                                   PASSED in 0.1s
Executed 1 out of 1 test: 1 test passes.

e2e ジョブ全体で 31 秒(07:21:28 → 07:21:59)。npm installbazelisk の Bazel 3.7.0 ダウンロードも、Node 24 で問題ありませんでした。

キャッシュも意図どおりのキーで保存されています。

Cache saved with key: Linux-e2e-node24-d22a199a6eb286f0419593d865e93362e1f68ff14824447e279a601dc69e8f6b-5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456

なお restore-keys を絞ったので、この run はキャッシュミスから始まっていますLinux- にぶら下がっていた既存キャッシュにはもう前方一致しません)。それでも 31 秒なので、実害はありません。次回以降は新しいキーでヒットします。


Generated by Claude Code

kogai commented Sep 14, 2026

Copy link
Copy Markdown
Owner Author

レビュー結果

差分そのものは安全です。CI が壊れる経路は見つかりませんでした。 ただし PR 本文に事実誤認が 2 点あり、うち 1 点は「やっていないこと」の理由付けを丸ごと無効にします。


必須

1. 「npm ci は v1 lockfile を受け付けない」は誤り

本文の「やっていないこと」にこうあります:

npm installnpm ci への変更もしていません。npm ci は v1 lockfile を受け付けないので、上の移行とセットでないと入れられません。

受け付けます。 このリポジトリの package.json / package-lock.jsonlockfileVersion: 1)をそのままコピーして npm 10.9.7 で実行した結果:

$ npm ci
npm warn old lockfile
npm warn old lockfile The package-lock.json file was created with an old version of npm,
npm warn old lockfile so supplemental metadata must be fetched from the registry.
npm warn old lockfile This is a one-time fix-up, please be patient...

added 4 packages, and audited 5 packages in 929ms
EXIT=0

npm install と同じ「old lockfile」警告が出るだけで、終了コードは 0 です。npm 7 以降の npm ci は v1 lockfile を読めます(packages キーが無い分をレジストリのメタデータで補う)。

npm ci 化を別 PR に回す判断自体には賛成ですが、理由が成立していません。実際の理由は「この PR をワークフロー 1 ファイルに閉じたいから」で十分なので、そう書き直してください。

なお npm ci 化するなら、現在 ./node_modules をキャッシュしている構成とは噛み合いません(npm ci は毎回 node_modules を消してから作り直すため、キャッシュしても捨てられます)。その PR では path~/.npm だけに絞るのが筋です。

2. 「npm は lockfile を v3 に書き換えます」は誤り — .npmrc を見落としています

本文:

警告は出ますがインストールは成功し、終了コードは 0。npm は lockfile を v3 に書き換えますが、CI はツリーの汚れを検査していないので問題になりません。

リポジトリ直下に .npmrc があり、中身は 1 行です:

lockfile-version=1

これが効くので、モダンな npm でも lockfile は v1 のままです。検証(npm 10.9.7、同じ package.json / package-lock.json):

.npmrc npm install 後の lockfileVersion
あり(リポジトリの実際の状態) 1(無変更)
なし 3(書き換わる)

つまり本文が「起きる」と書いている書き換えは起きません。結論(CI は通る)は変わりませんが、この PR が触る領域の前提条件を取り違えたまま報告されているので直してください。おそらく .npmrc を含まないディレクトリで検証されたのだと思います。

あわせて、この .npmrc#57 で意図的に入ったもので、コミットメッセージに根拠が明記されています:

The lockfile is regenerated with --lockfile-version 1 rather than being allowed to move to v3. rules_nodejs 3.1.0 runs npm_install with its own bundled npm, and the CI job still runs Node 12.x; neither reads a v3 lockfile's packages key, so they would silently re-resolve instead of honouring the lock. The lockfile version can move once the Node toolchain and rules_nodejs are updated.

ここが重要で、この PR は v1 固定の 2 つの根拠のうち片方(CI が Node 12.x)を解消します。残るのは rules_nodejs 3.1.0 の同梱 npm だけです。「v3 移行は #59 とのコンフリクトを避けて別 PR」という整理は妥当ですが、本文の「やっていないこと」は コンフリクト だけでなく .npmrc と rules_nodejs 3.1.0 という設計上の制約が別に存在することに触れるべきです。そうしないと、後続 PR が「#74 で Node を上げたからもう v3 にできる」と誤読します(rules_nodejs を上げない限りできません)。


推奨

3. 「Node 24 で npx bazelisk test が動くか」の答えは Yes。ただし根拠を本文に残してほしい

本文は「最終確認はこの PR の CI が行う」で止まっていますが、CI を回す前に確定できる話です。調べた結果:

  • @bazel/bazelisk 1.28.1 に engines フィールドはありませんengines: undefined)。Node バージョンの上限も下限も宣言していないので、npm install が EBADENGINE で落ちる経路はありません。
  • 同パッケージの bazelisk.jsos / path / child_process.spawn しか使っていない 2.3 KB のラッパーで、同梱の prebuilt Go バイナリ(bazelisk-linux_amd64 他 5 プラットフォーム)を spawn するだけです。postinstall スクリプトも native addon もありません。Node 24 で壊れる要素がありません。
  • Bazel 3.7.0 本体は Java/C++ なので host の node とは無関係、というご認識のとおりです。そして ubuntu-24.04 上で Bazel 3.7.0 は現に green です(run 34799473896 の e2e ジョブ: Downloading https://releases.bazel.build/3.7.0/release/bazel-3.7.0-linux-x86_64...//e2e/go:snapshot_test PASSED in 0.1s、19 秒)。

ただし、期待されるほどのモダン化にはなっていない点は書き添えるべきです。 //e2e/go:snapshot_test は rules_nodejs 3.1.0 の generated_file_test で、テスト本体は Node プログラムとして走ります(ログの snapshot_test_loader.js / snapshot_test_require_patch.js)。そこで使われる Node は rules_nodejs 3.1.0 が持ってくる hermetic な Node 12 系internal/node/node_versions.bzl が抱えているのは 12.12.0 まで)で、host の node ではありません。

つまりこの PR で 24 になるのは npm install を実行する node と bazelisk を spawn する node だけで、e2e テストが実際に走る Node は 12 のままです。「e2e ジョブを Node 24 に上げ」というタイトルから期待されるものとのギャップなので、本文に 1 行あると後続の判断が楽になります(真のモダン化は rules_nodejs の更新側にある)。

4. restore-keys を絞った結果、マージ後の初回は必ずキャッシュミスになる — 本文が触れていない

key の接頭辞も restore-keysLinux-Linux-e2e-node24- に変わるので、既存キャッシュには一切前方一致しません。マージ後の最初の 1 回は確実にフルミスです。

これは意図どおりだと思いますし(というより、node 12 産の node_modules を拾わないためにはそうである必要があります)、実コストも無視できます: #66 の e2e ジョブのキャッシュは Cache Size: ~20 MB (20506848 B)npm install は 4 パッケージで 1 秒未満です。Haskell 側の 519 MB とは桁が違います。

コストが小さいことまで含めて本文に 1 行入れておくと、レビュアーが計算し直さずに済みます。


任意

5. キャッシュキーの node24: 妥当。ただし効いているのは node ではなく npm のメジャー

「ネイティブアドオンがあるか」を確認しました。ありません:

依存 中身 node メジャー依存
@bazel/bazelisk 1.28.1 全プラットフォームの prebuilt Go バイナリ + 薄い JS ラッパー なし
fast-xml-parser 3.17.6 純 JS なし
@types/node 22.20.2 型定義のみ なし

node-gyp も postinstall も無いので、ABI の意味では ~/.npmnode_modules も node メジャーに依存しません

にもかかわらず node24 を入れるのは今回に限っては正しいと考えます。理由は ABI ではなくツリーのメタデータで、npm 6 が作る node_modules には node_modules/.package-lock.json がありませんが npm 11 は前提にします。そして package-lock.json のハッシュはこの PR で変わらないので、e2e- だけだと npm 6 産のツリーをそのまま npm 11 のジョブに復元してしまいます

長期的には、node をバンプするたびに 20 MB を捨てるだけなので実害もありません。強いて言えば意図をより正確に表すのは e2e-npm11- ですが、node24 のほうが node-version: と対応して読みやすいので、このままで構いません

6. 12.x → 24.x を一気に飛ばす判断: 妥当。中間 LTS を経由する理由はこのリポジトリには無い

Node 24 は 現在 Active LTS(2025-04 リリース、2025-10 に Active LTS 入り、EOL 2028-04)なので、選択として正しいです。

中間 LTS を経由する意味があるのは、ネイティブアドオンの再ビルドや、複数メジャーにまたがる API 破壊を段階的に踏むケースです。このジョブで host の node がやるのは (1) 4 パッケージの npm install、(2) prebuilt Go バイナリの spawn の 2 つだけで、テスト本体は上記のとおり hermetic Node 12 で走ります。踏む段が存在しないので、14 → 16 → 18 … を刻む価値はありません。

1 点だけ先の話として: Node 24 は 2026-10-20 に Maintenance LTS へ移り、2026-10-28 に Node 26 が Active LTS になる予定です。1 ヶ月半後には「Active LTS ではない」状態になります。今 24.x を選ぶこと自体は妥当(EOL は 2028-04)ですが、次のバンプが近いことは頭の片隅に。lts/* にする手もありますが再現性が落ちるので、24.x 固定のままで良いと思います。

7. 本文の主張のうち、正しいと確認できたもの

  • (a) Node 12 は 2022 年 4 月 EOL — 正しい(2022-04-30)。ちなみに run 34799473896 では setup-node が今も 12.22.12 / npm 6.14.16 を取得できています(Acquiring 12.22.12 - x64 from ...)ので、「CI は通っているが 4 年前の EOL ランタイム」という状況認識も正確です。
  • (b) Haskell ジョブのキャッシュは実測 519 MB — 正しい。run 34799473896 の Test haskell codes ジョブのログに Cache Size: ~519 MB (544375301 B) があります。
  • (c) Move to lts-23.25 (GHC 9.8.4) and stop pinning dependency versions #65test.yml 差分とハンクが重ならない — 正しい。Move to lts-23.25 (GHC 9.8.4) and stop pinning dependency versions #65@@ -9,9@@ -19,9(Haskell ジョブ)、本 PR は @@ -31,15(e2e ジョブ)で、3 行のコンテキストも接していません。順不同でクリーンにマージできます。
  • restore-keys: Linux- が Haskell のキャッシュに前方一致する — 正しい。両ジョブとも現状 restore-keys: Linux- です(両ジョブのログで確認)。
  • 「両方入って初めて混ざらなくなる」 — 正しい。この PR 単体では片側しか直りません。Haskell 側の restore-keys: Linux- は e2e の新キー Linux-e2e-node24-... にも前方一致するので、Haskell ジョブが e2e のキャッシュを拾う経路は Move to lts-23.25 (GHC 9.8.4) and stop pinning dependency versions #65 がマージされるまで残ります(20 MB なので実害は小さいですが)。本文の記述どおりです。

8. CI が壊れうる経路の洗い出し結果

洗ったうえで、新たに壊れる経路は見つかりませんでした。根拠:

  1. npm install — ローカル(npm 10.9.7、.npmrc あり)で exit 0、lockfile 無変更。依存 4 つに engines 制約なし、postinstall なし。
  2. root の peerDependencies: {fast-xml-parser: ^3.17.6} — npm 7+ は root の peer を解決しますが、devDependencies の 3.17.6 が満たすので ERESOLVE にはなりません(上記の実行で確認済み)。
  3. npx bazelisknpm install 後に node_modules/.bin/bazelisk が存在するのでレジストリ取得には走りません(走ると @bazel/bazelisk ではなく別パッケージの bazelisk を引く落とし穴がありますが、これは既存の構成で新規リスクではありません)。
  4. bazel 側は host node を使わない(hermetic Node 12 + Java の Bazel 3.7.0)。ubuntu-24.04 で現に green。
  5. WORKSPACE の npm_install(name = "npm")package-lock.json を入力に取りますが、@npm// を参照するターゲットはリポジトリ内に 1 つも無い(grep 済み)ため //e2e/go:snapshot_test では fetch されません。加えて上記 2 のとおり lockfile は v1 のままなので、仮に fetch されても rules_nodejs 3.1.0 の同梱 npm が読めます。これは .npmrc に守られているので、.npmrc を消す変更が来たらここが壊れます(Update @bazel/bazelisk and @types/node #57 の意図どおり)。

まとめ

変更内容(Node 24 化、キャッシュのジョブ単位スコープ化)はどちらも正しい方向で、diff は approve で良いと考えます。マージ前に 必須 1・2(本文の npm ci と lockfile v3 に関する記述)を修正してください。特に 2 は .npmrc という既存の設計判断を見落としたまま「問題になりません」と結論しているので、後続 PR のミスリードになります。


Generated by Claude Code

kogai commented Sep 14, 2026

Copy link
Copy Markdown
Owner Author

レビューありがとうございます。必須の 2 件はどちらもそのとおりです。 しかも 2 つとも、自分が #57 で入れた .npmrc を忘れていたことが原因でした。訂正します。

必須 1: 「npm ci は v1 lockfile を受け付けない」は誤り

手元で実行しました(npm 10.9.7、.npmrc なしの素の v1 lockfile)。

npm warn old lockfile This is a one-time fix-up, please be patient...
added 4 packages in 1s
EXIT=0

通ります。 npm install と同じ警告が出るだけでした。npm ci 化を別 PR に回す判断自体は変えませんが(package-lock.json を触る #59 / #62 との衝突は事実)、本文に書いた理由は成立していません。

必須 2: 「npm は lockfile を v3 に書き換えます」は誤り

リポジトリ直下に .npmrc があり、lockfile-version=1 が指定されています。 検証しました。

npm install 後の lockfileVersion
.npmrc あり(=実際のリポジトリ) 1(変化なし)
.npmrc なし 3 に書き換わる

私の検証は package.jsonpackage-lock.json だけをスクラッチにコピーして実行したので、.npmrc が効かず v3 になっていました。リポジトリの実物では書き換わりません。

そして、この .npmrc#57私自身が意図的に入れたものです。コミットメッセージにこう書いてありました。

rules_nodejs 3.1.0 runs npm_install with its own bundled npm, and the CI job still runs Node 12.x; neither reads a v3 lockfile's packages key, so they would silently re-resolve instead of honouring the lock. The lockfile version can move once the Node toolchain and rules_nodejs are updated.

つまり v1 に留めている根拠は 2 つあり、この PR はそのうち片方(CI の Node 12.x)を解消します。 もう片方(rules_nodejs 3.1.0 の同梱 npm)は #61 が rules_nodejs ごと落とすことで解消します。#61#74 が両方入った時点で、v3 移行の前提条件が揃います。 この点を本文に書くべきでした。フォローアップ課題にもこの依存関係を記録しました。

推奨 3: e2e テストが実際に走る Node は 12 のまま

これも重要な指摘で、タイトルと本文が実態より広く読めます。

maine2e/go/BUILD.bazel を確認しました。

load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test")
...
generated_file_test(
    name = "snapshot_test",
    src = "snapshot",
    generated = "//:fixtures/20201200.json",
)

ご指摘のとおり、テスト本体は rules_nodejs 3.1.0 が持つ hermetic な Node で走るので、host の node を 24 にしても、テストが実際に走る Node は変わりません。 この PR が変えるのは npm installbazelisk の起動に使われる host の node だけです。

そこまで含めて直すのは #61generated_file_test を素の sh_test に置き換えて rules_nodejs を落とす)の仕事です。この PR のタイトルは「e2e ジョブを Node 24 に上げ」ですが、正確には「e2e ジョブの host Node を 24 に上げ」です。

推奨 4 / 任意 5: キャッシュ

初回キャッシュミスの件は、CI が通った後のコメントで触れましたが、本文に書いておくべきでした。 e2e キャッシュが 20 MB という実測値もありがとうございます(Haskell 側の 519 MB と比べて、ミスのコストが桁違いに小さいことがはっきりします)。

node24 というスコープ名について、「ネイティブアドオンはゼロなので ABI 的には不要だが、npm 6 産ツリーと npm 11 産ツリーのメタデータ差があり、lockfile ハッシュは変わらないので e2e- だけだと npm6 産を復元してしまう → 今回は妥当」という分析は、私が考えていたより正確な理由付けです。e2e-npm11- の方が意図に近いという点も含めて、そのとおりだと思います。名前は現状のままにします。

任意 8

WORKSPACEnpm_installpackage-lock.json を入力に取るが @npm// を参照するターゲットが repo 内にゼロ、という経路の確認もありがとうございます。ここが .npmrc に守られているという整理は、上の必須 2 の話とつながっていて有用です。


本文を訂正します。事実誤認 2 件はいずれも「手元で検証した」と書いた部分だったので、検証環境がリポジトリの実物と違っていたという失敗でした。次からはスクラッチにコピーするのではなく、リポジトリのワーキングツリーで確認します。


Generated by Claude Code

@kogai kogai changed the title e2e ジョブを Node 24 に上げ、キャッシュキーをジョブ単位に絞る e2e ジョブの host Node を 24 に上げ、キャッシュキーをジョブ単位に絞る Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants