@redpanda-data/docs-extensions-and-macros 5.30.0 → 5.31.0
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/bin/doc-tools.js +2 -0
- package/package.json +1 -1
- package/tools/property-extractor/Makefile +11 -0
- package/tools/property-extractor/merge-rp-util.js +208 -0
- package/tools/property-extractor/rp-util-fetch.js +447 -0
- package/tools/property-extractor/rp_util_merge.py +599 -0
- package/tools/property-extractor/templates/property.hbs +12 -5
- package/tools/property-extractor/templates/topic-property.hbs +7 -4
package/bin/doc-tools.js
CHANGED
|
@@ -1082,6 +1082,7 @@ automation
|
|
|
1082
1082
|
.option('--output-dir <dir>', 'Where to write all generated files', 'modules/reference')
|
|
1083
1083
|
.option('--cloud-support', 'Add AsciiDoc tags to generated property docs to indicate which ones are supported in Redpanda Cloud. This data is fetched from the cloudv2 repository so requires a GitHub token with repo permissions. The token is resolved from GIT_CREDENTIALS, REDPANDA_GITHUB_TOKEN, ACTIONS_BOT_TOKEN, GITHUB_TOKEN, VBOT_GITHUB_API_TOKEN, or GH_TOKEN, in that priority order', true)
|
|
1084
1084
|
.option('--no-cloud-support', 'Skip Cloud support tags, and the cloudv2 repository access they need. A GitHub token is still required either way: the extractor clones the private streaming-enterprise repo to read the source')
|
|
1085
|
+
.option('--skip-rp-util', 'Keep cluster/broker scope Tree-sitter-only, skipping the rp_util merge step (default: use rp_util when available, falling back to Tree-sitter-only data if its schema cannot be obtained)')
|
|
1085
1086
|
.option('--template-property <path>', 'Custom Handlebars template for individual property sections')
|
|
1086
1087
|
.option('--template-topic-property <path>', 'Custom Handlebars template for topic property sections')
|
|
1087
1088
|
.option('--template-topic-property-mappings <path>', 'Custom Handlebars template for topic property mappings table')
|
|
@@ -1156,6 +1157,7 @@ automation
|
|
|
1156
1157
|
if (githubToken) env.GH_TOKEN = githubToken
|
|
1157
1158
|
if (overrides) env.OVERRIDES = path.resolve(overrides)
|
|
1158
1159
|
if (options.cloudSupport) env.CLOUD_SUPPORT = '1'
|
|
1160
|
+
if (options.skipRpUtil) env.SKIP_RP_UTIL = '1'
|
|
1159
1161
|
if (templates.property) env.TEMPLATE_PROPERTY = path.resolve(templates.property)
|
|
1160
1162
|
if (templates.topicProperty) env.TEMPLATE_TOPIC_PROPERTY = path.resolve(templates.topicProperty)
|
|
1161
1163
|
if (templates.topicPropertyMappings) env.TEMPLATE_TOPIC_PROPERTY_MAPPINGS = path.resolve(templates.topicPropertyMappings)
|
package/package.json
CHANGED
|
@@ -57,6 +57,17 @@ build: venv redpanda-git treesitter
|
|
|
57
57
|
$(if $(CLOUD_SUPPORT),--cloud-support,)
|
|
58
58
|
@echo "✅ JSON generated at $(TOOL_ROOT)/gen/properties-output.json"
|
|
59
59
|
@echo "✅ Enhanced JSON (with overrides) generated at $(TOOL_ROOT)/gen/$(TAG)-properties.json"
|
|
60
|
+
@if [ -z "$(SKIP_RP_UTIL)" ]; then \
|
|
61
|
+
echo "🔀 Merging rp_util schema for cluster/broker scope…"; \
|
|
62
|
+
cd $(TOOL_ROOT) && node merge-rp-util.js \
|
|
63
|
+
--tag $(TAG) \
|
|
64
|
+
--enhanced gen/$(TAG)-properties.json \
|
|
65
|
+
--output gen/$(TAG)-properties.json \
|
|
66
|
+
$(if $(OVERRIDES),$(if $(shell [ -f "$(OVERRIDES)" ] && echo exists),--overrides $(OVERRIDES),),) \
|
|
67
|
+
$(if $(CLOUD_SUPPORT),--cloud-support,); \
|
|
68
|
+
else \
|
|
69
|
+
echo "⏭️ Skipping rp_util merge (SKIP_RP_UTIL set) -- cluster/broker scope stays Tree-sitter-only"; \
|
|
70
|
+
fi
|
|
60
71
|
@$(MAKE) generate-docs
|
|
61
72
|
|
|
62
73
|
# --- Ensure Python venv & dependencies ---
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Overwrite cluster/broker scope in an already-extracted --enhanced-output
|
|
6
|
+
* file with rp_util's runtime-introspected data, in place.
|
|
7
|
+
*
|
|
8
|
+
* Called from the Makefile's `build` target, after property_extractor.py's
|
|
9
|
+
* Tree-sitter extraction and before generate-docs renders the result. Topic
|
|
10
|
+
* properties (rp_util has no equivalent) and anything rp_util doesn't cover
|
|
11
|
+
* pass through untouched -- see rp_util_merge.py.
|
|
12
|
+
*
|
|
13
|
+
* Failure behavior depends on what kind of ref is being built:
|
|
14
|
+
*
|
|
15
|
+
* Branch refs (dev, feature branches): never fails the build. If rp_util's
|
|
16
|
+
* schema can't be obtained (no published release for this ref, no GitHub
|
|
17
|
+
* token, no Docker/Bazel available to build from source) or the merge
|
|
18
|
+
* itself errors, this logs a warning and leaves the Tree-sitter-only
|
|
19
|
+
* extraction as the enhanced file, exactly as it already was before this
|
|
20
|
+
* step ran. In-progress content tolerates the degraded data; it gets
|
|
21
|
+
* regenerated constantly.
|
|
22
|
+
*
|
|
23
|
+
* Release tags (v26.3.0, v26.3.1-rc1, ...): fails the build. A release run
|
|
24
|
+
* is the one that publishes the property reference, and shipping the
|
|
25
|
+
* Tree-sitter-only extraction there is not a degradation readers can see
|
|
26
|
+
* past: post streaming-enterprise#63, it silently drops enum_set
|
|
27
|
+
* properties (http_authentication) and misparses others behind a green
|
|
28
|
+
* job. The fix is to publish the schema first (the publish-rp-util-schema
|
|
29
|
+
* workflow, which also runs on a schedule) and re-run; --skip-rp-util /
|
|
30
|
+
* SKIP_RP_UTIL=1 remains the explicit opt-out.
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* node merge-rp-util.js --tag <ref> --enhanced <path> [--overrides <path>] [--output <path>]
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
const fs = require('fs')
|
|
37
|
+
const os = require('os')
|
|
38
|
+
const path = require('path')
|
|
39
|
+
const { spawnSync } = require('child_process')
|
|
40
|
+
const { getRpUtilSchema, SCHEMA_FLAGS } = require('./rp-util-fetch')
|
|
41
|
+
const bigIntJson = require('../../cli-utils/big-int-json')
|
|
42
|
+
|
|
43
|
+
function getArg(args, flag) {
|
|
44
|
+
const i = args.indexOf(flag)
|
|
45
|
+
return i === -1 ? undefined : args[i + 1]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// A ref this pipeline treats as a release build: vX.Y.Z, with or without an
|
|
49
|
+
// -rcN suffix (RC tags feed the docs beta branch, which publishes too). Same
|
|
50
|
+
// release/RC shape streaming-enterprise's own dispatch-docs-updates.yml keys
|
|
51
|
+
// on. Everything else (dev, feature branches, bare SHAs) is in-progress
|
|
52
|
+
// content where a degraded merge is tolerable.
|
|
53
|
+
const RELEASE_TAG_RX = /^v?\d+\.\d+\.\d+(-rc\d+)?$/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Handle a step of the rp_util merge being unavailable: fatal for a release
|
|
57
|
+
* tag (see the header comment), a warning plus the Tree-sitter fallback for
|
|
58
|
+
* everything else.
|
|
59
|
+
*/
|
|
60
|
+
function handleMergeUnavailable(tag, enhanced, reason) {
|
|
61
|
+
if (RELEASE_TAG_RX.test(tag)) {
|
|
62
|
+
// Print the canonical v-prefixed tag in the remediation command:
|
|
63
|
+
// streaming-enterprise tags (and therefore schema release names) are
|
|
64
|
+
// always v-prefixed, so telling the operator to publish a v-less name
|
|
65
|
+
// would send them to a workflow run that can never help.
|
|
66
|
+
const releaseTag = tag.startsWith('v') ? tag : `v${tag}`
|
|
67
|
+
console.error(`Error: ${reason}`)
|
|
68
|
+
console.error(
|
|
69
|
+
`Refusing to publish Tree-sitter-only property data for release ${tag}: ` +
|
|
70
|
+
'it drops or misparses enum_set properties. Publish the rp_util schema ' +
|
|
71
|
+
`first (gh workflow run publish-rp-util-schema.yaml -f tag=${releaseTag}, or wait ` +
|
|
72
|
+
'for its scheduled run) and retry, or pass --skip-rp-util to override.'
|
|
73
|
+
)
|
|
74
|
+
process.exitCode = 1
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
console.warn(`Warning: ${reason}`)
|
|
78
|
+
console.warn('Skipping rp_util merge -- keeping the Tree-sitter-only extraction for cluster/broker scope.')
|
|
79
|
+
markRpUtilMergeUnavailable(enhanced)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// rp_util covers every cluster/broker-scope property (see this file's own
|
|
83
|
+
// header comment), so when its merge is skipped or fails, any cluster/
|
|
84
|
+
// broker property still missing gets_restored isn't "no annotation exists"
|
|
85
|
+
// (the pre-existing, legitimate case property.hbs already renders as an
|
|
86
|
+
// absent row) -- it's "we don't know, because the merge that would have
|
|
87
|
+
// told us didn't run". Mark those explicitly so the template can render
|
|
88
|
+
// that as a visible "Unknown" state instead of silently rendering nothing,
|
|
89
|
+
// which previously made a flaky rp_util fetch indistinguishable from a
|
|
90
|
+
// real upstream change in the generated docs.
|
|
91
|
+
const RP_UTIL_COVERED_SCOPES = new Set(['cluster', 'broker'])
|
|
92
|
+
|
|
93
|
+
function markRpUtilMergeUnavailable(enhancedPath) {
|
|
94
|
+
let data
|
|
95
|
+
try {
|
|
96
|
+
data = bigIntJson.parse(fs.readFileSync(enhancedPath, 'utf8'))
|
|
97
|
+
} catch (err) {
|
|
98
|
+
console.warn(`Warning: could not mark rp_util merge as unavailable in ${enhancedPath}: ${err.message}`)
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
const properties = data.properties || {}
|
|
102
|
+
let marked = 0
|
|
103
|
+
for (const prop of Object.values(properties)) {
|
|
104
|
+
if (!prop || !RP_UTIL_COVERED_SCOPES.has(prop.config_scope)) continue
|
|
105
|
+
if (prop.gets_restored !== undefined) continue
|
|
106
|
+
prop.rp_util_merge_status = 'unavailable'
|
|
107
|
+
marked++
|
|
108
|
+
}
|
|
109
|
+
if (marked === 0) return
|
|
110
|
+
try {
|
|
111
|
+
fs.writeFileSync(enhancedPath, bigIntJson.stringify(data))
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.warn(`Warning: could not write rp_util-unavailable marker to ${enhancedPath}: ${err.message}`)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function main() {
|
|
118
|
+
const args = process.argv.slice(2)
|
|
119
|
+
const tag = getArg(args, '--tag')
|
|
120
|
+
const enhanced = getArg(args, '--enhanced')
|
|
121
|
+
const overrides = getArg(args, '--overrides')
|
|
122
|
+
const output = getArg(args, '--output') || enhanced
|
|
123
|
+
const sourcePath = getArg(args, '--source-path')
|
|
124
|
+
// Cluster properties rp_util reports but the Tree-sitter pass never saw
|
|
125
|
+
// have no existing entry to carry cloud metadata forward from, so the
|
|
126
|
+
// merge needs its own CloudConfig to annotate them -- see rp_util_merge.py.
|
|
127
|
+
// Honours CLOUD_SUPPORT=1 as well because that is how doc-tools passes the
|
|
128
|
+
// request down to `make` in the first place.
|
|
129
|
+
const cloudSupport = args.includes('--cloud-support') || process.env.CLOUD_SUPPORT === '1'
|
|
130
|
+
|
|
131
|
+
if (!tag || !enhanced) {
|
|
132
|
+
console.error(
|
|
133
|
+
'Usage: node merge-rp-util.js --tag <ref> --enhanced <path> ' +
|
|
134
|
+
'[--overrides <path>] [--output <path>] [--source-path <dir>] [--cloud-support]'
|
|
135
|
+
)
|
|
136
|
+
process.exit(1)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(`Fetching rp_util schema for ${tag}...`)
|
|
140
|
+
let schemas
|
|
141
|
+
try {
|
|
142
|
+
// --source-path builds from an existing local streaming-enterprise
|
|
143
|
+
// checkout instead of fetching a published release or cloning+building
|
|
144
|
+
// fresh -- same option rp-util-fetch.js itself exposes, useful for
|
|
145
|
+
// local iteration against a branch that has no published schema yet.
|
|
146
|
+
schemas = await getRpUtilSchema(tag, sourcePath ? { sourcePath } : undefined)
|
|
147
|
+
} catch (err) {
|
|
148
|
+
handleMergeUnavailable(tag, enhanced, `could not get rp_util schema for ${tag}: ${err.message}`)
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const schemaDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rp-util-schemas-'))
|
|
153
|
+
try {
|
|
154
|
+
let anySchema = false
|
|
155
|
+
for (const { key } of SCHEMA_FLAGS) {
|
|
156
|
+
if (schemas[key]) {
|
|
157
|
+
fs.writeFileSync(path.join(schemaDir, `${key}.json`), bigIntJson.stringify(schemas[key]))
|
|
158
|
+
anySchema = true
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (!anySchema) {
|
|
162
|
+
handleMergeUnavailable(tag, enhanced, `rp_util schema for ${tag} came back empty.`)
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const venvPython = path.join(__dirname, 'tmp', 'redpanda-property-extractor-venv', 'bin', 'python')
|
|
167
|
+
const pythonBin = fs.existsSync(venvPython) ? venvPython : 'python3'
|
|
168
|
+
|
|
169
|
+
// Write to a temp path and only rename over the real output on success.
|
|
170
|
+
// output frequently equals enhanced (an in-place update), so a partial
|
|
171
|
+
// write from a mid-json.dump failure must never be able to leave that
|
|
172
|
+
// file truncated -- generate-docs reads it right after this returns.
|
|
173
|
+
const tempOutput = `${output}.rp-util-merge-tmp`
|
|
174
|
+
const mergeArgs = [
|
|
175
|
+
'rp_util_merge.py',
|
|
176
|
+
'--enhanced', enhanced,
|
|
177
|
+
'--rp-util-dir', schemaDir,
|
|
178
|
+
'--output', tempOutput
|
|
179
|
+
]
|
|
180
|
+
if (overrides && fs.existsSync(overrides)) {
|
|
181
|
+
mergeArgs.push('--overrides', overrides)
|
|
182
|
+
}
|
|
183
|
+
if (cloudSupport) {
|
|
184
|
+
mergeArgs.push('--cloud-support')
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log('Merging rp_util schema into extracted properties...')
|
|
188
|
+
const result = spawnSync(pythonBin, mergeArgs, { cwd: __dirname, stdio: 'inherit' })
|
|
189
|
+
if (result.error || result.status !== 0) {
|
|
190
|
+
fs.rmSync(tempOutput, { force: true })
|
|
191
|
+
handleMergeUnavailable(
|
|
192
|
+
tag,
|
|
193
|
+
enhanced,
|
|
194
|
+
`rp_util merge failed (${result.error ? result.error.message : `exit ${result.status}`}).`
|
|
195
|
+
)
|
|
196
|
+
} else {
|
|
197
|
+
fs.renameSync(tempOutput, output)
|
|
198
|
+
}
|
|
199
|
+
} finally {
|
|
200
|
+
fs.rmSync(schemaDir, { recursive: true, force: true })
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = { main, markRpUtilMergeUnavailable }
|
|
205
|
+
|
|
206
|
+
if (require.main === module) {
|
|
207
|
+
main()
|
|
208
|
+
}
|