diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/basic.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/basic.rs index 4e4449a0..3d0251c9 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/crate_overrides.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/crate_overrides.rs new file mode 100644 index 00000000..8b441cd0 --- /dev/null +++ b/crates/stackable-versioned-macros/fixtures/inputs/k8s/crate_overrides.rs @@ -0,0 +1,26 @@ +#[versioned( + version(name = "v1alpha1"), + version(name = "v1beta1"), + version(name = "v1"), + k8s( + group = "foo.example.org", + singular = "foo", + plural = "foos", + namespaced, + crates( + kube_core = ::kube::core + ) + ) +)] +// --- +#[derive( + Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, kube::CustomResource, +)] +pub struct FooSpec { + #[versioned( + added(since = "v1beta1"), + changed(since = "v1", from_name = "bah", from_type = "u16") + )] + bar: usize, + baz: bool, +} diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/module.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/module.rs index d37a5e5b..06822a91 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 58992b58..f45921fa 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/renamed_kind.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/renamed_kind.rs new file mode 100644 index 00000000..8cfa272d --- /dev/null +++ b/crates/stackable-versioned-macros/fixtures/inputs/k8s/renamed_kind.rs @@ -0,0 +1,24 @@ +#[versioned( + version(name = "v1alpha1"), + version(name = "v1beta1"), + version(name = "v1"), + k8s( + group = "stackable.tech", + kind = "FooBar", + singular = "foo", + plural = "foos", + namespaced, + ) +)] +// --- +#[derive( + Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, kube::CustomResource, +)] +pub struct FooSpec { + #[versioned( + added(since = "v1beta1"), + changed(since = "v1", from_name = "bah", from_type = "u16") + )] + bar: usize, + baz: bool, +} diff --git a/crates/stackable-versioned-macros/fixtures/inputs/k8s/skip.rs b/crates/stackable-versioned-macros/fixtures/inputs/k8s/skip.rs index aa9f908f..651ca184 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 694454b2..24ed425b 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", @@ -104,9 +122,9 @@ impl Foo { > { ::kube::core::crd::merge_crds( vec![ - < v1alpha1::Foo as ::kube::CustomResourceExt > ::crd(), < v1beta1::Foo as - ::kube::CustomResourceExt > ::crd(), < v1::Foo as - ::kube::CustomResourceExt > ::crd() + < v1alpha1::Foo as ::kube::core::CustomResourceExt > ::crd(), < + v1beta1::Foo as ::kube::core::CustomResourceExt > ::crd(), < v1::Foo as + ::kube::core::CustomResourceExt > ::crd() ], &stored_apiversion.to_string(), ) diff --git a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@crate_overrides.rs.snap b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@crate_overrides.rs.snap new file mode 100644 index 00000000..121bc32e --- /dev/null +++ b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@crate_overrides.rs.snap @@ -0,0 +1,180 @@ +--- +source: crates/stackable-versioned-macros/src/lib.rs +expression: formatted +input_file: crates/stackable-versioned-macros/fixtures/inputs/k8s/crate_overrides.rs +--- +#[automatically_derived] +pub mod v1alpha1 { + use super::*; + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] + #[kube( + group = "foo.example.org", + version = "v1alpha1", + kind = "Foo", + singular = "foo", + plural = "foos", + namespaced, + crates(kube_core = ::kube::core) + )] + pub struct FooSpec { + pub baz: bool, + } +} +#[automatically_derived] +impl ::std::convert::From for v1beta1::FooSpec { + fn from(__sv_foospec: v1alpha1::FooSpec) -> Self { + Self { + bah: ::std::default::Default::default(), + baz: __sv_foospec.baz, + } + } +} +#[automatically_derived] +pub mod v1beta1 { + use super::*; + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] + #[kube( + group = "foo.example.org", + version = "v1beta1", + kind = "Foo", + singular = "foo", + plural = "foos", + namespaced, + crates(kube_core = ::kube::core) + )] + pub struct FooSpec { + pub bah: u16, + pub baz: bool, + } +} +#[automatically_derived] +impl ::std::convert::From for v1::FooSpec { + fn from(__sv_foospec: v1beta1::FooSpec) -> Self { + Self { + bar: __sv_foospec.bah.into(), + baz: __sv_foospec.baz, + } + } +} +#[automatically_derived] +pub mod v1 { + use super::*; + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] + #[kube( + group = "foo.example.org", + version = "v1", + kind = "Foo", + singular = "foo", + plural = "foos", + namespaced, + crates(kube_core = ::kube::core) + )] + pub struct FooSpec { + pub bar: usize, + pub baz: bool, + } +} +#[automatically_derived] +pub enum Foo { + V1Alpha1, + V1Beta1, + V1, +} +#[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"), + Self::V1Beta1 => f.write_str("v1beta1"), + Self::V1 => f.write_str("v1"), + } + } +} +#[automatically_derived] +impl Foo { + /// 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![ + < v1alpha1::Foo as ::kube::core::CustomResourceExt > ::crd(), < + v1beta1::Foo as ::kube::core::CustomResourceExt > ::crd(), < v1::Foo as + ::kube::core::CustomResourceExt > ::crd() + ], + &stored_apiversion.to_string(), + ) + } + /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` + /// macro to a file located at `path`. + pub fn write_merged_crd

