Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,9 @@ jobs:
# trampoline would fail. current\bin\vp.exe is the real CLI.
export VP_SNAP_GLOBAL_VP="$USERPROFILE/.vite-plus/current/bin/vp.exe"
export VP_SNAP_JS_RUNTIME_DIR="$USERPROFILE/.vite-plus/js_runtime"
# Keep pwsh at its canonical installation path; copying pwsh.exe
# alone can break its adjacent runtime dependencies.
export VP_SNAP_PWSH_BIN="$(cygpath -w "$(command -v pwsh.exe)")"
# --no-fail-fast: on a snapshot suite every diff is diagnostic
# signal; cancelling on the first failure hides the rest.
cargo-nextest nextest run --archive-file windows-snapshot-tests.tar.zst --workspace-remap . --no-fail-fast
Expand Down
18 changes: 10 additions & 8 deletions crates/vp_cli_snapshots/tests/cli_snapshots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Environment overrides, mainly for CI:
| `VP_SNAP_ZSH_BIN` | Zsh binary for cases that execute the generated `env` file |
| `VP_SNAP_FISH_BIN` | Fish binary for cases that execute generated `env.fish` files |
| `VP_SNAP_NU_BIN` | Nushell binary for cases that execute generated `env.nu` files |
| `VP_SNAP_PWSH_BIN` | PowerShell binary for cases that execute generated `env.ps1` files |
| `VP_SNAP_SKIP_FLAVORS` | Comma-separated flavors to skip registering (e.g. `local`) |

