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

feat: production build #354

Merged
merged 8 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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,
al3mart marked this conversation as resolved.
Show resolved Hide resolved
/// Build profile [default: debug].
#[clap(long, value_enum)]
pub(crate) profile: Option<Profile>,
al3mart marked this conversation as resolved.
Show resolved Hide resolved
/// 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),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Option requirement should be removed when removing the deprecated parachain build and contract command.

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(())
}
}
31 changes: 17 additions & 14 deletions crates/pop-cli/src/commands/build/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ pub struct BuildParachainCommand {
/// The package to be built.
#[arg(short = 'p', long)]
pub(crate) package: Option<String>,
/// For production, always build in release mode to exclude debug features.
#[clap(short, long, default_value = "true")]
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")]
pub(crate) id: Option<u32>,
Expand All @@ -41,12 +41,13 @@ impl BuildParachainCommand {
let project = if self.package.is_some() { "package" } else { "parachain" };
cli.intro(format!("Building your {project}"))?;

let profile = self.profile.unwrap_or(Profile::Debug);
// Show warning if specified as deprecated.
if !self.valid {
cli.warning("NOTE: this command is deprecated. Please use `pop build` (or simply `pop b`) in future...")?;
#[cfg(not(test))]
sleep(Duration::from_secs(3))
} else if !self.release {
} else if profile == Profile::Debug {
cli.warning("NOTE: this command now defaults to DEBUG builds. Please use `--release` (or simply `-r`) for a release build...")?;
#[cfg(not(test))]
sleep(Duration::from_secs(3))
Expand All @@ -55,9 +56,8 @@ impl BuildParachainCommand {
// Build parachain.
cli.warning("NOTE: this may take some time...")?;
let project_path = self.path.unwrap_or_else(|| PathBuf::from("./"));
let mode: Profile = self.release.into();
let binary = build_parachain(&project_path, self.package, &mode, None)?;
cli.info(format!("The {project} was built in {mode} mode."))?;
let binary = build_parachain(&project_path, self.package, &profile, None)?;
cli.info(format!("The {project} was built in {} mode.", profile))?;
cli.outro("Build completed successfully!")?;
let generated_files = [format!("Binary generated at: {}", binary.display())];
let generated_files: Vec<_> = generated_files
Expand All @@ -79,7 +79,9 @@ mod tests {
use super::*;
use cli::MockCli;
use duct::cmd;
use pop_common::manifest::add_production_profile;
use std::{fs, io::Write, path::Path};
use strum::VariantArray;

// Function that generates a Cargo.toml inside node directory for testing.
fn generate_mock_node(temp_dir: &Path) -> anyhow::Result<()> {
Expand All @@ -106,33 +108,34 @@ mod tests {
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()?;
generate_mock_node(&temp_dir.path().join(name))?;
add_production_profile(&project_path)?;
generate_mock_node(&project_path)?;

for package in [None, Some(name.to_string())] {
for release in [false, true] {
for profile in Profile::VARIANTS {
for valid in [false, true] {
let project = if package.is_some() { "package" } else { "parachain" };
let mode = if release { Profile::Release } else { Profile::Debug };
let mut cli = MockCli::new()
.expect_intro(format!("Building your {project}"))
.expect_warning("NOTE: this may take some time...")
.expect_info(format!("The {project} was built in {mode} mode."))
.expect_info(format!("The {project} was built in {profile} mode."))
.expect_outro("Build completed successfully!");

if !valid {
cli = cli.expect_warning("NOTE: this command is deprecated. Please use `pop build` (or simply `pop b`) in future...");
} else {
if !release {
if profile == &Profile::Debug {
cli = cli.expect_warning("NOTE: this command now defaults to DEBUG builds. Please use `--release` (or simply `-r`) for a release build...");
}
}

assert_eq!(
BuildParachainCommand {
path: Some(path.join(name)),
path: Some(project_path.clone()),
package: package.clone(),
release,
profile: Some(profile.clone()),
id: None,
valid,
}
Expand Down
Loading