From 51f70157ca0b86cd35ddad787e79eee7e99917f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20Sewi=C5=82o?= <95349104+ksew1@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:19:57 +0200 Subject: [PATCH] Make scarb new and init command interactive (#1472) Closes #1207 Closes [#1982](https://github.com/foundry-rs/starknet-foundry/issues/1982) Make scarb new and init command interactive --- Cargo.lock | 14 ++++++++ Cargo.toml | 1 + scarb-metadata/tests/command.rs | 1 + scarb-metadata/tests/scarb_command.rs | 1 + scarb/Cargo.toml | 1 + scarb/src/bin/scarb/args.rs | 12 +++++-- scarb/src/bin/scarb/commands/init.rs | 8 +++-- scarb/src/bin/scarb/commands/new.rs | 8 +++-- scarb/src/bin/scarb/interactive.rs | 45 +++++++++++++++++++++++++ scarb/src/bin/scarb/main.rs | 1 + scarb/tests/new_and_init.rs | 37 +++++++++++++++++++- scarb/tests/snforge_init.rs | 2 +- utils/scarb-test-support/src/command.rs | 1 + 13 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 scarb/src/bin/scarb/interactive.rs diff --git a/Cargo.lock b/Cargo.lock index 06db27542..d39708e29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1620,6 +1620,19 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror", + "zeroize", +] + [[package]] name = "diff" version = "0.1.13" @@ -4603,6 +4616,7 @@ dependencies = [ "data-encoding", "deno_task_shell", "derive_builder", + "dialoguer", "directories", "dunce", "expect-test", diff --git a/Cargo.toml b/Cargo.toml index cfd30418a..0dd20cba5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ darling = "0.20" data-encoding = "2" deno_task_shell = ">=0.13" derive_builder = ">=0.12" +dialoguer = "0.11.0" directories = "5" dunce = "1" expect-test = "1.5" diff --git a/scarb-metadata/tests/command.rs b/scarb-metadata/tests/command.rs index 0a6b8d773..ffdc94f63 100644 --- a/scarb-metadata/tests/command.rs +++ b/scarb-metadata/tests/command.rs @@ -70,6 +70,7 @@ fn manifest_path() { fn init_project(t: &TempDir) { Command::new(scarb_bin()) .args(["init", "--name", "hello"]) + .env("SCARB_INIT_TEST_RUNNER", "cairo-test") .current_dir(t) .assert() .success(); diff --git a/scarb-metadata/tests/scarb_command.rs b/scarb-metadata/tests/scarb_command.rs index 6f9a80a5c..aaf525ef5 100644 --- a/scarb-metadata/tests/scarb_command.rs +++ b/scarb-metadata/tests/scarb_command.rs @@ -41,6 +41,7 @@ fn sample_project() { fn init_project(t: &TempDir) { Command::new(scarb_bin()) .args(["init", "--name", "hello"]) + .env("SCARB_INIT_TEST_RUNNER", "cairo-test") .current_dir(t) .assert() .success(); diff --git a/scarb/Cargo.toml b/scarb/Cargo.toml index d7eb49206..7329ee03c 100644 --- a/scarb/Cargo.toml +++ b/scarb/Cargo.toml @@ -40,6 +40,7 @@ create-output-dir = { path = "../utils/create-output-dir" } data-encoding.workspace = true deno_task_shell.workspace = true derive_builder.workspace = true +dialoguer.workspace = true directories.workspace = true dunce.workspace = true fs4.workspace = true diff --git a/scarb/src/bin/scarb/args.rs b/scarb/src/bin/scarb/args.rs index 80166e371..9ce1adadd 100644 --- a/scarb/src/bin/scarb/args.rs +++ b/scarb/src/bin/scarb/args.rs @@ -272,6 +272,12 @@ pub struct ScriptsRunnerArgs { pub args: Vec, } +#[derive(ValueEnum, Clone, Debug)] +pub enum TestRunner { + StarknetFoundry, + CairoTest, +} + /// Arguments accepted by the `init` command. #[derive(Parser, Clone, Debug)] pub struct InitArgs { @@ -283,9 +289,9 @@ pub struct InitArgs { #[arg(long)] pub no_vcs: bool, - /// Use a Starknet Foundry Forge template. - #[arg(long)] - pub snforge: bool, + /// Test runner to use. Starts interactive session if not specified. + #[arg(long, env = "SCARB_INIT_TEST_RUNNER")] + pub test_runner: Option, } /// Arguments accepted by the `metadata` command. diff --git a/scarb/src/bin/scarb/commands/init.rs b/scarb/src/bin/scarb/commands/init.rs index 8d53e9667..66243661a 100644 --- a/scarb/src/bin/scarb/commands/init.rs +++ b/scarb/src/bin/scarb/commands/init.rs @@ -6,7 +6,8 @@ use camino::Utf8PathBuf; use scarb::core::Config; use scarb::ops::{self, VersionControl}; -use crate::args::InitArgs; +use crate::args::{InitArgs, TestRunner}; +use crate::interactive::get_or_ask_for_test_runner; #[tracing::instrument(skip_all, level = "info")] pub fn run(args: InitArgs, config: &Config) -> Result<()> { @@ -24,7 +25,10 @@ pub fn run(args: InitArgs, config: &Config) -> Result<()> { } else { VersionControl::Git }, - snforge: args.snforge, + snforge: matches!( + get_or_ask_for_test_runner(args.test_runner)?, + TestRunner::StarknetFoundry + ), }, config, )?; diff --git a/scarb/src/bin/scarb/commands/new.rs b/scarb/src/bin/scarb/commands/new.rs index 1c721486b..5d84c99f5 100644 --- a/scarb/src/bin/scarb/commands/new.rs +++ b/scarb/src/bin/scarb/commands/new.rs @@ -3,7 +3,8 @@ use anyhow::Result; use scarb::core::Config; use scarb::ops::{self, VersionControl}; -use crate::args::NewArgs; +use crate::args::{NewArgs, TestRunner}; +use crate::interactive::get_or_ask_for_test_runner; #[tracing::instrument(skip_all, level = "info")] pub fn run(args: NewArgs, config: &Config) -> Result<()> { @@ -18,7 +19,10 @@ pub fn run(args: NewArgs, config: &Config) -> Result<()> { } else { VersionControl::Git }, - snforge: args.init.snforge, + snforge: matches!( + get_or_ask_for_test_runner(args.init.test_runner)?, + TestRunner::StarknetFoundry + ), }, config, )?; diff --git a/scarb/src/bin/scarb/interactive.rs b/scarb/src/bin/scarb/interactive.rs new file mode 100644 index 000000000..8a7f864cf --- /dev/null +++ b/scarb/src/bin/scarb/interactive.rs @@ -0,0 +1,45 @@ +use std::io::{self, IsTerminal}; + +use crate::args::TestRunner; +use anyhow::{ensure, Result}; +use dialoguer::theme::ColorfulTheme; +use dialoguer::Select; +use indoc::indoc; +use which::which; + +pub fn get_or_ask_for_test_runner(test_runner: Option) -> Result { + Ok(test_runner) + .transpose() + .unwrap_or_else(ask_for_test_runner) +} + +fn ask_for_test_runner() -> Result { + ensure!( + io::stdout().is_terminal(), + indoc! {r" + you are not running in terminal + help: please provide the --test-runner flag + "} + ); + + let options = if which("snforge").is_ok() { + vec!["Starknet Foundry (default)", "Cairo Test"] + } else { + vec![ + "Cairo Test (default)", + "Starknet Foundry (recommended, requires snforge installed: https://github.com/foundry-rs/starknet-foundry)", + ] + }; + + let selection = Select::with_theme(&ColorfulTheme::default()) + .with_prompt("Which test runner do you want to set up?") + .items(&options) + .default(0) + .interact()?; + + if options[selection].starts_with("Cairo Test") { + Ok(TestRunner::CairoTest) + } else { + Ok(TestRunner::StarknetFoundry) + } +} diff --git a/scarb/src/bin/scarb/main.rs b/scarb/src/bin/scarb/main.rs index 8d2bfb2b5..07df66318 100644 --- a/scarb/src/bin/scarb/main.rs +++ b/scarb/src/bin/scarb/main.rs @@ -17,6 +17,7 @@ use crate::errors::ErrorWithExitCode; mod args; mod commands; mod errors; +mod interactive; fn main() { let args = ScarbArgs::parse(); diff --git a/scarb/tests/new_and_init.rs b/scarb/tests/new_and_init.rs index 3129c1394..a6f3236a3 100644 --- a/scarb/tests/new_and_init.rs +++ b/scarb/tests/new_and_init.rs @@ -122,7 +122,7 @@ fn new_no_path_arg() { error: the following required arguments were not provided: - Usage: scarb[..] new + Usage: scarb[..] new [..] For more information, try '--help'. "#}); @@ -146,6 +146,41 @@ fn new_existing() { "#}); } +#[test] +fn new_interactive_not_in_terminal() { + let pt = assert_fs::TempDir::new().unwrap(); + + Scarb::quick_snapbox() + .arg("new") + .arg("hello") + .env_remove("SCARB_INIT_TEST_RUNNER") + .current_dir(&pt) + .assert() + .failure() + .stdout_eq(indoc! {r" + error: you are not running in terminal + help: please provide the --test-runner flag + "}); +} + +#[test] +fn init_interactive_not_in_terminal() { + let pt = assert_fs::TempDir::new().unwrap(); + let t = pt.child("hello"); + t.create_dir_all().unwrap(); + + Scarb::quick_snapbox() + .arg("init") + .env_remove("SCARB_INIT_TEST_RUNNER") + .current_dir(&t) + .assert() + .failure() + .stdout_eq(indoc! {r" + error: you are not running in terminal + help: please provide the --test-runner flag + "}); +} + #[test] fn issue_148() { let pt = assert_fs::TempDir::new().unwrap(); diff --git a/scarb/tests/snforge_init.rs b/scarb/tests/snforge_init.rs index 04f5818f2..4a7441328 100644 --- a/scarb/tests/snforge_init.rs +++ b/scarb/tests/snforge_init.rs @@ -12,7 +12,7 @@ fn new_simple() { Scarb::quick_snapbox() .arg("new") .arg("hello") - .arg("--snforge") + .args(["--test-runner", "starknet-foundry"]) .current_dir(&pt) .assert() .success(); diff --git a/utils/scarb-test-support/src/command.rs b/utils/scarb-test-support/src/command.rs index fc1c5a935..cb60528b8 100644 --- a/utils/scarb-test-support/src/command.rs +++ b/utils/scarb-test-support/src/command.rs @@ -54,6 +54,7 @@ impl Scarb { cmd.env("SCARB_LOG", self.log); cmd.env("SCARB_CACHE", self.cache.path()); cmd.env("SCARB_CONFIG", self.config.path()); + cmd.env("SCARB_INIT_TEST_RUNNER", "cairo-test"); cmd }