From fa0ec3c6aea4e7f4c51b67311ac7636b323b6b4d Mon Sep 17 00:00:00 2001 From: Techassi Date: Fri, 23 Oct 2026 12:28:40 +0200 Subject: [PATCH 1/3] feat(versioned): Add support for previous_docs in deprecated action --- .../stackable-versioned-macros/src/attrs/item/mod.rs | 6 ++++++ .../tests/inputs/pass/docs.rs | 12 +++++++++--- ...le_versioned_macros__snapshots__pass@docs.rs.snap | 11 +++++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/crates/stackable-versioned-macros/src/attrs/item/mod.rs b/crates/stackable-versioned-macros/src/attrs/item/mod.rs index 7b4092f52..c40a5c3f9 100644 --- a/crates/stackable-versioned-macros/src/attrs/item/mod.rs +++ b/crates/stackable-versioned-macros/src/attrs/item/mod.rs @@ -308,6 +308,10 @@ impl CommonItemAttributes { let docs = change.from_docs.as_deref()?; Some((*change.since, docs.into_doc_comments())) }) + .chain(self.deprecated.iter().filter_map(|deprecation| { + let docs = deprecation.previous_docs.as_deref()?; + Some((*deprecation.since, docs.into_doc_comments())) + })) .collect() } @@ -497,8 +501,10 @@ pub struct ChangedAttributes { /// Example usage: /// - `deprecated(since = "...")` /// - `deprecated(since = "...", note = "...")` +/// - `deprecated(since = "...", note = "..."), previous_docs = "..."` #[derive(Clone, Debug, FromMeta)] pub struct DeprecatedAttributes { pub since: SpannedValue, pub note: Option>, + pub previous_docs: Option>, } diff --git a/crates/stackable-versioned-macros/tests/inputs/pass/docs.rs b/crates/stackable-versioned-macros/tests/inputs/pass/docs.rs index 13f7c8d11..cb1e0af3a 100644 --- a/crates/stackable-versioned-macros/tests/inputs/pass/docs.rs +++ b/crates/stackable-versioned-macros/tests/inputs/pass/docs.rs @@ -53,12 +53,18 @@ mod versioned { #[serde(rename = "corge")] corge: String, - /// The docs of this field changed in v1, while it was renamed in v1beta1. + /// This field is now deprecated. + /// + /// Previously, the docs of this field changed in v1, while it was renamed in v1beta1. #[versioned( changed(since = "v1beta1", from_name = "waldo"), - changed(since = "v1", from_docs = "These are the docs before v1.") + changed(since = "v1", from_docs = "These are the docs before v1."), + deprecated( + since = "v2", + previous_docs = "The docs of this field changed in v1, while it was renamed in v1beta1." + ) )] - fred: String, + deprecated_fred: String, } /// Test 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 49d2ef516..4abcebe55 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 @@ -408,7 +408,7 @@ where baz: __sv_foo.baz.into(), quux: __sv_foo.quux.into(), corge: __sv_foo.corge.into(), - fred: __sv_foo.fred.into(), + deprecated_fred: __sv_foo.fred.into(), }; spec } @@ -427,7 +427,7 @@ where baz: __sv_foo.baz.into(), quux: __sv_foo.quux.into(), corge: __sv_foo.corge.into(), - fred: __sv_foo.fred.into(), + fred: __sv_foo.deprecated_fred.into(), }; spec } @@ -475,8 +475,11 @@ mod v2 { #[doc(alias = "grault")] #[serde(rename = "corge")] pub corge: String, - /// The docs of this field changed in v1, while it was renamed in v1beta1. - pub fred: String, + /// This field is now deprecated. + /// + /// Previously, the docs of this field changed in v1, while it was renamed in v1beta1. + #[deprecated] + pub deprecated_fred: String, } /// Test #[derive(Default)] From 43009a057451261e20236e8e354470141ed264e6 Mon Sep 17 00:00:00 2001 From: Techassi Date: Fri, 23 Oct 2026 12:34:14 +0200 Subject: [PATCH 2/3] chore(versioned): Add changelog entry --- crates/stackable-versioned/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/stackable-versioned/CHANGELOG.md b/crates/stackable-versioned/CHANGELOG.md index e1e03fea9..df7b172c0 100644 --- a/crates/stackable-versioned/CHANGELOG.md +++ b/crates/stackable-versioned/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Added +- Add support to provide the `previous_docs` argument in the `deprecated` action ([#1314]). - Add public `ExtractIfExt` trait ([#1306]). - Re-add support for generics in tracking impls ([#1304]). - Add support to provide `#[versioned(crd(selectable = "..."))]` arguments to configure selectable fields ([#1312]). @@ -29,6 +30,7 @@ All notable changes to this project will be documented in this file. [#1307]: https://github.com/stackabletech/operator-rs/pull/1307 [#1309]: https://github.com/stackabletech/operator-rs/pull/1309 [#1312]: https://github.com/stackabletech/operator-rs/pull/1312 +[#1314]: https://github.com/stackabletech/operator-rs/pull/1314 ## [0.13.0] - 2026-10-14 From 1f609ca36e70172b3b8ea5c39113753b36627112 Mon Sep 17 00:00:00 2001 From: Techassi Date: Fri, 23 Oct 2026 12:41:28 +0200 Subject: [PATCH 3/3] docs(versioned): Update doc comments --- crates/stackable-versioned-macros/src/lib.rs | 93 ++++++++++---------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/crates/stackable-versioned-macros/src/lib.rs b/crates/stackable-versioned-macros/src/lib.rs index 6d3e43526..9267dd7dc 100644 --- a/crates/stackable-versioned-macros/src/lib.rs +++ b/crates/stackable-versioned-macros/src/lib.rs @@ -567,22 +567,22 @@ mod utils; /// ``` /// /// -/// #### Changed Docs +/// ### Deprecated Action /// -/// The doc comments of an item can be changed using the `from_docs` argument. -/// The doc comments attached to the item are used after the version of the -/// last relevant change. All earlier versions use the doc comments provided via -/// `from_docs` instead. This is especially useful to adjust the description of -/// a field in the generated CRD schema without changing it for older versions. +/// This action indicates that an item is deprecated in a particular version. +/// Deprecated items are not removed. Available arguments are: +/// +/// - `since` to indicate since which version the item is deprecated. +/// - `note` to specify an optional deprecation note. +/// - `previous_docs` to provide the previous doc comments of the item. /// /// ``` /// # use stackable_versioned_macros::versioned; /// #[versioned(version(name = "v1alpha1"), version(name = "v1beta1"))] /// mod versioned { /// pub struct Foo { -/// /// The number of bars. -/// #[versioned(changed(since = "v1beta1", from_docs = "The bar."))] -/// bar: usize, +/// #[versioned(deprecated(since = "v1beta1"))] +/// deprecated_bar: usize, /// baz: bool, /// } /// } @@ -591,49 +591,62 @@ mod utils; ///
/// Expand Generated Code /// -/// 1. In version `v1alpha1` the field uses the doc comments provided via -/// `from_docs`. -/// 2. In the next version, `v1beta1`, the field uses the doc comments attached -/// to the field. +/// 1. In version `v1alpha1` the field `bar` is not yet deprecated and thus uses +/// the name without the `deprecated_` prefix. +/// 2. In version `v1beta1` the field is deprecated and now includes the +/// `deprecated_` prefix. It also uses the `#[deprecated]` attribute to +/// indicate to Clippy this part of Rust code is deprecated. Therefore, the +/// conversion implementations include `#[allow(deprecated)]` to allow the +/// usage of deprecated items in automatically generated code. /// /// ```ignore /// pub mod v1alpha1 { /// use super::*; /// pub struct Foo { -/// /// The bar. // 1 -/// pub bar: usize, +/// pub bar: usize, // 1 /// pub baz: bool, /// } /// } /// -/// // Snip +/// #[allow(deprecated)] // 2 +/// impl From for v1beta1::Foo { +/// fn from(foo: v1alpha1::Foo) -> Self { +/// Self { +/// deprecated_bar: foo.bar, // 2 +/// baz: foo.baz, +/// } +/// } +/// } /// /// pub mod v1beta1 { /// use super::*; /// pub struct Foo { -/// /// The number of bars. // 2 -/// pub bar: usize, +/// #[deprecated] // 2 +/// pub deprecated_bar: usize, /// pub baz: bool, /// } /// } /// ``` ///
/// -/// ### Deprecated Action -/// -/// This action indicates that an item is deprecated in a particular version. -/// Deprecated items are not removed. Available arguments are: +/// ### Changed Docs /// -/// - `since` to indicate since which version the item is deprecated. -/// - `note` to specify an optional deprecation note. +/// The doc comments of an item can be changed using the `from_docs` or +/// `previous_docs` argument in the `changed` and `deprecated` actions. +/// The doc comments attached to the item are used after the version of the +/// last relevant change. All earlier versions use the doc comments provided via +/// `from_docs`/`previous_docs` instead. This is especially useful to adjust the +/// description of a field in the generated CRD schema without changing it for +/// older versions. /// /// ``` /// # use stackable_versioned_macros::versioned; /// #[versioned(version(name = "v1alpha1"), version(name = "v1beta1"))] /// mod versioned { /// pub struct Foo { -/// #[versioned(deprecated(since = "v1beta1"))] -/// deprecated_bar: usize, +/// /// The number of bars. +/// #[versioned(changed(since = "v1beta1", from_docs = "The bar."))] +/// bar: usize, /// baz: bool, /// } /// } @@ -642,38 +655,28 @@ mod utils; ///
/// Expand Generated Code /// -/// 1. In version `v1alpha1` the field `bar` is not yet deprecated and thus uses -/// the name without the `deprecated_` prefix. -/// 2. In version `v1beta1` the field is deprecated and now includes the -/// `deprecated_` prefix. It also uses the `#[deprecated]` attribute to -/// indicate to Clippy this part of Rust code is deprecated. Therefore, the -/// conversion implementations include `#[allow(deprecated)]` to allow the -/// usage of deprecated items in automatically generated code. +/// 1. In version `v1alpha1` the field uses the doc comments provided via +/// `from_docs`. +/// 2. In the next version, `v1beta1`, the field uses the doc comments attached +/// to the field. /// /// ```ignore /// pub mod v1alpha1 { /// use super::*; /// pub struct Foo { -/// pub bar: usize, // 1 +/// /// The bar. // 1 +/// pub bar: usize, /// pub baz: bool, /// } /// } /// -/// #[allow(deprecated)] // 2 -/// impl From for v1beta1::Foo { -/// fn from(foo: v1alpha1::Foo) -> Self { -/// Self { -/// deprecated_bar: foo.bar, // 2 -/// baz: foo.baz, -/// } -/// } -/// } +/// // Snip /// /// pub mod v1beta1 { /// use super::*; /// pub struct Foo { -/// #[deprecated] // 2 -/// pub deprecated_bar: usize, +/// /// The number of bars. // 2 +/// pub bar: usize, /// pub baz: bool, /// } /// }