Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
213 changes: 213 additions & 0 deletions .github/workflows/test-standalone-install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ on:
paths:
- 'packages/cli/install.sh'
- 'packages/cli/install.ps1'
- 'packages/tools/src/install-global-cli.ts'
- 'crates/vp_installer/**'
- 'crates/vp_trampoline/**'
- 'crates/vp_global_cli/**'
- 'crates/vp_shared/**'
- 'crates/vp_pm_cli/**'
- 'crates/vp_setup/**'
- '.github/workflows/test-standalone-install.yml'
Expand Down Expand Up @@ -40,6 +44,12 @@ jobs:
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Pin VP_HOME for pre-split published CLI
# This job installs the npm-published CLI, which does not yet resolve
# the split layout. Pin VP_HOME so the new installer still writes a
# single-root tree the released binary understands.
run: echo "VP_HOME=$HOME/.vite-plus" >> $GITHUB_ENV

- name: Run install.sh
run: cat packages/cli/install.sh | bash

Expand Down Expand Up @@ -114,6 +124,195 @@ jobs:
vp upgrade --rollback
vp --version

test-install-sh-layout:
name: Test install.sh layout (fresh split + grandfather)
runs-on: ubuntu-latest
permissions:
contents: read
env:
VP_LOCAL_BINARY: ${{ github.workspace }}/target/release/vp
VP_SKIP_DEPS_INSTALL: '1'
VP_NODE_MANAGER: 'yes'
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2
- uses: ./.github/actions/clone
- uses: oxc-project/setup-rust@68c3199c5339f965e6e163924c3c450773eba42b # main (pending v1.0.17 — Swatinem/rust-cache v2.9.1 for node24)

- name: Build local vp
run: cargo build --release -p vp_global_cli

- name: Fresh home uses split layout
run: |
set -euo pipefail
FRESH=$(mktemp -d)
FAKE_TGZ=$(mktemp)
export HOME="$FRESH"
export USERPROFILE="$FRESH"
unset VP_HOME VP_BIN_DIR VP_DATA_DIR VP_CACHE_DIR
unset XDG_BIN_HOME XDG_DATA_HOME XDG_CACHE_HOME XDG_CONFIG_HOME XDG_STATE_HOME
VP_LOCAL_TGZ="$FAKE_TGZ" VP_VERSION=local-test bash packages/cli/install.sh

test ! -d "$FRESH/.vite-plus"
test -e "$FRESH/.local/share/vite-plus/current"
test -e "$FRESH/.local/bin/vp"
test -f "$FRESH/.config/vite-plus/env"
test "$(readlink "$FRESH/.local/bin/vp")" = "$FRESH/.local/share/vite-plus/current/bin/vp"
"$FRESH/.local/bin/vp" --version

- name: Existing ~/.vite-plus is reused
run: |
set -euo pipefail
GRAND=$(mktemp -d)
FAKE_TGZ=$(mktemp)
# A real prior install: grandfathering requires the `current` link,
# not a bare ~/.vite-plus directory.
mkdir -p "$GRAND/.vite-plus/0.0.1/bin"
ln -s 0.0.1 "$GRAND/.vite-plus/current"
echo keep > "$GRAND/.vite-plus/.keep"
export HOME="$GRAND"
export USERPROFILE="$GRAND"
unset VP_HOME VP_BIN_DIR VP_DATA_DIR VP_CACHE_DIR
unset XDG_BIN_HOME XDG_DATA_HOME XDG_CACHE_HOME XDG_CONFIG_HOME XDG_STATE_HOME
VP_LOCAL_TGZ="$FAKE_TGZ" VP_VERSION=local-test bash packages/cli/install.sh

test -f "$GRAND/.vite-plus/.keep"
test -e "$GRAND/.vite-plus/current"
test -e "$GRAND/.vite-plus/bin/vp"
test ! -d "$GRAND/.local/share/vite-plus"
test "$(readlink "$GRAND/.vite-plus/bin/vp")" = "$GRAND/.vite-plus/current/bin/vp"
"$GRAND/.vite-plus/bin/vp" --version

- name: Stray ~/.vite-plus does not capture a split install
run: |
set -euo pipefail
STRAY=$(mktemp -d)
FAKE_TGZ=$(mktemp)
export HOME="$STRAY"
export USERPROFILE="$STRAY"
unset VP_HOME VP_BIN_DIR VP_DATA_DIR VP_CACHE_DIR
unset XDG_BIN_HOME XDG_DATA_HOME XDG_CACHE_HOME XDG_CONFIG_HOME XDG_STATE_HOME
VP_LOCAL_TGZ="$FAKE_TGZ" VP_VERSION=local-test bash packages/cli/install.sh

