diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bf7bd8a..7487485f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,4 +75,4 @@ jobs: git-user: ${{ env.GITHUB_ACTOR }} - name: Run integration tests - run: cargo test --test parachain \ No newline at end of file + run: cargo test --test parachain diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml new file mode 100644 index 00000000..f2f40332 --- /dev/null +++ b/.github/workflows/install.yml @@ -0,0 +1,27 @@ +name: pop install + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +defaults: + run: + shell: bash + +jobs: + ubuntu: + runs-on: ubuntu-latest + container: ubuntu + steps: + - uses: actions/checkout@v4 + - name: Install prerequisites + run: apt-get update && apt-get -y install build-essential cmake curl git + - name: Install Rust + run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + - name: Install Pop + run: | + . "$HOME/.cargo/env" + cargo install --locked --path ./crates/pop-cli + pop --version \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7e81d469..803cb31e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,7 +54,7 @@ jobs: run: rustup target add ${{ matrix.platform.target }} - name: Build pop-cli - run: cargo build --profile=production -p pop-cli --target ${{ matrix.platform.target }} --features static-ssl + run: cargo build --profile=production -p pop-cli --target ${{ matrix.platform.target }} - name: Package binary (Linux) if: contains(matrix.platform.target, 'linux') diff --git a/README.md b/README.md index b1b38244..4a9fa082 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,16 @@ If no guidance is needed, proceed with: pop new parachain my-app ``` +`pop-cli` supports diverse project templates, to use a specific one use the flag `--template`: +```sh +# Create an assets parachain +pop new parachain my-app pop -t assets +# Create a contracts parachain +pop new parachain my-app pop -t contracts +# Create a evm parachain +pop new parachain my-app pop -t evm +``` + We also integrate other provider templates in the tool, check them running: ```sh diff --git a/crates/pop-cli/Cargo.toml b/crates/pop-cli/Cargo.toml index a164da99..2767e6cc 100644 --- a/crates/pop-cli/Cargo.toml +++ b/crates/pop-cli/Cargo.toml @@ -32,8 +32,8 @@ sp-weights = { workspace = true, optional = true } # parachains pop-parachains = { path = "../pop-parachains", optional = true } -dirs = { workspace = true, optional = true } -git2.workspace = true +dirs = { version = "5.0", optional = true } +git2 = { workspace = true, features = ["vendored-openssl"] } # telemetry pop-telemetry = { path = "../pop-telemetry", optional = true } @@ -54,4 +54,4 @@ parachain = [ "dep:pop-parachains", "dep:dirs", ] -telemetry = ["dep:pop-telemetry"] \ No newline at end of file +telemetry = ["dep:pop-telemetry"] diff --git a/crates/pop-cli/src/commands/new/parachain.rs b/crates/pop-cli/src/commands/new/parachain.rs index d9c587f4..06ab0bb9 100644 --- a/crates/pop-cli/src/commands/new/parachain.rs +++ b/crates/pop-cli/src/commands/new/parachain.rs @@ -139,7 +139,7 @@ async fn guide_user_to_generate_parachain() -> Result { decimals: 12, initial_endowment: "1u64 << 60".to_string(), }; - if matches!(template, Template::Base) { + if template.matches(&Provider::Pop) { customizable_options = prompt_customizable_options()?; } @@ -221,7 +221,7 @@ fn get_customization_value( decimals: Option, initial_endowment: Option, ) -> Result { - if !matches!(template, Template::Base) + if !matches!(template, Template::Standard) && (symbol.is_some() || decimals.is_some() || initial_endowment.is_some()) { log::warning("Customization options are not available for this template")?; @@ -335,7 +335,7 @@ mod tests { let command = NewParachainCommand { name: Some(dir.path().join("test_parachain").to_str().unwrap().to_string()), provider: Some(Provider::Pop), - template: Some(Template::Base), + template: Some(Template::Standard), release_tag: None, symbol: Some("UNIT".to_string()), decimals: Some(12), @@ -353,11 +353,11 @@ mod tests { #[test] fn test_is_template_supported() -> Result<()> { - is_template_supported(&Provider::Pop, &Template::Base)?; + is_template_supported(&Provider::Pop, &Template::Standard)?; assert!(is_template_supported(&Provider::Pop, &Template::ParityContracts).is_err()); assert!(is_template_supported(&Provider::Pop, &Template::ParityFPT).is_err()); - assert!(is_template_supported(&Provider::Parity, &Template::Base).is_err()); + assert!(is_template_supported(&Provider::Parity, &Template::Standard).is_err()); is_template_supported(&Provider::Parity, &Template::ParityContracts)?; is_template_supported(&Provider::Parity, &Template::ParityFPT) } @@ -365,7 +365,7 @@ mod tests { #[test] fn test_get_customization_values() -> Result<()> { let config = get_customization_value( - &Template::Base, + &Template::Standard, Some("DOT".to_string()), Some(6), Some("10000".to_string()), diff --git a/crates/pop-cli/src/main.rs b/crates/pop-cli/src/main.rs index ce1fa717..d7ab3a3c 100644 --- a/crates/pop-cli/src/main.rs +++ b/crates/pop-cli/src/main.rs @@ -1,16 +1,21 @@ // SPDX-License-Identifier: GPL-3.0 +#[cfg(not(any(feature = "contract", feature = "parachain")))] +compile_error!("feature \"contract\" or feature \"parachain\" must be enabled"); + #[cfg(any(feature = "parachain", feature = "contract"))] mod commands; -#[cfg(any(feature = "parachain", feature = "contract"))] mod style; -use anyhow::{anyhow, Result}; +#[cfg(feature = "parachain")] +use anyhow::anyhow; +use anyhow::Result; use clap::{Parser, Subcommand}; use commands::*; #[cfg(feature = "telemetry")] use pop_telemetry::{config_file_path, record_cli_command, record_cli_used, Telemetry}; use serde_json::{json, Value}; +#[cfg(feature = "parachain")] use std::{fs::create_dir_all, path::PathBuf}; #[derive(Parser)] @@ -25,9 +30,11 @@ pub struct Cli { enum Commands { /// Generate a new parachain, pallet or smart contract. #[clap(alias = "n")] + #[cfg(any(feature = "parachain", feature = "contract"))] New(new::NewArgs), /// Build a parachain or smart contract. #[clap(alias = "b")] + #[cfg(any(feature = "parachain", feature = "contract"))] Build(build::BuildArgs), /// Call a smart contract. #[clap(alias = "c")] @@ -35,6 +42,7 @@ enum Commands { Call(call::CallArgs), /// Deploy a parachain or smart contract. #[clap(alias = "u")] + #[cfg(any(feature = "parachain", feature = "contract"))] Up(up::UpArgs), /// Test a smart contract. #[clap(alias = "t")] @@ -49,6 +57,7 @@ async fn main() -> Result<()> { let cli = Cli::parse(); let res = match cli.command { + #[cfg(any(feature = "parachain", feature = "contract"))] Commands::New(args) => match args.command { #[cfg(feature = "parachain")] new::NewCommands::Parachain(cmd) => match cmd.execute().await { @@ -69,6 +78,7 @@ async fn main() -> Result<()> { cmd.execute().await.map(|_| json!("default")) }, }, + #[cfg(any(feature = "parachain", feature = "contract"))] Commands::Build(args) => match &args.command { #[cfg(feature = "parachain")] build::BuildCommands::Parachain(cmd) => cmd.execute().map(|_| Value::Null), @@ -79,6 +89,7 @@ async fn main() -> Result<()> { Commands::Call(args) => match &args.command { call::CallCommands::Contract(cmd) => cmd.execute().await.map(|_| Value::Null), }, + #[cfg(any(feature = "parachain", feature = "contract"))] Commands::Up(args) => match &args.command { #[cfg(feature = "parachain")] up::UpCommands::Parachain(cmd) => cmd.execute().await.map(|_| Value::Null), diff --git a/crates/pop-cli/src/style.rs b/crates/pop-cli/src/style.rs index d81872b4..ace4f4e7 100644 --- a/crates/pop-cli/src/style.rs +++ b/crates/pop-cli/src/style.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 - use cliclack::ThemeState; +#[cfg(any(feature = "parachain", feature = "contract"))] pub(crate) use console::style; use console::Style; diff --git a/crates/pop-parachains/README.md b/crates/pop-parachains/README.md index bf10722d..b5667f00 100644 --- a/crates/pop-parachains/README.md +++ b/crates/pop-parachains/README.md @@ -9,7 +9,7 @@ Generate a new Parachain: ```rust use pop_parachains::{instantiate_template_dir, Config, Git, Template}; -let template = Template::Base; +let template = Template::Standard; let destination_path = ...; let config = Config { symbol: ..., diff --git a/crates/pop-parachains/src/new_parachain.rs b/crates/pop-parachains/src/new_parachain.rs index d4cb6cfd..1784d8da 100644 --- a/crates/pop-parachains/src/new_parachain.rs +++ b/crates/pop-parachains/src/new_parachain.rs @@ -6,7 +6,7 @@ use crate::{ git::Git, helpers::{sanitize, write_to_file}, }, - Config, Template, + Config, Provider, Template, }; use anyhow::Result; use std::{fs, path::Path}; @@ -21,21 +21,21 @@ pub fn instantiate_template_dir( ) -> Result> { sanitize(target)?; - if matches!(template, &Template::Base) { - return instantiate_base_template(target, config, tag_version); + if template.matches(&Provider::Pop) { + return instantiate_standard_template(template, target, config, tag_version); } let tag = Git::clone_and_degit(template.repository_url()?, target, tag_version)?; Ok(tag) } -pub fn instantiate_base_template( +pub fn instantiate_standard_template( + template: &Template, target: &Path, config: Config, tag_version: Option, ) -> Result> { let temp_dir = ::tempfile::TempDir::new_in(std::env::temp_dir())?; let source = temp_dir.path(); - let template = crate::templates::Template::Base; let tag = Git::clone_and_degit(template.repository_url()?, source, tag_version)?; @@ -80,12 +80,12 @@ mod tests { decimals: 18, initial_endowment: "1000000".to_string(), }; - instantiate_base_template(temp_dir.path(), config, None)?; + instantiate_standard_template(&Template::Standard, temp_dir.path(), config, None)?; Ok(temp_dir) } #[test] - fn test_parachain_instantiate_base_template() -> Result<()> { + fn test_parachain_instantiate_standard_template() -> Result<()> { let temp_dir = setup_template_and_instantiate().expect("Failed to setup template and instantiate"); diff --git a/crates/pop-parachains/src/templates.rs b/crates/pop-parachains/src/templates.rs index eb934d86..aab7a328 100644 --- a/crates/pop-parachains/src/templates.rs +++ b/crates/pop-parachains/src/templates.rs @@ -37,7 +37,7 @@ impl Provider { pub fn default_template(&self) -> Template { match &self { - Provider::Pop => Template::Base, + Provider::Pop => Template::Standard, Provider::Parity => Template::ParityContracts, } } @@ -78,12 +78,12 @@ pub enum Template { // Pop #[default] #[strum( - serialize = "base", + serialize = "standard", message = "Standard", detailed_message = "A standard parachain", props(Provider = "Pop", Repository = "https://github.com/r0gue-io/base-parachain") )] - Base, + Standard, #[strum( serialize = "assets", message = "Assets", @@ -91,6 +91,20 @@ pub enum Template { props(Provider = "Pop", Repository = "https://github.com/r0gue-io/assets-parachain") )] Assets, + #[strum( + serialize = "contracts", + message = "Contracts", + detailed_message = "Parachain configured to supports Wasm-based contracts.", + props(Provider = "Pop", Repository = "https://github.com/r0gue-io/contracts-parachain") + )] + Contracts, + #[strum( + serialize = "evm", + message = "EVM", + detailed_message = "Parachain configured with frontier, enabling compatibility with the Ethereum Virtual Machine (EVM).", + props(Provider = "Pop", Repository = "https://github.com/r0gue-io/evm-parachain") + )] + EVM, // Parity #[strum( serialize = "cpt", @@ -147,64 +161,75 @@ pub enum Error { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use std::{collections::HashMap, str::FromStr}; + + fn templates_names() -> HashMap { + HashMap::from([ + ("standard".to_string(), Template::Standard), + ("assets".to_string(), Template::Assets), + ("contracts".to_string(), Template::Contracts), + ("evm".to_string(), Template::EVM), + ("cpt".to_string(), Template::ParityContracts), + ("fpt".to_string(), Template::ParityFPT), + ]) + } + fn templates_urls() -> HashMap { + HashMap::from([ + ("standard".to_string(), "https://github.com/r0gue-io/base-parachain"), + ("assets".to_string(), "https://github.com/r0gue-io/assets-parachain"), + ("contracts".to_string(), "https://github.com/r0gue-io/contracts-parachain"), + ("evm".to_string(), "https://github.com/r0gue-io/evm-parachain"), + ("cpt".to_string(), "https://github.com/paritytech/substrate-contracts-node"), + ("fpt".to_string(), "https://github.com/paritytech/frontier-parachain-template"), + ]) + } #[test] fn test_is_template_correct() { - let mut template = Template::Base; - assert_eq!(template.matches(&Provider::Pop), true); - assert_eq!(template.matches(&Provider::Parity), false); - - template = Template::ParityContracts; - assert_eq!(template.matches(&Provider::Pop), false); - assert_eq!(template.matches(&Provider::Parity), true); - - template = Template::ParityFPT; - assert_eq!(template.matches(&Provider::Pop), false); - assert_eq!(template.matches(&Provider::Parity), true); - - template = Template::Assets; - assert_eq!(template.matches(&Provider::Pop), true); - assert_eq!(template.matches(&Provider::Parity), false); + for template in Template::VARIANTS { + if matches!( + template, + Template::Standard | Template::Assets | Template::Contracts | Template::EVM + ) { + assert_eq!(template.matches(&Provider::Pop), true); + assert_eq!(template.matches(&Provider::Parity), false); + } + if matches!(template, Template::ParityContracts | Template::ParityFPT) { + assert_eq!(template.matches(&Provider::Pop), false); + assert_eq!(template.matches(&Provider::Parity), true); + } + } } #[test] fn test_convert_string_to_template() { - assert_eq!(Template::from_str("base").unwrap(), Template::Base); - assert_eq!(Template::from_str("").unwrap_or_default(), Template::Base); - assert_eq!(Template::from_str("assets").unwrap(), Template::Assets); - assert_eq!(Template::from_str("cpt").unwrap(), Template::ParityContracts); - assert_eq!(Template::from_str("fpt").unwrap(), Template::ParityFPT); + let template_names = templates_names(); + // Test the default + assert_eq!(Template::from_str("").unwrap_or_default(), Template::Standard); + // Test the rest + for template in Template::VARIANTS { + assert_eq!( + &Template::from_str(&template.to_string()).unwrap(), + template_names.get(&template.to_string()).unwrap() + ); + } } #[test] fn test_repository_url() { - let mut template = Template::Base; - assert_eq!( - template.repository_url().unwrap(), - "https://github.com/r0gue-io/base-parachain" - ); - template = Template::ParityContracts; - assert_eq!( - template.repository_url().unwrap(), - "https://github.com/paritytech/substrate-contracts-node" - ); - template = Template::ParityFPT; - assert_eq!( - template.repository_url().unwrap(), - "https://github.com/paritytech/frontier-parachain-template" - ); - template = Template::Assets; - assert_eq!( - template.repository_url().unwrap(), - "https://github.com/r0gue-io/assets-parachain" - ); + let template_urls = templates_urls(); + for template in Template::VARIANTS { + assert_eq!( + &template.repository_url().unwrap(), + template_urls.get(&template.to_string()).unwrap() + ); + } } #[test] fn test_default_template_of_provider() { let mut provider = Provider::Pop; - assert_eq!(provider.default_template(), Template::Base); + assert_eq!(provider.default_template(), Template::Standard); provider = Provider::Parity; assert_eq!(provider.default_template(), Template::ParityContracts); } @@ -212,7 +237,10 @@ mod tests { #[test] fn test_templates_of_provider() { let mut provider = Provider::Pop; - assert_eq!(provider.templates(), [&Template::Base, &Template::Assets]); + assert_eq!( + provider.templates(), + [&Template::Standard, &Template::Assets, &Template::Contracts, &Template::EVM] + ); provider = Provider::Parity; assert_eq!(provider.templates(), [&Template::ParityContracts, &Template::ParityFPT]); } diff --git a/crates/pop-parachains/src/up.rs b/crates/pop-parachains/src/up.rs index 83e06a7b..8f29b02a 100644 --- a/crates/pop-parachains/src/up.rs +++ b/crates/pop-parachains/src/up.rs @@ -368,17 +368,23 @@ impl Zombienet { async fn latest_polkadot_release() -> Result { let repo = Url::parse(POLKADOT_SDK).expect("repository url valid"); - // Fetching latest releases - for release in GitHub::get_latest_releases(&repo).await? { - if !release.prerelease && release.tag_name.starts_with("polkadot-v") { - return Ok(release - .tag_name - .strip_prefix("polkadot-") - .map_or_else(|| release.tag_name.clone(), |v| v.to_string())); - } + match GitHub::get_latest_releases(&repo).await { + Ok(releases) => { + // Fetching latest releases + for release in releases { + if !release.prerelease && release.tag_name.starts_with("polkadot-v") { + return Ok(release + .tag_name + .strip_prefix("polkadot-") + .map_or_else(|| release.tag_name.clone(), |v| v.to_string())); + } + } + // It should never reach this point, but in case we download a default version of polkadot + Ok(POLKADOT_DEFAULT_VERSION.to_string()) + }, + // If an error with Github API return the POLKADOT DEFAULT VERSION + Err(_) => Ok(POLKADOT_DEFAULT_VERSION.to_string()), } - // It should never reach this point, but in case we download a default version of polkadot - Ok(POLKADOT_DEFAULT_VERSION.to_string()) } } @@ -913,7 +919,7 @@ mod tests { name = "asset-hub" [[parachains]] - id = 9090 + id = 4385 default_command = "pop-node" [[parachains.collators]] diff --git a/crates/pop-parachains/templates/base/network.templ b/crates/pop-parachains/templates/base/network.templ index 0ef837c3..02a01cac 100644 --- a/crates/pop-parachains/templates/base/network.templ +++ b/crates/pop-parachains/templates/base/network.templ @@ -10,7 +10,7 @@ name = "bob" validator = true [[parachains]] -id = 1000 +id = 2000 default_command = "./target/release/^^node^^" [[parachains.collators]] diff --git a/tests/zombienet.toml b/tests/zombienet.toml index 7f7b73fa..68bdc7d4 100644 --- a/tests/zombienet.toml +++ b/tests/zombienet.toml @@ -17,7 +17,7 @@ chain = "asset-hub-rococo-local" name = "asset-hub" [[parachains]] -id = 9090 +id = 4385 default_command = "pop-node" [[parachains.collators]]