diff --git a/rust/src/application/commands/mod.rs b/rust/src/application/commands/mod.rs index d5bc141..8f22ca2 100644 --- a/rust/src/application/commands/mod.rs +++ b/rust/src/application/commands/mod.rs @@ -455,9 +455,10 @@ fn update_command() -> RuntimeCommandSpec { RuntimeCommandSpec::new_with_context( CommandSpec::new("update", "Update an application") .with_long( - "Update the label or description of a GoDaddy developer-platform application \ - by its ID. At least one of --label or --description must be provided. \ - Use `application info --name ` to retrieve the application ID.", + "Update the label, description, or status of a GoDaddy developer-platform \ + application by its ID. At least one of --label, --description, or --status \ + must be provided. Use `application info --name ` to retrieve the \ + application ID.", ) .with_system("applications") .with_tier(Tier::Mutate) @@ -474,13 +475,24 @@ fn update_command() -> RuntimeCommandSpec { clap::Arg::new("label") .long("label") .value_name("LABEL") + // CommandSpec has no ArgGroup; this enforces "at least one" at parse time. + .required_unless_present_any(["description", "status"]) .help("New label"), ) .with_arg( clap::Arg::new("description") .long("description") .value_name("TEXT") + .required_unless_present_any(["label", "status"]) .help("New description"), + ) + .with_arg( + clap::Arg::new("status") + .long("status") + .value_name("STATUS") + .value_parser(["ACTIVE", "INACTIVE"]) + .required_unless_present_any(["label", "description"]) + .help("Application status (ACTIVE or INACTIVE)"), ), |ctx| async move { let id = arg_str(&ctx, "id").to_owned(); @@ -491,6 +503,9 @@ fn update_command() -> RuntimeCommandSpec { if let Some(desc) = ctx.args.get("description").and_then(|v| v.as_str()) { input.insert("description".to_owned(), json!(desc)); } + if let Some(status) = ctx.args.get("status").and_then(|v| v.as_str()) { + input.insert("status".to_owned(), json!(status)); + } let client = make_client(&ctx).await?; let data = client .update_application(&id, json!(input)) @@ -1504,6 +1519,77 @@ pub fn add_extension_group() -> RuntimeGroupSpec { mod tests { use cli_engine::{Cli, CliConfig, Stage}; + use super::update_command; + + fn update_clap_command() -> clap::Command { + update_command().spec.clap_command() + } + + #[test] + fn status_rejects_values_outside_active_inactive() { + for bad in ["active", "DISABLED", "PENDING"] { + let err = update_clap_command() + .try_get_matches_from(["update", "--id", "app-1", "--status", bad]) + .expect_err("invalid --status should be rejected"); + assert_eq!( + err.kind(), + clap::error::ErrorKind::InvalidValue, + "--status {bad:?} should fail possible-value validation, got: {err}" + ); + } + } + + #[test] + fn status_accepts_active_and_inactive() { + for good in ["ACTIVE", "INACTIVE"] { + update_clap_command() + .try_get_matches_from(["update", "--id", "app-1", "--status", good]) + .expect("ACTIVE|INACTIVE --status should be accepted"); + } + } + + #[test] + fn update_requires_at_least_one_field() { + let err = update_clap_command() + .try_get_matches_from(["update", "--id", "app-1"]) + .expect_err("update with only --id should be rejected at parse time"); + assert_eq!( + err.kind(), + clap::error::ErrorKind::MissingRequiredArgument, + "expected MissingRequiredArgument, got: {err}" + ); + } + + #[test] + fn update_accepts_any_single_field() { + update_clap_command() + .try_get_matches_from(["update", "--id", "app-1", "--label", "New"]) + .expect("--label alone should be accepted"); + update_clap_command() + .try_get_matches_from(["update", "--id", "app-1", "--description", "Desc"]) + .expect("--description alone should be accepted"); + update_clap_command() + .try_get_matches_from(["update", "--id", "app-1", "--status", "ACTIVE"]) + .expect("--status alone should be accepted"); + } + + #[test] + fn update_accepts_multiple_fields() { + update_clap_command() + .try_get_matches_from([ + "update", + "--id", + "app-1", + "--label", + "New", + "--description", + "Desc", + "--status", + "INACTIVE", + ]) + .expect("multiple update fields should be allowed together"); + } + /// API commands must stay fail-closed: `application list` calls the backend, /// so it must require authentication. Built with **no auth provider /// registered**, the engine's default `AuthRequirement::Required` must reject