diff --git a/rust/Cargo.lock b/rust/Cargo.lock index ac038f2..1610a75 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -566,9 +566,9 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cli-engine" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff58277a6317a5efa96fd6e8d5f907a389d0be40bc6069191eb60957a9b2d549" +checksum = "9aa5f4804af96b594f5903628dc3f12c04a9a0a27dc691c851ffa9a0fcf0477e" dependencies = [ "async-trait", "base64 0.22.1", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 3d6f986..a35c12e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -20,7 +20,7 @@ async-trait = "0.1" bytes = "1" chrono = { version = "0.4", default-features = false, features = ["clock", "serde"] } clap = { version = "4.5", features = ["std", "string"] } -cli-engine = { features = ["pkce-auth"], version = "0.4.5" } +cli-engine = { features = ["pkce-auth"], version = "0.4.6" } dirs = "6" domains-client = { path = "domains-client" } fancy-regex = "0.14" diff --git a/rust/src/domain/available.rs b/rust/src/domain/available.rs index 220bf3d..a5dfc91 100644 --- a/rust/src/domain/available.rs +++ b/rust/src/domain/available.rs @@ -36,7 +36,7 @@ pub(super) fn command() -> RuntimeCommandSpec { ) .with_system("domain") .with_tier(Tier::Read) - .with_default_fields("domain,available,definitive,price,currency") + .with_default_fields("domain,available,definitive,price,renewalPrice,currency,period") .with_output_schema::() .with_scopes(&[DOMAINS_READ]) .with_arg( @@ -79,8 +79,9 @@ pub(super) fn command() -> RuntimeCommandSpec { // Emit the required identity fields concretely (never JSON null): the // domain falls back to the known input, and missing booleans read as // false — matching how availability is treated for the next action. + let resolved_domain = body.domain.clone().unwrap_or_else(|| domain.clone()); let mut result = json!({ - "domain": body.domain.clone().unwrap_or_else(|| domain.clone()), + "domain": resolved_domain, "available": body.available.unwrap_or(false), "definitive": body.definitive.unwrap_or(false), }); @@ -107,14 +108,31 @@ pub(super) fn command() -> RuntimeCommandSpec { if body.available.unwrap_or(false) { Ok(cmd.with_next_actions(vec![ next_action("domain quote ", "Price a registration") - .with_param("domain", NextActionParam::required()), + .with_param("domain", NextActionParam::value(resolved_domain)), ])) } else { Ok(cmd.with_next_actions(vec![ + // `domain suggest` accepts a seed domain, so the domain just + // checked as taken is a valid query to copy/paste directly. next_action("domain suggest ", "Find alternatives") - .with_param("query", NextActionParam::required()), + .with_param("query", NextActionParam::value(resolved_domain)), ])) } }, ) } + +#[cfg(test)] +mod tests { + use super::command; + + #[test] + fn default_fields_includes_renewal_price() { + // Regression for GDDEVPLAT-133: `renewalPrice` was computed and present + // in `--output json` but silently dropped from the default table view. + // An exact field match (not a substring check) so a future field like + // `renewalPrice1Year` can't produce a false pass here. + let fields = command().spec.default_fields.expect("default fields set"); + assert!(fields.split(',').any(|f| f == "renewalPrice"), "{fields}"); + } +} diff --git a/rust/src/domain/quote.rs b/rust/src/domain/quote.rs index 26941ed..5a3617e 100644 --- a/rust/src/domain/quote.rs +++ b/rust/src/domain/quote.rs @@ -190,7 +190,7 @@ pub(super) fn command() -> RuntimeCommandSpec { .with_system("domain") .with_tier(Tier::Read) .with_default_fields( - "domain,available,price,currency,period,quoteToken,expiresAt,agreements", + "domain,available,price,renewalPrice,currency,period,quoteToken,expiresAt,agreements", ) .with_output_schema::() .with_scopes(&[DOMAINS_READ]) @@ -327,9 +327,12 @@ pub(super) fn command() -> RuntimeCommandSpec { } else { // Not available (or no token was issued): point at discovery, the // same next step `domain available` offers for a taken name. + // `domain suggest` accepts a seed domain, so the domain just + // quoted is a valid query to copy/paste directly. + let resolved_domain = quote.domain.clone().unwrap_or_else(|| domain.clone()); next_actions.push( next_action("domain suggest ", "Find an available alternative") - .with_param("query", NextActionParam::required()), + .with_param("query", NextActionParam::value(resolved_domain)), ); } @@ -337,3 +340,18 @@ pub(super) fn command() -> RuntimeCommandSpec { }, ) } + +#[cfg(test)] +mod tests { + use super::command; + + #[test] + fn default_fields_includes_renewal_price() { + // Regression for GDDEVPLAT-133: `renewalPrice` was computed and present + // in `--output json` but silently dropped from the default table view. + // An exact field match (not a substring check) so a future field like + // `renewalPrice1Year` can't produce a false pass here. + let fields = command().spec.default_fields.expect("default fields set"); + assert!(fields.split(',').any(|f| f == "renewalPrice"), "{fields}"); + } +} diff --git a/rust/src/scopes_cmd.rs b/rust/src/scopes_cmd.rs index 58f3b3d..0f70a0d 100644 --- a/rust/src/scopes_cmd.rs +++ b/rust/src/scopes_cmd.rs @@ -84,6 +84,7 @@ pub(crate) fn auth_scopes_command() -> RuntimeCommandSpec { .with_system("auth") .with_tier(Tier::Read) .with_output_schema::() + .with_default_fields("scope,description,commands,default") .no_auth(true) .with_arg( clap::Arg::new("command")