CLI: generate a fixed list of valid values for enum types (#442)

This commit is contained in:
Adam Leventhal 2023-04-26 15:15:07 -07:00 committed by GitHub
parent b2e1eee042
commit 6a515c304f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 376 additions and 100 deletions

View File

@ -4,7 +4,7 @@ use heck::ToKebabCase;
use openapiv3::OpenAPI;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use typify::{TypeSpaceImpl, TypeStructPropInfo};
use typify::{Type, TypeEnumVariant, TypeSpaceImpl, TypeStructPropInfo};
use crate::{
method::{
@ -247,7 +247,6 @@ impl Generator {
prop_type
};
let prop_type_ident = prop_type.ident();
let scalar =
prop_type.has_impl(TypeSpaceImpl::FromStr);
let prop_name = prop_name.to_kebab_case();
@ -266,7 +265,7 @@ impl Generator {
prop_name.clone(),
required,
description.map(str::to_string),
prop_type_ident.clone(),
prop_type,
)
})
})
@ -296,52 +295,34 @@ impl Generator {
OperationParameterKind::Body(_) => unreachable!(),
};
let OperationParameterType::Type(arg_type_id) = &param.typ else {
let OperationParameterType::Type(arg_type_id) = &param.typ
else {
panic!()
};
let arg_type = self.type_space.get_type(arg_type_id).unwrap();
let arg_details = arg_type.details();
let arg_type_name = match &arg_details{
typify::TypeDetails::Option(opt_id) => {
let inner_type = self.type_space.get_type(opt_id).unwrap();
inner_type.ident()
}
_ => {
arg_type.ident()
}
let maybe_inner_type =
if let typify::TypeDetails::Option(inner_type_id) =
arg_type.details()
{
let inner_type =
self.type_space.get_type(&inner_type_id).unwrap();
Some(inner_type)
} else {
None
};
let arg_type = if let Some(inner_type) = maybe_inner_type {
inner_type
} else {
arg_type
};
let help = param.description.as_ref().map(|description| {
quote! {
.help(#description)
}
});
quote! {
clap::Arg::new(#arg_name)
.long(#arg_name)
.required(#required)
.value_parser(clap::value_parser!(#arg_type_name))
#help
}
clap_arg(&arg_name, required, &param.description, &arg_type)
});
let body_args = body_params.iter().map(
|(prop_name, required, description, prop_type_ident)| {
let help = description.as_ref().map(|description| {
quote! {
.help(#description)
}
});
quote! {
clap::Arg::new(#prop_name)
.long(#prop_name)
.required(#required)
.value_parser(clap::value_parser!(
#prop_type_ident
))
#help
}
|(prop_name, required, description, prop_type)| {
clap_arg(prop_name, *required, description, prop_type)
},
);
@ -421,25 +402,24 @@ impl Generator {
// Build up the iterator processing each body property we can handle.
let body_args =
body_params
.iter()
.map(|(prop_name, _, _, prop_type_ident)| {
let prop_fn =
format_ident!("{}", sanitize(prop_name, Case::Snake));
quote! {
if let Some(value) =
matches.get_one::<#prop_type_ident>(
#prop_name,
)
{
// clone here in case the arg type
// doesn't impl TryFrom<&T>
request = request.body_map(|body| {
body.#prop_fn(value.clone())
})
}
body_params.iter().map(|(prop_name, _, _, prop_type)| {
let prop_fn =
format_ident!("{}", sanitize(prop_name, Case::Snake));
let prop_type_ident = prop_type.ident();
quote! {
if let Some(value) =
matches.get_one::<#prop_type_ident>(
#prop_name,
)
{
// clone here in case the arg type
// doesn't impl TryFrom<&T>
request = request.body_map(|body| {
body.#prop_fn(value.clone())
})
}
});
}
});
let (_, success_type) = self.extract_responses(
method,
@ -520,3 +500,68 @@ impl Generator {
}
}
}
fn clap_arg(
arg_name: &str,
required: bool,
description: &Option<String>,
arg_type: &Type,
) -> TokenStream {
let help = description.as_ref().map(|description| {
quote! {
.help(#description)
}
});
let arg_type_name = arg_type.ident();
// For enums that have **only** simple variants, we do some slightly
// fancier argument handling to expose the possible values. In particular,
// we use clap's `PossibleValuesParser` with each variant converted to a
// string. Then we use TypedValueParser::map to translate that into the
// actual type of the enum.
let maybe_enum_parser =
if let typify::TypeDetails::Enum(e) = arg_type.details() {
let maybe_var_names = e
.variants()
.map(|(var_name, var_details)| {
if let TypeEnumVariant::Simple = var_details {
Some(format_ident!("{}", var_name))
} else {
None
}
})
.collect::<Option<Vec<_>>>();
maybe_var_names.map(|var_names| {
quote! {
clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
#( #arg_type_name :: #var_names.to_string(), )*
]),
|s| #arg_type_name :: try_from(s).unwrap()
)
}
})
} else {
None
};
let value_parser = if let Some(enum_parser) = maybe_enum_parser {
enum_parser
} else {
// Let clap pick a value parser for us. This has the benefit of
// allowing for override implementations. A generated client may
// implement ValueParserFactory for a type to create a custom parser.
quote! {
clap::value_parser!(#arg_type_name)
}
};
quote! {
clap::Arg::new(#arg_name)
.long(#arg_name)
.required(#required)
.value_parser(#value_parser)
#help
}
}

View File

@ -411,7 +411,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List groups")
}
@ -502,7 +507,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List organizations\n\nUse `GET /v1/organizations` instead")
}
@ -624,7 +636,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List projects\n\nUse `GET /v1/projects` instead")
}
@ -749,7 +768,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List disks\n\nUse `GET /v1/disks` instead")
}
@ -862,7 +886,17 @@ impl Cli {
clap::Arg::new("metric-name")
.long("metric-name")
.required(true)
.value_parser(clap::value_parser!(types::DiskMetricName)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::DiskMetricName::Activated.to_string(),
types::DiskMetricName::Flush.to_string(),
types::DiskMetricName::Read.to_string(),
types::DiskMetricName::ReadBytes.to_string(),
types::DiskMetricName::Write.to_string(),
types::DiskMetricName::WriteBytes.to_string(),
]),
|s| types::DiskMetricName::try_from(s).unwrap(),
)),
)
.arg(
clap::Arg::new("end-time")
@ -915,7 +949,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about(
"List images\n\nList images in a project. The images are returned sorted by \
@ -1031,7 +1070,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List instances")
}
@ -1180,7 +1224,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List an instance's disks\n\nUse `GET /v1/instances/{instance}/disks` instead")
}
@ -1329,7 +1378,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List network interfaces")
}
@ -1735,7 +1789,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List snapshots")
}
@ -1851,7 +1910,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List VPCs")
}
@ -2069,7 +2133,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List routers")
}
@ -2245,7 +2314,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List routes\n\nList the routes associated with a router in a particular VPC.")
}
@ -2439,7 +2513,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List subnets")
}
@ -2638,7 +2717,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List network interfaces")
}
@ -2692,7 +2776,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("Fetch the silo\u{a0}groups the current user belongs to")
}
@ -2710,7 +2799,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about(
"List SSH public keys\n\nLists SSH public keys for the currently authenticated \
@ -2819,7 +2913,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about(
"List system-wide certificates\n\nReturns a list of all the system-wide \
@ -2846,7 +2945,12 @@ impl Cli {
clap::Arg::new("service")
.long("service")
.required(true)
.value_parser(clap::value_parser!(types::ServiceUsingCertificate))
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::ServiceUsingCertificate::ExternalApi.to_string(),
]),
|s| types::ServiceUsingCertificate::try_from(s).unwrap(),
))
.help("The service using this certificate"),
)
.about(
@ -2893,7 +2997,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List physical disks")
}
@ -2911,7 +3020,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List racks")
}
@ -2941,7 +3055,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List sleds")
}
@ -2978,7 +3097,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List physical disks attached to sleds")
}
@ -2996,7 +3120,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about(
"List system-wide images\n\nReturns a list of all the system-wide images. \
@ -3066,7 +3195,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List IP pools")
}
@ -3206,7 +3342,14 @@ impl Cli {
clap::Arg::new("metric-name")
.long("metric-name")
.required(true)
.value_parser(clap::value_parser!(types::SystemMetricName)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::SystemMetricName::VirtualDiskSpaceProvisioned.to_string(),
types::SystemMetricName::CpusProvisioned.to_string(),
types::SystemMetricName::RamProvisioned.to_string(),
]),
|s| types::SystemMetricName::try_from(s).unwrap(),
)),
)
.arg(
clap::Arg::new("end-time")
@ -3267,7 +3410,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List sagas")
}
@ -3296,7 +3444,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about(
"List silos\n\nLists silos that are discoverable based on the current permissions.",
@ -3335,7 +3490,13 @@ impl Cli {
clap::Arg::new("identity-mode")
.long("identity-mode")
.required(true)
.value_parser(clap::value_parser!(types::SiloIdentityMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::SiloIdentityMode::SamlJit.to_string(),
types::SiloIdentityMode::LocalOnly.to_string(),
]),
|s| types::SiloIdentityMode::try_from(s).unwrap(),
)),
)
.arg(
clap::Arg::new("name")
@ -3390,7 +3551,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List a silo's IDPs")
}
@ -3592,7 +3758,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List users in a silo")
}
@ -3629,7 +3800,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameSortMode::NameAscending.to_string(),
]),
|s| types::NameSortMode::try_from(s).unwrap(),
)),
)
.about("List built-in users")
}
@ -3671,7 +3847,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List users")
}
@ -3701,7 +3882,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List disks")
}
@ -3813,7 +4001,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List instances")
}
@ -3960,7 +4155,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List an instance's disks")
}
@ -4214,7 +4416,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List organizations")
}
@ -4322,7 +4531,14 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::NameOrIdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::NameOrIdSortMode::NameAscending.to_string(),
types::NameOrIdSortMode::NameDescending.to_string(),
types::NameOrIdSortMode::IdAscending.to_string(),
]),
|s| types::NameOrIdSortMode::try_from(s).unwrap(),
)),
)
.about("List projects")
}
@ -4460,7 +4676,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("View version and update status of component tree")
}
@ -4478,7 +4699,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List all update deployments")
}
@ -4527,7 +4753,12 @@ impl Cli {
clap::Arg::new("sort-by")
.long("sort-by")
.required(false)
.value_parser(clap::value_parser!(types::IdSortMode)),
.value_parser(clap::builder::TypedValueParser::map(
clap::builder::PossibleValuesParser::new([
types::IdSortMode::IdAscending.to_string()
]),
|s| types::IdSortMode::try_from(s).unwrap(),
)),
)
.about("List all updates")
}