( + path: P, + stored_apiversion: Self, + operator_version: &str, + ) -> Result<(), ::stackable_versioned::Error> + where + P: AsRef<::std::path::Path>, + { + use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; + let merged_crd = Self::merged_crd(stored_apiversion) + .map_err(|err| ::stackable_versioned::Error::MergeCrd { + source: err, + })?; + YamlSchema::write_yaml_schema( + &merged_crd, + path, + operator_version, + SerializeOptions::default(), + ) + .map_err(|err| ::stackable_versioned::Error::SerializeYaml { + source: err, + }) + } + /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` + /// macro to stdout. + pub fn print_merged_crd( + stored_apiversion: Self, + operator_version: &str, + ) -> Result<(), ::stackable_versioned::Error> { + use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; + let merged_crd = Self::merged_crd(stored_apiversion) + .map_err(|err| ::stackable_versioned::Error::MergeCrd { + source: err, + })?; + YamlSchema::print_yaml_schema( + &merged_crd, + operator_version, + SerializeOptions::default(), + ) + .map_err(|err| ::stackable_versioned::Error::SerializeYaml { + source: err, + }) + } +} 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 c357340d..099c62bf 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", @@ -193,9 +235,9 @@ impl Foo { > { ::kube::core::crd::merge_crds( vec![ - < v1alpha1::Foo as ::kube::CustomResourceExt > ::crd(), < v1::Foo as - ::kube::CustomResourceExt > ::crd(), < v2alpha1::Foo as - ::kube::CustomResourceExt > ::crd() + < v1alpha1::Foo as ::kube::core::CustomResourceExt > ::crd(), < v1::Foo + as ::kube::core::CustomResourceExt > ::crd(), < v2alpha1::Foo as + ::kube::core::CustomResourceExt > ::crd() ], &stored_apiversion.to_string(), ) @@ -276,9 +318,9 @@ impl Bar { > { ::kube::core::crd::merge_crds( vec![ - < v1alpha1::Bar as ::kube::CustomResourceExt > ::crd(), < v1::Bar as - ::kube::CustomResourceExt > ::crd(), < v2alpha1::Bar as - ::kube::CustomResourceExt > ::crd() + < v1alpha1::Bar as ::kube::core::CustomResourceExt > ::crd(), < v1::Bar + as ::kube::core::CustomResourceExt > ::crd(), < v2alpha1::Bar as + ::kube::core::CustomResourceExt > ::crd() ], &stored_apiversion.to_string(), ) 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 a56f6ce5..01f4c033 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", @@ -181,9 +223,9 @@ pub(crate) mod versioned { > { ::kube::core::crd::merge_crds( vec![ - < v1alpha1::Foo as ::kube::CustomResourceExt > ::crd(), < v1::Foo as - ::kube::CustomResourceExt > ::crd(), < v2alpha1::Foo as - ::kube::CustomResourceExt > ::crd() + < v1alpha1::Foo as ::kube::core::CustomResourceExt > ::crd(), < + v1::Foo as ::kube::core::CustomResourceExt > ::crd(), < v2alpha1::Foo + as ::kube::core::CustomResourceExt > ::crd() ], &stored_apiversion.to_string(), ) @@ -261,9 +303,9 @@ pub(crate) mod versioned { > { ::kube::core::crd::merge_crds( vec![ - < v1alpha1::Bar as ::kube::CustomResourceExt > ::crd(), < v1::Bar as - ::kube::CustomResourceExt > ::crd(), < v2alpha1::Bar as - ::kube::CustomResourceExt > ::crd() + < v1alpha1::Bar as ::kube::core::CustomResourceExt > ::crd(), < + v1::Bar as ::kube::core::CustomResourceExt > ::crd(), < v2alpha1::Bar + as ::kube::core::CustomResourceExt > ::crd() ], &stored_apiversion.to_string(), ) diff --git a/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@renamed_kind.rs.snap b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@renamed_kind.rs.snap new file mode 100644 index 00000000..a64f9a35 --- /dev/null +++ b/crates/stackable-versioned-macros/fixtures/snapshots/stackable_versioned_macros__test__k8s_snapshots@renamed_kind.rs.snap @@ -0,0 +1,177 @@ +--- +source: crates/stackable-versioned-macros/src/lib.rs +expression: formatted +input_file: crates/stackable-versioned-macros/fixtures/inputs/k8s/renamed_kind.rs +--- +#[automatically_derived] +pub mod v1alpha1 { + use super::*; + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] + #[kube( + group = "stackable.tech", + version = "v1alpha1", + kind = "FooBar", + singular = "foo", + plural = "foos", + namespaced + )] + pub struct FooSpec { + pub baz: bool, + } +} +#[automatically_derived] +impl ::std::convert::From for v1beta1::FooSpec { + fn from(__sv_foospec: v1alpha1::FooSpec) -> Self { + Self { + bah: ::std::default::Default::default(), + baz: __sv_foospec.baz, + } + } +} +#[automatically_derived] +pub mod v1beta1 { + use super::*; + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] + #[kube( + group = "stackable.tech", + version = "v1beta1", + kind = "FooBar", + singular = "foo", + plural = "foos", + namespaced + )] + pub struct FooSpec { + pub bah: u16, + pub baz: bool, + } +} +#[automatically_derived] +impl ::std::convert::From for v1::FooSpec { + fn from(__sv_foospec: v1beta1::FooSpec) -> Self { + Self { + bar: __sv_foospec.bah.into(), + baz: __sv_foospec.baz, + } + } +} +#[automatically_derived] +pub mod v1 { + use super::*; + #[derive( + Clone, + Debug, + serde::Deserialize, + serde::Serialize, + schemars::JsonSchema, + kube::CustomResource, + )] + #[kube( + group = "stackable.tech", + version = "v1", + kind = "FooBar", + singular = "foo", + plural = "foos", + namespaced + )] + pub struct FooSpec { + pub bar: usize, + pub baz: bool, + } +} +#[automatically_derived] +pub enum FooBar { + V1Alpha1, + V1Beta1, + V1, +} +#[automatically_derived] +impl ::std::fmt::Display for FooBar { + fn fmt( + &self, + f: &mut ::std::fmt::Formatter<'_>, + ) -> ::std::result::Result<(), ::std::fmt::Error> { + match self { + Self::V1Alpha1 => f.write_str("v1alpha1"), + Self::V1Beta1 => f.write_str("v1beta1"), + Self::V1 => f.write_str("v1"), + } + } +} +#[automatically_derived] +impl FooBar { + /// 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![ + < v1alpha1::FooBar as ::kube::core::CustomResourceExt > ::crd(), < + v1beta1::FooBar as ::kube::core::CustomResourceExt > ::crd(), < + v1::FooBar as ::kube::core::CustomResourceExt > ::crd() + ], + &stored_apiversion.to_string(), + ) + } + /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` + /// macro to a file located at `path`. + pub fn write_merged_crd

