From 6677d93978bb496dc3638b9b48826150ae3af03b Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 12 Feb 2025 13:53:11 +0100 Subject: [PATCH 1/6] feat(stackable-versioned): Add support for multiple k8s `shortname` arguments --- .../fixtures/inputs/k8s/shortnames.rs | 9 ++ ...os__test__k8s_snapshots@shortnames.rs.snap | 55 ++++++++++++ .../src/attrs/k8s.rs | 85 ++++++++++++++++++- .../src/codegen/container/mod.rs | 4 +- .../src/codegen/container/struct.rs | 11 +-- 5 files changed, 156 insertions(+), 8 deletions(-) create mode 100644 crates/stackable-versioned-macros/fixtures/inputs/k8s/shortnames.rs create mode 100644 crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@shortnames.rs.snap diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/shortnames.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/shortnames.rs new file mode 100644 index 000000000..aa43ca7b0 --- /dev/null +++ b/crates/stackable-versioned-macros/fixtures/inputs/k8s/shortnames.rs @@ -0,0 +1,9 @@ +#[versioned( + version(name = "v1alpha1"), + k8s(group = "stackable.tech", shortname = "f", shortname = "fo",) +)] +// --- +#[derive( + Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, kube::CustomResource, +)] +pub(crate) struct FooSpec {} diff --git a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@shortnames.rs.snap b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@shortnames.rs.snap new file mode 100644 index 000000000..b92e44ecb --- /dev/null +++ b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@shortnames.rs.snap @@ -0,0 +1,55 @@ +--- +source: crates/stackable-versioned-macros/src/lib.rs +expression: formatted +input_file: crates/stackable-versioned-macros/fixtures/inputs/k8s/shortnames.rs +--- +#[automatically_derived] +pub(crate) mod v1alpha1 { + use super::*; + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] + #[kube( + group = "stackable.tech", + version = "v1alpha1", + kind = "Foo", + shortname = "f", + shortname = "fo" + )] + pub struct FooSpec {} +} +#[automatically_derived] +pub(crate) enum Foo { + V1Alpha1, +} +#[automatically_derived] +impl ::std::fmt::Display for Foo { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> ::std::result::Result<(), ::std::fmt::Error> { + match self { + Self::V1Alpha1 => f.write_str("v1alpha1"), + } + } +} +#[automatically_derived] +impl Foo { + /// Generates a merged CRD containing all versions and marking `stored_apiversion` as stored. + pub fn merged_crd( + stored_apiversion: Self, + ) -> ::std::result::Result< + ::k8s_openapi::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition, + ::kube::core::crd::MergeError, + > { + ::kube::core::crd::merge_crds( + vec![< v1alpha1::Foo as ::kube::core::CustomResourceExt > ::crd()], + &stored_apiversion.to_string(), + ) + } +} diff --git a/crates/stackable-versioned-macros/src/attrs/k8s.rs b/crates/stackable-versioned-macros/src/attrs/k8s.rs index 0397d12c7..de948282c 100644 --- a/crates/stackable-versioned-macros/src/attrs/k8s.rs +++ b/crates/stackable-versioned-macros/src/attrs/k8s.rs @@ -32,7 +32,8 @@ pub(crate) struct KubernetesArguments { // schema // scale // printcolumn - pub(crate) shortname: Option, + #[darling(multiple, rename = "shortname")] + pub(crate) shortnames: Vec, // category // selectable // doc @@ -41,6 +42,88 @@ pub(crate) struct KubernetesArguments { pub(crate) skip: Option, } +// #[derive(Debug, Default, Clone)] +// pub struct FromMetaVec(Vec); + +// impl Deref for FromMetaVec { +// type Target = Vec; + +// fn deref(&self) -> &Self::Target { +// &self.0 +// } +// } + +// impl FromMeta for FromMetaVec { +// fn from_nested_meta(item: &darling::ast::NestedMeta) -> darling::Result { +// (match *item { +// darling::ast::NestedMeta::Lit(ref lit) => Self::from_value(lit), +// darling::ast::NestedMeta::Meta(ref mi) => Self::from_meta(mi), +// }) +// .map_err(|e| e.with_span(item)) +// } + +// fn from_meta(item: &syn::Meta) -> darling::Result { +// (match *item { +// syn::Meta::Path(_) => Self::from_word(), +// syn::Meta::List(ref value) => Self::from_list( +// &darling::ast::NestedMeta::parse_meta_list(value.tokens.clone())?[..], +// ), +// syn::Meta::NameValue(ref value) => Self::from_expr(&value.value), +// }) +// .map_err(|e| e.with_span(item)) +// } + +// fn from_none() -> Option { +// None +// } + +// fn from_word() -> darling::Result { +// Err(darling::Error::unsupported_format("word")) +// } + +// fn from_list(items: &[darling::ast::NestedMeta]) -> darling::Result { +// Err(darling::Error::unsupported_format("list")) +// } + +// fn from_value(value: &syn::Lit) -> darling::Result { +// (match *value { +// syn::Lit::Bool(ref b) => Self::from_bool(b.value), +// syn::Lit::Str(ref s) => Self::from_string(&s.value()), +// syn::Lit::Char(ref ch) => Self::from_char(ch.value()), +// _ => Err(darling::Error::unexpected_lit_type(value)), +// }) +// .map_err(|e| e.with_span(value)) +// } + +// fn from_expr(expr: &syn::Expr) -> darling::Result { +// match *expr { +// syn::Expr::Lit(ref lit) => Self::from_value(&lit.lit), +// syn::Expr::Group(ref group) => { +// // syn may generate this invisible group delimiter when the input to the darling +// // proc macro (specifically, the attributes) are generated by a +// // macro_rules! (e.g. propagating a macro_rules!'s expr) +// // Since we want to basically ignore these invisible group delimiters, +// // we just propagate the call to the inner expression. +// Self::from_expr(&group.expr) +// } +// _ => Err(darling::Error::unexpected_expr_type(expr)), +// } +// .map_err(|e| e.with_span(expr)) +// } + +// fn from_char(value: char) -> darling::Result { +// Err(darling::Error::unexpected_type("char")) +// } + +// fn from_string(value: &str) -> darling::Result { +// Err(darling::Error::unexpected_type("string")) +// } + +// fn from_bool(value: bool) -> darling::Result { +// Err(darling::Error::unexpected_type("bool")) +// } +// } + /// This struct contains supported kubernetes skip arguments. /// /// Supported arguments are: diff --git a/crates/stackable-versioned-macros/src/codegen/container/mod.rs b/crates/stackable-versioned-macros/src/codegen/container/mod.rs index 580c857dd..6a7729f18 100644 --- a/crates/stackable-versioned-macros/src/codegen/container/mod.rs +++ b/crates/stackable-versioned-macros/src/codegen/container/mod.rs @@ -280,7 +280,7 @@ pub(crate) struct KubernetesOptions { // schema // scale // printcolumn - pub(crate) shortname: Option, + pub(crate) shortnames: Vec, // category // selectable // doc @@ -301,7 +301,7 @@ impl From for KubernetesOptions { .crates .map_or_else(KubernetesCrateOptions::default, |crates| crates.into()), status: args.status, - shortname: args.shortname, + shortnames: args.shortnames, skip_merged_crd: args.skip.map_or(false, |s| s.merged_crd.is_present()), } } diff --git a/crates/stackable-versioned-macros/src/codegen/container/struct.rs b/crates/stackable-versioned-macros/src/codegen/container/struct.rs index 5d3038f7c..081b9e9e8 100644 --- a/crates/stackable-versioned-macros/src/codegen/container/struct.rs +++ b/crates/stackable-versioned-macros/src/codegen/container/struct.rs @@ -282,10 +282,11 @@ impl Struct { .status .as_ref() .map(|s| quote! { , status = #s }); - let shortname = kubernetes_options - .shortname - .as_ref() - .map(|s| quote! { , shortname = #s }); + let shortnames: TokenStream = kubernetes_options + .shortnames + .iter() + .map(|s| quote! { , shortname = #s }) + .collect(); Some(quote! { // The end-developer needs to derive CustomResource and JsonSchema. @@ -294,7 +295,7 @@ impl Struct { // These must be comma separated (except the last) as they always exist: group = #group, version = #version, kind = #kind // These fields are optional, and therefore the token stream must prefix each with a comma: - #singular #plural #namespaced #crates #status #shortname + #singular #plural #namespaced #crates #status #shortnames )] }) } From 581dd954e840b0fa3e2cc86799c855147d707b15 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 12 Feb 2025 13:56:00 +0100 Subject: [PATCH 2/6] chore(stackable-versioned): Update changelog --- crates/stackable-versioned/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/stackable-versioned/CHANGELOG.md b/crates/stackable-versioned/CHANGELOG.md index 487ef1246..39fd686dd 100644 --- a/crates/stackable-versioned/CHANGELOG.md +++ b/crates/stackable-versioned/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- Add support for multiple k8s `shortname` arguments ([#958]). + +[#958]: https://github.com/stackabletech/operator-rs/pull/958 + ## [0.5.0] - 2024-12-03 ### Added From 996a732f04be0ff77bccbfdf85472cb7796eff4f Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 12 Feb 2025 13:58:12 +0100 Subject: [PATCH 3/6] chore(stackable-versioned): Remove commented out code --- .../src/attrs/k8s.rs | 82 ------------------- 1 file changed, 82 deletions(-) diff --git a/crates/stackable-versioned-macros/src/attrs/k8s.rs b/crates/stackable-versioned-macros/src/attrs/k8s.rs index de948282c..e4a854e36 100644 --- a/crates/stackable-versioned-macros/src/attrs/k8s.rs +++ b/crates/stackable-versioned-macros/src/attrs/k8s.rs @@ -42,88 +42,6 @@ pub(crate) struct KubernetesArguments { pub(crate) skip: Option, } -// #[derive(Debug, Default, Clone)] -// pub struct FromMetaVec(Vec); - -// impl Deref for FromMetaVec { -// type Target = Vec; - -// fn deref(&self) -> &Self::Target { -// &self.0 -// } -// } - -// impl FromMeta for FromMetaVec { -// fn from_nested_meta(item: &darling::ast::NestedMeta) -> darling::Result { -// (match *item { -// darling::ast::NestedMeta::Lit(ref lit) => Self::from_value(lit), -// darling::ast::NestedMeta::Meta(ref mi) => Self::from_meta(mi), -// }) -// .map_err(|e| e.with_span(item)) -// } - -// fn from_meta(item: &syn::Meta) -> darling::Result { -// (match *item { -// syn::Meta::Path(_) => Self::from_word(), -// syn::Meta::List(ref value) => Self::from_list( -// &darling::ast::NestedMeta::parse_meta_list(value.tokens.clone())?[..], -// ), -// syn::Meta::NameValue(ref value) => Self::from_expr(&value.value), -// }) -// .map_err(|e| e.with_span(item)) -// } - -// fn from_none() -> Option { -// None -// } - -// fn from_word() -> darling::Result { -// Err(darling::Error::unsupported_format("word")) -// } - -// fn from_list(items: &[darling::ast::NestedMeta]) -> darling::Result { -// Err(darling::Error::unsupported_format("list")) -// } - -// fn from_value(value: &syn::Lit) -> darling::Result { -// (match *value { -// syn::Lit::Bool(ref b) => Self::from_bool(b.value), -// syn::Lit::Str(ref s) => Self::from_string(&s.value()), -// syn::Lit::Char(ref ch) => Self::from_char(ch.value()), -// _ => Err(darling::Error::unexpected_lit_type(value)), -// }) -// .map_err(|e| e.with_span(value)) -// } - -// fn from_expr(expr: &syn::Expr) -> darling::Result { -// match *expr { -// syn::Expr::Lit(ref lit) => Self::from_value(&lit.lit), -// syn::Expr::Group(ref group) => { -// // syn may generate this invisible group delimiter when the input to the darling -// // proc macro (specifically, the attributes) are generated by a -// // macro_rules! (e.g. propagating a macro_rules!'s expr) -// // Since we want to basically ignore these invisible group delimiters, -// // we just propagate the call to the inner expression. -// Self::from_expr(&group.expr) -// } -// _ => Err(darling::Error::unexpected_expr_type(expr)), -// } -// .map_err(|e| e.with_span(expr)) -// } - -// fn from_char(value: char) -> darling::Result { -// Err(darling::Error::unexpected_type("char")) -// } - -// fn from_string(value: &str) -> darling::Result { -// Err(darling::Error::unexpected_type("string")) -// } - -// fn from_bool(value: bool) -> darling::Result { -// Err(darling::Error::unexpected_type("bool")) -// } -// } - /// This struct contains supported kubernetes skip arguments. /// /// Supported arguments are: From 3cbf4a0f50a69758a832a5c9bc41bf5002785eaf Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 12 Feb 2025 13:58:44 +0100 Subject: [PATCH 4/6] chore(stackable-versioned): Update doc-comment for shortname --- crates/stackable-versioned-macros/src/attrs/k8s.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-versioned-macros/src/attrs/k8s.rs b/crates/stackable-versioned-macros/src/attrs/k8s.rs index e4a854e36..3b322a834 100644 --- a/crates/stackable-versioned-macros/src/attrs/k8s.rs +++ b/crates/stackable-versioned-macros/src/attrs/k8s.rs @@ -16,7 +16,7 @@ use syn::Path; /// - `namespaced`, to specify that this is a namespaced resource rather than cluster level. /// - `crates`: Override specific crates. /// - `status`: Sets the specified struct as the status subresource. -/// - `shortname`: Sets the shortname of the CRD. +/// - `shortname`: Sets one or more shortnames for the CRD. /// - `skip`, which controls skipping parts of the generation. #[derive(Clone, Debug, FromMeta)] pub(crate) struct KubernetesArguments { From 227807507187252a402f3e1f38b192229cea5e84 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Fri, 14 Feb 2025 11:13:43 +0100 Subject: [PATCH 5/6] docs(stackable-versioned): Improve CRD shortname argument description --- crates/stackable-versioned-macros/src/attrs/k8s.rs | 2 +- crates/stackable-versioned-macros/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/stackable-versioned-macros/src/attrs/k8s.rs b/crates/stackable-versioned-macros/src/attrs/k8s.rs index 3b322a834..6323ba694 100644 --- a/crates/stackable-versioned-macros/src/attrs/k8s.rs +++ b/crates/stackable-versioned-macros/src/attrs/k8s.rs @@ -16,7 +16,7 @@ use syn::Path; /// - `namespaced`, to specify that this is a namespaced resource rather than cluster level. /// - `crates`: Override specific crates. /// - `status`: Sets the specified struct as the status subresource. -/// - `shortname`: Sets one or more shortnames for the CRD. +/// - `shortname`: Sets a shortname for the CRD. This can be specified multiple times. /// - `skip`, which controls skipping parts of the generation. #[derive(Clone, Debug, FromMeta)] pub(crate) struct KubernetesArguments { diff --git a/crates/stackable-versioned-macros/src/lib.rs b/crates/stackable-versioned-macros/src/lib.rs index b28e7a431..184d7f118 100644 --- a/crates/stackable-versioned-macros/src/lib.rs +++ b/crates/stackable-versioned-macros/src/lib.rs @@ -612,7 +612,8 @@ Currently, the following arguments are supported: a cluster scoped. - `crates`: Override specific crates. - `status`: Sets the specified struct as the status subresource. -- `shortname`: Sets the shortname of the CRD. +- `shortname`: Sets a shortname for the CRD. This can be specified multiple + times. ### Versioning Items in a Module From 975a65e026ff22d6b58004e3bd37e9ded5d5682b Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Fri, 14 Feb 2025 11:27:16 +0100 Subject: [PATCH 6/6] docs(stackable-versioned): Make k8s argument descriptions consistent. I copy/pasted from the module docs to keep wrapping new-lines consistent. --- .../src/attrs/k8s.rs | 21 +++++++++++-------- crates/stackable-versioned-macros/src/lib.rs | 19 +++++++++-------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/crates/stackable-versioned-macros/src/attrs/k8s.rs b/crates/stackable-versioned-macros/src/attrs/k8s.rs index 6323ba694..9a08424b9 100644 --- a/crates/stackable-versioned-macros/src/attrs/k8s.rs +++ b/crates/stackable-versioned-macros/src/attrs/k8s.rs @@ -8,16 +8,19 @@ use syn::Path; /// /// Supported arguments are: /// -/// - `group`, which sets the CRD group, usually the domain of the company. -/// - `kind`, which allows overwriting the kind field of the CRD. This defaults to the struct name -/// (without the 'Spec' suffix). -/// - `singular`, to specify the singular name of the CR object. -/// - `plural`, to specify the plural name of the CR object. -/// - `namespaced`, to specify that this is a namespaced resource rather than cluster level. +/// - `group`: Set the group of the CR object, usually the domain of the company. +/// This argument is Required. +/// - `kind`: Override the kind field of the CR object. This defaults to the struct +/// name (without the 'Spec' suffix). +/// - `singular`: Set the singular name of the CR object. +/// - `plural`: Set the plural name of the CR object. +/// - `namespaced`: Indicate that this is a namespaced scoped resource rather than a +/// cluster scoped resource. /// - `crates`: Override specific crates. -/// - `status`: Sets the specified struct as the status subresource. -/// - `shortname`: Sets a shortname for the CRD. This can be specified multiple times. -/// - `skip`, which controls skipping parts of the generation. +/// - `status`: Set the specified struct as the status subresource. +/// - `shortname`: Set a shortname for the CR object. This can be specified multiple +/// times. +/// - `skip`: Controls skipping parts of the generation. #[derive(Clone, Debug, FromMeta)] pub(crate) struct KubernetesArguments { pub(crate) group: String, diff --git a/crates/stackable-versioned-macros/src/lib.rs b/crates/stackable-versioned-macros/src/lib.rs index 184d7f118..368f94e3d 100644 --- a/crates/stackable-versioned-macros/src/lib.rs +++ b/crates/stackable-versioned-macros/src/lib.rs @@ -603,16 +603,17 @@ println!("{}", serde_yaml::to_string(&merged_crd).unwrap()); Currently, the following arguments are supported: -- `group`: Sets the CRD group, usually the domain of the company. -- `kind`: Allows overwriting the kind field of the CRD. This defaults - to the struct name (without the 'Spec' suffix). -- `singular`: Sets the singular name. -- `plural`: Sets the plural name. -- `namespaced`: Specifies that this is a namespaced resource rather than - a cluster scoped. +- `group`: Set the group of the CR object, usually the domain of the company. + This argument is Required. +- `kind`: Override the kind field of the CR object. This defaults to the struct + name (without the 'Spec' suffix). +- `singular`: Set the singular name of the CR object. +- `plural`: Set the plural name of the CR object. +- `namespaced`: Indicate that this is a namespaced scoped resource rather than a + cluster scoped resource. - `crates`: Override specific crates. -- `status`: Sets the specified struct as the status subresource. -- `shortname`: Sets a shortname for the CRD. This can be specified multiple +- `status`: Set the specified struct as the status subresource. +- `shortname`: Set a shortname for the CR object. This can be specified multiple times. ### Versioning Items in a Module