From de4614d7fb417c31ae076ef751aa26f8da8507d0 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Thu, 25 Jan 2024 12:21:37 +0100 Subject: [PATCH 01/17] :sparkles: Add a working ecs example on project init --- Cargo.lock | 2 + cli/Cargo.toml | 4 +- cli/src/lib.rs | 288 ++++++++++++++++++++++++++++++++++-- cli/src/rust_template.rs | 176 +++++++++++++++++++++- crates/bolt-lang/Cargo.toml | 5 +- 5 files changed, 455 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7dfb82e..41d4b21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -950,6 +950,7 @@ dependencies = [ "anyhow", "clap 4.4.11", "heck 0.4.1", + "syn 2.0.38", ] [[package]] @@ -968,6 +969,7 @@ version = "0.1.0" name = "bolt-lang" version = "0.0.1" dependencies = [ + "ahash 0.8.6", "anchor-lang 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", "bolt-attribute-bolt-account", "bolt-attribute-bolt-component", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a3307cc..79f09bf 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -16,7 +16,9 @@ path = "src/bin/main.rs" dev = [] [dependencies] -anchor-cli = { git = "https://github.com/coral-xyz/anchor.git", rev = "v0.29.0" } +anchor-cli = { git = "https://github.com/coral-xyz/anchor.git"} +anchor-client = { git = "https://github.com/coral-xyz/anchor.git" } anyhow = "1.0.32" heck = "0.4.0" clap = { version = "4.2.4", features = ["derive"] } +syn = { version = "1.0.60", features = ["full", "extra-traits"] } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index e360124..8e311df 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -1,21 +1,34 @@ mod rust_template; -use anchor_cli::config::{Config, ConfigOverride, WithPath}; +use std::collections::BTreeMap; +use anchor_cli::config::{Config, ConfigOverride, ProgramDeployment, TestValidator, Validator, WithPath}; use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; -use std::fs; +use std::fs::{self, File}; +use std::io::Write; +use std::process::Stdio; +use heck::{ToKebabCase, ToSnakeCase}; +use anchor_client::Cluster; +use crate::rust_template::{create_component, create_system}; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const ANCHOR_VERSION: &str = anchor_cli::VERSION; #[derive(Debug, Subcommand)] pub enum BoltCommand { - // Include all existing commands from anchor_cli::Command - #[clap(flatten)] - Anchor(anchor_cli::Command), #[clap(about = "Create a new component")] Component(ComponentCommand), #[clap(about = "Create a new system")] System(SystemCommand), + // Include all existing commands from anchor_cli::Command + #[clap(flatten)] + Anchor(anchor_cli::Command), +} + +#[derive(Debug, Parser)] +pub struct InitCommand { + #[clap(short, long, help = "Workspace name")] + pub workspace_name: String, } #[derive(Debug, Parser)] @@ -41,18 +54,271 @@ pub struct Opts { pub fn entry(opts: Opts) -> Result<()> { match opts.command { BoltCommand::Anchor(command) => { - // Delegate to the existing anchor_cli handler - let ops = anchor_cli::Opts { - cfg_override: opts.cfg_override, - command, - }; - anchor_cli::entry(ops) + if let anchor_cli::Command::Init { name, javascript, solidity, no_git, jest, template, force } = command { + init(&opts.cfg_override, name, javascript, solidity, no_git, jest, template, force) + } + else { + // Delegate to the existing anchor_cli handler + let opts = anchor_cli::Opts { + cfg_override: opts.cfg_override, + command, + }; + anchor_cli::entry(opts) + } } BoltCommand::Component(command) => new_component(&opts.cfg_override, command.name), BoltCommand::System(command) => new_system(&opts.cfg_override, command.name), } } +// Bolt Init + +fn init( + cfg_override: &ConfigOverride, + name: String, + javascript: bool, + solidity: bool, + no_git: bool, + jest: bool, + template: anchor_cli::rust_template::ProgramTemplate, + force: bool, +) -> Result<()> { + if !force && Config::discover(cfg_override)?.is_some() { + return Err(anyhow!("Workspace already initialized")); + } + + // We need to format different cases for the dir and the name + let rust_name = name.to_snake_case(); + let project_name = if name == rust_name { + rust_name.clone() + } else { + name.to_kebab_case() + }; + + // Additional keywords that have not been added to the `syn` crate as reserved words + // https://github.com/dtolnay/syn/pull/1098 + let extra_keywords = ["async", "await", "try"]; + let component_name = "position"; + let system_name = "movement"; + // Anchor converts to snake case before writing the program name + if syn::parse_str::(&rust_name).is_err() + || extra_keywords.contains(&rust_name.as_str()) + { + return Err(anyhow!( + "Anchor workspace name must be a valid Rust identifier. It may not be a Rust reserved word, start with a digit, or include certain disallowed characters. See https://doc.rust-lang.org/reference/identifiers.html for more detail.", + )); + } + + if force { + fs::create_dir_all(&project_name)?; + } else { + fs::create_dir(&project_name)?; + } + std::env::set_current_dir(&project_name)?; + fs::create_dir("app")?; + + let mut cfg = Config::default(); + if jest { + cfg.scripts.insert( + "test".to_owned(), + if javascript { + "yarn run jest" + } else { + "yarn run jest --preset ts-jest" + } + .to_owned(), + ); + } else { + cfg.scripts.insert( + "test".to_owned(), + if javascript { + "yarn run mocha -t 1000000 tests/" + } else { + "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" + } + .to_owned(), + ); + } + + let mut localnet = BTreeMap::new(); + let program_id = anchor_cli::rust_template::get_or_create_program_id(&rust_name); + localnet.insert( + rust_name, + ProgramDeployment { + address: program_id, + path: None, + idl: None, + }, + ); + if !solidity { + let component_id = anchor_cli::rust_template::get_or_create_program_id(component_name); + let system_id = anchor_cli::rust_template::get_or_create_program_id(system_name); + localnet.insert( + component_name.to_owned(), + ProgramDeployment { + address: component_id, + path: None, + idl: None, + }, + ); + localnet.insert( + system_name.to_owned(), + ProgramDeployment { + address: system_id, + path: None, + idl: None, + }, + ); + cfg.workspace.members.push("programs/*".to_owned()); + cfg.workspace.members.push("programs-ecs/components/*".to_owned()); + cfg.workspace.members.push("programs-ecs/systems/*".to_owned()); + } + + // Setup the test validator to clone Bolt programs from devnet + let mut validator = Validator::default(); + validator.url = Some("https://rpc.magicblock.app/devnet/".to_owned()); + validator.rpc_port = 8899; + validator.ledger = ".bolt/test-ledger".to_owned(); + validator.clone = Some(vec![ + // World program + anchor_cli::config::CloneEntry{ + address: "WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n".to_owned(), + }, + // World executable data + anchor_cli::config::CloneEntry{ + address: "CrsqUXPpJYpVAAx5qMKU6K8RT1TzT81T8BL6JndWSeo3".to_owned(), + }, + // Registry + anchor_cli::config::CloneEntry{ + address: "EHLkWwAT9oebVv9ht3mtqrvHhRVMKrt54tF3MfHTey2K".to_owned(), + }, + ]); + + let mut test_validator = TestValidator::default(); + test_validator.startup_wait = 5000; + test_validator.shutdown_wait = 2000; + test_validator.validator = Some(validator); + + cfg.test_validator = Some(test_validator); + cfg.programs.insert(Cluster::Localnet, localnet); + let toml = cfg.to_string(); + fs::write("Anchor.toml", toml)?; + + // Initialize .gitignore file + fs::write(".gitignore", rust_template::git_ignore())?; + + // Initialize .prettierignore file + fs::write(".prettierignore", anchor_cli::rust_template::prettier_ignore())?; + + // Remove the default programs if `--force` is passed + if force { + fs::remove_dir_all( + std::env::current_dir()? + .join(if solidity { "solidity" } else { "programs" }) + .join(&project_name), + )?; + fs::remove_dir_all( + std::env::current_dir()? + .join("programs-ecs" ) + .join(&project_name), + )?; + } + + // Build the program. + if solidity { + anchor_cli::solidity_template::create_program(&project_name)?; + } else { + create_component(component_name)?; + create_system(system_name)?; + anchor_cli::rust_template::create_program(&project_name, template)?; + } + + // Build the test suite. + fs::create_dir("tests")?; + // Build the migrations directory. + fs::create_dir("migrations")?; + + if javascript { + // Build javascript config + let mut package_json = File::create("package.json")?; + package_json.write_all(rust_template::package_json(jest).as_bytes())?; + + if jest { + let mut test = File::create(format!("tests/{}.test.js", &project_name))?; + if solidity { + test.write_all(anchor_cli::solidity_template::jest(&project_name).as_bytes())?; + } else { + test.write_all(anchor_cli::rust_template::jest(&project_name).as_bytes())?; + } + } else { + let mut test = File::create(format!("tests/{}.js", &project_name))?; + if solidity { + test.write_all(anchor_cli::solidity_template::mocha(&project_name).as_bytes())?; + } else { + test.write_all(anchor_cli::rust_template::mocha(&project_name).as_bytes())?; + } + } + + let mut deploy = File::create("migrations/deploy.js")?; + + deploy.write_all(anchor_cli::rust_template::deploy_script().as_bytes())?; + } else { + // Build typescript config + let mut ts_config = File::create("tsconfig.json")?; + ts_config.write_all(anchor_cli::rust_template::ts_config(jest).as_bytes())?; + + let mut ts_package_json = File::create("package.json")?; + ts_package_json.write_all(rust_template::ts_package_json(jest).as_bytes())?; + + let mut deploy = File::create("migrations/deploy.ts")?; + deploy.write_all(anchor_cli::rust_template::ts_deploy_script().as_bytes())?; + + let mut mocha = File::create(format!("tests/{}.ts", &project_name))?; + if solidity { + mocha.write_all(anchor_cli::solidity_template::ts_mocha(&project_name).as_bytes())?; + } else { + mocha.write_all(rust_template::ts_mocha(&project_name).as_bytes())?; + } + } + + let yarn_result = install_node_modules("yarn")?; + if !yarn_result.status.success() { + println!("Failed yarn install will attempt to npm install"); + install_node_modules("npm")?; + } + + if !no_git { + let git_result = std::process::Command::new("git") + .arg("init") + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .output() + .map_err(|e| anyhow::format_err!("git init failed: {}", e.to_string()))?; + if !git_result.status.success() { + eprintln!("Failed to automatically initialize a new git repository"); + } + } + + println!("{project_name} initialized"); + + Ok(()) +} + +// Install node modules +fn install_node_modules(cmd: &str) -> Result { + let mut command = std::process::Command::new(if cfg!(target_os = "windows") { "cmd" } else { cmd }); + if cfg!(target_os = "windows") { + command.arg(format!("/C {} install", cmd)); + } else { + command.arg("install"); + } + command + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .output() + .map_err(|e| anyhow::format_err!("{} install failed: {}", cmd, e.to_string())) +} + // Create a new component from the template fn new_component(cfg_override: &ConfigOverride, name: String) -> Result<()> { with_workspace(cfg_override, |cfg| { diff --git a/cli/src/rust_template.rs b/cli/src/rust_template.rs index 9e00812..d4d89e9 100644 --- a/cli/src/rust_template.rs +++ b/cli/src/rust_template.rs @@ -1,4 +1,5 @@ use crate::VERSION; +use crate::ANCHOR_VERSION; use anchor_cli::Files; use anyhow::Result; use heck::{ToKebabCase, ToSnakeCase, ToUpperCamelCase}; @@ -6,7 +7,7 @@ use std::path::{Path, PathBuf}; /// Create a component from the given name. pub fn create_component(name: &str) -> Result<()> { - let program_path = Path::new("programs").join(name); + let program_path = Path::new("programs-ecs/components").join(name); let common_files = vec![ ( PathBuf::from("Cargo.toml".to_string()), @@ -22,7 +23,7 @@ pub fn create_component(name: &str) -> Result<()> { /// Create a system from the given name. pub(crate) fn create_system(name: &str) -> Result<()> { - let program_path = Path::new("programs").join(name); + let program_path = Path::new("programs-ecs/systems").join(name); let common_files = vec![ ( PathBuf::from("Cargo.toml".to_string()), @@ -36,7 +37,7 @@ pub(crate) fn create_system(name: &str) -> Result<()> { anchor_cli::create_files(&[common_files, template_files].concat()) } -/// Create a program with a single `lib.rs` file. +/// Create a component which holds position data. fn create_component_template_simple(name: &str, program_path: &Path) -> Files { vec![( program_path.join("src").join("lib.rs"), @@ -70,7 +71,7 @@ pub struct {} {{ )] } -/// Create a program with a single `lib.rs` file. +/// Create a system which operates on a Position component. fn create_system_template_simple(name: &str, program_path: &Path) -> Files { vec![( program_path.join("src").join("lib.rs"), @@ -85,10 +86,8 @@ pub mod {} {{ use super::*; pub fn execute(ctx: Context, args: Vec) -> Result {{ - let mut position = Position::from_account_info(&ctx.accounts.position)?; position.x += 1; - Ok(position) }} }} @@ -118,7 +117,9 @@ pub struct Position {{ const fn workspace_manifest() -> &'static str { r#"[workspace] members = [ - "programs/*" + "programs/*", + "programs-ecs/components/*", + "programs-ecs/systems/*" ] resolver = "2" @@ -133,6 +134,155 @@ codegen-units = 1 "# } +pub fn package_json(jest: bool) -> String { + if jest { + format!( + r#"{{ + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{VERSION}" + }}, + "devDependencies": {{ + "jest": "^29.0.3", + "prettier": "^2.6.2" + }} + }} + "# + ) + } else { + format!( + r#"{{ + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{VERSION}" + }}, + "devDependencies": {{ + "chai": "^4.3.4", + "mocha": "^9.0.3", + "prettier": "^2.6.2" + }} +}} +"# + ) + } +} + +pub fn ts_package_json(jest: bool) -> String { + if jest { + format!( + r#"{{ + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{ANCHOR_VERSION}" + }}, + "devDependencies": {{ + "@types/bn.js": "^5.1.0", + "@types/jest": "^29.0.3", + "jest": "^29.0.3", + "prettier": "^2.6.2", + "ts-jest": "^29.0.2", + "typescript": "^4.3.5", + "@metaplex-foundation/beet": "^0.7.1", + "@metaplex-foundation/beet-solana": "^0.4.0", + "bolt-sdk": "latest" + }} + }} + "# + ) + } else { + format!( + r#"{{ + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{ANCHOR_VERSION}" + }}, + "devDependencies": {{ + "chai": "^4.3.4", + "mocha": "^9.0.3", + "ts-mocha": "^10.0.0", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "typescript": "^4.3.5", + "prettier": "^2.6.2", + "@metaplex-foundation/beet": "^0.7.1", + "@metaplex-foundation/beet-solana": "^0.4.0", + "bolt-sdk": "latest" + }} +}} +"# + ) + } +} + +pub fn ts_mocha(name: &str) -> String { + format!( + r#"import * as anchor from "@coral-xyz/anchor"; +import {{ Program }} from "@coral-xyz/anchor"; +import {{ PublicKey }} from "@solana/web3.js"; +import {{ {} }} from "../target/types/{}"; +import {{ + createInitializeNewWorldInstruction, + FindWorldPda, + FindWorldRegistryPda, + FindEntityPda, + Registry, + World, + createAddEntityInstruction, + createInitializeComponentInstruction, + FindComponentPda, createApplyInstruction +}} from "bolt-sdk" + +describe("{}", () => {{ + // Configure the client to use the local cluster. + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + + // Constants used to test the program. + const registryPda = FindWorldRegistryPda(); + let worldId: anchor.BN; + let worldPda: PublicKey; + let entityPda: PublicKey; + + const program = anchor.workspace.{} as Program<{}>; + + it("InitializeNewWorld", async () => {{ + const registry = await Registry.fromAccountAddress(provider.connection, registryPda); + worldId = new BN(registry.worlds); + worldPda = FindWorldPda(new BN(worldId)) + const initializeWorldIx = createInitializeNewWorldInstruction( + {{ + world: worldPda, + registry: registryPda, + payer: provider.wallet.publicKey, + }}); + + const tx = new anchor.web3.Transaction().add(initializeWorldIx); + const txSign = await provider.sendAndConfirm(tx); + console.log(`Initialized a new world (ID=${{worldId}}). Initialization signature: ${{txSign}}`); + }}); +}}); +"#, + name.to_upper_camel_case(), + name.to_snake_case(), + name, + name.to_upper_camel_case(), + name.to_upper_camel_case(), + ) +} + fn cargo_toml(name: &str) -> String { format!( r#"[package] @@ -168,3 +318,15 @@ fn xargo_toml() -> &'static str { features = [] "# } +pub fn git_ignore() -> &'static str { + r#" +.anchor +.bolt +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn +"# +} diff --git a/crates/bolt-lang/Cargo.toml b/crates/bolt-lang/Cargo.toml index 92c8dfb..b531dd3 100644 --- a/crates/bolt-lang/Cargo.toml +++ b/crates/bolt-lang/Cargo.toml @@ -20,4 +20,7 @@ bolt-system = { path = "../../programs/bolt-system", features = ["cpi"], version # Other dependencies serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" \ No newline at end of file +serde_json = "1.0" + +# TODO: Remove once https://github.com/solana-labs/solana/issues/33504 is resolved. +ahash = "=0.8.6" \ No newline at end of file From fe8a41f6164a61e976b6d975038e46359fed59df Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Thu, 25 Jan 2024 14:59:46 +0100 Subject: [PATCH 02/17] :recycle: Code refactoring --- Cargo.lock | 84 +++++++++++++++-------------- cli/src/lib.rs | 112 ++++++++++++++++++++++++++------------- cli/src/rust_template.rs | 7 ++- 3 files changed, 120 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41d4b21..8f0bd91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,9 +126,9 @@ dependencies = [ [[package]] name = "anchor-attribute-access-control" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "proc-macro2", "quote", "syn 1.0.109", @@ -150,9 +150,9 @@ dependencies = [ [[package]] name = "anchor-attribute-account" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "bs58 0.5.0", "proc-macro2", "quote", @@ -173,9 +173,9 @@ dependencies = [ [[package]] name = "anchor-attribute-constant" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", "syn 1.0.109", ] @@ -194,9 +194,9 @@ dependencies = [ [[package]] name = "anchor-attribute-error" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", "syn 1.0.109", ] @@ -216,9 +216,9 @@ dependencies = [ [[package]] name = "anchor-attribute-event" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "proc-macro2", "quote", "syn 1.0.109", @@ -238,9 +238,9 @@ dependencies = [ [[package]] name = "anchor-attribute-program" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", "syn 1.0.109", ] @@ -248,13 +248,13 @@ dependencies = [ [[package]] name = "anchor-cli" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ "anchor-client", - "anchor-lang 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-lang 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "anyhow", - "base64 0.13.1", + "base64 0.21.5", "bincode", "cargo_toml", "chrono", @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "anchor-client" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-lang 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-lang 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "anyhow", "futures", "regex", @@ -314,9 +314,9 @@ dependencies = [ [[package]] name = "anchor-derive-accounts" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", "syn 1.0.109", ] @@ -337,10 +337,10 @@ dependencies = [ [[package]] name = "anchor-derive-serde" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ - "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "borsh-derive-internal 0.10.3", + "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "borsh-derive-internal 0.9.3", "proc-macro2", "quote", "syn 1.0.109", @@ -360,7 +360,7 @@ dependencies = [ [[package]] name = "anchor-derive-space" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ "proc-macro2", "quote", @@ -395,21 +395,22 @@ dependencies = [ [[package]] name = "anchor-lang" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" -dependencies = [ - "anchor-attribute-access-control 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-attribute-account 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-attribute-constant 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-attribute-error 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-attribute-event 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-attribute-program 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-derive-accounts 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-derive-serde 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", - "anchor-derive-space 0.29.0 (git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0)", +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +dependencies = [ + "ahash 0.8.6", + "anchor-attribute-access-control 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-attribute-account 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-attribute-constant 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-attribute-error 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-attribute-event 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-attribute-program 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-derive-accounts 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-derive-serde 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", + "anchor-derive-space 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "arrayref", - "base64 0.13.1", + "base64 0.21.5", "bincode", - "borsh 0.10.3", + "borsh 0.9.3", "bytemuck", "getrandom 0.2.10", "solana-program", @@ -437,7 +438,7 @@ dependencies = [ [[package]] name = "anchor-syn" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git?rev=v0.29.0#fc9fd6d24b9be84abb2f40e47ed3faf7b11864ae" +source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" dependencies = [ "anyhow", "bs58 0.5.0", @@ -947,10 +948,11 @@ name = "bolt-cli" version = "0.0.1" dependencies = [ "anchor-cli", + "anchor-client", "anyhow", "clap 4.4.11", "heck 0.4.1", - "syn 2.0.38", + "syn 1.0.109", ] [[package]] @@ -4686,9 +4688,9 @@ dependencies = [ [[package]] name = "solang-parser" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cb9fa2fa2fa6837be8a2495486ff92e3ffe68a99b6eeba288e139efdd842457" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" dependencies = [ "itertools 0.11.0", "lalrpop", diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 8e311df..2adcab6 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -1,15 +1,17 @@ mod rust_template; -use std::collections::BTreeMap; -use anchor_cli::config::{Config, ConfigOverride, ProgramDeployment, TestValidator, Validator, WithPath}; +use crate::rust_template::{create_component, create_system}; +use anchor_cli::config::{ + Config, ConfigOverride, ProgramDeployment, TestValidator, Validator, WithPath, +}; +use anchor_client::Cluster; use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; +use heck::{ToKebabCase, ToSnakeCase}; +use std::collections::BTreeMap; use std::fs::{self, File}; use std::io::Write; use std::process::Stdio; -use heck::{ToKebabCase, ToSnakeCase}; -use anchor_client::Cluster; -use crate::rust_template::{create_component, create_system}; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const ANCHOR_VERSION: &str = anchor_cli::VERSION; @@ -54,10 +56,27 @@ pub struct Opts { pub fn entry(opts: Opts) -> Result<()> { match opts.command { BoltCommand::Anchor(command) => { - if let anchor_cli::Command::Init { name, javascript, solidity, no_git, jest, template, force } = command { - init(&opts.cfg_override, name, javascript, solidity, no_git, jest, template, force) - } - else { + if let anchor_cli::Command::Init { + name, + javascript, + solidity, + no_git, + jest, + template, + force, + } = command + { + init( + &opts.cfg_override, + name, + javascript, + solidity, + no_git, + jest, + template, + force, + ) + } else { // Delegate to the existing anchor_cli handler let opts = anchor_cli::Opts { cfg_override: opts.cfg_override, @@ -73,6 +92,7 @@ pub fn entry(opts: Opts) -> Result<()> { // Bolt Init +#[allow(clippy::too_many_arguments)] fn init( cfg_override: &ConfigOverride, name: String, @@ -126,7 +146,7 @@ fn init( } else { "yarn run jest --preset ts-jest" } - .to_owned(), + .to_owned(), ); } else { cfg.scripts.insert( @@ -136,7 +156,7 @@ fn init( } else { "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" } - .to_owned(), + .to_owned(), ); } @@ -170,34 +190,43 @@ fn init( }, ); cfg.workspace.members.push("programs/*".to_owned()); - cfg.workspace.members.push("programs-ecs/components/*".to_owned()); - cfg.workspace.members.push("programs-ecs/systems/*".to_owned()); + cfg.workspace + .members + .push("programs-ecs/components/*".to_owned()); + cfg.workspace + .members + .push("programs-ecs/systems/*".to_owned()); } // Setup the test validator to clone Bolt programs from devnet - let mut validator = Validator::default(); - validator.url = Some("https://rpc.magicblock.app/devnet/".to_owned()); - validator.rpc_port = 8899; - validator.ledger = ".bolt/test-ledger".to_owned(); - validator.clone = Some(vec![ - // World program - anchor_cli::config::CloneEntry{ - address: "WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n".to_owned(), - }, - // World executable data - anchor_cli::config::CloneEntry{ - address: "CrsqUXPpJYpVAAx5qMKU6K8RT1TzT81T8BL6JndWSeo3".to_owned(), - }, - // Registry - anchor_cli::config::CloneEntry{ - address: "EHLkWwAT9oebVv9ht3mtqrvHhRVMKrt54tF3MfHTey2K".to_owned(), - }, - ]); + let validator = Validator { + url: Some("https://rpc.magicblock.app/devnet/".to_owned()), + rpc_port: 8899, + bind_address: "0.0.0.0".to_owned(), + ledger: ".bolt/test-ledger".to_owned(), + clone: Some(vec![ + // World program + anchor_cli::config::CloneEntry { + address: "WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n".to_owned(), + }, + // World executable data + anchor_cli::config::CloneEntry { + address: "CrsqUXPpJYpVAAx5qMKU6K8RT1TzT81T8BL6JndWSeo3".to_owned(), + }, + // Registry + anchor_cli::config::CloneEntry { + address: "EHLkWwAT9oebVv9ht3mtqrvHhRVMKrt54tF3MfHTey2K".to_owned(), + }, + ]), + ..Default::default() + }; - let mut test_validator = TestValidator::default(); - test_validator.startup_wait = 5000; - test_validator.shutdown_wait = 2000; - test_validator.validator = Some(validator); + let test_validator = TestValidator { + startup_wait: 5000, + shutdown_wait: 2000, + validator: Some(validator), + ..Default::default() + }; cfg.test_validator = Some(test_validator); cfg.programs.insert(Cluster::Localnet, localnet); @@ -208,7 +237,10 @@ fn init( fs::write(".gitignore", rust_template::git_ignore())?; // Initialize .prettierignore file - fs::write(".prettierignore", anchor_cli::rust_template::prettier_ignore())?; + fs::write( + ".prettierignore", + anchor_cli::rust_template::prettier_ignore(), + )?; // Remove the default programs if `--force` is passed if force { @@ -219,7 +251,7 @@ fn init( )?; fs::remove_dir_all( std::env::current_dir()? - .join("programs-ecs" ) + .join("programs-ecs") .join(&project_name), )?; } @@ -306,7 +338,11 @@ fn init( // Install node modules fn install_node_modules(cmd: &str) -> Result { - let mut command = std::process::Command::new(if cfg!(target_os = "windows") { "cmd" } else { cmd }); + let mut command = std::process::Command::new(if cfg!(target_os = "windows") { + "cmd" + } else { + cmd + }); if cfg!(target_os = "windows") { command.arg(format!("/C {} install", cmd)); } else { diff --git a/cli/src/rust_template.rs b/cli/src/rust_template.rs index d4d89e9..7c0d6fa 100644 --- a/cli/src/rust_template.rs +++ b/cli/src/rust_template.rs @@ -1,5 +1,5 @@ -use crate::VERSION; use crate::ANCHOR_VERSION; +use crate::VERSION; use anchor_cli::Files; use anyhow::Result; use heck::{ToKebabCase, ToSnakeCase, ToUpperCamelCase}; @@ -104,7 +104,6 @@ pub struct Position {{ pub x: i64, pub y: i64, pub z: i64, - #[max_len(20)] pub description: String, }} "#, @@ -260,8 +259,8 @@ describe("{}", () => {{ it("InitializeNewWorld", async () => {{ const registry = await Registry.fromAccountAddress(provider.connection, registryPda); - worldId = new BN(registry.worlds); - worldPda = FindWorldPda(new BN(worldId)) + worldId = new anchor.BN(registry.worlds); + worldPda = FindWorldPda(new anchor.BN(worldId)) const initializeWorldIx = createInitializeNewWorldInstruction( {{ world: worldPda, From 17e137483cccd907f4234f3e9ed0cdcf9c47cbdf Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Fri, 26 Jan 2024 17:53:14 +0100 Subject: [PATCH 03/17] :recycle: Refactor & Bug Fixes --- Cargo.lock | 30 +++++++------- cli/Cargo.toml | 2 +- cli/src/lib.rs | 13 +++--- cli/src/rust_template.rs | 87 +++++++++++++++++++++++++++++++++++----- 4 files changed, 99 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f0bd91..8380693 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,7 +126,7 @@ dependencies = [ [[package]] name = "anchor-attribute-access-control" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "proc-macro2", @@ -150,7 +150,7 @@ dependencies = [ [[package]] name = "anchor-attribute-account" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "bs58 0.5.0", @@ -173,7 +173,7 @@ dependencies = [ [[package]] name = "anchor-attribute-constant" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", @@ -194,7 +194,7 @@ dependencies = [ [[package]] name = "anchor-attribute-error" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "anchor-attribute-event" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "proc-macro2", @@ -238,7 +238,7 @@ dependencies = [ [[package]] name = "anchor-attribute-program" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "anchor-cli" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-client", "anchor-lang 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", @@ -285,7 +285,7 @@ dependencies = [ [[package]] name = "anchor-client" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-lang 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "anyhow", @@ -314,7 +314,7 @@ dependencies = [ [[package]] name = "anchor-derive-accounts" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", "quote", @@ -337,10 +337,10 @@ dependencies = [ [[package]] name = "anchor-derive-serde" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anchor-syn 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", - "borsh-derive-internal 0.9.3", + "borsh-derive-internal 0.10.3", "proc-macro2", "quote", "syn 1.0.109", @@ -360,7 +360,7 @@ dependencies = [ [[package]] name = "anchor-derive-space" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "proc-macro2", "quote", @@ -395,7 +395,7 @@ dependencies = [ [[package]] name = "anchor-lang" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "ahash 0.8.6", "anchor-attribute-access-control 0.29.0 (git+https://github.com/coral-xyz/anchor.git)", @@ -410,7 +410,7 @@ dependencies = [ "arrayref", "base64 0.21.5", "bincode", - "borsh 0.9.3", + "borsh 0.10.3", "bytemuck", "getrandom 0.2.10", "solana-program", @@ -438,7 +438,7 @@ dependencies = [ [[package]] name = "anchor-syn" version = "0.29.0" -source = "git+https://github.com/coral-xyz/anchor.git#ef3b1493484e9d193f3cb270753484c30f75bcd8" +source = "git+https://github.com/coral-xyz/anchor.git#169264d730ffeae16c12a33c0c353b7d3a461532" dependencies = [ "anyhow", "bs58 0.5.0", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 79f09bf..96d8b71 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -16,7 +16,7 @@ path = "src/bin/main.rs" dev = [] [dependencies] -anchor-cli = { git = "https://github.com/coral-xyz/anchor.git"} +anchor-cli = { git = "https://github.com/coral-xyz/anchor.git" } anchor-client = { git = "https://github.com/coral-xyz/anchor.git" } anyhow = "1.0.32" heck = "0.4.0" diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 2adcab6..bc6f426 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -35,17 +35,16 @@ pub struct InitCommand { #[derive(Debug, Parser)] pub struct ComponentCommand { - #[clap(short, long, help = "Name of the component")] pub name: String, } #[derive(Debug, Parser)] pub struct SystemCommand { - #[clap(short, long, help = "Name of the system")] pub name: String, } #[derive(Debug, Parser)] +#[clap(version = VERSION)] pub struct Opts { #[clap(flatten)] pub cfg_override: ConfigOverride, @@ -135,7 +134,7 @@ fn init( fs::create_dir(&project_name)?; } std::env::set_current_dir(&project_name)?; - fs::create_dir("app")?; + fs::create_dir_all("app")?; let mut cfg = Config::default(); if jest { @@ -239,7 +238,7 @@ fn init( // Initialize .prettierignore file fs::write( ".prettierignore", - anchor_cli::rust_template::prettier_ignore(), + rust_template::prettier_ignore(), )?; // Remove the default programs if `--force` is passed @@ -256,7 +255,7 @@ fn init( )?; } - // Build the program. + //Build the program. if solidity { anchor_cli::solidity_template::create_program(&project_name)?; } else { @@ -266,9 +265,9 @@ fn init( } // Build the test suite. - fs::create_dir("tests")?; + fs::create_dir_all("tests")?; // Build the migrations directory. - fs::create_dir("migrations")?; + fs::create_dir_all("migrations")?; if javascript { // Build javascript config diff --git a/cli/src/rust_template.rs b/cli/src/rust_template.rs index 7c0d6fa..7e8119e 100644 --- a/cli/src/rust_template.rs +++ b/cli/src/rust_template.rs @@ -2,7 +2,7 @@ use crate::ANCHOR_VERSION; use crate::VERSION; use anchor_cli::Files; use anyhow::Result; -use heck::{ToKebabCase, ToSnakeCase, ToUpperCamelCase}; +use heck::{ToSnakeCase, ToUpperCamelCase}; use std::path::{Path, PathBuf}; /// Create a component from the given name. @@ -53,7 +53,7 @@ pub mod {} {{ }} #[account] -#[bolt_account(component_id = "{}")] +#[bolt_account(component_id = "")] pub struct {} {{ pub x: i64, pub y: i64, @@ -65,7 +65,6 @@ pub struct {} {{ anchor_cli::rust_template::get_or_create_program_id(name), name.to_upper_camel_case(), name.to_snake_case(), - name.to_kebab_case(), name.to_upper_camel_case(), ), )] @@ -164,7 +163,10 @@ pub fn package_json(jest: bool) -> String { "devDependencies": {{ "chai": "^4.3.4", "mocha": "^9.0.3", - "prettier": "^2.6.2" + "prettier": "^2.6.2", + "@metaplex-foundation/beet": "^0.7.1", + "@metaplex-foundation/beet-solana": "^0.4.0", + "bolt-sdk": "latest" }} }} "# @@ -231,7 +233,8 @@ pub fn ts_mocha(name: &str) -> String { r#"import * as anchor from "@coral-xyz/anchor"; import {{ Program }} from "@coral-xyz/anchor"; import {{ PublicKey }} from "@solana/web3.js"; -import {{ {} }} from "../target/types/{}"; +import {{ Position }} from "../target/types/position"; +import {{ Movement }} from "../target/types/movement"; import {{ createInitializeNewWorldInstruction, FindWorldPda, @@ -243,6 +246,7 @@ import {{ createInitializeComponentInstruction, FindComponentPda, createApplyInstruction }} from "bolt-sdk" +import {{expect}} from "chai"; describe("{}", () => {{ // Configure the client to use the local cluster. @@ -255,7 +259,8 @@ describe("{}", () => {{ let worldPda: PublicKey; let entityPda: PublicKey; - const program = anchor.workspace.{} as Program<{}>; + const positionComponent = anchor.workspace.Position as Program; + const systemMovement = anchor.workspace.Movement as Program; it("InitializeNewWorld", async () => {{ const registry = await Registry.fromAccountAddress(provider.connection, registryPda); @@ -272,13 +277,62 @@ describe("{}", () => {{ const txSign = await provider.sendAndConfirm(tx); console.log(`Initialized a new world (ID=${{worldId}}). Initialization signature: ${{txSign}}`); }}); + + it("Add an entity", async () => {{ + const world = await World.fromAccountAddress(provider.connection, worldPda); + const entityId = new anchor.BN(world.entities); + entityPda = FindEntityPda(worldId, entityId); + + let createEntityIx = createAddEntityInstruction({{ + world: worldPda, + payer: provider.wallet.publicKey, + entity: entityPda, + }}); + const tx = new anchor.web3.Transaction().add(createEntityIx); + const txSign = await provider.sendAndConfirm(tx); + console.log(`Initialized a new Entity (ID=${{worldId}}). Initialization signature: ${{txSign}}`); + }}); + + it("Add a component", async () => {{ + const positionComponentPda = FindComponentPda(positionComponent.programId, entityPda, ""); + let initComponentIx = createInitializeComponentInstruction({{ + payer: provider.wallet.publicKey, + entity: entityPda, + data: positionComponentPda, + componentProgram: positionComponent.programId, + }}); + + const tx = new anchor.web3.Transaction().add(initComponentIx); + const txSign = await provider.sendAndConfirm(tx); + console.log(`Initialized a new component. Initialization signature: ${{txSign}}`); + }}); + + it("Apply a system", async () => {{ + const positionComponentPda = FindComponentPda(positionComponent.programId, entityPda, ""); + // Check that the component has been initialized and x is 0 + let positionData = await positionComponent.account.position.fetch( + positionComponentPda + ); + expect(positionData.x.toNumber()).to.eq(0); + let applySystemIx = createApplyInstruction({{ + componentProgram: positionComponent.programId, + boltSystem: systemMovement.programId, + boltComponent: positionComponentPda, + }}, {{args: new Uint8Array()}}); + + const tx = new anchor.web3.Transaction().add(applySystemIx); + await provider.sendAndConfirm(tx); + + // Check that the system has been applied and x is > 0 + positionData = await positionComponent.account.position.fetch( + positionComponentPda + ); + expect(positionData.x.toNumber()).to.gt(0); + }}); + }}); "#, name.to_upper_camel_case(), - name.to_snake_case(), - name, - name.to_upper_camel_case(), - name.to_upper_camel_case(), ) } @@ -329,3 +383,16 @@ test-ledger .yarn "# } + +pub fn prettier_ignore() -> &'static str { + r#" +.anchor +.bolt +.DS_Store +target +node_modules +dist +build +test-ledger +"# +} From 1b224b97a23baf3b48f3b7387cb84ad597e62dc7 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 11:11:50 +0100 Subject: [PATCH 04/17] :bug: Fix --force flag handling --- cli/src/lib.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index bc6f426..db67705 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -236,26 +236,23 @@ fn init( fs::write(".gitignore", rust_template::git_ignore())?; // Initialize .prettierignore file - fs::write( - ".prettierignore", - rust_template::prettier_ignore(), - )?; + fs::write(".prettierignore", rust_template::prettier_ignore())?; // Remove the default programs if `--force` is passed if force { - fs::remove_dir_all( - std::env::current_dir()? - .join(if solidity { "solidity" } else { "programs" }) - .join(&project_name), - )?; - fs::remove_dir_all( - std::env::current_dir()? - .join("programs-ecs") - .join(&project_name), - )?; + let programs_path = std::env::current_dir()? + .join(if solidity { "solidity" } else { "programs" }) + .join(&project_name); + fs::create_dir_all(&programs_path)?; + fs::remove_dir_all(&programs_path)?; + let programs_ecs_path = std::env::current_dir()? + .join("programs-ecs") + .join(&project_name); + fs::create_dir_all(&programs_ecs_path)?; + fs::remove_dir_all(&programs_ecs_path)?; } - //Build the program. + // Build the program. if solidity { anchor_cli::solidity_template::create_program(&project_name)?; } else { From 1684d4066560e4419ee4cceb4ebed1cd1cbc2869 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 11:18:47 +0100 Subject: [PATCH 05/17] :construction_worker: Add tests for CLI --- .github/workflows/run-tests.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index b58c224..98a73fc 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -144,6 +144,12 @@ jobs: npm i -g @coral-xyz/anchor-cli@${{ env.anchor_version }} ts-mocha typescript anchor test + - name: Install the Bolt CLI, create a project and run tests + run: | + cargo install --path cli --force --locked + bolt init test-project --force + cd test-project && bolt test + - uses: actions/upload-artifact@v3 if: always() with: From 58eda84430816e5b7eaeb5d42ed884692f0d9aa6 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 11:30:19 +0100 Subject: [PATCH 06/17] :sparkles: Add InitWorld example for js (jest and mocha) --- cli/src/lib.rs | 4 +- cli/src/rust_template.rs | 82 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index db67705..8c3c4fc 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -276,14 +276,14 @@ fn init( if solidity { test.write_all(anchor_cli::solidity_template::jest(&project_name).as_bytes())?; } else { - test.write_all(anchor_cli::rust_template::jest(&project_name).as_bytes())?; + test.write_all(rust_template::jest(&project_name).as_bytes())?; } } else { let mut test = File::create(format!("tests/{}.js", &project_name))?; if solidity { test.write_all(anchor_cli::solidity_template::mocha(&project_name).as_bytes())?; } else { - test.write_all(anchor_cli::rust_template::mocha(&project_name).as_bytes())?; + test.write_all(rust_template::mocha(&project_name).as_bytes())?; } } diff --git a/cli/src/rust_template.rs b/cli/src/rust_template.rs index 7e8119e..4ab80cc 100644 --- a/cli/src/rust_template.rs +++ b/cli/src/rust_template.rs @@ -228,6 +228,88 @@ pub fn ts_package_json(jest: bool) -> String { } } +pub fn mocha(name: &str) -> String { + format!( + r#"const anchor = require("@coral-xyz/anchor"); +const boltSdk = require("bolt-sdk"); +const {{ + createInitializeNewWorldInstruction, + FindWorldPda, + FindWorldRegistryPda, + Registry, + World +}} = boltSdk; + +describe("{}", () => {{ + // Configure the client to use the local cluster. + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + + it("InitializeNewWorld", async () => {{ + const registry = await Registry.fromAccountAddress(provider.connection, registryPda); + worldId = new anchor.BN(registry.worlds); + worldPda = FindWorldPda(new anchor.BN(worldId)) + const initializeWorldIx = createInitializeNewWorldInstruction( + {{ + world: worldPda, + registry: registryPda, + payer: provider.wallet.publicKey, + }}); + + const tx = new anchor.web3.Transaction().add(initializeWorldIx); + const txSign = await provider.sendAndConfirm(tx); + console.log(`Initialized a new world (ID=${{worldId}}). Initialization signature: ${{txSign}}`); + }}); + }}); +}}); +"#, + name, + ) +} + +pub fn jest(name: &str) -> String { + format!( + r#"const anchor = require("@coral-xyz/anchor"); +const boltSdk = require("bolt-sdk"); +const {{ + createInitializeNewWorldInstruction, + FindWorldPda, + FindWorldRegistryPda, + Registry, + World +}} = boltSdk; + +describe("{}", () => {{ + // Configure the client to use the local cluster. + const provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + + // Constants used to test the program. + const registryPda = FindWorldRegistryPda(); + let worldId: anchor.BN; + let worldPda: PublicKey; + + it("InitializeNewWorld", async () => {{ + const registry = await Registry.fromAccountAddress(provider.connection, registryPda); + worldId = new anchor.BN(registry.worlds); + worldPda = FindWorldPda(new anchor.BN(worldId)) + const initializeWorldIx = createInitializeNewWorldInstruction( + {{ + world: worldPda, + registry: registryPda, + payer: provider.wallet.publicKey, + }}); + + const tx = new anchor.web3.Transaction().add(initializeWorldIx); + const txSign = await provider.sendAndConfirm(tx); + console.log(`Initialized a new world (ID=${{worldId}}). Initialization signature: ${{txSign}}`); + }}); + }}); +"#, + name, + ) +} + pub fn ts_mocha(name: &str) -> String { format!( r#"import * as anchor from "@coral-xyz/anchor"; From e44833b137a18f143bfff3f7a0b14c4c19448b2d Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 11:48:40 +0100 Subject: [PATCH 07/17] :construction_worker: Update CI --- .github/workflows/run-tests.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 98a73fc..611fca2 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -42,7 +42,8 @@ jobs: export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" yarn --frozen-lockfile --network-concurrency 2 - - uses: dtolnay/rust-toolchain@stable + - name: install rust + uses: dtolnay/rust-toolchain@stable with: toolchain: stable @@ -148,7 +149,7 @@ jobs: run: | cargo install --path cli --force --locked bolt init test-project --force - cd test-project && bolt test + cd test-project && anchor test - uses: actions/upload-artifact@v3 if: always() From c757396cf1919bd9fc128c7ec85ad20e487a1cec Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 12:17:36 +0100 Subject: [PATCH 08/17] :construction_worker: Add CI --- .github/workflows/run-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 611fca2..4e2c826 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -149,7 +149,8 @@ jobs: run: | cargo install --path cli --force --locked bolt init test-project --force - cd test-project && anchor test + sleep 5 + cd test-project && bolt test - uses: actions/upload-artifact@v3 if: always() From 15bfe180189f8892923cba1c0603040ab54e5966 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 12:19:09 +0100 Subject: [PATCH 09/17] :construction_worker: Update CI --- .github/workflows/run-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 4e2c826..d0bc3e6 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -147,6 +147,8 @@ jobs: - name: Install the Bolt CLI, create a project and run tests run: | + rustc --version + cargo --version cargo install --path cli --force --locked bolt init test-project --force sleep 5 From 69ee946455f3766a45dcade0ae6adf939357b88d Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 12:40:13 +0100 Subject: [PATCH 10/17] :construction_worker: Change rust toolchain --- .github/workflows/run-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index d0bc3e6..1053e83 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -43,7 +43,7 @@ jobs: yarn --frozen-lockfile --network-concurrency 2 - name: install rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.73.0 with: toolchain: stable @@ -151,7 +151,6 @@ jobs: cargo --version cargo install --path cli --force --locked bolt init test-project --force - sleep 5 cd test-project && bolt test - uses: actions/upload-artifact@v3 From 296c4075162ba5243edc33aa49b8f26435e928c8 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 16:20:20 +0100 Subject: [PATCH 11/17] :construction_worker: Update CI --- .github/workflows/run-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 1053e83..695570c 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -43,7 +43,7 @@ jobs: yarn --frozen-lockfile --network-concurrency 2 - name: install rust - uses: dtolnay/rust-toolchain@1.73.0 + uses: dtolnay/rust-toolchain@stable with: toolchain: stable @@ -147,8 +147,8 @@ jobs: - name: Install the Bolt CLI, create a project and run tests run: | - rustc --version - cargo --version + export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" + cargo add solana-readonly-account cargo install --path cli --force --locked bolt init test-project --force cd test-project && bolt test From 4abcc1a31681286fd4a319eee27e4b5989da30cb Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 16:32:41 +0100 Subject: [PATCH 12/17] :construction_worker: Fix CI --- .github/workflows/run-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 695570c..46c68db 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -148,7 +148,7 @@ jobs: - name: Install the Bolt CLI, create a project and run tests run: | export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" - cargo add solana-readonly-account + cargo add --package bolt-cli solana-readonly-account cargo install --path cli --force --locked bolt init test-project --force cd test-project && bolt test From 81dfcf1c60961d5984d5f208b407730f66ba9791 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 16:59:20 +0100 Subject: [PATCH 13/17] :construction_worker: Update CI --- .github/workflows/run-tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 46c68db..eb46317 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -43,7 +43,7 @@ jobs: yarn --frozen-lockfile --network-concurrency 2 - name: install rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1.75.0 with: toolchain: stable @@ -147,6 +147,8 @@ jobs: - name: Install the Bolt CLI, create a project and run tests run: | + rustc --version + cargo --version export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" cargo add --package bolt-cli solana-readonly-account cargo install --path cli --force --locked From d43980bb8eb391eb484e219c5286a976843ae98b Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 18:01:53 +0100 Subject: [PATCH 14/17] :construction_worker: Update CI --- .github/workflows/run-tests.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index eb46317..3609ff2 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -4,14 +4,14 @@ on: pull_request: env: - solana_version: v1.17.0 + solana_version: v1.18.0 anchor_version: 0.29.0 jobs: install: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/cache@v3 name: cache solana cli @@ -43,15 +43,11 @@ jobs: yarn --frozen-lockfile --network-concurrency 2 - name: install rust - uses: dtolnay/rust-toolchain@1.75.0 + uses: dtolnay/rust-toolchain@stable with: toolchain: stable - - name: Cache rust - uses: Swatinem/rust-cache@v2 - - name: install solana - if: steps.cache-solana.outputs.cache-hit != 'true' run: | sh -c "$(curl -sSfL https://release.solana.com/${{ env.solana_version }}/install)" export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH" @@ -150,7 +146,6 @@ jobs: rustc --version cargo --version export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" - cargo add --package bolt-cli solana-readonly-account cargo install --path cli --force --locked bolt init test-project --force cd test-project && bolt test From b2bab10b36984299b08c7a54e9aada7981a7b41a Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 18:47:23 +0100 Subject: [PATCH 15/17] :construction_worker: Update CI --- .github/workflows/run-tests.yml | 34 +++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 3609ff2..80da8b5 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -4,7 +4,7 @@ on: pull_request: env: - solana_version: v1.18.0 + solana_version: v1.17.0 anchor_version: 0.29.0 jobs: @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: cache solana cli id: cache-solana with: @@ -22,7 +22,7 @@ jobs: ~/.local/share/solana/ key: solana-${{ runner.os }}-v0000-${{ env.solana_version }} - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 20 @@ -47,7 +47,11 @@ jobs: with: toolchain: stable + - name: Cache rust + uses: Swatinem/rust-cache@v2 + - name: install solana + if: steps.cache-solana.outputs.cache-hit != 'true' run: | sh -c "$(curl -sSfL https://release.solana.com/${{ env.solana_version }}/install)" export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH" @@ -58,7 +62,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache rust uses: Swatinem/rust-cache@v2 - name: Run fmt @@ -70,14 +74,14 @@ jobs: needs: install runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node ${{ matrix.node }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20 - name: Cache node dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} @@ -90,10 +94,18 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: install rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + + - name: Cache rust + uses: Swatinem/rust-cache@v2 + + - uses: actions/checkout@v4 - name: Use Node ${{ matrix.node }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20 @@ -107,7 +119,7 @@ jobs: export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" yarn --frozen-lockfile - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: cache solana cli id: cache-solana with: @@ -143,8 +155,6 @@ jobs: - name: Install the Bolt CLI, create a project and run tests run: | - rustc --version - cargo --version export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" cargo install --path cli --force --locked bolt init test-project --force From 54a146962625fd124094f6ecbee193291e106b33 Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 19:05:10 +0100 Subject: [PATCH 16/17] :construction_worker: Update CI --- .github/workflows/run-tests.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 80da8b5..7f06176 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -4,7 +4,7 @@ on: pull_request: env: - solana_version: v1.17.0 + solana_version: v1.18.0 anchor_version: 0.29.0 jobs: @@ -153,12 +153,11 @@ jobs: npm i -g @coral-xyz/anchor-cli@${{ env.anchor_version }} ts-mocha typescript anchor test - - name: Install the Bolt CLI, create a project and run tests + - name: Install the Bolt CLI and create a new project run: | export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" cargo install --path cli --force --locked bolt init test-project --force - cd test-project && bolt test - uses: actions/upload-artifact@v3 if: always() From 817989c238a83904cb9a81830af758087c3014ae Mon Sep 17 00:00:00 2001 From: Gabriele Picco Date: Sat, 27 Jan 2024 19:31:52 +0100 Subject: [PATCH 17/17] :construction_worker: Add build step --- .github/workflows/run-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 7f06176..8c388a8 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -153,11 +153,12 @@ jobs: npm i -g @coral-xyz/anchor-cli@${{ env.anchor_version }} ts-mocha typescript anchor test - - name: Install the Bolt CLI and create a new project + - name: Install the Bolt CLI and create & build a new project run: | export PATH="/home/runner/.local/share/solana/install/active_release/bin:$PATH" cargo install --path cli --force --locked bolt init test-project --force + cd test-project && bolt build - uses: actions/upload-artifact@v3 if: always()