feat(init/npm): add --yes flag to bypass prompt (#31499)
Some checks are pending
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / pre-build (push) Waiting to run
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / build libs (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions

This commit is contained in:
David Sherret 2025-12-05 11:07:07 -05:00 committed by GitHub
parent e687220588
commit dd3a7d394b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 96 additions and 28 deletions

View file

@ -287,6 +287,7 @@ pub struct InitFlags {
pub dir: Option<String>,
pub lib: bool,
pub serve: bool,
pub yes: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
@ -3165,6 +3166,14 @@ fn init_subcommand() -> Command {
.conflicts_with("lib")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("yes")
.short('y')
.long("yes")
.requires("npm")
.help("Bypass the prompt and run with full permissions")
.action(ArgAction::SetTrue),
)
},
)
}
@ -5936,6 +5945,7 @@ fn init_parse(
) -> Result<(), clap::Error> {
let mut lib = matches.get_flag("lib");
let mut serve = matches.get_flag("serve");
let mut yes = matches.get_flag("yes");
let mut dir = None;
let mut package = None;
let mut package_args = vec![];
@ -5955,6 +5965,7 @@ fn init_parse(
let inner_matches = init_subcommand().try_get_matches_from_mut(args)?;
lib = inner_matches.get_flag("lib");
serve = inner_matches.get_flag("serve");
yes = inner_matches.get_flag("yes");
}
}
}
@ -5965,6 +5976,7 @@ fn init_parse(
dir,
lib,
serve,
yes,
});
Ok(())
@ -12589,6 +12601,7 @@ mod tests {
dir: None,
lib: false,
serve: false,
yes: false,
}),
..Flags::default()
}
@ -12604,6 +12617,7 @@ mod tests {
dir: Some(String::from("foo")),
lib: false,
serve: false,
yes: false,
}),
..Flags::default()
}
@ -12619,6 +12633,7 @@ mod tests {
dir: None,
lib: false,
serve: false,
yes: false,
}),
log_level: Some(Level::Error),
..Flags::default()
@ -12635,6 +12650,7 @@ mod tests {
dir: None,
lib: true,
serve: false,
yes: false,
}),
..Flags::default()
}
@ -12650,6 +12666,7 @@ mod tests {
dir: None,
lib: false,
serve: true,
yes: false,
}),
..Flags::default()
}
@ -12665,6 +12682,7 @@ mod tests {
dir: Some(String::from("foo")),
lib: true,
serve: false,
yes: false,
}),
..Flags::default()
}
@ -12686,6 +12704,7 @@ mod tests {
dir: None,
lib: false,
serve: false,
yes: false,
}),
..Flags::default()
}
@ -12701,6 +12720,7 @@ mod tests {
dir: None,
lib: false,
serve: false,
yes: false,
}),
..Flags::default()
}
@ -12716,6 +12736,23 @@ mod tests {
dir: None,
lib: false,
serve: false,
yes: false,
}),
..Flags::default()
}
);
let r = flags_from_vec(svec!["deno", "init", "--npm", "--yes", "vite"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Init(InitFlags {
package: Some("vite".to_string()),
package_args: vec![],
dir: None,
lib: false,
serve: false,
yes: true,
}),
..Flags::default()
}

View file

@ -30,9 +30,13 @@ use crate::util::progress_bar::ProgressBar;
pub async fn init_project(init_flags: InitFlags) -> Result<i32, AnyError> {
if let Some(package) = &init_flags.package {
return init_npm(package, init_flags.package_args)
.boxed_local()
.await;
return init_npm(InitNpmOptions {
name: package,
args: init_flags.package_args,
yes: init_flags.yes,
})
.boxed_local()
.await;
}
let cwd =
@ -301,43 +305,53 @@ fn npm_name_to_create_package(name: &str) -> String {
s
}
async fn init_npm(name: &str, args: Vec<String>) -> Result<i32, AnyError> {
let script_name = npm_name_to_create_package(name);
struct InitNpmOptions<'a> {
name: &'a str,
args: Vec<String>,
yes: bool,
}
async fn init_npm(options: InitNpmOptions<'_>) -> Result<i32, AnyError> {
let script_name = npm_name_to_create_package(options.name);
fn print_manual_usage(script_name: &str, args: &[String]) -> i32 {
log::info!(
"{}",
cformat!(
"You can initialize project manually by running <u>deno run {} {}</> and applying desired permissions.",
script_name,
args.join(" ")
"You can initialize project manually by running <u>deno run {}</> and applying desired permissions.",
std::iter::once(script_name)
.chain(args.iter().map(|a| a.as_ref()))
.collect::<Vec<_>>()
.join(" ")
)
);
1
}
if std::io::stdin().is_terminal() {
log::info!(
cstr!(
"⚠️ Do you fully trust <y>{}</> package? Deno will invoke code from it with all permissions. Do you want to continue? <p(245)>[y/n]</>"
),
script_name
);
loop {
let _ = std::io::stdout().write(b"> ")?;
std::io::stdout().flush()?;
let mut answer = String::new();
if std::io::stdin().read_line(&mut answer).is_ok() {
let answer = answer.trim().to_ascii_lowercase();
if answer != "y" {
return Ok(print_manual_usage(&script_name, &args));
} else {
break;
if !options.yes {
if std::io::stdin().is_terminal() {
log::info!(
cstr!(
"⚠️ Do you fully trust <y>{}</> package? Deno will invoke code from it with all permissions. Do you want to continue? <p(245)>[y/n]</>"
),
script_name
);
loop {
let _ = std::io::stdout().write(b"> ")?;
std::io::stdout().flush()?;
let mut answer = String::new();
if std::io::stdin().read_line(&mut answer).is_ok() {
let answer = answer.trim().to_ascii_lowercase();
if answer != "y" {
return Ok(print_manual_usage(&script_name, &options.args));
} else {
break;
}
}
}
} else {
return Ok(print_manual_usage(&script_name, &options.args));
}
} else {
return Ok(print_manual_usage(&script_name, &args));
}
let temp_node_modules_parent_tempdir = create_temp_node_modules_parent_dir()
@ -360,7 +374,7 @@ async fn init_npm(name: &str, args: Vec<String>) -> Result<i32, AnyError> {
..Default::default()
},
allow_scripts: PackagesAllowedScripts::All,
argv: args,
argv: options.args,
node_modules_dir: Some(NodeModulesDirMode::Auto),
subcommand: DenoSubcommand::Run(RunFlags {
script: script_name,

View file

@ -0,0 +1,14 @@
{
"tempDir": true,
"tests": {
"missing": {
"args": "init --npm @denotest",
"output": "missing.out",
"exitCode": 1
},
"yes": {
"args": "init --npm --yes @denotest",
"output": "init.out"
}
}
}

View file

@ -0,0 +1,2 @@
[WILDCARD]
Initialized!

View file

@ -0,0 +1 @@
You can initialize project manually by running deno run npm:@denotest/create and applying desired permissions.