Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: build spec experience #331

Merged
merged 35 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4fbb674
fix: add chain to specify the chain specification
AlexD10S Nov 1, 2024
eaf1f94
fix: default_bootnode by default to true
AlexD10S Nov 1, 2024
908c4d2
chore: fmt
AlexD10S Nov 1, 2024
d20f92f
chore: deprecate flag --release in build specs
AlexD10S Nov 5, 2024
fda3904
fix: clean output (#334)
al3mart Nov 5, 2024
a51df3a
fix: undo deprecation of --release flag
AlexD10S Nov 5, 2024
97e26e5
refactor: small fix
AlexD10S Nov 5, 2024
b493ae6
style: remove extra space
al3mart Nov 8, 2024
63922e5
fix(spec): better handling of spinner
al3mart Nov 8, 2024
c7275b3
style: use spinner instead of multispinner
AlexD10S Nov 20, 2024
f532a4b
docs: help message to include build
AlexD10S Nov 20, 2024
8ed07d2
feat: reuse existing chain spec
Daanvdplas Nov 26, 2024
e5a46ff
refactor: remove clone
Daanvdplas Nov 26, 2024
804a07b
refactor: opt in to edit provided chain spec
Daanvdplas Nov 26, 2024
3f8dd45
docs: improve
Daanvdplas Nov 26, 2024
88d1299
refactor: flow flag input
Daanvdplas Nov 26, 2024
d164332
fix: prepare_output_path
Daanvdplas Nov 28, 2024
db65ebf
refactor: resolve small improvements
Daanvdplas Nov 28, 2024
505535f
fix: protocol id prompt
Daanvdplas Nov 28, 2024
47ed21b
fix: spinner
Daanvdplas Nov 28, 2024
5fd5cb5
fix: docs
Daanvdplas Nov 28, 2024
1c01334
test: test cli
Daanvdplas Nov 28, 2024
faf3038
chore: refactor
al3mart Nov 29, 2024
b80b5bb
chore: amend test
al3mart Nov 29, 2024
fab0584
feat: production profile
Daanvdplas Nov 26, 2024
91fa45e
refactor: improve profile experience
Daanvdplas Nov 27, 2024
c3898b0
chore: feedback and rebase
al3mart Nov 29, 2024
7deea0d
chore: add profile tests
al3mart Nov 29, 2024
05c0fcc
fix(test): parachain_lifecycle
al3mart Dec 2, 2024
0fca3d9
style: fmt
al3mart Dec 2, 2024
39b26ed
fix: clippy
Daanvdplas Dec 4, 2024
204296a
fix: cli required changes introduced by PR
Daanvdplas Dec 4, 2024
daf0983
fix: test
Daanvdplas Dec 4, 2024
68a9065
fix: clippy
Daanvdplas Dec 5, 2024
3cd8194
docs: deprecation message
Daanvdplas Dec 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ tar = "0.4.40"
tempfile = "3.10"
thiserror = "1.0.58"
tokio-test = "0.4.4"
toml = "0.5.0"

# networking
reqwest = { version = "0.12", features = ["json"] }
Expand Down
67 changes: 51 additions & 16 deletions crates/pop-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ pub(crate) mod traits {

/// A select prompt.
pub trait Select<T> {
/// Sets the initially selected value.
fn initial_value(self, initial_value: T) -> Self;
/// Starts the prompt interaction.
fn interact(&mut self) -> Result<T>;
/// Adds an item to the selection prompt.
Expand Down Expand Up @@ -133,20 +135,22 @@ impl traits::Cli for Cli {

/// A confirmation prompt using cliclack.
struct Confirm(cliclack::Confirm);

impl traits::Confirm for Confirm {
/// Starts the prompt interaction.
fn interact(&mut self) -> Result<bool> {
self.0.interact()
}
/// Sets the initially selected value.
fn initial_value(mut self, initial_value: bool) -> Self {
self.0 = self.0.initial_value(initial_value);
self
}
/// Starts the prompt interaction.
fn interact(&mut self) -> Result<bool> {
self.0.interact()
}
}

/// A input prompt using cliclack.
struct Input(cliclack::Input);

impl traits::Input for Input {
/// Sets the default value for the input.
fn default_input(mut self, value: &str) -> Self {
Expand Down Expand Up @@ -203,6 +207,12 @@ impl<T: Clone + Eq> traits::MultiSelect<T> for MultiSelect<T> {
struct Select<T: Clone + Eq>(cliclack::Select<T>);

impl<T: Clone + Eq> traits::Select<T> for Select<T> {
/// Sets the initially selected value.
fn initial_value(mut self, initial_value: T) -> Self {
self.0 = self.0.initial_value(initial_value);
self
}

/// Starts the prompt interaction.
fn interact(&mut self) -> Result<T> {
self.0.interact()
Expand Down Expand Up @@ -231,8 +241,7 @@ pub(crate) mod tests {
multiselect_expectation:
Option<(String, Option<bool>, bool, Option<Vec<(String, String)>>)>,
outro_cancel_expectation: Option<String>,
select_expectation:
Option<(String, Option<bool>, bool, Option<Vec<(String, String)>>, usize)>,
select_expectation: Vec<(String, Option<bool>, bool, Option<Vec<(String, String)>>, usize)>,
success_expectations: Vec<String>,
warning_expectations: Vec<String>,
}
Expand All @@ -243,17 +252,17 @@ pub(crate) mod tests {
}

pub(crate) fn expect_confirm(mut self, prompt: impl Display, confirm: bool) -> Self {
self.confirm_expectation.push((prompt.to_string(), confirm));
self.confirm_expectation.insert(0, (prompt.to_string(), confirm));
self
}

pub(crate) fn expect_input(mut self, prompt: impl Display, input: String) -> Self {
self.input_expectations.push((prompt.to_string(), input));
self.input_expectations.insert(0, (prompt.to_string(), input));
self
}

pub(crate) fn expect_info(mut self, message: impl Display) -> Self {
self.info_expectations.push(message.to_string());
self.info_expectations.insert(0, message.to_string());
self
}

Expand Down Expand Up @@ -283,15 +292,16 @@ pub(crate) mod tests {
self
}

pub(crate) fn expect_select<T>(
pub(crate) fn expect_select(
mut self,
prompt: impl Display,
required: Option<bool>,
collect: bool,
items: Option<Vec<(String, String)>>,
item: usize,
) -> Self {
self.select_expectation = Some((prompt.to_string(), required, collect, items, item));
self.select_expectation
.insert(0, (prompt.to_string(), required, collect, items, item));
self
}

Expand Down Expand Up @@ -327,8 +337,15 @@ pub(crate) mod tests {
if let Some(expectation) = self.outro_cancel_expectation {
panic!("`{expectation}` outro cancel expectation not satisfied")
}
if let Some((prompt, _, _, _, _)) = self.select_expectation {
panic!("`{prompt}` select prompt expectation not satisfied")
if !self.select_expectation.is_empty() {
panic!(
"`{}` select prompt expectation not satisfied",
self.select_expectation
.iter()
.map(|(s, _, _, _, _)| s.clone()) // Extract the `String` part
.collect::<Vec<_>>()
.join(", ")
);
}
if !self.success_expectations.is_empty() {
panic!(
Expand Down Expand Up @@ -425,10 +442,16 @@ pub(crate) mod tests {
fn select<T: Clone + Eq>(&mut self, prompt: impl Display) -> impl Select<T> {
let prompt = prompt.to_string();
if let Some((expectation, _, collect, items_expectation, item)) =
self.select_expectation.take()
self.select_expectation.pop()
{
assert_eq!(expectation, prompt, "prompt does not satisfy expectation");
return MockSelect { items_expectation, collect, items: vec![], item };
return MockSelect {
items_expectation,
collect,
items: vec![],
item,
initial_value: None,
};
}

MockSelect::default()
Expand Down Expand Up @@ -553,15 +576,27 @@ pub(crate) mod tests {
collect: bool,
items: Vec<T>,
item: usize,
initial_value: Option<T>,
}

impl<T> MockSelect<T> {
pub(crate) fn default() -> Self {
Self { items_expectation: None, collect: false, items: vec![], item: 0 }
Self {
items_expectation: None,
collect: false,
items: vec![],
item: 0,
initial_value: None,
}
}
}

impl<T: Clone + Eq> Select<T> for MockSelect<T> {
fn initial_value(mut self, initial_value: T) -> Self {
self.initial_value = Some(initial_value);
self
}

fn interact(&mut self) -> Result<T> {
Ok(self.items[self.item].clone())
}
Expand Down
80 changes: 49 additions & 31 deletions crates/pop-cli/src/commands/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use clap::{Args, Subcommand};
#[cfg(feature = "contract")]
use contract::BuildContractCommand;
use duct::cmd;
use pop_common::Profile;
use std::path::PathBuf;
#[cfg(feature = "parachain")]
use {parachain::BuildParachainCommand, spec::BuildSpecCommand};
Expand All @@ -29,8 +30,11 @@ pub(crate) struct BuildArgs {
#[arg(short = 'p', long)]
pub(crate) package: Option<String>,
/// For production, always build in release mode to exclude debug features.
#[clap(short, long)]
#[clap(short, long, conflicts_with = "profile")]
pub(crate) release: bool,
/// Build profile [default: debug].
#[clap(long, value_enum)]
pub(crate) profile: Option<Profile>,
/// Parachain ID to be used when generating the chain spec files.
#[arg(short = 'i', long = "id")]
#[cfg(feature = "parachain")]
Expand Down Expand Up @@ -62,19 +66,26 @@ impl Command {
#[cfg(feature = "contract")]
if pop_contracts::is_supported(args.path.as_deref())? {
// All commands originating from root command are valid
BuildContractCommand { path: args.path, release: args.release, valid: true }
.execute()?;
let release = match args.profile {
Some(profile) => profile.into(),
None => args.release,
};
BuildContractCommand { path: args.path, release, valid: true }.execute()?;
return Ok("contract");
}

// If only parachain feature enabled, build as parachain
#[cfg(feature = "parachain")]
if pop_parachains::is_supported(args.path.as_deref())? {
let profile = match args.profile {
Some(profile) => profile,
None => args.release.into(),
};
// All commands originating from root command are valid
BuildParachainCommand {
path: args.path,
package: args.package,
release: args.release,
profile: Some(profile),
id: args.id,
valid: true,
}
Expand All @@ -101,13 +112,15 @@ impl Command {
_args.push("--package");
_args.push(package)
}
if args.release {
let profile = args.profile.unwrap_or(Profile::Debug);
if profile == Profile::Release {
_args.push("--release");
} else if profile == Profile::Production {
_args.push("--profile=production");
}
cmd("cargo", _args).dir(args.path.unwrap_or_else(|| "./".into())).run()?;

let mode = if args.release { "RELEASE" } else { "DEBUG" };
cli.info(format!("The {project} was built in {mode} mode."))?;
cli.info(format!("The {project} was built in {} mode.", profile))?;
cli.outro("Build completed successfully!")?;
Ok(project)
}
Expand All @@ -117,41 +130,46 @@ impl Command {
mod tests {
use super::*;
use cli::MockCli;
use pop_common::manifest::add_production_profile;
use strum::VariantArray;

#[test]
fn build_works() -> anyhow::Result<()> {
let name = "hello_world";
let temp_dir = tempfile::tempdir()?;
let path = temp_dir.path();
let project_path = path.join(name);
cmd("cargo", ["new", name, "--bin"]).dir(&path).run()?;
add_production_profile(&project_path)?;

for package in [None, Some(name.to_string())] {
for release in [false, true] {
let project = if package.is_some() { "package" } else { "project" };
let mode = if release { "RELEASE" } else { "DEBUG" };
let mut cli = MockCli::new()
.expect_intro(format!("Building your {project}"))
.expect_info(format!("The {project} was built in {mode} mode."))
.expect_outro("Build completed successfully!");

assert_eq!(
Command::build(
BuildArgs {
command: None,
path: Some(path.join(name)),
package: package.clone(),
release,
id: None,
},
&mut cli,
)?,
project
);

cli.verify()?;
for release in [true, false] {
for profile in Profile::VARIANTS {
let profile = if release { Profile::Release } else { profile.clone() };
let project = if package.is_some() { "package" } else { "project" };
let mut cli = MockCli::new()
.expect_intro(format!("Building your {project}"))
.expect_info(format!("The {project} was built in {profile} mode."))
.expect_outro("Build completed successfully!");

assert_eq!(
Command::build(
BuildArgs {
command: None,
path: Some(project_path.clone()),
package: package.clone(),
release,
profile: Some(profile.clone()),
id: None,
},
&mut cli,
)?,
project
);
cli.verify()?;
}
}
}

Ok(())
}
}
Loading
Loading