diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17af2ee299..790c3c7957 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,32 +269,36 @@ jobs: RUST_MIN_STACK: 8388608 - name: Test global package install (powershell) - if: ${{ matrix.os == 'windows-latest' }} + if: ${{ matrix.os != 'namespace-profile-linux-x64-default' }} shell: pwsh run: | - echo "PATH: $env:Path" - where.exe node - where.exe npm - where.exe npx - where.exe vp + $vpHome = Join-Path $HOME ".vite-plus" + $vpBin = Join-Path $vpHome "bin" + . (Join-Path $vpHome 'env.ps1') + + Write-Host "PATH: $env:Path" + Get-Command node + Get-Command npm + Get-Command npx + Get-Command vp vp env doctor # Test 1: Install a JS-based CLI (typescript) vp install -g typescript tsc --version - where.exe tsc + Get-Command tsc # Test 2: Verify the package was installed correctly - Get-ChildItem "$env:USERPROFILE\.vite-plus\packages\typescript\" - Get-ChildItem "$env:USERPROFILE\.vite-plus\bin\" + Get-ChildItem (Join-Path $vpHome "packages/typescript") + Get-ChildItem $vpBin # Test 3: Uninstall vp uninstall -g typescript # Test 4: Verify uninstall removed shim Write-Host "Checking bin dir after uninstall:" - Get-ChildItem "$env:USERPROFILE\.vite-plus\bin\" - $shimPath = "$env:USERPROFILE\.vite-plus\bin\tsc.cmd" + Get-ChildItem $vpBin + $shimPath = if ($IsWindows) { Join-Path $vpBin "tsc.cmd" } else { Join-Path $vpBin "tsc" } if (Test-Path $shimPath) { Write-Error "tsc shim file still exists at $shimPath" exit 1 @@ -444,14 +448,16 @@ jobs: fi - name: Test upgrade (powershell) - if: ${{ matrix.os == 'windows-latest' }} + if: ${{ matrix.os != 'namespace-profile-linux-x64-default' }} shell: pwsh run: | - Get-ChildItem "$env:USERPROFILE\.vite-plus\" + $vpHome = Join-Path $HOME ".vite-plus" + . (Join-Path $vpHome 'env.ps1') + Get-ChildItem $vpHome # Helper to read the installed CLI version from package.json function Get-CliVersion { - node -p "require(require('path').resolve(process.env.USERPROFILE, '.vite-plus', 'current', 'node_modules', 'vite-plus', 'package.json')).version" + node -p "require(require('path').resolve(process.env.USERPROFILE || process.env.HOME, '.vite-plus', 'current', 'node_modules', 'vite-plus', 'package.json')).version" } # Save initial (dev build) version @@ -466,7 +472,7 @@ jobs: vp --version vp env doctor - Get-ChildItem "$env:USERPROFILE\.vite-plus\" + Get-ChildItem $vpHome # Verify version changed after update $updatedVersion = Get-CliVersion @@ -552,20 +558,28 @@ jobs: vp --version - name: Test implode (powershell) - if: ${{ matrix.os == 'windows-latest' }} + if: ${{ matrix.os != 'namespace-profile-linux-x64-default' }} shell: pwsh run: | - # Retry — Windows file locks can cause transient "Access is denied" errors - foreach ($i in 1..3) { - vp implode --yes - if ($LASTEXITCODE -eq 0) { break } - Write-Host "Retry $i`: vp implode failed, waiting 5s..." + $vpHome = Join-Path $HOME ".vite-plus" + . (Join-Path $vpHome 'env.ps1') + + if ($IsWindows) { + # Retry — Windows file locks can cause transient "Access is denied" errors + foreach ($i in 1..3) { + vp implode --yes + if ($LASTEXITCODE -eq 0) { break } + Write-Host "Retry $i`: vp implode failed, waiting 5s..." + Start-Sleep -Seconds 5 + } Start-Sleep -Seconds 5 + } else { + vp implode --yes } - Start-Sleep -Seconds 5 - dir "$env:USERPROFILE\" - if (Test-Path "$env:USERPROFILE\.vite-plus") { - Write-Error "~/.vite-plus still exists after implode" + + Get-ChildItem $HOME + if (Test-Path $vpHome) { + Write-Error "$vpHome still exists after implode" exit 1 } pnpm bootstrap-cli:ci diff --git a/crates/vite_global_cli/src/commands/env/setup.rs b/crates/vite_global_cli/src/commands/env/setup.rs index 1748a9b8fd..6d4c48a1d4 100644 --- a/crates/vite_global_cli/src/commands/env/setup.rs +++ b/crates/vite_global_cli/src/commands/env/setup.rs @@ -641,10 +641,11 @@ if ($env:Path -split ';' -notcontains $__vp_bin) { function vp { if ($args.Count -ge 2 -and $args[0] -eq "env" -and $args[1] -eq "use") { if ($args -contains "-h" -or $args -contains "--help") { - & (Join-Path $__vp_bin "vp.exe") @args; return + & (Join-Path $__vp_bin "vp") @args; return } $env:VP_ENV_USE_EVAL_ENABLE = "1" - $output = & (Join-Path $__vp_bin "vp.exe") @args 2>&1 | ForEach-Object { + $env:VP_SHELL_PWSH = "1" + $output = & (Join-Path $__vp_bin "vp") @args 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { Write-Host $_.Exception.Message } else { @@ -652,17 +653,18 @@ function vp { } } Remove-Item Env:VP_ENV_USE_EVAL_ENABLE -ErrorAction SilentlyContinue + Remove-Item Env:VP_SHELL_PWSH -ErrorAction SilentlyContinue if ($LASTEXITCODE -eq 0 -and $output) { Invoke-Expression ($output -join "`n") } } else { - & (Join-Path $__vp_bin "vp.exe") @args + & (Join-Path $__vp_bin "vp") @args } } # Dynamic shell completion for PowerShell $env:VP_COMPLETE = "powershell" -& (Join-Path $__vp_bin "vp.exe") | Out-String | Invoke-Expression +& (Join-Path $__vp_bin "vp") | Out-String | Invoke-Expression Remove-Item Env:\VP_COMPLETE -ErrorAction SilentlyContinue $__vpr_comp = { @@ -674,7 +676,7 @@ $__vpr_comp = { $args = $args -replace '^(vpr\.exe|vpr)\b', 'vp run' if ($wordToComplete -eq "") { $args += " ''" } $results = Invoke-Expression @" -& (Join-Path $__vp_bin 'vp.exe') -- $args +& (Join-Path $__vp_bin 'vp') -- $args "@; if ($prev) { $env:VP_COMPLETE = $prev } else { Remove-Item Env:\VP_COMPLETE } $results | ForEach-Object { diff --git a/crates/vite_global_cli/src/commands/env/use.rs b/crates/vite_global_cli/src/commands/env/use.rs index 27ee6dc819..9bf51fef0b 100644 --- a/crates/vite_global_cli/src/commands/env/use.rs +++ b/crates/vite_global_cli/src/commands/env/use.rs @@ -36,7 +36,7 @@ fn detect_shell() -> Shell { Shell::Fish } else if config.vp_shell_nu { Shell::NuShell - } else if cfg!(windows) && config.ps_module_path.is_some() { + } else if config.vp_shell_pwsh { Shell::PowerShell } else if cfg!(windows) { Shell::Cmd @@ -178,15 +178,12 @@ mod tests { use super::*; #[test] - fn test_detect_shell_posix_even_with_psmodulepath() { + fn test_detect_shell_pwsh() { let _guard = vite_shared::EnvConfig::test_guard(vite_shared::EnvConfig { - ps_module_path: Some("/some/path".into()), + vp_shell_pwsh: true, ..vite_shared::EnvConfig::for_test() }); let shell = detect_shell(); - #[cfg(not(windows))] - assert!(matches!(shell, Shell::Posix)); - #[cfg(windows)] assert!(matches!(shell, Shell::PowerShell)); } diff --git a/crates/vite_shared/src/env_config.rs b/crates/vite_shared/src/env_config.rs index 6818058c5b..841e2b4b14 100644 --- a/crates/vite_shared/src/env_config.rs +++ b/crates/vite_shared/src/env_config.rs @@ -135,6 +135,11 @@ pub struct EnvConfig { /// /// Env: `VP_SHELL_NU` pub vp_shell_nu: bool, + + /// Explicit PowerShell eval signal set by the `env.ps1` wrapper. + /// + /// Env: `VP_SHELL_PWSH` + pub vp_shell_pwsh: bool, } impl EnvConfig { @@ -166,6 +171,7 @@ impl EnvConfig { ps_module_path: std::env::var("PSModulePath").ok(), nu_version: std::env::var("NU_VERSION").ok(), vp_shell_nu: std::env::var(env_vars::VP_SHELL_NU).is_ok(), + vp_shell_pwsh: std::env::var(env_vars::VP_SHELL_PWSH).is_ok(), } } @@ -250,6 +256,7 @@ impl EnvConfig { ps_module_path: None, nu_version: None, vp_shell_nu: false, + vp_shell_pwsh: false, } } diff --git a/crates/vite_shared/src/env_vars.rs b/crates/vite_shared/src/env_vars.rs index 5618e416fc..55badcfdab 100644 --- a/crates/vite_shared/src/env_vars.rs +++ b/crates/vite_shared/src/env_vars.rs @@ -43,6 +43,9 @@ pub const VP_ENV_USE_EVAL_ENABLE: &str = "VP_ENV_USE_EVAL_ENABLE"; /// bash/zsh is launched from a Nushell session. pub const VP_SHELL_NU: &str = "VP_SHELL_NU"; +/// Explicit signal set by the PowerShell wrapper to indicate PowerShell eval context. +pub const VP_SHELL_PWSH: &str = "VP_SHELL_PWSH"; + /// Filter for update task types. pub const VITE_UPDATE_TASK_TYPES: &str = "VITE_UPDATE_TASK_TYPES";