# A pre-split local vite-plus can create ~/.vite-plus at any time
# for caches, config, and managed runtimes. No `current` link, so
# this is a stray tree, not an install.
mkdir -p "$STRAY/.vite-plus/cache" "$STRAY/.vite-plus/js_runtime"
echo '{}' > "$STRAY/.vite-plus/config.json"

# Resolution must stay on the split roots, with and without the
# env-script pins.
data_root() { VP_DUMP_DIRS=1 "$STRAY/.local/bin/vp" | awk -F'\t' '$1=="data"{print $2}'; }
test "$(data_root)" = "$STRAY/.local/share/vite-plus"
test "$(VP_DATA_DIR="$STRAY/.local/share/vite-plus" VP_BIN_DIR="$STRAY/.local/bin" data_root)" = "$STRAY/.local/share/vite-plus"

# A reinstall (vp upgrade selects its root through the same chain)
# must keep targeting the split roots and leave the stray tree alone.
VP_LOCAL_TGZ="$FAKE_TGZ" VP_VERSION=local-test2 bash packages/cli/install.sh

test -x "$STRAY/.local/share/vite-plus/local-test2/bin/vp"
test "$(readlink "$STRAY/.local/share/vite-plus/current")" = "local-test2"
test ! -e "$STRAY/.vite-plus/current"
test ! -e "$STRAY/.vite-plus/bin"
"$STRAY/.local/bin/vp" --version

test-install-sh-old-version:
name: Test install.sh pre-split release (${{ matrix.name }})
runs-on: ${{ matrix.os }}
permissions:
contents: read
env:
VP_VERSION: '0.2.9'
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: Linux x64 glibc
- os: macos-latest
name: macOS ARM64
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Run install.sh for a pre-split release
# No VP_HOME pin: a release that predates VpDirs must fall back to the
# monolithic ~/.vite-plus root on its own.
run: |
cat packages/cli/install.sh | bash | tee install-output.txt
grep -F "does not support the split directory layout" install-output.txt

- name: Verify monolithic layout
run: |
test -x "$HOME/.vite-plus/$VP_VERSION/bin/vp"
test -e "$HOME/.vite-plus/current"
test -f "$HOME/.vite-plus/env"
# No split-layout leftovers.
test ! -d "$HOME/.local/share/vite-plus"
test ! -d "$HOME/.config/vite-plus"
test ! -e "$HOME/.local/bin/vp"
ls -al "$HOME/.vite-plus/bin"
for shim in vp vpr vpx node npm npx corepack; do
test -e "$HOME/.vite-plus/bin/$shim"
done

- name: Verify PATH-resolved commands work
run: |
export PATH="$HOME/.vite-plus/bin:$PATH"
command -v vp | grep -F "$HOME/.vite-plus/bin/vp"
vp --version
node --version
npm --version
vp env doctor

test-install-ps1-old-version:
name: Test install.ps1 pre-split release (Windows x64)
# GitHub-hosted runner: %USERPROFILE% matches the OS profile, so the old
# release's own path resolution and `vp env doctor` agree with the install.
runs-on: windows-latest
permissions:
contents: read
env:
VP_VERSION: '0.2.9'
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Run install.ps1 for a pre-split release
# No VP_HOME pin: a release that predates VpDirs must fall back to the
# monolithic %USERPROFILE%\.vite-plus root on its own.
shell: pwsh
run: |
# *>&1 merges the information stream (Write-Host) into the pipeline
# so Tee-Object can capture the installer notices.
& ./packages/cli/install.ps1 *>&1 | Tee-Object -FilePath install-output.txt
if (-not (Select-String -Path install-output.txt -Pattern "does not support the split directory layout" -SimpleMatch -Quiet)) {
Write-Error "Expected the pre-split fallback notice in installer output"
exit 1
}

