diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/basic.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/basic.rs index 4e4449a0c..3d0251c97 100644 --- a/crates/stackable-versioned-macros/fixtures/inputs/k8s/basic.rs +++ b/crates/stackable-versioned-macros/fixtures/inputs/k8s/basic.rs @@ -10,7 +10,9 @@ ) )] // --- -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +#[derive( + Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, kube::CustomResource, +)] pub struct FooSpec { #[versioned( added(since = "v1beta1"), diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/module.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/module.rs index d37a5e5b0..06822a914 100644 --- a/crates/stackable-versioned-macros/fixtures/inputs/k8s/module.rs +++ b/crates/stackable-versioned-macros/fixtures/inputs/k8s/module.rs @@ -12,6 +12,14 @@ pub(crate) mod versioned { } #[versioned(k8s(group = "foo.example.org", plural = "foos", namespaced))] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] pub struct FooSpec { bar: usize, @@ -23,6 +31,14 @@ pub(crate) mod versioned { } #[versioned(k8s(group = "bar.example.org", plural = "bars"))] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] pub struct BarSpec { baz: String, } diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/module_preserve.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/module_preserve.rs index 58992b58c..f45921fab 100644 --- a/crates/stackable-versioned-macros/fixtures/inputs/k8s/module_preserve.rs +++ b/crates/stackable-versioned-macros/fixtures/inputs/k8s/module_preserve.rs @@ -13,6 +13,14 @@ pub(crate) mod versioned { } #[versioned(k8s(group = "foo.example.org", plural = "foos", namespaced))] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] pub struct FooSpec { bar: usize, @@ -24,6 +32,14 @@ pub(crate) mod versioned { } #[versioned(k8s(group = "bar.example.org", plural = "bars"))] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] pub struct BarSpec { baz: String, } diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/skip.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/skip.rs index aa9f908fa..651ca184e 100644 --- a/crates/stackable-versioned-macros/fixtures/inputs/k8s/skip.rs +++ b/crates/stackable-versioned-macros/fixtures/inputs/k8s/skip.rs @@ -11,7 +11,9 @@ ) )] // --- -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] +#[derive( + Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, kube::CustomResource, +)] pub struct FooSpec { #[versioned( added(since = "v1beta1"), diff --git a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@basic.rs.snap b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@basic.rs.snap index 694454b2c..fce0647e8 100644 --- a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@basic.rs.snap +++ b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@basic.rs.snap @@ -6,8 +6,14 @@ input_file: crates/stackable-versioned-macros/fixtures/inputs/k8s/basic.rs #[automatically_derived] pub mod v1alpha1 { use super::*; - #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "stackable.tech", version = "v1alpha1", @@ -32,8 +38,14 @@ impl ::std::convert::From for v1beta1::FooSpec { #[automatically_derived] pub mod v1beta1 { use super::*; - #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "stackable.tech", version = "v1beta1", @@ -59,8 +71,14 @@ impl ::std::convert::From for v1::FooSpec { #[automatically_derived] pub mod v1 { use super::*; - #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "stackable.tech", version = "v1", diff --git a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module.rs.snap b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module.rs.snap index c357340de..dfbe2f797 100644 --- a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module.rs.snap +++ b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module.rs.snap @@ -9,7 +9,14 @@ pub(crate) mod v1alpha1 { pub struct Baz { pub boom: Option, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "foo.example.org", version = "v1alpha1", @@ -21,7 +28,14 @@ pub(crate) mod v1alpha1 { pub bar: usize, pub foo: String, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "bar.example.org", version = "v1alpha1", @@ -73,7 +87,14 @@ pub(crate) mod v1 { pub struct Baz { pub boom: Option, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "foo.example.org", version = "v1", @@ -86,7 +107,14 @@ pub(crate) mod v1 { pub baz: bool, pub foo: String, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube(group = "bar.example.org", version = "v1", kind = "Bar", plural = "bars")] pub struct BarSpec { pub baz: String, @@ -134,7 +162,14 @@ pub(crate) mod v2alpha1 { pub struct Baz { pub boom: Option, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "foo.example.org", version = "v2alpha1", @@ -148,7 +183,14 @@ pub(crate) mod v2alpha1 { #[deprecated] pub deprecated_foo: String, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "bar.example.org", version = "v2alpha1", diff --git a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module_preserve.rs.snap b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module_preserve.rs.snap index a56f6ce55..402468292 100644 --- a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module_preserve.rs.snap +++ b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@module_preserve.rs.snap @@ -10,7 +10,14 @@ pub(crate) mod versioned { pub struct Baz { pub boom: Option, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "foo.example.org", version = "v1alpha1", @@ -22,7 +29,14 @@ pub(crate) mod versioned { pub bar: usize, pub foo: String, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "bar.example.org", version = "v1alpha1", @@ -69,7 +83,14 @@ pub(crate) mod versioned { pub struct Baz { pub boom: Option, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "foo.example.org", version = "v1", @@ -82,7 +103,14 @@ pub(crate) mod versioned { pub baz: bool, pub foo: String, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube(group = "bar.example.org", version = "v1", kind = "Bar", plural = "bars")] pub struct BarSpec { pub baz: String, @@ -125,7 +153,14 @@ pub(crate) mod versioned { pub struct Baz { pub boom: Option, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "foo.example.org", version = "v2alpha1", @@ -139,7 +174,14 @@ pub(crate) mod versioned { #[deprecated] pub deprecated_foo: String, } - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "bar.example.org", version = "v2alpha1", diff --git a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@skip.rs.snap b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@skip.rs.snap index 1b81fbf41..d5fb55027 100644 --- a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@skip.rs.snap +++ b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@skip.rs.snap @@ -6,8 +6,14 @@ input_file: crates/stackable-versioned-macros/fixtures/inputs/k8s/skip.rs #[automatically_derived] pub mod v1alpha1 { use super::*; - #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "stackable.tech", version = "v1alpha1", @@ -32,8 +38,14 @@ impl ::std::convert::From for v1beta1::FooSpec { #[automatically_derived] pub mod v1beta1 { use super::*; - #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "stackable.tech", version = "v1beta1", @@ -59,8 +71,14 @@ impl ::std::convert::From for v1::FooSpec { #[automatically_derived] pub mod v1 { use super::*; - #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] - #[derive(::kube::CustomResource)] + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] #[kube( group = "stackable.tech", version = "v1", diff --git a/crates/stackable-versioned-macros/src/attrs/k8s.rs b/crates/stackable-versioned-macros/src/attrs/k8s.rs index 085136925..f4ad98510 100644 --- a/crates/stackable-versioned-macros/src/attrs/k8s.rs +++ b/crates/stackable-versioned-macros/src/attrs/k8s.rs @@ -1,4 +1,7 @@ use darling::{util::Flag, FromMeta}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::Path; /// This struct contains supported Kubernetes arguments. /// @@ -7,21 +10,37 @@ use darling::{util::Flag, FromMeta}; /// /// Supported arguments are: /// -/// - `skip`, which controls skipping parts of the generation. -/// - `singular`, to specify the singular name of the CR object. -/// - `plural`, to specify the plural name of the CR object. +/// - `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`, which sets the CRD group, usually the domain of the company. +/// - `crates`: Override specific crates. +/// - `status`: Sets the specified struct as the status subresource. +/// - `shortname`: Sets the shortname of the CRD. +/// - `skip`, which controls skipping parts of the generation. #[derive(Clone, Debug, FromMeta)] pub(crate) struct KubernetesArguments { - pub(crate) skip: Option, + pub(crate) group: String, + pub(crate) kind: Option, pub(crate) singular: Option, pub(crate) plural: Option, - pub(crate) kind: Option, pub(crate) namespaced: Flag, - pub(crate) group: String, + // root + pub(crate) crates: Option, + pub(crate) status: Option, + // derive + // schema + // scale + // printcolumn + pub(crate) shortname: Option, + // category + // selectable + // doc + // annotation + // label + pub(crate) skip: Option, } /// This struct contains supported kubernetes skip arguments. @@ -36,3 +55,39 @@ pub(crate) struct KubernetesSkipArguments { /// this container. pub(crate) merged_crd: Flag, } + +/// This struct contains crate overrides to be passed to `#[kube]`. +#[derive(Clone, Debug, FromMeta)] +pub(crate) struct KubernetesCrateArguments { + pub(crate) kube_core: Option, + pub(crate) k8s_openapi: Option, + pub(crate) schemars: Option, + pub(crate) serde: Option, + pub(crate) serde_json: Option, +} + +impl ToTokens for KubernetesCrateArguments { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let mut crate_overrides = TokenStream::new(); + + if let Some(path) = &self.k8s_openapi { + crate_overrides.extend(quote! { k8s_openapi = #path, }); + } + if let Some(path) = &self.kube_core { + crate_overrides.extend(quote! { kube_core = #path, }); + } + if let Some(path) = &self.schemars { + crate_overrides.extend(quote! { schemars = #path, }); + } + if let Some(path) = &self.serde { + crate_overrides.extend(quote! { serde = #path, }); + } + if let Some(path) = &self.serde_json { + crate_overrides.extend(quote! { serde_json = #path, }); + } + + if !crate_overrides.is_empty() { + tokens.extend(quote! { , crates(#crate_overrides) }); + } + } +} diff --git a/crates/stackable-versioned-macros/src/codegen/container/mod.rs b/crates/stackable-versioned-macros/src/codegen/container/mod.rs index 0bdaa3309..ef8f247b6 100644 --- a/crates/stackable-versioned-macros/src/codegen/container/mod.rs +++ b/crates/stackable-versioned-macros/src/codegen/container/mod.rs @@ -4,7 +4,10 @@ use quote::quote; use syn::{Attribute, Ident, ItemEnum, ItemStruct, Visibility}; use crate::{ - attrs::{container::StandaloneContainerAttributes, k8s::KubernetesArguments}, + attrs::{ + container::StandaloneContainerAttributes, + k8s::{KubernetesArguments, KubernetesCrateArguments}, + }, codegen::{ container::{r#enum::Enum, r#struct::Struct}, VersionDefinition, @@ -250,23 +253,39 @@ pub(crate) struct ContainerOptions { #[derive(Debug)] pub(crate) struct KubernetesOptions { + pub(crate) group: String, + pub(crate) kind: Option, pub(crate) singular: Option, pub(crate) plural: Option, - pub(crate) skip_merged_crd: bool, - pub(crate) kind: Option, pub(crate) namespaced: bool, - pub(crate) group: String, + // root + pub(crate) crates: Option, + pub(crate) status: Option, + // derive + // schema + // scale + // printcolumn + pub(crate) shortname: Option, + // category + // selectable + // doc + // annotation + // label + pub(crate) skip_merged_crd: bool, } impl From for KubernetesOptions { fn from(args: KubernetesArguments) -> Self { KubernetesOptions { - skip_merged_crd: args.skip.map_or(false, |s| s.merged_crd.is_present()), - namespaced: args.namespaced.is_present(), - singular: args.singular, - plural: args.plural, group: args.group, kind: args.kind, + singular: args.singular, + plural: args.plural, + namespaced: args.namespaced.is_present(), + crates: args.crates, + status: args.status, + shortname: args.shortname, + 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 1dd0c8955..ae3853602 100644 --- a/crates/stackable-versioned-macros/src/codegen/container/struct.rs +++ b/crates/stackable-versioned-macros/src/codegen/container/struct.rs @@ -1,8 +1,8 @@ use std::ops::Not; -use darling::{util::IdentString, Error, FromAttributes, Result}; +use darling::{util::IdentString, Error, FromAttributes, FromMeta, Result}; use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, ToTokens}; use syn::{parse_quote, ItemStruct, Path}; use crate::{ @@ -143,12 +143,12 @@ impl Struct { } // This only returns Some, if K8s features are enabled - let kubernetes_cr_derive = self.generate_kubernetes_cr_derive(version); + let kube_attribute = self.generate_kube_attribute(version); quote! { #(#[doc = #version_docs])* #(#original_attributes)* - #kubernetes_cr_derive + #kube_attribute pub struct #ident { #fields } @@ -249,7 +249,7 @@ impl Struct { // Kubernetes-specific token generation impl Struct { - pub(crate) fn generate_kubernetes_cr_derive( + pub(crate) fn generate_kube_attribute( &self, version: &VersionDefinition, ) -> Option { @@ -266,9 +266,6 @@ impl Struct { }); // Optional arguments - let namespaced = kubernetes_options - .namespaced - .then_some(quote! { , namespaced }); let singular = kubernetes_options .singular .as_ref() @@ -277,10 +274,28 @@ impl Struct { .plural .as_ref() .map(|p| quote! { , plural = #p }); + let namespaced = kubernetes_options + .namespaced + .then_some(quote! { , namespaced }); + let crates = kubernetes_options.crates.to_token_stream(); + let status = kubernetes_options + .status + .as_ref() + .map(|s| quote! { , status = #s }); + let shortname = kubernetes_options + .shortname + .as_ref() + .map(|s| quote! { , shortname = #s }); Some(quote! { - #[derive(::kube::CustomResource)] - #[kube(group = #group, version = #version, kind = #kind #singular #plural #namespaced)] + // The end-developer needs to derive CustomResource and JsonSchema. + // This is because we don't know if they want to use a re-exported or renamed import. + #[kube( + // 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 + )] }) } None => None, @@ -291,6 +306,19 @@ impl Struct { &self, version: &VersionDefinition, ) -> Option<(IdentString, String, TokenStream)> { + let kube_core_module_default = &Path::from_string("::kube::core").expect("valid path"); + let kube_core_module = self.common.options.kubernetes_options.as_ref().map_or_else( + || quote! {#kube_core_module_default}, + |options| { + if let Some(crates) = &options.crates { + if let Some(kube_core) = &crates.kube_core { + return quote! {#kube_core}; + } + } + quote! {#kube_core_module_default} + }, + ); + match &self.common.options.kubernetes_options { Some(options) if !options.skip_merged_crd => { let enum_variant_ident = version.inner.as_variant_ident(); @@ -301,7 +329,7 @@ impl Struct { let qualified_path: Path = parse_quote!(#module_ident::#struct_ident); let merge_crds_fn_call = quote! { - <#qualified_path as ::kube::CustomResourceExt>::crd() + <#qualified_path as #kube_core_module::CustomResourceExt>::crd() }; Some((enum_variant_ident, enum_variant_string, merge_crds_fn_call)) @@ -327,6 +355,32 @@ impl Struct { // module (in standalone mode). let automatically_derived = is_nested.not().then(|| quote! {#[automatically_derived]}); + let kube_core_module_default = &Path::from_string("::kube::core").expect("valid path"); + let kube_core_module = self.common.options.kubernetes_options.as_ref().map_or_else( + || quote! {#kube_core_module_default}, + |options| { + if let Some(crates) = &options.crates { + if let Some(kube_core) = &crates.kube_core { + return quote! {#kube_core}; + } + } + quote! {#kube_core_module_default} + }, + ); + + let k8s_openapi_crate_default = &Path::from_string("::k8s_openapi").expect("valid path"); + let k8s_openapi_crate = self.common.options.kubernetes_options.as_ref().map_or_else( + || quote! {#k8s_openapi_crate_default}, + |options| { + if let Some(crates) = &options.crates { + if let Some(k8s_openapi) = &crates.k8s_openapi { + return quote! {#k8s_openapi}; + } + } + quote! {#k8s_openapi_crate_default} + }, + ); + // TODO (@Techassi): Use proper visibility instead of hard-coding 'pub' // TODO (@Techassi): Move the YAML printing code into 'stackable-versioned' so that we don't // have any cross-dependencies and the macro can be used on it's own (K8s features of course @@ -351,8 +405,8 @@ impl Struct { /// Generates a merged CRD which contains all versions defined using the `#[versioned()]` macro. 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![#(#fn_calls),*], &stored_apiversion.to_string()) + ) -> ::std::result::Result<#k8s_openapi_crate::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition, #kube_core_module::crd::MergeError> { + #kube_core_module::crd::merge_crds(vec![#(#fn_calls),*], &stored_apiversion.to_string()) } /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` diff --git a/crates/stackable-versioned-macros/src/lib.rs b/crates/stackable-versioned-macros/src/lib.rs index 8e2750d09..0ea0c3ea7 100644 --- a/crates/stackable-versioned-macros/src/lib.rs +++ b/crates/stackable-versioned-macros/src/lib.rs @@ -434,18 +434,21 @@ mod utils; /// } /// ``` /// -/// ## Kubernetes-specific Features -/// -/// This macro also offers support for Kubernetes-specific versioning, -/// especially for CustomResourceDefinitions (CRDs). These features are -/// completely opt-in. You need to enable the `k8s` feature (which enables -/// optional dependencies) and use the `k8s()` parameter in the macro. -/// #[cfg_attr( feature = "k8s", doc = r#" +## Kubernetes-specific Features + +This macro also offers support for Kubernetes-specific versioning, +especially for CustomResourceDefinitions (CRDs). These features are +completely opt-in. You need to enable the `k8s` feature (which enables +optional dependencies) and use the `k8s()` parameter in the macro. + +You need to derive both [`kube::CustomResource`] and [`schemars::JsonSchema`]. + ``` # use stackable_versioned_macros::versioned; +use kube::CustomResource; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -455,7 +458,7 @@ use serde::{Deserialize, Serialize}; version(name = "v1"), k8s(group = "example.com") )] -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] +#[derive(Clone, Debug, Deserialize, Serialize, CustomResource, JsonSchema)] pub struct FooSpec { #[versioned( added(since = "v1beta1"), @@ -470,17 +473,21 @@ let merged_crd = Foo::merged_crd(Foo::V1).unwrap(); 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. +- `crates`: Override specific crates. +- `status`: Sets the specified struct as the status subresource. +- `shortname`: Sets the shortname of the CRD. "# )] -/// 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. #[proc_macro_attribute] pub fn versioned(attrs: TokenStream, input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as Item); diff --git a/crates/stackable-versioned/CHANGELOG.md b/crates/stackable-versioned/CHANGELOG.md index e83c31fe2..af68f2211 100644 --- a/crates/stackable-versioned/CHANGELOG.md +++ b/crates/stackable-versioned/CHANGELOG.md @@ -8,6 +8,13 @@ All notable changes to this project will be documented in this file. - Add support to apply the `#[versioned()]` macro to modules to version all contained items at once ([#891]). +- Add support for passing a `status`, `crates`, and `shortname` arguments through to the `#[kube]` + derive attribute ([#914]). +- Add support for overriding `kube::core` and `k8s_openapi` in generated code ([#914]). + +### Removed + +- BREAKING: Remove the `CustomResource` derive ([#914]). ### Changed @@ -21,6 +28,7 @@ All notable changes to this project will be documented in this file. [#891]: https://github.com/stackabletech/operator-rs/pull/891 [#912]: https://github.com/stackabletech/operator-rs/pull/912 [#913]: https://github.com/stackabletech/operator-rs/pull/913 +[#914]: https://github.com/stackabletech/operator-rs/pull/914 ## [0.4.1] - 2024-10-23