diff --git a/lib/cli/src/commands/package/mod.rs b/lib/cli/src/commands/package/mod.rs index 700ab1be823..1126e34c918 100644 --- a/lib/cli/src/commands/package/mod.rs +++ b/lib/cli/src/commands/package/mod.rs @@ -13,6 +13,7 @@ pub use common::wait::PublishWait; // Allowing missing_docs because the comment would override the doc comment on // the command struct. #[allow(missing_docs)] +#[allow(clippy::large_enum_variant)] pub enum Package { Download(download::PackageDownload), Build(build::PackageBuild), diff --git a/lib/cli/src/commands/package/publish.rs b/lib/cli/src/commands/package/publish.rs index e7e1a2dc3dd..0543bdbb765 100644 --- a/lib/cli/src/commands/package/publish.rs +++ b/lib/cli/src/commands/package/publish.rs @@ -120,6 +120,7 @@ impl PackagePublish { package_path: self.package_path.clone(), package_hash, package_id: None, + maybe_user_package: None, } .tag( client, diff --git a/lib/cli/src/commands/package/tag.rs b/lib/cli/src/commands/package/tag.rs index c3099db0186..d31535cb096 100644 --- a/lib/cli/src/commands/package/tag.rs +++ b/lib/cli/src/commands/package/tag.rs @@ -13,7 +13,7 @@ use std::{ path::{Path, PathBuf}, str::FromStr, }; -use wasmer_api::WasmerClient; +use wasmer_api::{types::PackageVersionWithPackage, WasmerClient}; use wasmer_config::package::{ Manifest, NamedPackageId, NamedPackageIdent, PackageBuilder, PackageHash, PackageIdent, }; @@ -88,6 +88,10 @@ pub struct PackageTag { value_enum )] pub wait: PublishWait, + + #[clap(skip)] + /// The package related to the NamedPackageId the user chose to tag. + pub(crate) maybe_user_package: Option, } impl PackageTag { @@ -373,7 +377,7 @@ impl PackageTag { } async fn get_version( - &self, + &mut self, client: &WasmerClient, manifest: Option<&Manifest>, manifest_path: Option<&Path>, @@ -425,6 +429,28 @@ impl PackageTag { registry_version.clone() }; + // Must necessarily bump if there's a package with the chosen version with a different hash. + let must_bump = { + let maybe_pkg = wasmer_api::query::get_package_version( + client, + full_pkg_name.to_string(), + user_version.to_string(), + ) + .await?; + let maybe_hash = maybe_pkg + .as_ref() + .and_then(|p| p.distribution_v3.pirita_sha256_hash.clone()); + + self.maybe_user_package = maybe_pkg; + + if let Some(hash) = maybe_hash { + let registry_package_hash = PackageHash::from_str(&format!("sha256:{hash}"))?; + registry_package_hash != self.package_hash + } else { + false + } + }; + if user_version <= registry_version { if self.bump { user_version = registry_version.clone(); @@ -433,12 +459,34 @@ impl PackageTag { let theme = ColorfulTheme::default(); let mut new_version = registry_version.clone(); new_version.patch += 1; - if Confirm::with_theme(&theme) + if must_bump { + eprintln!("{}: Registry already has version {user_version} of {full_pkg_name}, but with different contents.", "Warn".bold().yellow()); + eprintln!( + "{}: Not bumping the version will make this action fail.", + "Warn".bold().yellow() + ); + let res = Confirm::with_theme(&theme) + .with_prompt(format!("Continue ({user_version} -> {new_version})?")) + .interact()?; + if res { + user_version = new_version.clone(); + self.update_manifest_version(manifest_path, manifest, &user_version) + .await?; + } else { + anyhow::bail!( + "Refusing to map two different releases of {full_pkg_name} to the same version." + ) + } + } else { + let res = Confirm::with_theme(&theme) .with_prompt(format!("Do you want to bump the package's version ({user_version} -> {new_version})?")) - .interact()? { + .interact()?; + if res { user_version = new_version.clone(); - self.update_manifest_version(manifest_path, manifest, &user_version).await?; - } + self.update_manifest_version(manifest_path, manifest, &user_version) + .await?; + } + } } } @@ -450,7 +498,9 @@ impl PackageTag { Some(v) => Ok(v), None => { if self.non_interactive { - anyhow::bail!("No package name specified: use --version ") + anyhow::bail!( + "No package version specified: use --version " + ) } else { let version = crate::utils::prompts::prompt_for_package_version( "Enter the package version", @@ -468,7 +518,7 @@ impl PackageTag { } async fn synthesize_id( - &self, + &mut self, client: &WasmerClient, manifest: Option<&Manifest>, manifest_path: Option<&Path>, @@ -504,7 +554,7 @@ impl PackageTag { } pub async fn tag( - &self, + &mut self, client: &WasmerClient, manifest: Option<&Manifest>, manifest_path: Option<&Path>, @@ -547,20 +597,25 @@ impl PackageTag { return Ok(false); } - if let Some(pkg) = wasmer_api::query::get_package_version( - client, - id.full_name.clone(), - id.version.to_string(), - ) - .await? - { - if let Some(hash) = pkg.distribution_v3.pirita_sha256_hash { - let registry_package_hash = PackageHash::from_str(&format!("sha256:{hash}"))?; - if registry_package_hash == self.package_hash { - return Ok(false); - } + let hash = if let Some(pkg) = self.maybe_user_package.as_ref() { + pkg.distribution_v3.pirita_sha256_hash.clone() + } else { + wasmer_api::query::get_package_version( + client, + id.full_name.clone(), + id.version.to_string(), + ) + .await? + .and_then(|p| p.distribution_v3.pirita_sha256_hash) + }; + + if let Some(hash) = hash { + let registry_package_hash = PackageHash::from_str(&format!("sha256:{hash}"))?; + if registry_package_hash == self.package_hash { + return Ok(false); } } + Ok(true) } } @@ -569,7 +624,7 @@ impl PackageTag { impl AsyncCliCommand for PackageTag { type Output = (); - async fn run_async(self) -> Result { + async fn run_async(mut self) -> Result { tracing::info!("Checking if user is logged in"); let client = login_user(&self.api, &self.env, !self.non_interactive, "tag a package").await?;