From 14244d7759a6b61eec7de5d67e137dea00ae9d80 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 21:27:02 +0000 Subject: [PATCH] =?UTF-8?q?fix(jj-helpers):=20workspace=20root=20=E8=A7=A3?= =?UTF-8?q?=E6=B1=BA=E3=81=AE=E6=AD=A3=E8=A6=8F=E5=8C=96=E7=B2=92=E5=BA=A6?= =?UTF-8?q?=E3=82=92=E6=8F=83=E3=81=88=E3=82=8B=20(nightly-todo=20?= =?UTF-8?q?=E9=A0=86=E4=BD=8D=20412)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 夜間ループが実装した内容に、人間側で Windows 向けのテスト修正を 1 件加えた (2026-08-30、PR #459 の CI 失敗対応)。 - production コード (colocated 経路も canonicalize + verbatim prefix 剥がし) は そのまま。順位 412 の意図どおり colocated / secondary の正規化粒度が揃う - colocated_main_returns_itself の期待値が Windows で必ず食い違っていた: canonicalize() は \?\ 付きを返すのに対し production は剥がした値を返すため。 期待値側も strip_windows_verbatim_prefix を通す形へ修正 - 夜間ループの事前フィルタは ubuntu のみで cargo test を回すため、Linux では 両辺が一致してすり抜けていた (PR 本文が「単一 OS のコストフィルタであって 品質の保証ではない」と書いているとおりの抜け方) - Windows ローカルで修正前の失敗再現と修正後の green を実測済み --- src/lib-jj-helpers/src/workspace.rs | 43 +++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/lib-jj-helpers/src/workspace.rs b/src/lib-jj-helpers/src/workspace.rs index c234dce2..4529cb2f 100644 --- a/src/lib-jj-helpers/src/workspace.rs +++ b/src/lib-jj-helpers/src/workspace.rs @@ -75,17 +75,21 @@ pub fn resolve_git_dir(workspace_root: &std::path::Path) -> GitDirResolution { /// [`resolve_git_dir`] と同じ layout 解釈 (相対パス基準、verbatim prefix 剥がし) を共有する: /// /// 1. `/.jj/repo` がディレクトリ → この root 自身がメイン (colocated) workspace → -/// `Some(root)` をそのまま返す +/// `canonicalize()` (失敗時は入力のまま) を返す /// 2. `/.jj/repo` がファイル → 内容が main repo store への (相対なら `/.jj/` 基準の) /// パス (`
/.jj/repo`)。その 2 階層上がメイン workspace root /// 3. `.jj/repo` 不在 / 読み取り失敗 / 導出パス不存在 → `None` (caller は現 root に fail-open) /// -/// `GIT_DIR` を扱う [`resolve_git_dir`] と違い最終 store ではなく **workspace root** を返す点、 -/// および colocated root を `Resolved` ではなく入力そのまま返す点で用途が異なる。 +/// `GIT_DIR` を扱う [`resolve_git_dir`] と違い最終 store ではなく **workspace root** を返す点で +/// 用途が異なる。colocated / secondary いずれの経路も `canonicalize()` + verbatim prefix 剥がしで +/// 揃える (順位 412 — #385 では入口ごとに正規化の粒度が異なっていた)。 pub fn resolve_main_workspace_root(workspace_root: &std::path::Path) -> Option { let repo_entry = workspace_root.join(".jj").join("repo"); if repo_entry.is_dir() { - return Some(workspace_root.to_path_buf()); + return Some(match workspace_root.canonicalize() { + Ok(p) => strip_windows_verbatim_prefix(&p), + Err(_) => workspace_root.to_path_buf(), + }); } if !repo_entry.is_file() { return None; @@ -447,7 +451,36 @@ mod tests { make_colocated_main(tmp.path()); let resolved = resolve_main_workspace_root(tmp.path()) .expect("colocated main (.jj/repo がディレクトリ) は自身を返す"); - assert_eq!(resolved.as_path(), tmp.path()); + assert_eq!( + resolved, + strip_windows_verbatim_prefix(&tmp.path().canonicalize().unwrap()), + "期待値も verbatim prefix を剥がして比べる。Windows の canonicalize() は + verbatim 付きを返すため、生値と比べると production 側の剥がし処理と必ず + 食い違う (単一 OS の事前フィルタでは Linux 側だけ一致して通り抜ける)" + ); + assert!( + !resolved.to_string_lossy().starts_with(r"\\?\"), + "verbatim prefix は剥がされていること: {:?}", + resolved + ); + } + + /// 順位 412: colocated 経路と secondary 経路が同じ形式のパスを返すことを固定する + /// (#385 の CodeRabbit 指摘 — 以前は colocated が入力そのまま、secondary のみ canonicalize)。 + #[test] + fn colocated_and_secondary_paths_agree_on_normalization() { + let tmp = tempfile::tempdir().unwrap(); + let main = tmp.path().join("main"); + let ws = tmp.path().join("ws"); + make_colocated_main(&main); + make_secondary_workspace(&ws, "../../main/.jj/repo"); + + let via_colocated = resolve_main_workspace_root(&main).expect("colocated 経路"); + let via_secondary = resolve_main_workspace_root(&ws).expect("secondary 経路"); + assert_eq!( + via_colocated, via_secondary, + "同じチェックアウトに対し、colocated 経路と secondary 経路は同じ形式のパスを返すこと" + ); } #[test]