diff --git a/Cargo.lock b/Cargo.lock index 0fb49ca5e..bc5848908 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3947,7 +3947,6 @@ dependencies = [ "serde_json", "snafu 0.9.2", "stackable-versioned-macros", - "yaml_serde", ] [[package]] diff --git a/crates/stackable-versioned-macros/src/codegen/item/field.rs b/crates/stackable-versioned-macros/src/codegen/item/field.rs index 17ee2beb1..78e80cd49 100644 --- a/crates/stackable-versioned-macros/src/codegen/item/field.rs +++ b/crates/stackable-versioned-macros/src/codegen/item/field.rs @@ -315,7 +315,7 @@ impl VersionedField { Direction::Downgrade => { let next_change = changes.get_expect(&next_version.inner); - let yaml_serde_path = &*mod_gen_ctx.crates.yaml_serde; + let serde_json_path = &*mod_gen_ctx.crates.serde_json; let versioned_path = &*mod_gen_ctx.crates.versioned; match next_change { @@ -327,7 +327,7 @@ impl VersionedField { Some(quote! { upgrades.push(#versioned_path::ChangedValue { json_path: #json_path_ident, - value: #yaml_serde_path::to_value(&#from_struct_ident.#ident).unwrap(), + value: #serde_json_path::to_value(&#from_struct_ident.#ident).unwrap(), }); }) } @@ -349,7 +349,7 @@ impl VersionedField { // for applying a tracked value. let changes = self.changes.as_ref()?; - let yaml_serde_path = &*mod_gen_ctx.crates.yaml_serde; + let serde_json_path = &*mod_gen_ctx.crates.serde_json; let versioned_path = &*mod_gen_ctx.crates.versioned; match direction { @@ -368,7 +368,7 @@ impl VersionedField { Some(quote! { if let Some(#versioned_path::ChangedValue { value, .. }) = upgrades.extract_first_if(|u| u.json_path == #json_path_ident) { // TODO (@Techassi): Switch to serde_json - spec.#ident = #yaml_serde_path::from_value(value).expect(#expect_message); + spec.#ident = #serde_json_path::from_value(value).expect(#expect_message); } }) } diff --git a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking.rs.snap b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking.rs.snap index 348dac6f8..a45505f0a 100644 --- a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking.rs.snap +++ b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking.rs.snap @@ -69,7 +69,7 @@ where if let Some(::stackable_versioned::ChangedValue { value, .. }) = upgrades .extract_first_if(|u| u.json_path == __sv_bah_path) { - spec.bah = ::yaml_serde::from_value(value) + spec.bah = ::serde_json::from_value(value) .expect( "internal error: {__sv_bah_path} must be serializable for spec.bah", ); @@ -102,7 +102,7 @@ where upgrades .push(::stackable_versioned::ChangedValue { json_path: __sv_bah_path, - value: ::yaml_serde::to_value(&__sv_foospec.bah).unwrap(), + value: ::serde_json::to_value(&__sv_foospec.bah).unwrap(), }); let mut spec = Self { baz: __sv_foospec.baz.into(), diff --git a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_enum.rs.snap b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_enum.rs.snap index ef0ba4fd1..3bbc513a1 100644 --- a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_enum.rs.snap +++ b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_enum.rs.snap @@ -237,7 +237,7 @@ where if let Some(::stackable_versioned::ChangedValue { value, .. }) = upgrades .extract_first_if(|u| u.json_path == __sv_rest_catalog_uri_path) { - spec.rest_catalog_uri = ::yaml_serde::from_value(value) + spec.rest_catalog_uri = ::serde_json::from_value(value) .expect( "internal error: {__sv_rest_catalog_uri_path} must be serializable for spec.rest_catalog_uri", ); @@ -275,7 +275,7 @@ where upgrades .push(::stackable_versioned::ChangedValue { json_path: __sv_rest_catalog_uri_path, - value: ::yaml_serde::to_value(&__sv_icebergconnector.rest_catalog_uri) + value: ::serde_json::to_value(&__sv_icebergconnector.rest_catalog_uri) .unwrap(), }); let mut spec = Self { diff --git a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_generics.rs.snap b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_generics.rs.snap index 5782cc0d4..390ce25bf 100644 --- a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_generics.rs.snap +++ b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_generics.rs.snap @@ -79,7 +79,7 @@ where if let Some(::stackable_versioned::ChangedValue { value, .. }) = upgrades .extract_first_if(|u| u.json_path == __sv_bah_path) { - spec.bah = ::yaml_serde::from_value(value) + spec.bah = ::serde_json::from_value(value) .expect( "internal error: {__sv_bah_path} must be serializable for spec.bah", ); @@ -113,7 +113,7 @@ where upgrades .push(::stackable_versioned::ChangedValue { json_path: __sv_bah_path, - value: ::yaml_serde::to_value(&__sv_foospec.bah).unwrap(), + value: ::serde_json::to_value(&__sv_foospec.bah).unwrap(), }); let mut spec = Self { baz: __sv_foospec.baz.tracking_into(status, &__sv_baz_path), @@ -279,7 +279,7 @@ where if let Some(::stackable_versioned::ChangedValue { value, .. }) = upgrades .extract_first_if(|u| u.json_path == __sv_inner_3_path) { - spec.inner_3 = ::yaml_serde::from_value(value) + spec.inner_3 = ::serde_json::from_value(value) .expect( "internal error: {__sv_inner_3_path} must be serializable for spec.inner_3", ); @@ -309,7 +309,7 @@ where upgrades .push(::stackable_versioned::ChangedValue { json_path: __sv_inner_3_path, - value: ::yaml_serde::to_value(&__sv_baz.inner_3).unwrap(), + value: ::serde_json::to_value(&__sv_baz.inner_3).unwrap(), }); let mut spec = Self { inner_1: __sv_baz.inner_1.into(), diff --git a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_hints.rs.snap b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_hints.rs.snap index 884853255..97b387009 100644 --- a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_hints.rs.snap +++ b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@conversion_tracking_hints.rs.snap @@ -78,7 +78,7 @@ where if let Some(::stackable_versioned::ChangedValue { value, .. }) = upgrades .extract_first_if(|u| u.json_path == __sv_baz_baz_path) { - spec.baz_baz = ::yaml_serde::from_value(value) + spec.baz_baz = ::serde_json::from_value(value) .expect( "internal error: {__sv_baz_baz_path} must be serializable for spec.baz_baz", ); @@ -111,7 +111,7 @@ where upgrades .push(::stackable_versioned::ChangedValue { json_path: __sv_baz_baz_path, - value: ::yaml_serde::to_value(&__sv_bar.baz_baz).unwrap(), + value: ::serde_json::to_value(&__sv_bar.baz_baz).unwrap(), }); let mut spec = Self { bar_bar: __sv_bar.bar_bar.into(), diff --git a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@docs.rs.snap b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@docs.rs.snap index 50a37ba62..49d2ef516 100644 --- a/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@docs.rs.snap +++ b/crates/stackable-versioned-macros/tests/snapshots/stackable_versioned_macros__snapshots__pass@docs.rs.snap @@ -56,7 +56,7 @@ where if let Some(::stackable_versioned::ChangedValue { value, .. }) = upgrades .extract_first_if(|u| u.json_path == __sv_baz_path) { - spec.baz = ::yaml_serde::from_value(value) + spec.baz = ::serde_json::from_value(value) .expect( "internal error: {__sv_baz_path} must be serializable for spec.baz", ); @@ -90,7 +90,7 @@ where upgrades .push(::stackable_versioned::ChangedValue { json_path: __sv_baz_path, - value: ::yaml_serde::to_value(&__sv_foo.baz).unwrap(), + value: ::serde_json::to_value(&__sv_foo.baz).unwrap(), }); let mut spec = Self { foo: __sv_foo.foo.into(), diff --git a/crates/stackable-versioned/CHANGELOG.md b/crates/stackable-versioned/CHANGELOG.md index 7ea0a63bd..bb4868a01 100644 --- a/crates/stackable-versioned/CHANGELOG.md +++ b/crates/stackable-versioned/CHANGELOG.md @@ -9,12 +9,19 @@ All notable changes to this project will be documented in this file. - Add public `ExtractIfExt` trait ([#13006]). - Re-add support for generics in tracking impls ([#1304]). +### Changed + +- BREAKING: `stackable_versioned::ChangedValue`'s `value` field type is now `serde_json::Value` instead + of `yaml_serde::Value` ([#1307]). + ### Fixed +- Fix how the generated code (de)serializes enums in the tracking status ([#1307]). - Correctly handle tracked per-version changes across multiple containers ([#1306]). [#1304]: https://github.com/stackabletech/operator-rs/pull/1304 [#1306]: https://github.com/stackabletech/operator-rs/pull/1306 +[#1307]: https://github.com/stackabletech/operator-rs/pull/1307 ## [0.13.0] - 2026-10-14 diff --git a/crates/stackable-versioned/Cargo.toml b/crates/stackable-versioned/Cargo.toml index d465779e1..fe80f1654 100644 --- a/crates/stackable-versioned/Cargo.toml +++ b/crates/stackable-versioned/Cargo.toml @@ -17,7 +17,6 @@ kube.workspace = true schemars.workspace = true serde.workspace = true serde_json.workspace = true -yaml_serde.workspace = true snafu.workspace = true [dev-dependencies] diff --git a/crates/stackable-versioned/src/lib.rs b/crates/stackable-versioned/src/lib.rs index 708ebb98c..853517c77 100644 --- a/crates/stackable-versioned/src/lib.rs +++ b/crates/stackable-versioned/src/lib.rs @@ -114,7 +114,7 @@ pub struct ChangedValue { /// The value to be used when upgrading or downgrading the custom resource. #[schemars(schema_with = "raw_object_schema")] - pub value: yaml_serde::Value, + pub value: serde_json::Value, } // TODO (@Techassi): Think about where this should live. Basically this already exists in diff --git a/crates/stackable-versioned/tests/person.rs b/crates/stackable-versioned/tests/person.rs index 74fba62a4..7f3bf16a5 100644 --- a/crates/stackable-versioned/tests/person.rs +++ b/crates/stackable-versioned/tests/person.rs @@ -75,10 +75,10 @@ pub mod versioned { #[versioned(added(since = "v2"), changed(since = "v3", from_type = "Gender"))] gender: String, - // FIXME (@Techassi): This currently breaks because of how enum are serialized by default - // by yaml_serde (singleton map) - // #[versioned(added(since = "v1alpha2"), nested)] - #[versioned(nested)] + // TODO (@Techassi): Dealing with Default here is kinda meh UX wise. What would really help + // is enabling per-container versioning and maybe the ability to place impl blocks in here + // for automatic implementations for all versions of a container. + #[versioned(added(since = "v1alpha2", default = default_relationship), nested)] relationship: Relationship, #[versioned(nested)] @@ -115,22 +115,62 @@ pub mod versioned { } } +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] +pub struct PersonStatus { + pub alive: bool, +} + +impl Default for PersonStatus { + fn default() -> Self { + Self { alive: true } + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "PascalCase")] +pub enum Gender { + #[default] + Unknown, + Male, + Female, +} + +impl From for String { + fn from(value: Gender) -> Self { + match value { + Gender::Unknown => "Unknown".to_owned(), + Gender::Male => "Male".to_owned(), + Gender::Female => "Female".to_owned(), + } + } +} + +impl From for Gender { + fn from(value: String) -> Self { + match value.as_str() { + "Male" => Self::Male, + "Female" => Self::Female, + _ => Self::Unknown, + } + } +} + +fn default_relationship() -> v1alpha2::Relationship { + v1alpha2::Relationship::Other {} +} + #[cfg(test)] impl stackable_versioned::test_utils::RoundtripTestData for v1alpha1::PersonSpec { fn roundtrip_test_data() -> Vec { vec![ Self { username: "jdoe".to_string(), - relationship: v1alpha1::Relationship::Married(v1alpha1::Married { - with: "Jane Doe".into(), - }), socials: v1alpha1::Socials { email: "jdoe@example.com".to_owned(), }, }, Self { username: String::new(), - relationship: v1alpha1::Relationship::Single {}, socials: v1alpha1::Socials { email: String::new(), }, @@ -185,43 +225,3 @@ impl stackable_versioned::test_utils::RoundtripTestData for v3::PersonSpec { ] } } - -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct PersonStatus { - pub alive: bool, -} - -impl Default for PersonStatus { - fn default() -> Self { - Self { alive: true } - } -} - -#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema)] -#[serde(rename_all = "PascalCase")] -pub enum Gender { - #[default] - Unknown, - Male, - Female, -} - -impl From for String { - fn from(value: Gender) -> Self { - match value { - Gender::Unknown => "Unknown".to_owned(), - Gender::Male => "Male".to_owned(), - Gender::Female => "Female".to_owned(), - } - } -} - -impl From for Gender { - fn from(value: String) -> Self { - match value.as_str() { - "Male" => Self::Male, - "Female" => Self::Female, - _ => Self::Unknown, - } - } -} diff --git a/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v1alpha1.json.snap b/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v1alpha1.json.snap index eab916aad..d0df2091a 100644 --- a/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v1alpha1.json.snap +++ b/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v1alpha1.json.snap @@ -37,11 +37,6 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ "kind": "Person", "metadata": {}, "spec": { - "relationship": { - "married": { - "with": "Jane Doe" - } - }, "socials": { "email": "jdoe@example.com" }, @@ -60,6 +55,14 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ { "jsonPath": "$.last_name", "value": "Doe" + }, + { + "jsonPath": "$.relationship", + "value": { + "married": { + "with": "Jane Doe" + } + } } ] } @@ -71,11 +74,6 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ "kind": "Person", "metadata": {}, "spec": { - "relationship": { - "married": { - "with": "Jane Doe" - } - }, "socials": { "email": "jdoe@example.com" }, @@ -94,6 +92,14 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ { "jsonPath": "$.last_name", "value": "Doe" + }, + { + "jsonPath": "$.relationship", + "value": { + "married": { + "with": "Jane Doe" + } + } } ], "v1beta1": [ @@ -111,11 +117,6 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ "kind": "Person", "metadata": {}, "spec": { - "relationship": { - "married": { - "with": "Jane Doe" - } - }, "socials": { "email": "jdoe@example.com" }, @@ -134,6 +135,14 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ { "jsonPath": "$.last_name", "value": "Doe" + }, + { + "jsonPath": "$.relationship", + "value": { + "married": { + "with": "Jane Doe" + } + } } ], "v1beta1": [ @@ -161,11 +170,6 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ "kind": "Person", "metadata": {}, "spec": { - "relationship": { - "married": { - "with": "Jane Doe" - } - }, "socials": { "email": "jdoe@example.com" }, @@ -184,6 +188,14 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ { "jsonPath": "$.last_name", "value": "Doe" + }, + { + "jsonPath": "$.relationship", + "value": { + "married": { + "with": "Jane Doe" + } + } } ], "v1beta1": [ diff --git a/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v3.json.snap b/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v3.json.snap index 1db1b46ff..c56664bde 100644 --- a/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v3.json.snap +++ b/crates/stackable-versioned/tests/snapshots/conversions__pass@persons_to_v3.json.snap @@ -25,10 +25,7 @@ input_file: crates/stackable-versioned/tests/inputs/conversions/pass/persons_to_ "gender": "Unknown", "lastName": "", "relationship": { - "married": { - "since": "", - "with": "Jane Doe" - } + "other": {} }, "socials": { "email": "jdoe@example.com",