Skip to content

Commit

Permalink
fix: limit API calls when generating parachain (#299)
Browse files Browse the repository at this point in the history
* fix: api queries under flag

* test: add the flag verify in the integration tests

* chore: add note if verify flag is picked

* fix: default value if already 403 error
  • Loading branch information
AlexD10S committed Sep 6, 2024
1 parent f9ebdd3 commit 32d5870
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 25 deletions.
58 changes: 44 additions & 14 deletions crates/pop-cli/src/commands/new/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,20 @@ pub struct NewParachainCommand {
default_value = DEFAULT_INITIAL_ENDOWMENT
)]
pub(crate) initial_endowment: Option<String>,
#[arg(
short = 'v',
long,
help = "Verifies the commit SHA when fetching the latest license and release from GitHub."
)]
pub(crate) verify: bool,
}

impl NewParachainCommand {
/// Executes the command.
pub(crate) async fn execute(self) -> Result<Parachain> {
// If user doesn't select the name guide them to generate a parachain.
let parachain_config = if self.name.is_none() {
guide_user_to_generate_parachain().await?
guide_user_to_generate_parachain(self.verify).await?
} else {
self.clone()
};
Expand All @@ -93,13 +99,21 @@ impl NewParachainCommand {

let tag_version = parachain_config.release_tag.clone();

generate_parachain_from_template(name, provider, &template, tag_version, config)?;
generate_parachain_from_template(
name,
provider,
&template,
tag_version,
config,
self.verify,
)
.await?;
Ok(template)
}
}

/// Guide the user to generate a parachain from available templates.
async fn guide_user_to_generate_parachain() -> Result<NewParachainCommand> {
async fn guide_user_to_generate_parachain(verify: bool) -> Result<NewParachainCommand> {
Cli.intro("Generate a parachain")?;

// Prompt for template selection.
Expand All @@ -121,7 +135,7 @@ async fn guide_user_to_generate_parachain() -> Result<NewParachainCommand> {
}
let provider = prompt.interact()?;
let template = display_select_options(provider)?;
let release_name = choose_release(template).await?;
let release_name = choose_release(template, verify).await?;

// Prompt for location.
let name: String = input("Where should your project be created?")
Expand All @@ -147,15 +161,17 @@ async fn guide_user_to_generate_parachain() -> Result<NewParachainCommand> {
symbol: Some(customizable_options.symbol),
decimals: Some(customizable_options.decimals),
initial_endowment: Some(customizable_options.initial_endowment),
verify,
})
}

fn generate_parachain_from_template(
async fn generate_parachain_from_template(
name_template: &String,
provider: &Provider,
template: &Parachain,
tag_version: Option<String>,
config: Config,
verify: bool,
) -> Result<()> {
Cli.intro(format!(
"Generating \"{name_template}\" using {} from {}!",
Expand All @@ -177,9 +193,16 @@ fn generate_parachain_from_template(

// Replace spinner with success.
console::Term::stderr().clear_last_lines(2)?;
let mut verify_note = "".to_string();
if verify && tag.is_some() {
let url = url::Url::parse(&template.repository_url()?).expect("valid repository url");
let repo = GitHub::parse(url.as_str())?;
let commit = repo.get_commit_sha_from_release(&tag.clone().unwrap()).await;
verify_note = format!(" ✅ Fetched the latest release of the template along with its license based on the commit SHA for the release ({}).", commit.unwrap_or_default());
}
success(format!(
"Generation complete{}",
tag.map(|t| format!("\n{}", style(format!("Version: {t}")).dim()))
tag.map(|t| format!("\n{}", style(format!("Version: {t} {}", verify_note)).dim()))
.unwrap_or_default()
))?;

Expand Down Expand Up @@ -281,15 +304,19 @@ fn check_destination_path(name_template: &String) -> Result<&Path> {
/// Otherwise, the default release is used.
///
/// return: `Option<String>` - The release name selected by the user or None if no releases found.
async fn choose_release(template: &Parachain) -> Result<Option<String>> {
async fn choose_release(template: &Parachain, verify: bool) -> Result<Option<String>> {
let url = url::Url::parse(&template.repository_url()?).expect("valid repository url");
let repo = GitHub::parse(url.as_str())?;

let license = repo.get_repo_license().await?;
let license = if verify || template.license().is_none() {
repo.get_repo_license().await?
} else {
template.license().unwrap().to_string() // unwrap is safe as it is checked above
};
log::info(format!("Template {}: {}", style("License").bold(), license))?;

// Get only the latest 3 releases that are supported by the template (default is all)
let latest_3_releases: Vec<Release> = get_latest_3_releases(&repo)
let latest_3_releases: Vec<Release> = get_latest_3_releases(&repo, verify)
.await?
.into_iter()
.filter(|r| template.is_supported_version(&r.tag_name))
Expand All @@ -312,13 +339,15 @@ async fn choose_release(template: &Parachain) -> Result<Option<String>> {
Ok(release_name)
}

async fn get_latest_3_releases(repo: &GitHub) -> Result<Vec<Release>> {
async fn get_latest_3_releases(repo: &GitHub, verify: bool) -> Result<Vec<Release>> {
let mut latest_3_releases: Vec<Release> =
repo.releases().await?.into_iter().filter(|r| !r.prerelease).take(3).collect();
// Get the commit sha for the releases
for release in latest_3_releases.iter_mut() {
let commit = repo.get_commit_sha_from_release(&release.tag_name).await?;
release.commit = Some(commit);
if verify {
// Get the commit sha for the releases
for release in latest_3_releases.iter_mut() {
let commit = repo.get_commit_sha_from_release(&release.tag_name).await?;
release.commit = Some(commit);
}
}
Ok(latest_3_releases)
}
Expand Down Expand Up @@ -422,6 +451,7 @@ mod tests {
symbol: Some("UNIT".to_string()),
decimals: Some(12),
initial_endowment: Some("1u64 << 60".to_string()),
verify: false,
};
command.execute().await?;

Expand Down
6 changes: 4 additions & 2 deletions crates/pop-cli/tests/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async fn parachain_lifecycle() -> Result<()> {
// let temp_dir = Path::new("./"); //For testing locally
// Test that all templates are generated correctly
generate_all_the_templates(&temp_dir)?;
// pop new parachain test_parachain (default)
// pop new parachain test_parachain --verify (default)
Command::cargo_bin("pop")
.unwrap()
.current_dir(&temp_dir)
Expand All @@ -30,6 +30,7 @@ async fn parachain_lifecycle() -> Result<()> {
"6",
"--endowment",
"1u64 << 60",
"--verify",
])
.assert()
.success();
Expand Down Expand Up @@ -106,7 +107,7 @@ fn generate_all_the_templates(temp_dir: &Path) -> Result<()> {
for template in Parachain::VARIANTS {
let parachain_name = format!("test_parachain_{}", template);
let provider = template.template_type()?.to_lowercase();
// pop new parachain test_parachain
// pop new parachain test_parachain --verify
Command::cargo_bin("pop")
.unwrap()
.current_dir(&temp_dir)
Expand All @@ -117,6 +118,7 @@ fn generate_all_the_templates(temp_dir: &Path) -> Result<()> {
&provider,
"--template",
&template.to_string(),
"--verify",
])
.assert()
.success();
Expand Down
53 changes: 44 additions & 9 deletions crates/pop-parachains/src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ pub enum Parachain {
props(
Provider = "Pop",
Repository = "https://github.com/r0gue-io/base-parachain",
Network = "./network.toml"
Network = "./network.toml",
License = "Unlicense"
)
)]
Standard,
Expand All @@ -88,7 +89,8 @@ pub enum Parachain {
props(
Provider = "Pop",
Repository = "https://github.com/r0gue-io/assets-parachain",
Network = "./network.toml"
Network = "./network.toml",
License = "Unlicense"
)
)]
Assets,
Expand All @@ -100,7 +102,8 @@ pub enum Parachain {
props(
Provider = "Pop",
Repository = "https://github.com/r0gue-io/contracts-parachain",
Network = "./network.toml"
Network = "./network.toml",
License = "Unlicense"
)
)]
Contracts,
Expand All @@ -113,7 +116,8 @@ pub enum Parachain {
props(
Provider = "Pop",
Repository = "https://github.com/r0gue-io/evm-parachain",
Network = "./network.toml"
Network = "./network.toml",
License = "Unlicense"
)
)]
EVM,
Expand All @@ -127,7 +131,8 @@ pub enum Parachain {
Repository = "https://github.com/OpenZeppelin/polkadot-runtime-templates",
Network = "./zombienet-config/devnet.toml",
SupportedVersions = "v1.0.0",
IsAudited = "true"
IsAudited = "true",
License = "GPL-3.0"
)
)]
OpenZeppelinGeneric,
Expand All @@ -139,7 +144,8 @@ pub enum Parachain {
props(
Provider = "Parity",
Repository = "https://github.com/paritytech/substrate-contracts-node",
Network = "./zombienet.toml"
Network = "./zombienet.toml",
License = "Unlicense"
)
)]
ParityContracts,
Expand All @@ -151,7 +157,8 @@ pub enum Parachain {
props(
Provider = "Parity",
Repository = "https://github.com/paritytech/frontier-parachain-template",
Network = "./zombienet-config.toml"
Network = "./zombienet-config.toml",
License = "Unlicense"
)
)]
ParityFPT,
Expand All @@ -167,7 +174,8 @@ pub enum Parachain {
Repository = "",
Network = "",
SupportedVersions = "v1.0.0,v2.0.0",
IsAudited = "true"
IsAudited = "true",
License = "Unlicense"
)
)]
TestTemplate01,
Expand All @@ -176,7 +184,7 @@ pub enum Parachain {
serialize = "test_02",
message = "Test_02",
detailed_message = "Test template only compiled in test mode.",
props(Provider = "Test", Repository = "", Network = "",)
props(Provider = "Test", Repository = "", Network = "", License = "GPL-3.0")
)]
TestTemplate02,
}
Expand Down Expand Up @@ -204,6 +212,10 @@ impl Parachain {
pub fn is_audited(&self) -> bool {
self.get_str("IsAudited").map_or(false, |s| s == "true")
}

pub fn license(&self) -> Option<&str> {
self.get_str("License")
}
}

#[cfg(test)]
Expand Down Expand Up @@ -261,6 +273,21 @@ mod tests {
.into()
}

fn template_license() -> HashMap<Parachain, Option<&'static str>> {
[
(Standard, Some("Unlicense")),
(Assets, Some("Unlicense")),
(Contracts, Some("Unlicense")),
(EVM, Some("Unlicense")),
(OpenZeppelinGeneric, Some("GPL-3.0")),
(ParityContracts, Some("Unlicense")),
(ParityFPT, Some("Unlicense")),
(TestTemplate01, Some("Unlicense")),
(TestTemplate02, Some("GPL-3.0")),
]
.into()
}

#[test]
fn test_is_template_correct() {
for template in Parachain::VARIANTS {
Expand Down Expand Up @@ -308,6 +335,14 @@ mod tests {
}
}

#[test]
fn test_license() {
let licenses = template_license();
for template in Parachain::VARIANTS {
assert_eq!(template.license(), licenses[template]);
}
}

#[test]
fn test_default_template_of_provider() {
let mut provider = Provider::Pop;
Expand Down

0 comments on commit 32d5870

Please sign in to comment.