Skip to content

Commit b9db571

Browse files
leslieeilselfengmk2
authored andcommitted
fix(migrate): reject workspace member targets
1 parent 6480db3 commit b9db571

7 files changed

Lines changed: 188 additions & 0 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "workspace-root",
3+
"private": true,
4+
"workspaces": [
5+
"vendor/*"
6+
]
7+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
[[case]]
2+
name = "migration_workspace_member_cwd"
3+
vp = "global"
4+
cwd = "vendor/sub"
5+
steps = [
6+
{ argv = [
7+
"vp",
8+
"migrate",
9+
"--no-interactive",
10+
"--no-agent",
11+
"--no-editor",
12+
"--no-hooks",
13+
], comment = "reject migration from a workspace member before changing files", continue-on-failure = true },
14+
{ argv = [
15+
"vpt",
16+
"print-file",
17+
"../../package.json",
18+
], comment = "workspace root remains unchanged", continue-on-failure = true },
19+
{ argv = [
20+
"vpt",
21+
"print-file",
22+
"package.json",
23+
], comment = "workspace member remains unchanged", continue-on-failure = true },
24+
{ argv = [
25+
"vpt",
26+
"stat-file",
27+
"../../pnpm-workspace.yaml",
28+
"--assert",
29+
"missing",
30+
], comment = "no package-manager files are created at the workspace root" },
31+
]
32+
33+
[[case]]
34+
name = "migration_workspace_member_explicit_path"
35+
vp = "global"
36+
cwd = "vendor/sub"
37+
steps = [
38+
{ argv = [
39+
"vp",
40+
"migrate",
41+
".",
42+
"--no-interactive",
43+
"--no-agent",
44+
"--no-editor",
45+
"--no-hooks",
46+
], comment = "reject an explicit workspace-member target before changing files", continue-on-failure = true },
47+
{ argv = [
48+
"vpt",
49+
"print-file",
50+
"../../package.json",
51+
], comment = "workspace root remains unchanged", continue-on-failure = true },
52+
{ argv = [
53+
"vpt",
54+
"print-file",
55+
"package.json",
56+
], comment = "workspace member remains unchanged", continue-on-failure = true },
57+
{ argv = [
58+
"vpt",
59+
"stat-file",
60+
"../../pnpm-workspace.yaml",
61+
"--assert",
62+
"missing",
63+
], comment = "no package-manager files are created at the workspace root" },
64+
]
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# migration_workspace_member_cwd
2+
3+
## `vp migrate --no-interactive --no-agent --no-editor --no-hooks`
4+
5+
reject migration from a workspace member before changing files
6+
7+
**Exit code:** 1
8+
9+
```
10+
VITE+ - The Unified Toolchain for the Web
11+
12+
Cannot migrate a workspace member independently. Run `vp migrate` from the workspace root at <workspace>.
13+
```
14+
15+
## `vpt print-file ../../package.json`
16+
17+
workspace root remains unchanged
18+
19+
```
20+
{
21+
"name": "workspace-root",
22+
"private": true,
23+
"workspaces": [
24+
"vendor/*"
25+
]
26+
}
27+
```
28+
29+
## `vpt print-file package.json`
30+
31+
workspace member remains unchanged
32+
33+
```
34+
{
35+
"name": "workspace-member",
36+
"private": true,
37+
"devDependencies": {
38+
"vitest": "<version>"
39+
}
40+
}
41+
```
42+
43+
## `vpt stat-file ../../pnpm-workspace.yaml --assert missing`
44+
45+
no package-manager files are created at the workspace root
46+
47+
```
48+
../../pnpm-workspace.yaml: missing
49+
```
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# migration_workspace_member_explicit_path
2+
3+
## `vp migrate . --no-interactive --no-agent --no-editor --no-hooks`
4+
5+
reject an explicit workspace-member target before changing files
6+
7+
**Exit code:** 1
8+
9+
```
10+
VITE+ - The Unified Toolchain for the Web
11+
12+
Cannot migrate a workspace member independently. Run `vp migrate` from the workspace root at <workspace>.
13+
```
14+
15+
## `vpt print-file ../../package.json`
16+
17+
workspace root remains unchanged
18+
19+
```
20+
{
21+
"name": "workspace-root",
22+
"private": true,
23+
"workspaces": [
24+
"vendor/*"
25+
]
26+
}
27+
```
28+
29+
## `vpt print-file package.json`
30+
31+
workspace member remains unchanged
32+
33+
```
34+
{
35+
"name": "workspace-member",
36+
"private": true,
37+
"devDependencies": {
38+
"vitest": "<version>"
39+
}
40+
}
41+
```
42+
43+
## `vpt stat-file ../../pnpm-workspace.yaml --assert missing`
44+
45+
no package-manager files are created at the workspace root
46+
47+
```
48+
../../pnpm-workspace.yaml: missing
49+
```
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "workspace-member",
3+
"private": true,
4+
"devDependencies": {
5+
"vitest": "4.1.10"
6+
}
7+
}

docs/guide/migrate.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ The positional `PATH` argument is optional.
2222

2323
- If omitted, `vp migrate` migrates the current directory
2424
- If provided, it migrates that target directory instead
25+
- For a monorepo, the target must be the workspace root. Workspace members
26+
cannot be migrated independently because migration updates shared package
27+
manager configuration, catalogs, and lockfiles.
2528

2629
```bash
2730
vp migrate

packages/cli/src/migration/bin.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,15 @@ async function main() {
10441044
printHeader();
10451045

10461046
const workspaceInfoOptional = await detectWorkspace(projectPath);
1047+
if (
1048+
workspaceInfoOptional.isMonorepo &&
1049+
path.resolve(projectPath) !== path.resolve(workspaceInfoOptional.rootDir)
1050+
) {
1051+
cancelAndExit(
1052+
`Cannot migrate a workspace member independently. Run \`vp migrate\` from the workspace root at ${workspaceInfoOptional.rootDir}.`,
1053+
1,
1054+
);
1055+
}
10471056
const initialChangedPaths = await collectChangedFormatPaths(workspaceInfoOptional.rootDir);
10481057
const preExistingChangedPaths = initialChangedPaths ? new Set(initialChangedPaths) : undefined;
10491058
const resolvedPackageManager = workspaceInfoOptional.packageManager ?? 'unknown';

0 commit comments

Comments
 (0)