From b7c8aa870a31683c8740f4fad3584e8b9389d81a Mon Sep 17 00:00:00 2001 From: Leslie Lau <1178273431@qq.com> Date: Thu, 23 Jul 2026 16:51:33 +0800 Subject: [PATCH] fix(migrate): reject workspace member targets --- .../package.json | 7 ++ .../snapshots.toml | 64 +++++++++++++++++++ .../migration_workspace_member_cwd.md | 49 ++++++++++++++ ...igration_workspace_member_explicit_path.md | 49 ++++++++++++++ .../vendor/sub/package.json | 7 ++ docs/guide/migrate.md | 3 + packages/cli/src/migration/bin.ts | 9 +++ 7 files changed, 188 insertions(+) create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/package.json create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots.toml create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_cwd.md create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_explicit_path.md create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/vendor/sub/package.json diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/package.json b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/package.json new file mode 100644 index 0000000000..6a2f1757bc --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspace-root", + "private": true, + "workspaces": [ + "vendor/*" + ] +} diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots.toml b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots.toml new file mode 100644 index 0000000000..5108714d14 --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots.toml @@ -0,0 +1,64 @@ +[[case]] +name = "migration_workspace_member_cwd" +vp = "global" +cwd = "vendor/sub" +steps = [ + { argv = [ + "vp", + "migrate", + "--no-interactive", + "--no-agent", + "--no-editor", + "--no-hooks", + ], comment = "reject migration from a workspace member before changing files", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "../../package.json", + ], comment = "workspace root remains unchanged", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "package.json", + ], comment = "workspace member remains unchanged", continue-on-failure = true }, + { argv = [ + "vpt", + "stat-file", + "../../pnpm-workspace.yaml", + "--assert", + "missing", + ], comment = "no package-manager files are created at the workspace root" }, +] + +[[case]] +name = "migration_workspace_member_explicit_path" +vp = "global" +cwd = "vendor/sub" +steps = [ + { argv = [ + "vp", + "migrate", + ".", + "--no-interactive", + "--no-agent", + "--no-editor", + "--no-hooks", + ], comment = "reject an explicit workspace-member target before changing files", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "../../package.json", + ], comment = "workspace root remains unchanged", continue-on-failure = true }, + { argv = [ + "vpt", + "print-file", + "package.json", + ], comment = "workspace member remains unchanged", continue-on-failure = true }, + { argv = [ + "vpt", + "stat-file", + "../../pnpm-workspace.yaml", + "--assert", + "missing", + ], comment = "no package-manager files are created at the workspace root" }, +] diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_cwd.md b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_cwd.md new file mode 100644 index 0000000000..977c1f6c08 --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_cwd.md @@ -0,0 +1,49 @@ +# migration_workspace_member_cwd + +## `vp migrate --no-interactive --no-agent --no-editor --no-hooks` + +reject migration from a workspace member before changing files + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +Cannot migrate a workspace member independently. Run `vp migrate` from the workspace root at . +``` + +## `vpt print-file ../../package.json` + +workspace root remains unchanged + +``` +{ + "name": "workspace-root", + "private": true, + "workspaces": [ + "vendor/*" + ] +} +``` + +## `vpt print-file package.json` + +workspace member remains unchanged + +``` +{ + "name": "workspace-member", + "private": true, + "devDependencies": { + "vitest": "" + } +} +``` + +## `vpt stat-file ../../pnpm-workspace.yaml --assert missing` + +no package-manager files are created at the workspace root + +``` +../../pnpm-workspace.yaml: missing +``` diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_explicit_path.md b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_explicit_path.md new file mode 100644 index 0000000000..e04e07e3a3 --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/snapshots/migration_workspace_member_explicit_path.md @@ -0,0 +1,49 @@ +# migration_workspace_member_explicit_path + +## `vp migrate . --no-interactive --no-agent --no-editor --no-hooks` + +reject an explicit workspace-member target before changing files + +**Exit code:** 1 + +``` +VITE+ - The Unified Toolchain for the Web + +Cannot migrate a workspace member independently. Run `vp migrate` from the workspace root at . +``` + +## `vpt print-file ../../package.json` + +workspace root remains unchanged + +``` +{ + "name": "workspace-root", + "private": true, + "workspaces": [ + "vendor/*" + ] +} +``` + +## `vpt print-file package.json` + +workspace member remains unchanged + +``` +{ + "name": "workspace-member", + "private": true, + "devDependencies": { + "vitest": "" + } +} +``` + +## `vpt stat-file ../../pnpm-workspace.yaml --assert missing` + +no package-manager files are created at the workspace root + +``` +../../pnpm-workspace.yaml: missing +``` diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/vendor/sub/package.json b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/vendor/sub/package.json new file mode 100644 index 0000000000..96df63ca31 --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/migration_workspace_member_target/vendor/sub/package.json @@ -0,0 +1,7 @@ +{ + "name": "workspace-member", + "private": true, + "devDependencies": { + "vitest": "4.1.10" + } +} diff --git a/docs/guide/migrate.md b/docs/guide/migrate.md index c954fd5de3..37b7289162 100644 --- a/docs/guide/migrate.md +++ b/docs/guide/migrate.md @@ -22,6 +22,9 @@ The positional `PATH` argument is optional. - If omitted, `vp migrate` migrates the current directory - If provided, it migrates that target directory instead +- For a monorepo, the target must be the workspace root. Workspace members + cannot be migrated independently because migration updates shared package + manager configuration, catalogs, and lockfiles. ```bash vp migrate diff --git a/packages/cli/src/migration/bin.ts b/packages/cli/src/migration/bin.ts index 4065458314..c11f0df633 100644 --- a/packages/cli/src/migration/bin.ts +++ b/packages/cli/src/migration/bin.ts @@ -1043,6 +1043,15 @@ async function main() { printHeader(); const workspaceInfoOptional = await detectWorkspace(projectPath); + if ( + workspaceInfoOptional.isMonorepo && + path.resolve(projectPath) !== path.resolve(workspaceInfoOptional.rootDir) + ) { + cancelAndExit( + `Cannot migrate a workspace member independently. Run \`vp migrate\` from the workspace root at ${workspaceInfoOptional.rootDir}.`, + 1, + ); + } const initialChangedPaths = await collectChangedFormatPaths(workspaceInfoOptional.rootDir); const preExistingChangedPaths = initialChangedPaths ? new Set(initialChangedPaths) : undefined; const resolvedPackageManager = workspaceInfoOptional.packageManager ?? 'unknown';