( + path: P, + stored_apiversion: Self, + operator_version: &str, + ) -> Result<(), ::stackable_versioned::Error> + where + P: AsRef<::std::path::Path>, + { + use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; + let merged_crd = Self::merged_crd(stored_apiversion) + .map_err(|err| ::stackable_versioned::Error::MergeCrd { + source: err, + })?; + YamlSchema::write_yaml_schema( + &merged_crd, + path, + operator_version, + SerializeOptions::default(), + ) + .map_err(|err| ::stackable_versioned::Error::SerializeYaml { + source: err, + }) + } + /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` + /// macro to stdout. + pub fn print_merged_crd( + stored_apiversion: Self, + operator_version: &str, + ) -> Result<(), ::stackable_versioned::Error> { + use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; + let merged_crd = Self::merged_crd(stored_apiversion) + .map_err(|err| ::stackable_versioned::Error::MergeCrd { + source: err, + })?; + YamlSchema::print_yaml_schema( + &merged_crd, + operator_version, + SerializeOptions::default(), + ) + .map_err(|err| ::stackable_versioned::Error::SerializeYaml { + source: err, + }) + } +} 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 1b81fbf4..d5fb5502 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 08513692..0397d12c 100644 --- a/crates/stackable-versioned-macros/src/attrs/k8s.rs +++ b/crates/stackable-versioned-macros/src/attrs/k8s.rs @@ -1,4 +1,5 @@ use darling::{util::Flag, FromMeta}; +use syn::Path; /// This struct contains supported Kubernetes arguments. /// @@ -7,21 +8,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 +53,13 @@ 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, +} diff --git a/crates/stackable-versioned-macros/src/codegen/container/enum.rs b/crates/stackable-versioned-macros/src/codegen/container/enum.rs index ed2244e6..052706f6 100644 --- a/crates/stackable-versioned-macros/src/codegen/container/enum.rs +++ b/crates/stackable-versioned-macros/src/codegen/container/enum.rs @@ -37,7 +37,7 @@ impl Container { .map_or(false, |s| s.from.is_present()), }; - let idents: ContainerIdents = item_enum.ident.into(); + let idents = ContainerIdents::from(item_enum.ident, None); let common = CommonContainerData { original_attributes: item_enum.attrs, @@ -73,7 +73,7 @@ impl Container { .map_or(false, |s| s.from.is_present()), }; - let idents: ContainerIdents = item_enum.ident.into(); + let idents = ContainerIdents::from(item_enum.ident, None); let common = CommonContainerData { original_attributes: item_enum.attrs, diff --git a/crates/stackable-versioned-macros/src/codegen/container/mod.rs b/crates/stackable-versioned-macros/src/codegen/container/mod.rs index 0bdaa330..f05cef9a 100644 --- a/crates/stackable-versioned-macros/src/codegen/container/mod.rs +++ b/crates/stackable-versioned-macros/src/codegen/container/mod.rs @@ -1,10 +1,15 @@ +use std::ops::Deref; + use darling::{util::IdentString, Result}; -use proc_macro2::TokenStream; -use quote::quote; -use syn::{Attribute, Ident, ItemEnum, ItemStruct, Visibility}; +use proc_macro2::{Span, TokenStream}; +use quote::{quote, ToTokens}; +use syn::{parse_quote, Attribute, Ident, ItemEnum, ItemStruct, Path, Visibility}; use crate::{ - attrs::{container::StandaloneContainerAttributes, k8s::KubernetesArguments}, + attrs::{ + container::StandaloneContainerAttributes, + k8s::{KubernetesArguments, KubernetesCrateArguments}, + }, codegen::{ container::{r#enum::Enum, r#struct::Struct}, VersionDefinition, @@ -232,12 +237,22 @@ pub(crate) struct ContainerIdents { pub(crate) from: IdentString, } -impl From for ContainerIdents { - fn from(ident: Ident) -> Self { +impl ContainerIdents { + pub(crate) fn from(ident: Ident, kubernetes_options: Option<&KubernetesOptions>) -> Self { + let kubernetes = kubernetes_options.map_or_else( + || ident.as_cleaned_kubernetes_ident(), + |options| { + options.kind.as_ref().map_or_else( + || ident.as_cleaned_kubernetes_ident(), + |kind| IdentString::from(Ident::new(kind, Span::call_site())), + ) + }, + ); + Self { - kubernetes: ident.as_cleaned_kubernetes_ident(), from: ident.as_from_impl_ident(), original: ident.into(), + kubernetes, } } } @@ -250,23 +265,146 @@ 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: KubernetesCrateOptions, + 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 + .map_or_else(KubernetesCrateOptions::default, |crates| crates.into()), + status: args.status, + shortname: args.shortname, + skip_merged_crd: args.skip.map_or(false, |s| s.merged_crd.is_present()), + } + } +} + +#[derive(Debug)] +pub(crate) struct KubernetesCrateOptions { + pub(crate) kube_core: Override, + pub(crate) k8s_openapi: Override, + pub(crate) schemars: Override, + pub(crate) serde: Override, + pub(crate) serde_json: Override, +} + +impl Default for KubernetesCrateOptions { + fn default() -> Self { + Self { + k8s_openapi: Override::Default(parse_quote! { ::k8s_openapi }), + serde_json: Override::Default(parse_quote! { ::serde_json }), + kube_core: Override::Default(parse_quote! { ::kube::core }), + schemars: Override::Default(parse_quote! { ::schemars }), + serde: Override::Default(parse_quote! { ::serde }), + } + } +} + +impl From for KubernetesCrateOptions { + fn from(args: KubernetesCrateArguments) -> Self { + let mut crate_options = Self::default(); + + if let Some(k8s_openapi) = args.k8s_openapi { + crate_options.k8s_openapi = Override::Overridden(k8s_openapi); + } + + if let Some(serde_json) = args.serde_json { + crate_options.serde_json = Override::Overridden(serde_json); + } + + if let Some(kube_core) = args.kube_core { + crate_options.kube_core = Override::Overridden(kube_core); + } + + if let Some(schemars) = args.schemars { + crate_options.schemars = Override::Overridden(schemars); + } + + if let Some(serde) = args.serde { + crate_options.serde = Override::Overridden(serde); + } + + crate_options + } +} + +impl ToTokens for KubernetesCrateOptions { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let mut crate_overrides = TokenStream::new(); + + let KubernetesCrateOptions { + k8s_openapi, + serde_json, + kube_core, + schemars, + serde, + } = self; + + if let Override::Overridden(k8s_openapi) = k8s_openapi { + crate_overrides.extend(quote! { k8s_openapi = #k8s_openapi, }); + } + + if let Override::Overridden(serde_json) = serde_json { + crate_overrides.extend(quote! { serde_json = #serde_json, }); + } + + if let Override::Overridden(kube_core) = kube_core { + crate_overrides.extend(quote! { kube_core = #kube_core, }); + } + + if let Override::Overridden(schemars) = schemars { + crate_overrides.extend(quote! { schemars = #schemars, }); + } + + if let Override::Overridden(serde) = serde { + crate_overrides.extend(quote! { serde = #serde, }); + } + + if !crate_overrides.is_empty() { + tokens.extend(quote! { , crates(#crate_overrides) }); + } + } +} + +/// Wraps a value to indicate whether it is original or has been overridden. +#[derive(Debug)] +pub(crate) enum Override { + Default(T), + Overridden(T), +} + +impl Deref for Override { + type Target = T; + + fn deref(&self) -> &Self::Target { + match &self { + Override::Default(inner) => inner, + Override::Overridden(inner) => inner, } } } diff --git a/crates/stackable-versioned-macros/src/codegen/container/struct.rs b/crates/stackable-versioned-macros/src/codegen/container/struct.rs index 1dd0c895..2295ae9a 100644 --- a/crates/stackable-versioned-macros/src/codegen/container/struct.rs +++ b/crates/stackable-versioned-macros/src/codegen/container/struct.rs @@ -2,7 +2,7 @@ use std::ops::Not; use darling::{util::IdentString, Error, FromAttributes, Result}; use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, ToTokens}; use syn::{parse_quote, ItemStruct, Path}; use crate::{ @@ -32,7 +32,7 @@ impl Container { } let kubernetes_options = attributes.kubernetes_arguments.map(Into::into); - let idents: ContainerIdents = item_struct.ident.into(); + let idents = ContainerIdents::from(item_struct.ident, kubernetes_options.as_ref()); // Validate K8s specific requirements // Ensure that the struct name includes the 'Spec' suffix. @@ -78,7 +78,7 @@ impl Container { } let kubernetes_options = attributes.kubernetes_arguments.map(Into::into); - let idents: ContainerIdents = item_struct.ident.into(); + let idents = ContainerIdents::from(item_struct.ident, kubernetes_options.as_ref()); // Validate K8s specific requirements // Ensure that the struct name includes the 'Spec' suffix. @@ -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, @@ -293,6 +308,8 @@ impl Struct { ) -> Option<(IdentString, String, TokenStream)> { match &self.common.options.kubernetes_options { Some(options) if !options.skip_merged_crd => { + let kube_core_path = &*options.crates.kube_core; + let enum_variant_ident = version.inner.as_variant_ident(); let enum_variant_string = version.inner.to_string(); @@ -301,7 +318,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_path::CustomResourceExt>::crd() }; Some((enum_variant_ident, enum_variant_string, merge_crds_fn_call)) @@ -317,83 +334,89 @@ impl Struct { fn_calls: &[TokenStream], is_nested: bool, ) -> Option { - if enum_variant_idents.is_empty() { - return None; - } + match &self.common.options.kubernetes_options { + Some(kubernetes_options) if !kubernetes_options.skip_merged_crd => { + let enum_ident = &self.common.idents.kubernetes; + + // Only add the #[automatically_derived] attribute if this impl is used outside of a + // module (in standalone mode). + let automatically_derived = + is_nested.not().then(|| quote! {#[automatically_derived]}); + + // Get the crate paths + let k8s_openapi_path = &*kubernetes_options.crates.k8s_openapi; + let kube_core_path = &*kubernetes_options.crates.kube_core; + + // 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 + // still need kube and friends). + Some(quote! { + #automatically_derived + pub enum #enum_ident { + #(#enum_variant_idents),* + } - let enum_ident = &self.common.idents.kubernetes; + #automatically_derived + impl ::std::fmt::Display for #enum_ident { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::result::Result<(), ::std::fmt::Error> { + match self { + #(Self::#enum_variant_idents => f.write_str(#enum_variant_strings)),* + } + } + } - // Only add the #[automatically_derived] attribute if this impl is used outside of a - // module (in standalone mode). - let automatically_derived = is_nested.not().then(|| quote! {#[automatically_derived]}); + #automatically_derived + impl #enum_ident { + /// 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_path::apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition, #kube_core_path::crd::MergeError> { + #kube_core_path::crd::merge_crds(vec![#(#fn_calls),*], &stored_apiversion.to_string()) + } - // 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 - // still need kube and friends). - Some(quote! { - #automatically_derived - pub enum #enum_ident { - #(#enum_variant_idents),* - } + /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` + /// macro to a file located at `path`. + pub fn write_merged_crd

