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
79 changes: 79 additions & 0 deletions crates/vite_global_cli/src/commands/env/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,13 @@ pub async fn resolve_version(cwd: &AbsolutePath) -> Result<VersionResolution, Er
});
}

resolve_version_from_files(cwd).await
}

/// Resolve Node.js version from project files only (skipping session overrides).
///
/// This is used by `vp env use` without arguments to revert to file-based resolution.
pub async fn resolve_version_from_files(cwd: &AbsolutePath) -> Result<VersionResolution, Error> {
let provider = NodeProvider::new();

// Use shared version resolution with directory walking
Expand Down Expand Up @@ -1091,4 +1098,76 @@ mod tests {
assert_eq!(resolution.version, "20.18.0");
assert_eq!(resolution.source, ".node-version");
}

// ── resolve_version_from_files tests ──

/// Verify that `resolve_version_from_files` ignores session env var override.
/// This is the key behavior for `vp env use` without arguments.
#[tokio::test]
async fn test_resolve_version_from_files_ignores_env_var() {
let temp_dir = TempDir::new().unwrap();
let temp_path = AbsolutePathBuf::new(temp_dir.path().to_path_buf()).unwrap();
let _guard = vite_shared::EnvConfig::test_guard(vite_shared::EnvConfig {
node_version: Some("22.0.0".into()),
..vite_shared::EnvConfig::for_test()
});

// Create .node-version file with different version
tokio::fs::write(temp_path.join(".node-version"), "20.18.0\n").await.unwrap();

// resolve_version_from_files should skip env var and use .node-version
let resolution = resolve_version_from_files(&temp_path).await.unwrap();

assert_eq!(resolution.version, "20.18.0");
assert_eq!(resolution.source, ".node-version");
}

/// Verify that `resolve_version_from_files` ignores session file override.
#[tokio::test]
async fn test_resolve_version_from_files_ignores_session_file() {
let temp_dir = TempDir::new().unwrap();
let temp_path = AbsolutePathBuf::new(temp_dir.path().to_path_buf()).unwrap();
let _guard = vite_shared::EnvConfig::test_guard(
vite_shared::EnvConfig::for_test_with_home(temp_dir.path()),
);

// Write session version file
write_session_version("22.0.0").await.unwrap();

// Create .node-version file with different version
tokio::fs::write(temp_path.join(".node-version"), "20.18.0\n").await.unwrap();

// resolve_version_from_files should skip session file and use .node-version
let resolution = resolve_version_from_files(&temp_path).await.unwrap();

assert_eq!(resolution.version, "20.18.0");
assert_eq!(resolution.source, ".node-version");

// Clean up
delete_session_version().await.unwrap();
}

/// Verify that `resolve_version_from_files` still respects both env var and session file.
#[tokio::test]
async fn test_resolve_version_still_respects_overrides() {
let temp_dir = TempDir::new().unwrap();
let temp_path = AbsolutePathBuf::new(temp_dir.path().to_path_buf()).unwrap();
let _guard = vite_shared::EnvConfig::test_guard(vite_shared::EnvConfig {
node_version: Some("22.0.0".into()),
..vite_shared::EnvConfig::for_test_with_home(temp_dir.path())
});

// Create .node-version file
tokio::fs::write(temp_path.join(".node-version"), "20.18.0\n").await.unwrap();

// resolve_version should still use env var (existing behavior)
let resolution = resolve_version(&temp_path).await.unwrap();
assert_eq!(resolution.version, "22.0.0");
assert_eq!(resolution.source, VERSION_ENV_VAR);

// But resolve_version_from_files should skip it
let resolution_from_files = resolve_version_from_files(&temp_path).await.unwrap();
assert_eq!(resolution_from_files.version, "20.18.0");
assert_eq!(resolution_from_files.source, ".node-version");
}
}
10 changes: 9 additions & 1 deletion crates/vite_global_cli/src/commands/env/use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,19 @@ pub async fn execute(
let provider = vite_js_runtime::NodeProvider::new();

// Resolve version: explicit argument or from project files
// When no argument provided, unset session override and resolve from project files
let (resolved_version, source_desc) = if let Some(ref ver) = version {
let resolved = config::resolve_version_alias(ver, &provider).await?;
(resolved, format!("{ver}"))
} else {
let resolution = config::resolve_version(&cwd).await?;
// No version argument - unset session override first
if has_eval_wrapper() {
println!("{}", format_unset(&shell));
} else {
config::delete_session_version().await?;
}
// Now resolve from project files (not from session override)
let resolution = config::resolve_version_from_files(&cwd).await?;
let source = resolution.source.clone();
(resolution.version, source)
};
Expand Down
Loading