@redpanda-data/docs-extensions-and-macros 5.38.8 → 5.38.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extensions/render-property-descriptions.js +18 -3
- package/package.json +1 -1
- package/tools/property-extractor/merge-rp-util.js +20 -9
- package/tools/property-extractor/templates/property.hbs +4 -2
- package/tools/property-extractor/templates/topic-property.hbs +2 -2
- package/tools/property-extractor/topic_property_extractor.py +20 -0
- package/tools/property-extractor/transformers.py +46 -7
|
@@ -261,11 +261,26 @@ function anchorIndex (contentCatalog, attachment, properties, logger) {
|
|
|
261
261
|
}
|
|
262
262
|
for (const [name, entry] of pages) {
|
|
263
263
|
if (!entry || !entry.page) continue
|
|
264
|
-
|
|
264
|
+
const anchor = propertyAnchor(name)
|
|
265
|
+
index.set(anchor, { page: entry.page, name, anchor })
|
|
266
|
+
// Legacy spelling. Before anchors replaced dots with hyphens they dropped
|
|
267
|
+
// them, so descriptions written then say <<redpandaremoteread>> for
|
|
268
|
+
// redpanda.remote.read, and some carry a stray hyphen (<<redpandastorage-mode>>).
|
|
269
|
+
// Those still name a documented property; only the spelling is old. Index
|
|
270
|
+
// the dot-and-hyphen-free form too, so they resolve to the real anchor
|
|
271
|
+
// instead of degrading to plain text and a warning on every build of every
|
|
272
|
+
// version still carrying them. A real anchor always wins over a legacy one.
|
|
273
|
+
const legacy = LEGACY_ANCHOR_PREFIX + legacyAnchorKey(name)
|
|
274
|
+
if (!index.has(legacy)) index.set(legacy, { page: entry.page, name, anchor })
|
|
265
275
|
}
|
|
266
276
|
return index
|
|
267
277
|
}
|
|
268
278
|
|
|
279
|
+
const LEGACY_ANCHOR_PREFIX = 'legacy:'
|
|
280
|
+
function legacyAnchorKey (name) {
|
|
281
|
+
return name.replace(/[.-]/g, '')
|
|
282
|
+
}
|
|
283
|
+
|
|
269
284
|
/**
|
|
270
285
|
* Rewrite <<anchor>> to an xref before conversion.
|
|
271
286
|
*
|
|
@@ -278,8 +293,8 @@ function anchorIndex (contentCatalog, attachment, properties, logger) {
|
|
|
278
293
|
function resolveInternalRefs (description, anchors, report) {
|
|
279
294
|
return description.replace(INTERNAL_REF_RX, (match, anchor, display) => {
|
|
280
295
|
const text = (display || '').trim()
|
|
281
|
-
const target = anchors.get(anchor)
|
|
282
|
-
if (target) return `xref:reference:${target.page}.adoc#${anchor}[${attrlistValue(text || `\`${target.name}\``)}]`
|
|
296
|
+
const target = anchors.get(anchor) || anchors.get(LEGACY_ANCHOR_PREFIX + legacyAnchorKey(anchor))
|
|
297
|
+
if (target) return `xref:reference:${target.page}.adoc#${target.anchor || anchor}[${attrlistValue(text || `\`${target.name}\``)}]`
|
|
283
298
|
// The anchor names no documented property, so there is nothing to link to.
|
|
284
299
|
// Asciidoctor would render a same-page fragment, and a tooltip is shown on
|
|
285
300
|
// arbitrary pages, so that link would go nowhere and still invite a click --
|
package/package.json
CHANGED
|
@@ -207,15 +207,21 @@ async function handleMergeUnavailable(tag, enhanced, reason, output = enhanced)
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
// rp_util covers every cluster/broker-scope property (see this file's own
|
|
210
|
-
// header comment), so when its merge is skipped or fails,
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
210
|
+
// header comment), so when its merge is skipped or fails, a cluster/broker
|
|
211
|
+
// property still missing gets_restored means "we don't know, because the
|
|
212
|
+
// merge that would have told us didn't run". Mark those so the template can
|
|
213
|
+
// render a visible "Unknown" instead of silently rendering nothing, which
|
|
214
|
+
// made a flaky rp_util fetch indistinguishable from a real upstream change.
|
|
215
|
+
//
|
|
216
|
+
// Since the Tree-sitter pass materializes the declared default (see
|
|
217
|
+
// GetsRestoredTransformer), a source-parsed property always arrives with the
|
|
218
|
+
// key set, so this now marks only entries with no source to default from.
|
|
219
|
+
// That is the honest scope for it: an override-fabricated stub has no
|
|
220
|
+
// declaration to read, but the reason is the missing property, not the
|
|
221
|
+
// missing merge, so those are skipped too and simply render no row.
|
|
218
222
|
const RP_UTIL_COVERED_SCOPES = new Set(['cluster', 'broker'])
|
|
223
|
+
const NO_SOURCE_PROVENANCE = 'override'
|
|
224
|
+
|
|
219
225
|
|
|
220
226
|
function markRpUtilMergeUnavailable(enhancedPath) {
|
|
221
227
|
let data
|
|
@@ -230,12 +236,17 @@ function markRpUtilMergeUnavailable(enhancedPath) {
|
|
|
230
236
|
for (const prop of Object.values(properties)) {
|
|
231
237
|
if (!prop || !RP_UTIL_COVERED_SCOPES.has(prop.config_scope)) continue
|
|
232
238
|
if (prop.gets_restored !== undefined) continue
|
|
239
|
+
if (prop.defined_in === NO_SOURCE_PROVENANCE) continue
|
|
233
240
|
prop.rp_util_merge_status = 'unavailable'
|
|
234
241
|
marked++
|
|
235
242
|
}
|
|
236
243
|
if (marked === 0) return
|
|
237
244
|
try {
|
|
238
|
-
|
|
245
|
+
// indent 4, matching what property_extractor.py and rp_util_merge.py
|
|
246
|
+
// write. Without it this rewrite minified the whole dataset onto one
|
|
247
|
+
// line, flipping the committed attachment from 14,000 diffable lines
|
|
248
|
+
// to one.
|
|
249
|
+
fs.writeFileSync(enhancedPath, bigIntJson.stringify(data, 4))
|
|
239
250
|
} catch (err) {
|
|
240
251
|
console.warn(`Warning: could not write rp_util-unavailable marker to ${enhancedPath}: ${err.message}`)
|
|
241
252
|
}
|
|
@@ -155,17 +155,19 @@ endif::[]
|
|
|
155
155
|
{{/if}}
|
|
156
156
|
{{/if}}
|
|
157
157
|
|
|
158
|
-
ifndef::env-cloud[]
|
|
159
158
|
{{#if (ne gets_restored undefined)}}
|
|
160
159
|
|
|
160
|
+
ifndef::env-cloud[]
|
|
161
161
|
| Restored on xref:manage:whole-cluster-restore.adoc[Whole Cluster Restore]
|
|
162
162
|
| {{#if gets_restored}}Yes{{else}}No{{/if}}
|
|
163
|
+
endif::[]
|
|
163
164
|
{{else if (eq rp_util_merge_status "unavailable")}}
|
|
164
165
|
|
|
166
|
+
ifndef::env-cloud[]
|
|
165
167
|
| Restored on xref:manage:whole-cluster-restore.adoc[Whole Cluster Restore]
|
|
166
168
|
| Unknown (rp_util merge unavailable this build)
|
|
167
|
-
{{/if}}
|
|
168
169
|
endif::[]
|
|
170
|
+
{{/if}}
|
|
169
171
|
{{#if visibility}}
|
|
170
172
|
|
|
171
173
|
ifndef::env-cloud[]
|
|
@@ -132,13 +132,13 @@ endif::[]
|
|
|
132
132
|
| Nullable
|
|
133
133
|
| {{#if nullable}}Yes{{else}}No{{/if}}
|
|
134
134
|
|
|
135
|
-
ifndef::env-cloud[]
|
|
136
135
|
{{#if (ne gets_restored undefined)}}
|
|
137
136
|
|
|
137
|
+
ifndef::env-cloud[]
|
|
138
138
|
| Restored on xref:manage:whole-cluster-restore.adoc[Whole Cluster Restore]
|
|
139
139
|
| {{#if gets_restored}}Yes{{else}}No{{/if}}
|
|
140
|
-
{{/if}}
|
|
141
140
|
endif::[]
|
|
141
|
+
{{/if}}
|
|
142
142
|
{{#if example}}
|
|
143
143
|
|
|
144
144
|
| Example
|
|
@@ -119,6 +119,16 @@ class TopicPropertyExtractor:
|
|
|
119
119
|
"default": None, # Will be populated from cluster property if available
|
|
120
120
|
"is_noop": False, # Will be updated later in _correlate_properties_with_data
|
|
121
121
|
"is_topic_property": True,
|
|
122
|
+
# A topic property is a Kafka topic config, not a
|
|
123
|
+
# config::property, so there is no per-property
|
|
124
|
+
# `restored` annotation to read and rp_util's dumps
|
|
125
|
+
# do not cover topic scope. Whole Cluster Restore
|
|
126
|
+
# restores topic metadata (see the WCR docs), which
|
|
127
|
+
# is where these live, so the answer is yes for all
|
|
128
|
+
# of them. Set it explicitly: topic-property.hbs
|
|
129
|
+
# drops the row when the key is absent, which
|
|
130
|
+
# silently deleted it from all 48 properties.
|
|
131
|
+
"gets_restored": True,
|
|
122
132
|
"config_scope": "topic"
|
|
123
133
|
}
|
|
124
134
|
print(f"Found {total_matches} topic properties in {file_path}")
|
|
@@ -176,6 +186,16 @@ class TopicPropertyExtractor:
|
|
|
176
186
|
"default": None, # Will be populated from cluster property if available
|
|
177
187
|
"is_noop": False, # Will be updated later in _correlate_properties_with_data
|
|
178
188
|
"is_topic_property": True,
|
|
189
|
+
# A topic property is a Kafka topic config, not a
|
|
190
|
+
# config::property, so there is no per-property
|
|
191
|
+
# `restored` annotation to read and rp_util's dumps
|
|
192
|
+
# do not cover topic scope. Whole Cluster Restore
|
|
193
|
+
# restores topic metadata (see the WCR docs), which
|
|
194
|
+
# is where these live, so the answer is yes for all
|
|
195
|
+
# of them. Set it explicitly: topic-property.hbs
|
|
196
|
+
# drops the row when the key is absent, which
|
|
197
|
+
# silently deleted it from all 48 properties.
|
|
198
|
+
"gets_restored": True,
|
|
179
199
|
"config_scope": "topic"
|
|
180
200
|
}
|
|
181
201
|
except Exception as e:
|
|
@@ -479,7 +479,15 @@ def find_meta_dict(info):
|
|
|
479
479
|
|
|
480
480
|
# Case 1: Already parsed dict
|
|
481
481
|
if isinstance(val, dict) and any(
|
|
482
|
-
k in val
|
|
482
|
+
k in val
|
|
483
|
+
for k in (
|
|
484
|
+
"needs_restart", "visibility", "deprecated", "secret", "experimental",
|
|
485
|
+
# A block holding only one of these is still a meta block. Left
|
|
486
|
+
# out, `meta{ .gets_restored = gets_restored::no }` resolved to
|
|
487
|
+
# None here and the caller fell back to its default, inverting
|
|
488
|
+
# the value it had already parsed correctly.
|
|
489
|
+
"gets_restored", "restored",
|
|
490
|
+
)
|
|
483
491
|
):
|
|
484
492
|
return val
|
|
485
493
|
|
|
@@ -1072,14 +1080,45 @@ class GetsRestoredTransformer:
|
|
|
1072
1080
|
"""
|
|
1073
1081
|
|
|
1074
1082
|
def accepts(self, info, file_pair):
|
|
1075
|
-
"""Process
|
|
1076
|
-
|
|
1077
|
-
|
|
1083
|
+
"""Process every property parsed from source, annotated or not.
|
|
1084
|
+
|
|
1085
|
+
Accepting only annotated properties left the key absent for the
|
|
1086
|
+
majority, and absent then had to carry two incompatible meanings:
|
|
1087
|
+
"the declared default applies" and "the data never reached us". The
|
|
1088
|
+
templates cannot tell those apart, and for a release whose rp_util
|
|
1089
|
+
schema can never be published they picked the second, rendering
|
|
1090
|
+
"Unknown" for 626 properties whose value is not in doubt.
|
|
1091
|
+
|
|
1092
|
+
A property reaching this transformer was parsed out of the C++, so the
|
|
1093
|
+
first meaning is the true one and this is the place that knows it.
|
|
1094
|
+
"""
|
|
1095
|
+
return True
|
|
1078
1096
|
|
|
1079
1097
|
def parse(self, property, info, file_pair):
|
|
1080
|
-
"""Extract restoration flag
|
|
1081
|
-
|
|
1082
|
-
|
|
1098
|
+
"""Extract the restoration flag, defaulting to the declared default.
|
|
1099
|
+
|
|
1100
|
+
base_property.h declares `gets_restored gets_restored{gets_restored::yes}`,
|
|
1101
|
+
so a property carrying no annotation is restored. Materialize that
|
|
1102
|
+
rather than leaving it implicit: at v26.2.2 every one of the 17
|
|
1103
|
+
annotated properties says `no`, so the default is what the other 674
|
|
1104
|
+
actually rely on.
|
|
1105
|
+
|
|
1106
|
+
rp_util's runtime value still wins wherever the merge runs -- it sets
|
|
1107
|
+
the same key afterwards (see rp_util_merge.map_rp_util_property) -- so
|
|
1108
|
+
this is the fallback for the releases the merge cannot cover, not a
|
|
1109
|
+
competing source of truth.
|
|
1110
|
+
"""
|
|
1111
|
+
val = get_meta_value(info, "gets_restored")
|
|
1112
|
+
if val is None:
|
|
1113
|
+
val = get_meta_value(info, "restored")
|
|
1114
|
+
if val is not None:
|
|
1115
|
+
property["gets_restored"] = (val != "no")
|
|
1116
|
+
else:
|
|
1117
|
+
# MetaParamTransformer runs first (property_extractor.py) and sets
|
|
1118
|
+
# this key off the same meta block, so only default when nothing
|
|
1119
|
+
# upstream resolved a real value. Assigning unconditionally would
|
|
1120
|
+
# overwrite an explicit `no` with the default.
|
|
1121
|
+
property.setdefault("gets_restored", True)
|
|
1083
1122
|
return property
|
|
1084
1123
|
|
|
1085
1124
|
|