(path: P, stored_apiversion: Self, operator_version: &str) -> Result<(), ::stackable_versioned::Error> + where P: AsRef<::std::path::Path> + { + use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; + + let merged_crd = Self::merged_crd(stored_apiversion).map_err(|err| ::stackable_versioned::Error::MergeCrd { + source: err, + })?; + + YamlSchema::write_yaml_schema( + &merged_crd, + path, + operator_version, + SerializeOptions::default() + ).map_err(|err| ::stackable_versioned::Error::SerializeYaml { + source: err, + }) + } - #automatically_derived - impl ::std::fmt::Display for #enum_ident { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::result::Result<(), ::std::fmt::Error> { - match self { - #(Self::#enum_variant_idents => f.write_str(#enum_variant_strings)),* + /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` + /// macro to stdout. + pub fn print_merged_crd(stored_apiversion: Self, operator_version: &str) -> Result<(), ::stackable_versioned::Error> { + use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; + + let merged_crd = Self::merged_crd(stored_apiversion).map_err(|err| ::stackable_versioned::Error::MergeCrd { + source: err, + })?; + + YamlSchema::print_yaml_schema( + &merged_crd, + operator_version, + SerializeOptions::default() + ).map_err(|err| ::stackable_versioned::Error::SerializeYaml { + source: err, + }) + } } - } - } - - #automatically_derived - impl #enum_ident { - /// 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()) - } - - /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` - /// macro to a file located at `path`. - pub fn write_merged_crd