## Case reference
Expand All @@ -79,7 +80,7 @@ vp = "local" # "local" | "global" | ["local", "global"]
comment = "What this proves." # rendered into the snapshot
cwd = "packages/app" # optional, relative to the fixture root
skip-platforms = ["windows"] # or { os = "linux", libc = "musl" }
requires = ["bash"] # "sh" | "bash" | "zsh" | "fish" | "nu"
requires = ["bash"] # "sh" | "bash" | "zsh" | "fish" | "nu" | "pwsh"
ignore = false # true: only runs with `-- --ignored`
seed-runtime = true # false: start from an empty VP_HOME
link-node-modules = false # true: expose the run-root node_modules as
Expand Down Expand Up @@ -122,9 +123,9 @@ A step is a bare argv array or a table:
interactions = [ ... ] }
```

`argv[0]` may be `vpt`, a runner-provisioned shell, or any
executable exposed by the case's Vite+ installation, including default shims
such as `vp`, `node`, and `corepack` and globally installed package binaries.
`argv[0]` may be `vpt`, a runner-approved shell, or any executable exposed by
the case's Vite+ installation, including default shims such as `vp`, `node`,
and `corepack` and globally installed package binaries.
There is no shell: no `&&`, no
redirects, no globs. File setup and assertions go through `vpt` so behavior
is identical on every platform:
Expand Down Expand Up @@ -189,10 +190,11 @@ case-owned tool dirs, then a system tail for child processes and direct `git` st
`TERM=xterm-256color`, `VP_CLI_TEST=1`, `VP_EMIT_MILESTONES=1`, a fresh
`HOME`, `VP_HOME`, and npm prefix. The runner still rejects direct step tools
that resolve outside the case-owned dirs, except for `git`; `vpt` is the only
required runner helper on PATH, while optional shells are linked there when
available. `CI` and `NO_COLOR` are deliberately NOT
set: with a PTY attached, the CLI behaves interactively by default, which is
the point.
required runner helper on PATH, while optional POSIX, Fish, and Nushell binaries
are linked there when available. PowerShell runs from its canonical path so it
can load files installed beside `pwsh.exe`. `CI` and `NO_COLOR` are deliberately
NOT set: with a PTY attached, the CLI behaves interactively by default, which
is the point.
`seed-runtime = true` (default) symlinks a provisioned managed Node runtime
into the case `VP_HOME` so commands do not download ~50MB per case.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
$ErrorActionPreference = "Stop"

. (Join-Path $env:EXPECTED_VP_HOME "env.ps1")

if ($env:VP_HOME -ne $env:EXPECTED_VP_HOME) {
throw "VP_HOME mismatch: expected $env:EXPECTED_VP_HOME, got $env:VP_HOME"
}

$expectedBin = Join-Path $env:EXPECTED_VP_HOME "bin"
$binCount = @($env:Path -split [IO.Path]::PathSeparator | Where-Object { $_ -ieq $expectedBin }).Count
if ($binCount -ne 1) {
throw "PATH contains the Vite+ bin directory $binCount times"
}

if (-not (Get-Command vp -CommandType Function -ErrorAction SilentlyContinue)) {
throw "env.ps1 did not define the vp wrapper"
}

$vpOutput = vp --version
if ($LASTEXITCODE -ne 0) {
throw "vp --version failed through the PowerShell wrapper"
}
if ([string]::IsNullOrWhiteSpace(($vpOutput -join ""))) {
throw "vp --version returned no output"
}

$env:VP_NODE_VERSION = "18.20.0"
vp env use --help *> $null
if ($LASTEXITCODE -ne 0) {
throw "vp env use --help failed through the PowerShell wrapper"
}
if ($env:VP_NODE_VERSION -ne "18.20.0") {
throw "vp env use --help changed VP_NODE_VERSION"
}

vp env use 20.18.0 --no-install
if ($LASTEXITCODE -ne 0) {
throw "vp env use failed through the PowerShell wrapper"
}
if ($env:VP_NODE_VERSION -ne "20.18.0") {
throw "VP_NODE_VERSION mismatch: expected 20.18.0, got $env:VP_NODE_VERSION"
}

vp env use --unset
if ($LASTEXITCODE -ne 0) {
throw "vp env use --unset failed through the PowerShell wrapper"
}
if (Test-Path Env:VP_NODE_VERSION) {
throw "vp env use --unset did not remove VP_NODE_VERSION"
}

vp env use --no-install
if ($LASTEXITCODE -ne 0) {
throw "vp env use without a version failed through the PowerShell wrapper"
}
if ($env:VP_NODE_VERSION -ne "22.18.0") {
throw "file-based VP_NODE_VERSION mismatch: expected 22.18.0, got $env:VP_NODE_VERSION"
}

Write-Output "PowerShell environment checks passed"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[[case]]
name = "command_env_powershell"
vp = "global"
skip-platforms = ["linux", "macos"]
requires = ["pwsh"]
steps = [
{ argv = ["vp", "env", "setup", "--refresh"], snapshot = false },
{ argv = ["vpt", "write-file", ".node-version", "22.18.0\n"], snapshot = false },
{ argv = ["pwsh", "-NoLogo", "-NoProfile", "-NonInteractive", "-File", "assert.ps1"], comment = "dot-sources env.ps1 and verifies PowerShell environment setup and wrapper behavior", envs = [["EXPECTED_VP_HOME", "${VP_HOME}"]] },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# command_env_powershell

## `vp env setup --refresh`


## `vpt write-file .node-version '22.18.0
'`


## `EXPECTED_VP_HOME=${VP_HOME} pwsh -NoLogo -NoProfile -NonInteractive -File assert.ps1`

dot-sources env.ps1 and verifies PowerShell environment setup and wrapper behavior

```
Using Node.js <version> (resolved from 20.18.0)
Reverted to file-based Node.js version resolution
Using Node.js <version> (resolved from .node-version)
PowerShell environment checks passed
```
27 changes: 26 additions & 1 deletion crates/vp_cli_snapshots/tests/cli_snapshots/flavor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//! Each flavor gets one runner bin directory per run (created under the run
//! temp root) for runner-owned helpers. `vpt` always lives there; optional
//! external shells are linked there when available.
//! PowerShell keeps its original installation path because `pwsh.exe` may
//! depend on files installed beside it.

use std::path::{Path, PathBuf};

