diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/apps-ts/kami/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/apps-ts/kami/package.json new file mode 100644 index 0000000000..964f3c5674 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/apps-ts/kami/package.json @@ -0,0 +1,9 @@ +{ + "name": "kami", + "private": true, + "devDependencies": { + "typescript": "~6.0.2", + "vite": "catalog:", + "vite-plus": "catalog:" + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/package.json b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/package.json new file mode 100644 index 0000000000..ef1969511c --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/package.json @@ -0,0 +1,13 @@ +{ + "name": "home-workspace", + "private": true, + "dependencies": { + "kami": "workspace:*" + }, + "devEngines": { + "packageManager": { + "name": "pnpm", + "version": "11.25.0" + } + } +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/pnpm-lock.yaml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/pnpm-lock.yaml new file mode 100644 index 0000000000..afff75e01a --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/pnpm-lock.yaml @@ -0,0 +1,13 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + kami: + specifier: workspace:* + version: link:apps-ts/kami + apps-ts/kami: {} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/pnpm-workspace.yaml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/pnpm-workspace.yaml new file mode 100644 index 0000000000..64ef5df68a --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/home/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +packages: + - apps-ts/* +catalog: + vite: 8.2.2 + vite-plus: 0.3.1 diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/setup.mjs b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/setup.mjs new file mode 100644 index 0000000000..39e3c5b1f4 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/setup.mjs @@ -0,0 +1,15 @@ +import { existsSync, mkdirSync, realpathSync, symlinkSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +const installDir = path.resolve('home/.vite-plus'); +mkdirSync(installDir, { recursive: true }); + +// Reuse the runner's managed runtime in the installation under the parent workspace. +const runtime = path.join(process.env.VP_HOME, 'js_runtime'); +if (existsSync(runtime)) { + symlinkSync(realpathSync(runtime), path.join(installDir, 'js_runtime'), 'junction'); +} + +if (process.argv.includes('--valid-lockfile')) { + writeFileSync('home/apps-ts/kami/package.json', '{"name":"kami","private":true}\n'); +} diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots.toml b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots.toml new file mode 100644 index 0000000000..db18862683 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots.toml @@ -0,0 +1,26 @@ +[[case]] +name = "command_upgrade_parent_workspace_stale_lockfile" +vp = "global" +skip-platforms = ["windows"] +comment = "Regression test for #2639: an upgrade invoked outside a parent pnpm workspace must not read its stale lockfile." +steps = [ + { argv = ["node", "setup.mjs"], snapshot = false }, + # Pin the released payload so the test also runs when the checkout version is unpublished. + { argv = ["vp", "upgrade", "0.3.1", "--force"], envs = [["VP_HOME", "${workspace}/home/.vite-plus"]], timeout = 120000, snapshot = false }, + { argv = ["vpt", "stat-file", "home/.vite-plus/current/node_modules/vite-plus/package.json", "--assert", "file"] }, + { argv = ["vpt", "stat-file", "home/node_modules", "home/apps-ts/kami/node_modules", "--assert", "missing"] }, + { argv = ["vpt", "print-file", "home/pnpm-lock.yaml"], comment = "The parent workspace lockfile is unchanged." }, +] + +[[case]] +name = "command_upgrade_parent_workspace_valid_lockfile" +vp = "global" +skip-platforms = ["windows"] +comment = "An upgrade must install its own dependencies even when the parent workspace lockfile is valid." +steps = [ + { argv = ["node", "setup.mjs", "--valid-lockfile"], snapshot = false }, + { argv = ["vp", "upgrade", "0.3.1", "--force"], envs = [["VP_HOME", "${workspace}/home/.vite-plus"]], timeout = 120000, snapshot = false }, + { argv = ["vpt", "stat-file", "home/.vite-plus/current/node_modules/vite-plus/package.json", "--assert", "file"] }, + { argv = ["vpt", "stat-file", "home/node_modules", "home/apps-ts/kami/node_modules", "--assert", "missing"] }, + { argv = ["vpt", "print-file", "home/pnpm-lock.yaml"], comment = "The parent workspace lockfile is unchanged." }, +] diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots/command_upgrade_parent_workspace_stale_lockfile.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots/command_upgrade_parent_workspace_stale_lockfile.md new file mode 100644 index 0000000000..e92d597291 --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots/command_upgrade_parent_workspace_stale_lockfile.md @@ -0,0 +1,42 @@ +# command_upgrade_parent_workspace_stale_lockfile + +Regression test for #2639: an upgrade invoked outside a parent pnpm workspace must not read its stale lockfile. + +## `node setup.mjs` + + +## `VP_HOME=${workspace}/home/.vite-plus vp upgrade 0.3.1 --force` + + +## `vpt stat-file home/.vite-plus/current/node_modules/vite-plus/package.json --assert file` + +``` +home/.vite-plus/current/node_modules/vite-plus/package.json: file +``` + +## `vpt stat-file home/node_modules home/apps-ts/kami/node_modules --assert missing` + +``` +home/node_modules: missing +home/apps-ts/kami/node_modules: missing +``` + +## `vpt print-file home/pnpm-lock.yaml` + +The parent workspace lockfile is unchanged. + +``` +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + kami: + specifier: workspace:* + version: link:apps-ts/kami + apps-ts/kami: {} +``` diff --git a/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots/command_upgrade_parent_workspace_valid_lockfile.md b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots/command_upgrade_parent_workspace_valid_lockfile.md new file mode 100644 index 0000000000..39124e104f --- /dev/null +++ b/crates/vp_cli_snapshots/tests/cli_snapshots/fixtures/command_upgrade_parent_workspace/snapshots/command_upgrade_parent_workspace_valid_lockfile.md @@ -0,0 +1,42 @@ +# command_upgrade_parent_workspace_valid_lockfile + +An upgrade must install its own dependencies even when the parent workspace lockfile is valid. + +## `node setup.mjs --valid-lockfile` + + +## `VP_HOME=${workspace}/home/.vite-plus vp upgrade 0.3.1 --force` + + +## `vpt stat-file home/.vite-plus/current/node_modules/vite-plus/package.json --assert file` + +``` +home/.vite-plus/current/node_modules/vite-plus/package.json: file +``` + +## `vpt stat-file home/node_modules home/apps-ts/kami/node_modules --assert missing` + +``` +home/node_modules: missing +home/apps-ts/kami/node_modules: missing +``` + +## `vpt print-file home/pnpm-lock.yaml` + +The parent workspace lockfile is unchanged. + +``` +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + kami: + specifier: workspace:* + version: link:apps-ts/kami + apps-ts/kami: {} +``` diff --git a/crates/vp_setup/src/install.rs b/crates/vp_setup/src/install.rs index 6228b69b9c..e4970941db 100644 --- a/crates/vp_setup/src/install.rs +++ b/crates/vp_setup/src/install.rs @@ -171,8 +171,8 @@ pub async fn write_upgrade_log( /// Install production dependencies with managed Node.js LTS and pinned pnpm. /// -/// Spawns: `node /bin/pnpm.cjs install [--registry ]` with `CI=true`. -/// On failure, writes stdout+stderr to `{version_dir}/upgrade.log` for debugging. +/// Spawns: `node /bin/pnpm.cjs install --ignore-workspace [--registry ]` +/// with `CI=true`. On failure, writes stdout+stderr to the parent directory's `upgrade.log`. pub async fn install_production_deps( version_dir: &AbsolutePath, registry: Option<&str>, @@ -182,7 +182,8 @@ pub async fn install_production_deps( // Keep the bypass local to this Vite+ installation. write_release_age_overrides(version_dir).await?; - let mut args = vec!["install"]; + // An ancestor workspace must not capture the install or supply its lockfile. + let mut args = vec!["install", "--ignore-workspace"]; if let Some(registry_url) = registry { args.push("--registry"); args.push(registry_url);