(path: P, stored_apiversion: Self, operator_version: &str) -> Result<(), ::stackable_versioned::Error> - where P: AsRef<::std::path::Path> - { - use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; - - let merged_crd = Self::merged_crd(stored_apiversion).map_err(|err| ::stackable_versioned::Error::MergeCrd { - source: err, - })?; - - YamlSchema::write_yaml_schema( - &merged_crd, - path, - operator_version, - SerializeOptions::default() - ).map_err(|err| ::stackable_versioned::Error::SerializeYaml { - source: err, - }) - } - - /// Generates and writes a merged CRD which contains all versions defined using the `#[versioned()]` - /// macro to stdout. - pub fn print_merged_crd(stored_apiversion: Self, operator_version: &str) -> Result<(), ::stackable_versioned::Error> { - use ::stackable_shared::yaml::{YamlSchema, SerializeOptions}; - - let merged_crd = Self::merged_crd(stored_apiversion).map_err(|err| ::stackable_versioned::Error::MergeCrd { - source: err, - })?; - - YamlSchema::print_yaml_schema( - &merged_crd, - operator_version, - SerializeOptions::default() - ).map_err(|err| ::stackable_versioned::Error::SerializeYaml { - source: err, - }) - } + }) } - }) + _ => None, + } } } diff --git a/crates/stackable-versioned-macros/src/lib.rs b/crates/stackable-versioned-macros/src/lib.rs index 8e2750d0..0ea0c3ea 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 e83c31fe..bffa7bd9 100644 --- a/crates/stackable-versioned/CHANGELOG.md +++ b/crates/stackable-versioned/CHANGELOG.md @@ -8,19 +8,33 @@ 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 +- Simplify crate override handling and generation ([#919]). - Bump Rust to 1.82.0 ([#891]). +- Refactor the Override type ([#922]). ### Fixed +- Emit correct enum ident based on kube/k8s kind argument ([#920]). - Generate Kubernetes code independent of container order ([#913]). - Correctly emit Kubernetes code when macro is used on modules ([#912]). [#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 +[#919]: https://github.com/stackabletech/operator-rs/pull/919 +[#920]: https://github.com/stackabletech/operator-rs/pull/920 +[#922]: https://github.com/stackabletech/operator-rs/pull/922 ## [0.4.1] - 2024-10-23