From ebe93487f6963a537da7e2e915b776ab0ffb990c Mon Sep 17 00:00:00 2001 From: ddoktorski <45050160+ddoktorski@users.noreply.github.com> Date: Fri, 13 Dec 2024 15:06:59 +0100 Subject: [PATCH] Add `snforge new` command (#2770) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2645 ## Introduced changes - `snforge new` command, which allows specifying the name of the package and the path where it should be created - Deprecation warning to the `snforge init` command Docs and changelog will be updated in a separate PR. ## Checklist - [X] Linked relevant issue - [X] Updated relevant documentation - [X] Added relevant tests - [X] Performed self-review of the code - [X] Added changes to `CHANGELOG.md` --------- Co-authored-by: Artur Michałek <52135326+cptartur@users.noreply.github.com> --- CHANGELOG.md | 5 + crates/forge/src/init.rs | 238 ++-------------------- crates/forge/src/lib.rs | 28 ++- crates/forge/src/new.rs | 257 ++++++++++++++++++++++++ crates/forge/tests/e2e/running.rs | 91 +++++++-- docs/src/SUMMARY.md | 3 +- docs/src/appendix/snforge.md | 3 +- docs/src/appendix/snforge/init.md | 4 + docs/src/appendix/snforge/new.md | 23 +++ docs/src/getting-started/first-steps.md | 4 +- 10 files changed, 420 insertions(+), 236 deletions(-) create mode 100644 crates/forge/src/new.rs create mode 100644 docs/src/appendix/snforge/new.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 62fefe6d62..3ad3a2a17b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Requirements validation during `snforge` runtime - `snforge check-requirements` command +- `snforge new` command #### Changed @@ -24,6 +25,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `--fee-token` and `--version` flags are now optional, `strk` and `v3` will be used by default +#### Deprecated + +- `snforge init` command has been deprecated + ## [0.34.0] - 2024-11-26 ### Forge diff --git a/crates/forge/src/init.rs b/crates/forge/src/init.rs index a99ed4f0a6..aedd3b144e 100644 --- a/crates/forge/src/init.rs +++ b/crates/forge/src/init.rs @@ -1,223 +1,25 @@ -use crate::scarb::config::SCARB_MANIFEST_TEMPLATE_CONTENT; -use crate::CAIRO_EDITION; -use anyhow::{anyhow, bail, Context, Ok, Result}; -use include_dir::{include_dir, Dir}; -use indoc::formatdoc; -use scarb_api::ScarbCommand; -use semver::Version; -use shared::consts::FREE_RPC_PROVIDER_URL; -use std::env; -use std::fs::{self, OpenOptions}; -use std::io::Write; -use std::path::{Path, PathBuf}; -use toml_edit::{value, ArrayOfTables, DocumentMut, Item, Table}; +use crate::{new, NewArgs}; +use anyhow::{anyhow, Context, Result}; +use camino::Utf8PathBuf; +use shared::print::print_as_warning; -static TEMPLATE: Dir = include_dir!("starknet_forge_template"); - -const DEFAULT_ASSERT_MACROS: Version = Version::new(0, 1, 0); -const MINIMAL_SCARB_FOR_CORRESPONDING_ASSERT_MACROS: Version = Version::new(2, 8, 0); - -fn create_snfoundry_manifest(path: &PathBuf) -> Result<()> { - fs::write( - path, - formatdoc! {r#" - # Visit https://foundry-rs.github.io/starknet-foundry/appendix/snfoundry-toml.html - # and https://foundry-rs.github.io/starknet-foundry/projects/configuration.html for more information - - # [sncast.default] # Define a profile name - # url = "{default_rpc_url}" # Url of the RPC provider - # accounts-file = "../account-file" # Path to the file with the account data - # account = "mainuser" # Account from `accounts_file` or default account file that will be used for the transactions - # keystore = "~/keystore" # Path to the keystore file - # wait-params = {{ timeout = 300, retry-interval = 10 }} # Wait for submitted transaction parameters - # block-explorer = "StarkScan" # Block explorer service used to display links to transaction details - # show-explorer-links = true # Print links pointing to pages with transaction details in the chosen block explorer - "#, - default_rpc_url = FREE_RPC_PROVIDER_URL, - }, - )?; - - Ok(()) -} - -fn add_template_to_scarb_manifest(path: &PathBuf) -> Result<()> { - if !path.exists() { - bail!("Scarb.toml not found"); - } - - let mut file = OpenOptions::new() - .append(true) - .open(path) - .context("Failed to open Scarb.toml")?; - - file.write_all(SCARB_MANIFEST_TEMPLATE_CONTENT.as_bytes()) - .context("Failed to write to Scarb.toml")?; - Ok(()) -} - -fn overwrite_files_from_scarb_template( - dir_to_overwrite: &str, - base_path: &Path, - project_name: &str, -) -> Result<()> { - let copy_from_dir = TEMPLATE.get_dir(dir_to_overwrite).ok_or_else(|| { - anyhow!( - "Directory {} doesn't exist in the template.", - dir_to_overwrite - ) - })?; - - for file in copy_from_dir.files() { - fs::create_dir_all(base_path.join(Path::new(dir_to_overwrite)))?; - let path = base_path.join(file.path()); - let contents = file.contents(); - let contents = replace_project_name(contents, project_name)?; - - fs::write(path, contents)?; - } - - Ok(()) -} - -fn replace_project_name(contents: &[u8], project_name: &str) -> Result> { - let contents = std::str::from_utf8(contents).context("UTF-8 error")?; - let contents = contents.replace("{{ PROJECT_NAME }}", project_name); - Ok(contents.into_bytes()) -} - -fn update_config(config_path: &Path, scarb: &Version) -> Result<()> { - let config_file = fs::read_to_string(config_path)?; - let mut document = config_file - .parse::() - .context("invalid document")?; - - add_target_to_toml(&mut document); - set_cairo_edition(&mut document, CAIRO_EDITION); - add_test_script(&mut document); - add_assert_macros(&mut document, scarb)?; - - fs::write(config_path, document.to_string())?; - - Ok(()) -} - -fn add_test_script(document: &mut DocumentMut) { - let mut test = Table::new(); - - test.insert("test", value("snforge test")); - document.insert("scripts", Item::Table(test)); -} - -fn add_target_to_toml(document: &mut DocumentMut) { - let mut array_of_tables = ArrayOfTables::new(); - let mut sierra = Table::new(); - let mut contract = Table::new(); - contract.set_implicit(true); - - sierra.insert("sierra", Item::Value(true.into())); - array_of_tables.push(sierra); - contract.insert("starknet-contract", Item::ArrayOfTables(array_of_tables)); - - document.insert("target", Item::Table(contract)); -} - -fn set_cairo_edition(document: &mut DocumentMut, cairo_edition: &str) { - document["package"]["edition"] = value(cairo_edition); -} - -fn add_assert_macros(document: &mut DocumentMut, scarb: &Version) -> Result<()> { - let version = if scarb < &MINIMAL_SCARB_FOR_CORRESPONDING_ASSERT_MACROS { - &DEFAULT_ASSERT_MACROS - } else { - scarb - }; - - document - .get_mut("dev-dependencies") - .and_then(|dep| dep.as_table_mut()) - .context("Failed to get dev-dependencies from Scarb.toml")? - .insert("assert_macros", value(version.to_string())); - - Ok(()) -} - -fn extend_gitignore(path: &Path) -> Result<()> { - let mut file = OpenOptions::new() - .append(true) - .open(path.join(".gitignore"))?; - writeln!(file, ".snfoundry_cache/")?; - - Ok(()) -} - -pub fn run(project_name: &str) -> Result<()> { +pub fn init(project_name: &str) -> Result<()> { let current_dir = std::env::current_dir().context("Failed to get current directory")?; - let project_path = current_dir.join(project_name); - let scarb_manifest_path = project_path.join("Scarb.toml"); - let snfoundry_manifest_path = project_path.join("snfoundry.toml"); - - // if there is no Scarb.toml run `scarb new` - if !scarb_manifest_path.is_file() { - ScarbCommand::new_with_stdio() - .current_dir(current_dir) - .arg("new") - .arg(&project_path) - .env("SCARB_INIT_TEST_RUNNER", "cairo-test") - .run() - .context("Failed to initialize a new project")?; - - ScarbCommand::new_with_stdio() - .current_dir(&project_path) - .manifest_path(scarb_manifest_path.clone()) - .offline() - .arg("remove") - .arg("--dev") - .arg("cairo_test") - .run() - .context("Failed to remove cairo_test")?; - } - - add_template_to_scarb_manifest(&scarb_manifest_path)?; - - if !snfoundry_manifest_path.is_file() { - create_snfoundry_manifest(&snfoundry_manifest_path)?; + let project_path = Utf8PathBuf::from_path_buf(current_dir) + .expect("Failed to create Utf8PathBuf for the current directory") + .join(project_name); + + // To prevent printing this warning when running scarb init/new with an older version of Scarb + if !project_path.join("Scarb.toml").exists() { + print_as_warning(&anyhow!( + "Command `snforge init` is deprecated and will be removed in the future. Please use `snforge new` instead." + )); } - let version = env!("CARGO_PKG_VERSION"); - let cairo_version = ScarbCommand::version().run()?.cairo; - - if env::var("DEV_DISABLE_SNFORGE_STD_DEPENDENCY").is_err() { - ScarbCommand::new_with_stdio() - .current_dir(&project_path) - .manifest_path(scarb_manifest_path.clone()) - .offline() - .arg("add") - .arg("--dev") - .arg(format!("snforge_std@{version}")) - .run() - .context("Failed to add snforge_std")?; - } - - ScarbCommand::new_with_stdio() - .current_dir(&project_path) - .manifest_path(scarb_manifest_path.clone()) - .offline() - .arg("add") - .arg(format!("starknet@{cairo_version}")) - .run() - .context("Failed to add starknet")?; - - update_config(&project_path.join("Scarb.toml"), &cairo_version)?; - extend_gitignore(&project_path)?; - overwrite_files_from_scarb_template("src", &project_path, project_name)?; - overwrite_files_from_scarb_template("tests", &project_path, project_name)?; - - // Fetch to create lock file. - ScarbCommand::new_with_stdio() - .manifest_path(scarb_manifest_path) - .arg("fetch") - .run() - .context("Failed to fetch created project")?; - - Ok(()) + new::new(NewArgs { + path: project_path, + name: Some(project_name.to_string()), + no_vcs: false, + overwrite: true, + }) } diff --git a/crates/forge/src/lib.rs b/crates/forge/src/lib.rs index 54adad9dab..151a5335b4 100644 --- a/crates/forge/src/lib.rs +++ b/crates/forge/src/lib.rs @@ -1,5 +1,6 @@ use crate::compatibility_check::{create_version_parser, Requirement, RequirementsChecker}; use anyhow::Result; +use camino::Utf8PathBuf; use clap::{Parser, Subcommand, ValueEnum}; use forge_runner::CACHE_DIR; use run_tests::workspace::run_for_workspace; @@ -14,6 +15,7 @@ pub mod block_number_map; mod combine_configs; mod compatibility_check; mod init; +mod new; pub mod pretty_printing; pub mod run_tests; pub mod scarb; @@ -76,6 +78,11 @@ enum ForgeSubcommand { /// Name of a new project name: String, }, + /// Create a new Forge project at + New { + #[command(flatten)] + args: NewArgs, + }, /// Clean Forge cache directory CleanCache {}, /// Check if all `snforge` requirements are installed @@ -160,6 +167,21 @@ pub struct TestArgs { additional_args: Vec, } +#[derive(Parser, Debug)] +pub struct NewArgs { + /// Path to a location where the new project will be created + path: Utf8PathBuf, + /// Name of a new project, defaults to the directory name + #[arg(short, long)] + name: Option, + /// Do not initialize a new Git repository + #[arg(long)] + no_vcs: bool, + /// Try to create the project even if the specified directory at is not empty, which can result in overwriting existing files + #[arg(long)] + overwrite: bool, +} + pub enum ExitStatus { Success, Failure, @@ -172,7 +194,11 @@ pub fn main_execution() -> Result { match cli.subcommand { ForgeSubcommand::Init { name } => { - init::run(name.as_str())?; + init::init(name.as_str())?; + Ok(ExitStatus::Success) + } + ForgeSubcommand::New { args } => { + new::new(args)?; Ok(ExitStatus::Success) } ForgeSubcommand::CleanCache {} => { diff --git a/crates/forge/src/new.rs b/crates/forge/src/new.rs new file mode 100644 index 0000000000..83f3c33f64 --- /dev/null +++ b/crates/forge/src/new.rs @@ -0,0 +1,257 @@ +use crate::scarb::config::SCARB_MANIFEST_TEMPLATE_CONTENT; +use crate::{NewArgs, CAIRO_EDITION}; +use anyhow::{anyhow, bail, ensure, Context, Ok, Result}; +use camino::Utf8PathBuf; +use include_dir::{include_dir, Dir}; +use indoc::formatdoc; +use scarb_api::ScarbCommand; +use semver::Version; +use shared::consts::FREE_RPC_PROVIDER_URL; +use std::env; +use std::fs::{self, OpenOptions}; +use std::io::Write; +use std::path::{Path, PathBuf}; +use toml_edit::{value, ArrayOfTables, DocumentMut, Item, Table}; + +static TEMPLATE: Dir = include_dir!("starknet_forge_template"); + +const DEFAULT_ASSERT_MACROS: Version = Version::new(0, 1, 0); +const MINIMAL_SCARB_FOR_CORRESPONDING_ASSERT_MACROS: Version = Version::new(2, 8, 0); + +fn create_snfoundry_manifest(path: &PathBuf) -> Result<()> { + fs::write( + path, + formatdoc! {r#" + # Visit https://foundry-rs.github.io/starknet-foundry/appendix/snfoundry-toml.html + # and https://foundry-rs.github.io/starknet-foundry/projects/configuration.html for more information + + # [sncast.default] # Define a profile name + # url = "{default_rpc_url}" # Url of the RPC provider + # accounts-file = "../account-file" # Path to the file with the account data + # account = "mainuser" # Account from `accounts_file` or default account file that will be used for the transactions + # keystore = "~/keystore" # Path to the keystore file + # wait-params = {{ timeout = 300, retry-interval = 10 }} # Wait for submitted transaction parameters + # block-explorer = "StarkScan" # Block explorer service used to display links to transaction details + # show-explorer-links = true # Print links pointing to pages with transaction details in the chosen block explorer + "#, + default_rpc_url = FREE_RPC_PROVIDER_URL, + }, + )?; + + Ok(()) +} + +fn add_template_to_scarb_manifest(path: &PathBuf) -> Result<()> { + if !path.exists() { + bail!("Scarb.toml not found"); + } + + let mut file = OpenOptions::new() + .append(true) + .open(path) + .context("Failed to open Scarb.toml")?; + + file.write_all(SCARB_MANIFEST_TEMPLATE_CONTENT.as_bytes()) + .context("Failed to write to Scarb.toml")?; + Ok(()) +} + +fn overwrite_files_from_scarb_template( + dir_to_overwrite: &str, + base_path: &Path, + project_name: &str, +) -> Result<()> { + let copy_from_dir = TEMPLATE.get_dir(dir_to_overwrite).ok_or_else(|| { + anyhow!( + "Directory {} doesn't exist in the template.", + dir_to_overwrite + ) + })?; + + for file in copy_from_dir.files() { + fs::create_dir_all(base_path.join(Path::new(dir_to_overwrite)))?; + let path = base_path.join(file.path()); + let contents = file.contents(); + let contents = replace_project_name(contents, project_name)?; + + fs::write(path, contents)?; + } + + Ok(()) +} + +fn replace_project_name(contents: &[u8], project_name: &str) -> Result> { + let contents = std::str::from_utf8(contents).context("UTF-8 error")?; + let contents = contents.replace("{{ PROJECT_NAME }}", project_name); + Ok(contents.into_bytes()) +} + +fn update_config(config_path: &Path, scarb: &Version) -> Result<()> { + let config_file = fs::read_to_string(config_path)?; + let mut document = config_file + .parse::() + .context("invalid document")?; + + add_target_to_toml(&mut document); + set_cairo_edition(&mut document, CAIRO_EDITION); + add_test_script(&mut document); + add_assert_macros(&mut document, scarb)?; + + fs::write(config_path, document.to_string())?; + + Ok(()) +} + +fn add_test_script(document: &mut DocumentMut) { + let mut test = Table::new(); + + test.insert("test", value("snforge test")); + document.insert("scripts", Item::Table(test)); +} + +fn add_target_to_toml(document: &mut DocumentMut) { + let mut array_of_tables = ArrayOfTables::new(); + let mut sierra = Table::new(); + let mut contract = Table::new(); + contract.set_implicit(true); + + sierra.insert("sierra", Item::Value(true.into())); + array_of_tables.push(sierra); + contract.insert("starknet-contract", Item::ArrayOfTables(array_of_tables)); + + document.insert("target", Item::Table(contract)); +} + +fn set_cairo_edition(document: &mut DocumentMut, cairo_edition: &str) { + document["package"]["edition"] = value(cairo_edition); +} + +fn add_assert_macros(document: &mut DocumentMut, scarb: &Version) -> Result<()> { + let version = if scarb < &MINIMAL_SCARB_FOR_CORRESPONDING_ASSERT_MACROS { + &DEFAULT_ASSERT_MACROS + } else { + scarb + }; + + document + .get_mut("dev-dependencies") + .and_then(|dep| dep.as_table_mut()) + .context("Failed to get dev-dependencies from Scarb.toml")? + .insert("assert_macros", value(version.to_string())); + + Ok(()) +} + +fn extend_gitignore(path: &Path) -> Result<()> { + if path.join(".gitignore").exists() { + let mut file = OpenOptions::new() + .append(true) + .open(path.join(".gitignore"))?; + writeln!(file, ".snfoundry_cache/")?; + } + Ok(()) +} + +pub fn new( + NewArgs { + path, + name, + no_vcs, + overwrite, + }: NewArgs, +) -> Result<()> { + if !overwrite { + ensure!( + !path.exists() || path.read_dir().is_ok_and(|mut i| i.next().is_none()), + format!("The provided path `{path}` points to a non-empty directory. If you wish to create a project in this directory, use the `--overwrite` flag") + ); + } + let name = infer_name(name, &path)?; + + fs::create_dir_all(&path)?; + let project_path = path.canonicalize()?; + let scarb_manifest_path = project_path.join("Scarb.toml"); + let snfoundry_manifest_path = project_path.join("snfoundry.toml"); + + // if there is no Scarb.toml run `scarb init` + if !scarb_manifest_path.is_file() { + let mut cmd = ScarbCommand::new_with_stdio(); + cmd.current_dir(&project_path) + .args(["init", "--name", &name]); + + if no_vcs { + cmd.arg("--no-vcs"); + } + + cmd.env("SCARB_INIT_TEST_RUNNER", "cairo-test") + .run() + .context("Failed to initialize a new project")?; + + ScarbCommand::new_with_stdio() + .current_dir(&project_path) + .manifest_path(scarb_manifest_path.clone()) + .offline() + .arg("remove") + .arg("--dev") + .arg("cairo_test") + .run() + .context("Failed to remove cairo_test dependency")?; + } + + add_template_to_scarb_manifest(&scarb_manifest_path)?; + + if !snfoundry_manifest_path.is_file() { + create_snfoundry_manifest(&snfoundry_manifest_path)?; + } + + let version = env!("CARGO_PKG_VERSION"); + let cairo_version = ScarbCommand::version().run()?.cairo; + + if env::var("DEV_DISABLE_SNFORGE_STD_DEPENDENCY").is_err() { + ScarbCommand::new_with_stdio() + .current_dir(&project_path) + .manifest_path(scarb_manifest_path.clone()) + .offline() + .arg("add") + .arg("--dev") + .arg(format!("snforge_std@{version}")) + .run() + .context("Failed to add snforge_std dependency")?; + } + + ScarbCommand::new_with_stdio() + .current_dir(&project_path) + .manifest_path(scarb_manifest_path.clone()) + .offline() + .arg("add") + .arg(format!("starknet@{cairo_version}")) + .run() + .context("Failed to add starknet dependency")?; + + update_config(&project_path.join("Scarb.toml"), &cairo_version)?; + extend_gitignore(&project_path)?; + overwrite_files_from_scarb_template("src", &project_path, &name)?; + overwrite_files_from_scarb_template("tests", &project_path, &name)?; + + // Fetch to create lock file. + ScarbCommand::new_with_stdio() + .manifest_path(scarb_manifest_path) + .arg("fetch") + .run() + .context("Failed to fetch created project")?; + + Ok(()) +} + +fn infer_name(name: Option, path: &Utf8PathBuf) -> Result { + let name = if let Some(name) = name { + name + } else { + let Some(file_name) = path.file_name() else { + bail!("Cannot infer package name from path: {path}. Please: use the flag `--name`"); + }; + file_name.to_string() + }; + + Ok(name) +} diff --git a/crates/forge/tests/e2e/running.rs b/crates/forge/tests/e2e/running.rs index 3fc93d6ff5..2b743e3f6d 100644 --- a/crates/forge/tests/e2e/running.rs +++ b/crates/forge/tests/e2e/running.rs @@ -1,7 +1,7 @@ use super::common::runner::{ get_current_branch, get_remote_url, runner, setup_package, snforge_test_bin_path, test_runner, }; -use assert_fs::fixture::{FileWriteStr, PathChild, PathCopy}; +use assert_fs::fixture::{FileTouch, FileWriteStr, PathChild, PathCopy}; use assert_fs::TempDir; use camino::Utf8PathBuf; use forge::scarb::config::SCARB_MANIFEST_TEMPLATE_CONTENT; @@ -11,6 +11,7 @@ use shared::test_utils::output_assert::assert_stdout_contains; use snapbox::assert_matches; use snapbox::cmd::Command as SnapboxCommand; use std::ffi::OsString; +use std::path::PathBuf; use std::{env, fs, iter, path::Path, str::FromStr}; use test_utils::{get_local_snforge_std_absolute_path, tempdir_with_tool_versions}; use toml_edit::{value, DocumentMut, Formatted, InlineTable, Item, Value}; @@ -690,13 +691,76 @@ fn with_exit_first_flag() { fn init_new_project() { let temp = tempdir_with_tool_versions().unwrap(); - runner(&temp) + let output = runner(&temp) .args(["init", "test_name"]) .env("DEV_DISABLE_SNFORGE_STD_DEPENDENCY", "true") .assert() .success(); - validate_init(&temp, false); + assert_stdout_contains( + output, + indoc!( + r" + [WARNING] Command `snforge init` is deprecated and will be removed in the future. Please use `snforge new` instead. + " + ), + ); + + validate_init(&temp.join("test_name"), false); +} + +#[test] +fn create_new_project_dir_not_exist() { + let temp = tempdir_with_tool_versions().unwrap(); + let project_path = temp.join("new").join("project"); + + runner(&temp) + .args(["new", "--name", "test_name"]) + .arg(&project_path) + .env("DEV_DISABLE_SNFORGE_STD_DEPENDENCY", "true") + .assert() + .success(); + + validate_init(&project_path, false); +} + +#[test] +fn create_new_project_dir_not_empty() { + let temp = tempdir_with_tool_versions().unwrap(); + temp.child("empty.txt").touch().unwrap(); + + let output = runner(&temp) + .args(["new", "--name", "test_name"]) + .arg(temp.path()) + .assert() + .code(2); + + assert_stdout_contains( + output, + indoc!( + r" + [ERROR] The provided path [..] points to a non-empty directory. If you wish to create a project in this directory, use the `--overwrite` flag + " + ), + ); +} + +#[test] +fn create_new_project_dir_exists_and_empty() { + let temp = tempdir_with_tool_versions().unwrap(); + let project_path = temp.join("new").join("project"); + + fs::create_dir_all(&project_path).unwrap(); + assert!(project_path.exists()); + + runner(&temp) + .args(["new", "--name", "test_name"]) + .arg(&project_path) + .env("DEV_DISABLE_SNFORGE_STD_DEPENDENCY", "true") + .assert() + .success(); + + validate_init(&project_path, false); } #[test] @@ -714,7 +778,7 @@ fn init_new_project_from_scarb() { .assert() .success(); - validate_init(&temp, true); + validate_init(&temp.join("test_name"), true); } pub fn append_to_path_var(path: &Path) -> OsString { @@ -724,8 +788,8 @@ pub fn append_to_path_var(path: &Path) -> OsString { env::join_paths(script_path.chain(other_paths)).unwrap() } -fn validate_init(temp: &TempDir, validate_snforge_std: bool) { - let manifest_path = temp.join("test_name/Scarb.toml"); +fn validate_init(project_path: &PathBuf, validate_snforge_std: bool) { + let manifest_path = project_path.join("Scarb.toml"); let scarb_toml = fs::read_to_string(manifest_path.clone()).unwrap(); let snforge_std_assert = if validate_snforge_std { @@ -784,8 +848,8 @@ fn validate_init(temp: &TempDir, validate_snforge_std: bool) { std::fs::write(manifest_path, scarb_toml.to_string()).unwrap(); - let output = test_runner(temp) - .current_dir(temp.child(Path::new("test_name"))) + let output = test_runner(&TempDir::new().unwrap()) + .current_dir(project_path) .assert() .success(); @@ -812,14 +876,15 @@ fn test_init_project_with_custom_snforge_dependency_git() { let temp = tempdir_with_tool_versions().unwrap(); runner(&temp) - .args(["init", "test_name"]) + .args(["new", "test_name"]) .env("DEV_DISABLE_SNFORGE_STD_DEPENDENCY", "true") .assert() .success(); - let manifest_path = temp.child("test_name/Scarb.toml"); + let project_path = temp.join("test_name"); + let manifest_path = project_path.join("Scarb.toml"); - let scarb_toml = std::fs::read_to_string(manifest_path.path()).unwrap(); + let scarb_toml = std::fs::read_to_string(&manifest_path).unwrap(); let mut scarb_toml = DocumentMut::from_str(&scarb_toml).unwrap(); let dependencies = scarb_toml @@ -838,10 +903,10 @@ fn test_init_project_with_custom_snforge_dependency_git() { dependencies.remove("snforge_std"); dependencies.insert("snforge_std", Item::Value(Value::InlineTable(snforge_std))); - std::fs::write(manifest_path.path(), scarb_toml.to_string()).unwrap(); + std::fs::write(&manifest_path, scarb_toml.to_string()).unwrap(); let output = test_runner(&temp) - .current_dir(temp.child(Path::new("test_name"))) + .current_dir(&project_path) .assert() .success(); diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index b8a51cf774..f91ced61be 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -70,8 +70,9 @@ * [`snforge` Commands](appendix/snforge.md) * [test](appendix/snforge/test.md) * [init](appendix/snforge/init.md) + * [new](appendix/snforge/new.md) * [clean-cache](appendix/snforge/clean-cache.md) - * [check-requirements](appendix/snforge/check-requirements) + * [check-requirements](appendix/snforge/check-requirements.md) * [Cheatcodes Reference](appendix/cheatcodes.md) * [Cheating Globally](appendix/cheatcodes/global.md) * [CheatSpan](appendix/cheatcodes/cheat_span.md) diff --git a/docs/src/appendix/snforge.md b/docs/src/appendix/snforge.md index 81d4146a73..b262a11453 100644 --- a/docs/src/appendix/snforge.md +++ b/docs/src/appendix/snforge.md @@ -2,8 +2,9 @@ * [`snforge test`](./snforge/test.md) * [`snforge init`](./snforge/init.md) +* [`snforge new`](./snforge/new.md) * [`snforge clean-cache`](./snforge/clean-cache.md) -* [`snforge check-requirements`](./snforge/check-requirements) +* [`snforge check-requirements`](./snforge/check-requirements.md) You can check your version of `snforge` via `snforge --version`. To display help run `snforge --help`. diff --git a/docs/src/appendix/snforge/init.md b/docs/src/appendix/snforge/init.md index fab3e57a96..8fd1728d30 100644 --- a/docs/src/appendix/snforge/init.md +++ b/docs/src/appendix/snforge/init.md @@ -9,3 +9,7 @@ Name of a new project. ## `-h`, `--help` Print help. + +> ⚠️ **Warning** +> +> The `snforge init` command is deprecated. Please use the [`snforge new`](./new.md) command instead. diff --git a/docs/src/appendix/snforge/new.md b/docs/src/appendix/snforge/new.md new file mode 100644 index 0000000000..5e7b9a9c15 --- /dev/null +++ b/docs/src/appendix/snforge/new.md @@ -0,0 +1,23 @@ +# `snforge new` + +Create a new StarkNet Foundry project at the provided path that should either be empty or not exist. + +## `` + +Path to a location where the new project will be created. + +## `-n`, `--name` + +Name of a package to create, defaults to the directory name. + +## `--no-vcs` + +Do not initialize a new Git repository. + +## `--overwrite` + +Try to create the project even if the specified directory is not empty, which can result in overwriting existing files + +## `-h`, `--help` + +Print help. diff --git a/docs/src/getting-started/first-steps.md b/docs/src/getting-started/first-steps.md index 8aa0231c48..342b9114c9 100644 --- a/docs/src/getting-started/first-steps.md +++ b/docs/src/getting-started/first-steps.md @@ -3,10 +3,10 @@ In this section we provide an overview of Starknet Foundry `snforge` command line tool. We demonstrate how to create a new project, compile, and test it. -To start a new project with Starknet Foundry, run `snforge init` +To start a new project with Starknet Foundry, run `snforge new` ```shell -$ snforge init hello_starknet +$ snforge new hello_starknet ``` Let's check out the project structure