Skip to content
Draft
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
504 changes: 504 additions & 0 deletions crates/vite_install/src/commands/approve_builds.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions crates/vite_install/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod add;
pub mod approve_builds;
pub mod audit;
pub mod cache;
pub mod config;
Expand Down
69 changes: 69 additions & 0 deletions crates/vite_pm_cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,23 @@ impl PackageManagerCommand {
/// Package manager subcommands (`vp pm <subcommand>`).
#[derive(Subcommand, Debug, Clone)]
pub enum PmCommands {
/// Approve dependency lifecycle scripts (install/postinstall) to run
#[command(name = "approve-builds")]
ApproveBuilds {
/// Packages to approve. Prefix with `!` to deny (pnpm >= 11.0.0 only).
/// Omit to launch interactive mode (pnpm only).
packages: Vec<String>,

/// Approve every package currently pending approval (pnpm >= 10.32.0).
/// Mutually exclusive with positional packages.
#[arg(long, conflicts_with = "packages")]
all: bool,

/// Additional arguments to pass through to the package manager
#[arg(last = true, allow_hyphen_values = true)]
pass_through_args: Option<Vec<String>>,
},

/// Remove unnecessary packages
Prune {
/// Remove devDependencies
Expand Down Expand Up @@ -1182,4 +1199,56 @@ mod tests {

assert_eq!(error.kind(), clap::error::ErrorKind::ValueValidation);
}

#[test]
fn approve_builds_all_conflicts_with_packages() {
let error = parse_pm_command(&["vp", "pm", "approve-builds", "--all", "esbuild"])
.expect_err("expected --all + positional to fail");

assert_eq!(error.kind(), clap::error::ErrorKind::ArgumentConflict);
}

#[test]
fn approve_builds_all_conflicts_with_deny_packages() {
let error = parse_pm_command(&["vp", "pm", "approve-builds", "--all", "!core-js"])
.expect_err("expected --all + !pkg to fail");

assert_eq!(error.kind(), clap::error::ErrorKind::ArgumentConflict);
}

#[test]
fn approve_builds_all_alone_parses() {
let command = parse_pm_command(&["vp", "pm", "approve-builds", "--all"])
.expect("--all alone should parse");

assert!(matches!(
command,
PackageManagerCommand::Pm(PmCommands::ApproveBuilds { all: true, .. })
));
}

#[test]
fn approve_builds_packages_alone_parses() {
let command = parse_pm_command(&["vp", "pm", "approve-builds", "esbuild", "fsevents"])
.expect("positional packages should parse");

assert!(matches!(
command,
PackageManagerCommand::Pm(PmCommands::ApproveBuilds { all: false, .. })
));
}

#[test]
fn approve_builds_pass_through_args_capture() {
let command =
parse_pm_command(&["vp", "pm", "approve-builds", "esbuild", "--", "--workspace-root"])
.expect("pass-through args should parse");

let PackageManagerCommand::Pm(PmCommands::ApproveBuilds { pass_through_args, .. }) =
command
else {
panic!("expected ApproveBuilds variant");
};
assert_eq!(pass_through_args, Some(vec!["--workspace-root".to_string()]));
}
}
16 changes: 16 additions & 0 deletions crates/vite_pm_cli/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use vite_install::{
PackageManager,
commands::{
add::AddCommandOptions,
approve_builds::ApproveBuildsCommandOptions,
audit::AuditCommandOptions,
cache::CacheCommandOptions,
config::ConfigCommandOptions,
Expand Down Expand Up @@ -194,6 +195,21 @@ pub async fn run_pm_subcommand(
};

match command {
PmCommands::ApproveBuilds { packages, all, pass_through_args } => {
let options = ApproveBuildsCommandOptions {
packages: &packages,
all,
pass_through_args: pass_through_args.as_deref(),
};
// Map `Error::InvalidArgument` from the resolver to `UserMessage`
// so the version-gate failure renders without the harsh `error:` prefix.
match pm.run_approve_builds_command(&options, cwd).await {
Ok(status) => Ok(status),
Err(vite_error::Error::InvalidArgument(msg)) => Err(Error::UserMessage(msg)),
Err(other) => Err(Error::Install(other)),
}
}

PmCommands::Prune { prod, no_optional, pass_through_args } => {
let options = PruneCommandOptions {
prod,
Expand Down
39 changes: 20 additions & 19 deletions packages/cli/snap-tests-global/cli-helper-message/snap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -313,25 +313,26 @@ Usage: vp pm <COMMAND>
Forward a command to the package manager

Commands:
prune Remove unnecessary packages
pack Create a tarball of the package
list List installed packages [aliases: ls]
view View package information from the registry [aliases: info, show]
publish Publish package to registry
owner Manage package owners [aliases: author]
cache Manage package cache
config Manage package manager configuration [aliases: c]
login Log in to a registry [aliases: adduser]
logout Log out from a registry
whoami Show the current logged-in user
token Manage authentication tokens
audit Run a security audit
dist-tag Manage distribution tags
deprecate Deprecate a package version
search Search for packages in the registry
rebuild Rebuild native modules [aliases: rb]
fund Show funding information for installed packages
ping Ping the registry
approve-builds Approve dependency lifecycle scripts (install/postinstall) to run
prune Remove unnecessary packages
pack Create a tarball of the package
list List installed packages [aliases: ls]
view View package information from the registry [aliases: info, show]
publish Publish package to registry
owner Manage package owners [aliases: author]
cache Manage package cache
config Manage package manager configuration [aliases: c]
login Log in to a registry [aliases: adduser]
logout Log out from a registry
whoami Show the current logged-in user
token Manage authentication tokens
audit Run a security audit
dist-tag Manage distribution tags
deprecate Deprecate a package version
search Search for packages in the registry
rebuild Rebuild native modules [aliases: rb]
fund Show funding information for installed packages
ping Ping the registry

Options:
-h, --help Print help
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "command-pm-approve-builds-bun",
"version": "1.0.0",
"packageManager": "bun@1.3.11"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
> vp pm approve-builds --help # should show help with --all caveat
Usage: vp pm approve-builds [OPTIONS] [PACKAGES]... [-- <PASS_THROUGH_ARGS>...]

Approve dependency lifecycle scripts (install/postinstall) to run

Arguments:
[PACKAGES]... Packages to approve. Prefix with `!` to deny (pnpm >= <semver> only). Omit to launch interactive mode (pnpm only)
[PASS_THROUGH_ARGS]... Additional arguments to pass through to the package manager

Options:
--all Approve every package currently pending approval (pnpm >= <semver>). Mutually exclusive with positional packages
-h, --help Print help

Documentation: https://viteplus.dev/guide/install


> vp pm approve-builds # bun no-args: prints contextual note, exit 0
note: bun pm trust requires package names. Run `bun pm untrusted` to see which packages are pending, then pass them explicitly: `vp pm approve-builds <pkg> [<pkg>...]` or `vp pm approve-builds --all`.

> vp pm approve-builds '!core-js' # deny-only: prints deny warn, no redundant note
warn: bun does not support denylisting build scripts. Packages outside `trustedDependencies` in package.json are already denied by default. Skipping: core-js

[1]> vp pm approve-builds --all # forwards bun pm trust --all (nothing to trust in this empty project)
bun pm trust v<semver> (af24e281)
error: Lockfile not found
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"commands": [
"vp pm approve-builds --help # should show help with --all caveat",
"vp pm approve-builds # bun no-args: prints contextual note, exit 0",
"vp pm approve-builds '!core-js' # deny-only: prints deny warn, no redundant note",
"vp pm approve-builds --all # forwards bun pm trust --all (nothing to trust in this empty project)"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "command-pm-approve-builds-pnpm10-old",
"version": "1.0.0",
"packageManager": "pnpm@10.31.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[1]> vp pm approve-builds --all # pnpm 10.31.0 < 10.32.0 → rejected with friendly UserMessage (no `error:` prefix)
`--all` requires pnpm >= <semver>. Upgrade pnpm or pass package names explicitly.

[1]> vp pm approve-builds esbuild '!core-js' # pnpm 10.31.0 < 11.0.0 → !pkg deny syntax rejected
`!<pkg>` deny syntax requires pnpm >= <semver>. Upgrade pnpm or omit the `!` entries.

> vp pm approve-builds esbuild # plain positional still works on old pnpm
There are no packages awaiting approval
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"commands": [
"vp pm approve-builds --all # pnpm 10.31.0 < 10.32.0 → rejected with friendly UserMessage (no `error:` prefix)",
"vp pm approve-builds esbuild '!core-js' # pnpm 10.31.0 < 11.0.0 → !pkg deny syntax rejected",
"vp pm approve-builds esbuild # plain positional still works on old pnpm"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "command-pm-approve-builds-npm",
"version": "1.0.0",
"private": true,
"packageManager": "npm@10.9.0"
}
21 changes: 21 additions & 0 deletions packages/cli/snap-tests/command-pm-approve-builds-npm/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
> vp pm approve-builds --help # should show help
Approve dependency lifecycle scripts (install/postinstall) to run

Usage: vp pm approve-builds [OPTIONS] [PACKAGES]... [-- <PASS_THROUGH_ARGS>...]

Arguments:
[PACKAGES]... Packages to approve. Prefix with `!` to deny (pnpm >= <semver> only). Omit to launch interactive mode (pnpm only)
[PASS_THROUGH_ARGS]... Additional arguments to pass through to the package manager

Options:
--all Approve every package currently pending approval (pnpm >= <semver>). Mutually exclusive with positional packages
-h, --help Print help

> vp pm approve-builds # warn and exit 0 (no-op on npm)
warn: npm runs lifecycle scripts by default. To restrict them, set `ignore-scripts=true` in .npmrc and rebuild approved packages with `vp pm rebuild <package>`.

> vp pm approve-builds esbuild # warn and exit 0 (no-op on npm)
warn: npm runs lifecycle scripts by default. To restrict them, set `ignore-scripts=true` in .npmrc and rebuild approved packages with `vp pm rebuild <package>`.

> vp pm approve-builds --all # warn and exit 0 (no-op on npm)
warn: npm runs lifecycle scripts by default. To restrict them, set `ignore-scripts=true` in .npmrc and rebuild approved packages with `vp pm rebuild <package>`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"commands": [
"vp pm approve-builds --help # should show help",
"vp pm approve-builds # warn and exit 0 (no-op on npm)",
"vp pm approve-builds esbuild # warn and exit 0 (no-op on npm)",
"vp pm approve-builds --all # warn and exit 0 (no-op on npm)"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "command-pm-approve-builds-pnpm10",
"version": "1.0.0",
"private": true,
"packageManager": "pnpm@10.32.0"
}
18 changes: 18 additions & 0 deletions packages/cli/snap-tests/command-pm-approve-builds-pnpm10/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
> vp pm approve-builds --help # should show help
Approve dependency lifecycle scripts (install/postinstall) to run

Usage: vp pm approve-builds [OPTIONS] [PACKAGES]... [-- <PASS_THROUGH_ARGS>...]

Arguments:
[PACKAGES]... Packages to approve. Prefix with `!` to deny (pnpm >= <semver> only). Omit to launch interactive mode (pnpm only)
[PASS_THROUGH_ARGS]... Additional arguments to pass through to the package manager

Options:
--all Approve every package currently pending approval (pnpm >= <semver>). Mutually exclusive with positional packages
-h, --help Print help

> vp pm approve-builds --all # forwards to pnpm approve-builds --all (nothing to approve)
There are no packages awaiting approval

> vp pm approve-builds esbuild fsevents # forwards positional packages to pnpm
There are no packages awaiting approval
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"commands": [
"vp pm approve-builds --help # should show help",
"vp pm approve-builds --all # forwards to pnpm approve-builds --all (nothing to approve)",
"vp pm approve-builds esbuild fsevents # forwards positional packages to pnpm"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "command-pm-approve-builds-yarn",
"version": "1.0.0",
"private": true,
"packageManager": "yarn@1.22.22"
}
21 changes: 21 additions & 0 deletions packages/cli/snap-tests/command-pm-approve-builds-yarn/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
> vp pm approve-builds --help # should show help
Approve dependency lifecycle scripts (install/postinstall) to run

Usage: vp pm approve-builds [OPTIONS] [PACKAGES]... [-- <PASS_THROUGH_ARGS>...]

Arguments:
[PACKAGES]... Packages to approve. Prefix with `!` to deny (pnpm >= <semver> only). Omit to launch interactive mode (pnpm only)
[PASS_THROUGH_ARGS]... Additional arguments to pass through to the package manager

Options:
--all Approve every package currently pending approval (pnpm >= <semver>). Mutually exclusive with positional packages
-h, --help Print help

> vp pm approve-builds # warn and exit 0 (no-op on yarn)
warn: yarn (v1) runs lifecycle scripts by default. To restrict them, set `ignore-scripts true` in .npmrc and rebuild approved packages with `vp pm rebuild <package>`.

> vp pm approve-builds esbuild # warn and exit 0 (no-op on yarn)
warn: yarn (v1) runs lifecycle scripts by default. To restrict them, set `ignore-scripts true` in .npmrc and rebuild approved packages with `vp pm rebuild <package>`.

> vp pm approve-builds --all # warn and exit 0 (no-op on yarn)
warn: yarn (v1) runs lifecycle scripts by default. To restrict them, set `ignore-scripts true` in .npmrc and rebuild approved packages with `vp pm rebuild <package>`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ignoredPlatforms": ["linux", "win32"],
"commands": [
"vp pm approve-builds --help # should show help",
"vp pm approve-builds # warn and exit 0 (no-op on yarn)",
"vp pm approve-builds esbuild # warn and exit 0 (no-op on yarn)",
"vp pm approve-builds --all # warn and exit 0 (no-op on yarn)"
]
}
Loading
Loading