Expand Down Expand Up @@ -41,6 +43,9 @@ pub struct FlavorRuntime {
/// Runner-owned Nushell binary used by fixtures that execute generated
/// `env.nu` files. CI supplies it through `VP_SNAP_NU_BIN`.
pub nu: Option<PathBuf>,
/// Canonical PowerShell binary used by fixtures that execute generated
/// `env.ps1` files. CI supplies it through `VP_SNAP_PWSH_BIN`.
pub pwsh: Option<PathBuf>,
/// Source global `vp` binary to install into each case's `VP_HOME/current`.
pub global_vp: PathBuf,
/// Source package installed into each case's `VP_HOME/current/node_modules`.
Expand Down Expand Up @@ -241,6 +246,12 @@ pub fn nushell_path() -> Result<Option<PathBuf>, String> {
optional_tool_path("VP_SNAP_NU_BIN", "nu")
}

/// Resolves an optional PowerShell binary for fixtures that exercise generated
/// `env.ps1` files.
pub fn powershell_path() -> Result<Option<PathBuf>, String> {
optional_tool_path("VP_SNAP_PWSH_BIN", "pwsh")
}

/// Home-layout names, shared with `CaseHome` in main.rs so the product's
/// `~/.vite-plus/js_runtime` layout is spelled once.
pub const VP_HOME_DIR: &str = ".vite-plus";
Expand Down Expand Up @@ -349,10 +360,24 @@ pub fn provision(flavor: Flavor, run_root: &Path) -> Result<FlavorRuntime, Strin
let nu = nushell_path()?
.map(|path| install_runner_tool(&runner_bin_dir, "nu", &path))
.transpose()?;
// Keep PowerShell at its canonical installation path. Relocating only
// pwsh.exe can break its lookup of adjacent runtime and managed files.
let pwsh = powershell_path()?;
let global_vp = global_vp_path()?;
let cli_package_dir = match flavor {
Flavor::Local => local_cli_package_dir()?,
Flavor::Global => repo_root().join("packages/cli"),
};
Ok(FlavorRuntime { runner_bin_dir, vpt, sh, bash, zsh, fish, nu, global_vp, cli_package_dir })
Ok(FlavorRuntime {
runner_bin_dir,
vpt,
sh,
bash,
zsh,
fish,
nu,
pwsh,
global_vp,
cli_package_dir,
})
}
11 changes: 11 additions & 0 deletions crates/vp_cli_snapshots/tests/cli_snapshots/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ enum RequiredTool {
Zsh,
Fish,
Nu,
Pwsh,
}

impl RequiredTool {
Expand All @@ -336,6 +337,7 @@ impl RequiredTool {
Self::Zsh => matches!(flavor::zsh_path(), Ok(None)),
Self::Fish => matches!(flavor::fish_path(), Ok(None)),
Self::Nu => matches!(flavor::nushell_path(), Ok(None)),
Self::Pwsh => matches!(flavor::powershell_path(), Ok(None)),
}
}
}
Expand Down Expand Up @@ -470,6 +472,7 @@ struct CaseInstall {
zsh: Option<PathBuf>,
fish: Option<PathBuf>,
nu: Option<PathBuf>,
pwsh: Option<PathBuf>,
}

impl CaseInstall {
Expand Down Expand Up @@ -514,6 +517,13 @@ impl CaseInstall {
.to_owned()
});
}
if program == "pwsh" {
return self.pwsh.clone().ok_or_else(|| {
"`pwsh` is required by this snapshot case; install PowerShell or set \
VP_SNAP_PWSH_BIN"
.to_owned()
});
}

// An explicit `./`-prefixed program runs a file the case itself
// produced inside the staged workspace (a packed executable); the
Expand Down Expand Up @@ -614,6 +624,7 @@ impl CaseHome {
zsh: runtime.zsh.clone(),
fish: runtime.fish.clone(),
nu: runtime.nu.clone(),
pwsh: runtime.pwsh.clone(),
})
}

Expand Down
Loading