- name: Verify monolithic layout
shell: pwsh
run: |
$root = Join-Path $env:USERPROFILE ".vite-plus"
if (-not (Test-Path "$root\$env:VP_VERSION\bin\vp.exe")) { Write-Error "payload missing"; exit 1 }
if (-not (Test-Path "$root\current")) { Write-Error "current link missing"; exit 1 }
# No split-layout leftovers.
foreach ($split in @((Join-Path $env:LOCALAPPDATA "vite-plus"), (Join-Path $env:APPDATA "vite-plus"))) {
if (Test-Path $split) { Write-Error "unexpected split dir: $split"; exit 1 }
}
Get-ChildItem -Force "$root\bin"
foreach ($shim in @("vp.exe", "vpr.exe", "vpx.exe", "node.exe", "npm.exe", "npx.exe")) {
if (-not (Test-Path "$root\bin\$shim")) { Write-Error "shim missing: $shim"; exit 1 }
}

- name: Verify PATH-resolved commands work
shell: pwsh
run: |
$env:Path = "$env:USERPROFILE\.vite-plus\bin;$env:Path"
where.exe vp
vp --version
node --version
npm --version
vp env doctor

test-install-sh-readonly-config:
name: Test install.sh (readonly shell config)
runs-on: ubuntu-latest
Expand All @@ -122,6 +321,9 @@ jobs:
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Pin VP_HOME for pre-split published CLI
run: echo "VP_HOME=$HOME/.vite-plus" >> $GITHUB_ENV

- name: Make shell config files read-only
run: |
# Simulate Nix-managed or read-only shell configs
Expand Down Expand Up @@ -169,6 +371,7 @@ jobs:
ubuntu:20.04 bash -c "
ls -al ~/
apt-get update && apt-get install -y curl ca-certificates
export VP_HOME=\"\$HOME/.vite-plus\"
cat /workspace/packages/cli/install.sh | bash
if [ -f ~/.profile ]; then
source ~/.profile
Expand Down Expand Up @@ -228,6 +431,7 @@ jobs:
alpine:3.21 sh -c "
# libstdc++: required by unofficial-builds Node.js musl binary
apk add --no-cache bash curl ca-certificates libstdc++
export VP_HOME=\"\$HOME/.vite-plus\"
cat /workspace/packages/cli/install.sh | bash
export PATH=\"\$HOME/.vite-plus/bin:\$PATH\"

Expand Down Expand Up @@ -285,6 +489,7 @@ jobs:
alpine:3.21 sh -c "
# libstdc++ is needed by unofficial-builds Node.js musl binary
apk add --no-cache bash curl ca-certificates libstdc++
export VP_HOME=\"\$HOME/.vite-plus\"
cat /workspace/packages/cli/install.sh | bash
export PATH=\"\$HOME/.vite-plus/bin:\$PATH\"

Expand Down Expand Up @@ -420,6 +625,10 @@ jobs:
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Pin VP_HOME for pre-split published CLI
shell: bash
run: echo "VP_HOME=$USERPROFILE\.vite-plus" >> $GITHUB_ENV

- name: Run install.ps1
shell: pwsh
run: |
Expand Down Expand Up @@ -664,6 +873,10 @@ jobs:
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- name: Pin VP_HOME for pre-split published CLI
shell: bash
run: echo "VP_HOME=$USERPROFILE\.vite-plus" >> $GITHUB_ENV

- name: Run install.ps1
shell: pwsh
run: |
Expand Down
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ vite-plus/
└── crates/vp_trampoline/ # Windows shim trampoline
```

On-disk paths (bin, data, cache, and derived helpers) are resolved centrally via `vp_shared::VpDirs` (`crates/vp_shared/src/dirs.rs`, source chain in `dirs/resolution.rs`) — split XDG/platform roots, or a single root when `VP_HOME` is set or an existing `~/.vite-plus` install is found; no call site constructs category paths or reads `VP_HOME`/`XDG_*` itself.

`packages/test` is no longer tracked. The public test API is `vite-plus/test*`, generated by `packages/cli/build.ts` as shims over upstream `vitest` and `@vitest/browser*` exports.

## Where to Start
Expand Down Expand Up @@ -108,7 +110,7 @@ pnpm bootstrap-cli # Build packages, compile vp/NAPI, and install the global CL
vp --version
```

Use `pnpm bootstrap-cli` when you need to validate the installed global CLI at `~/.vite-plus`.
Use `pnpm bootstrap-cli` when you need to validate the installed global CLI end-to-end.

### Routine validation

Expand Down
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ sugar_path = { version = "3", features = ["cached_current_dir"] }
supports-color = "3"
syn = { version = "2", default-features = false }
tar = "0.4.43"
temp-env = "0.3.6"
tempfile = "3.14.0"
terminal_size = "0.4.2"
test-log = { version = "0.2.18", features = ["trace"] }
Expand Down
Loading
Loading