@redpanda-data/docs-extensions-and-macros 4.3.0 → 4.4.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.
Files changed (44) hide show
  1. package/bin/doc-tools.js +328 -0
  2. package/cli-utils/add-caret-external-links.py +68 -0
  3. package/cli-utils/beta-from-antora.js +27 -0
  4. package/cli-utils/generate-cluster-docs.sh +83 -0
  5. package/cli-utils/install-test-dependencies.sh +158 -0
  6. package/cli-utils/python-venv.sh +20 -0
  7. package/cli-utils/start-cluster.sh +53 -0
  8. package/docker-compose/bootstrap.yml +67 -0
  9. package/docker-compose/docker-compose.yml +414 -0
  10. package/docker-compose/generate-profiles.yaml +77 -0
  11. package/docker-compose/rpk-profile.yaml +24 -0
  12. package/docker-compose/transactions-schema.json +37 -0
  13. package/docker-compose/transactions.md +46 -0
  14. package/docker-compose/transform/README.adoc +73 -0
  15. package/docker-compose/transform/go.mod +5 -0
  16. package/docker-compose/transform/go.sum +2 -0
  17. package/docker-compose/transform/regex.wasm +0 -0
  18. package/docker-compose/transform/transform.go +122 -0
  19. package/docker-compose/transform/transform.yaml +33 -0
  20. package/extension-utils/compute-out.js +38 -0
  21. package/extension-utils/create-asciidoc-file.js +15 -0
  22. package/macros/data-template.js +2 -2
  23. package/package.json +15 -3
  24. package/tools/docusaurus-to-antora-conversion-scripts/convert-docs.sh +114 -0
  25. package/tools/docusaurus-to-antora-conversion-scripts/get-file-changes.sh +9 -0
  26. package/tools/docusaurus-to-antora-conversion-scripts/post-process-asciidoc.js +63 -0
  27. package/tools/docusaurus-to-antora-conversion-scripts/pre-process-markdown.js +108 -0
  28. package/tools/fetch-from-github.js +63 -0
  29. package/tools/gen-rpk-ascii.py +477 -0
  30. package/tools/get-console-version.js +53 -0
  31. package/tools/get-redpanda-version.js +53 -0
  32. package/tools/metrics/metrics.py +199 -0
  33. package/tools/metrics/requirements.txt +1 -0
  34. package/tools/property-extractor/Makefile +99 -0
  35. package/tools/property-extractor/README.adoc +206 -0
  36. package/tools/property-extractor/definitions.json +245 -0
  37. package/tools/property-extractor/file_pair.py +7 -0
  38. package/tools/property-extractor/json-to-asciidoc/generate_docs.py +460 -0
  39. package/tools/property-extractor/parser.py +224 -0
  40. package/tools/property-extractor/property_bag.py +4 -0
  41. package/tools/property-extractor/property_extractor.py +243 -0
  42. package/tools/property-extractor/requirements.txt +2 -0
  43. package/tools/property-extractor/tests/transformers_test.py +376 -0
  44. package/tools/property-extractor/transformers.py +397 -0
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ const yaml = require('js-yaml');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const GetLatestConsoleVersion = require('../extensions/version-fetcher/get-latest-console-version.js');
7
+ const { getPrereleaseFromAntora } = require('../cli-utils/beta-from-antora.js');
8
+
9
+ /**
10
+ * Fetches and prints the latest Console version and Docker repo.
11
+ * @param {Object} options
12
+ * @param {boolean} options.beta - Return beta version if available
13
+ * @param {boolean} options.fromAntora - Derive beta flag from antora.yml
14
+ */
15
+ module.exports = async function getConsoleVersion({ beta = false, fromAntora = false }) {
16
+ const owner = 'redpanda-data';
17
+ const repo = 'console';
18
+ const CONSOLE_DOCKER_REPO = repo;
19
+
20
+ // Determine whether to use beta based on antora.yml or flag
21
+ let useBeta = beta;
22
+ if (fromAntora) {
23
+ useBeta = getPrereleaseFromAntora();
24
+ }
25
+
26
+ // Initialize GitHub client
27
+ const { Octokit } = await import('@octokit/rest');
28
+ const octokit = process.env.REDPANDA_GITHUB_TOKEN
29
+ ? new Octokit({ auth: process.env.REDPANDA_GITHUB_TOKEN })
30
+ : new Octokit();
31
+
32
+ // Fetch latest release info
33
+ let data;
34
+ try {
35
+ data = await GetLatestConsoleVersion(octokit, owner, repo);
36
+ } catch (err) {
37
+ console.error('Failed to fetch Console version:', err.message);
38
+ process.exit(1);
39
+ }
40
+
41
+ if (!data) {
42
+ console.error('No version data returned for Console');
43
+ process.exit(1);
44
+ }
45
+
46
+ // Select the version
47
+ const version = useBeta
48
+ ? (data.latestBetaRelease || data.latestStableRelease)
49
+ : data.latestStableRelease;
50
+
51
+ console.log(`CONSOLE_VERSION=${version}`);
52
+ console.log(`CONSOLE_DOCKER_REPO=${CONSOLE_DOCKER_REPO}`);
53
+ };
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ const GetLatestRedpandaVersion = require('../extensions/version-fetcher/get-latest-redpanda-version.js');
4
+ const { getPrereleaseFromAntora } = require('../cli-utils/beta-from-antora.js');
5
+
6
+ /**
7
+ * Fetches and prints the latest Redpanda version and Docker repository.
8
+ * @param {Object} options
9
+ * @param {boolean} options.beta - Whether to prefer RC (beta) releases
10
+ * @param {boolean} options.fromAntora - Whether to derive beta flag from antora.yml
11
+ */
12
+ module.exports = async function getRedpandaVersion({ beta = false, fromAntora = false }) {
13
+ const owner = 'redpanda-data';
14
+ const repo = 'redpanda';
15
+
16
+ // Determine whether to treat this as a beta (RC) release
17
+ let useBeta = beta;
18
+ if (fromAntora) {
19
+ useBeta = getPrereleaseFromAntora();
20
+ }
21
+
22
+ // Load Octokit
23
+ const { Octokit } = await import('@octokit/rest');
24
+ const octokit = process.env.REDPANDA_GITHUB_TOKEN
25
+ ? new Octokit({ auth: process.env.REDPANDA_GITHUB_TOKEN })
26
+ : new Octokit();
27
+
28
+ // Fetch version data
29
+ let data;
30
+ try {
31
+ data = await GetLatestRedpandaVersion(octokit, owner, repo);
32
+ } catch (err) {
33
+ console.error('Failed to fetch the latest Redpanda version:', err.message);
34
+ process.exit(1);
35
+ }
36
+
37
+ if (!data) {
38
+ console.error('No version data returned for Redpanda');
39
+ process.exit(1);
40
+ }
41
+
42
+ // Determine the version string
43
+ const stableVersion = data.latestRedpandaRelease.version;
44
+ const rc = data.latestRcRelease;
45
+ const version = useBeta && rc ? rc.version : stableVersion;
46
+
47
+ // Determine the Docker repository
48
+ const dockerRepo = (useBeta && rc) ? 'redpanda-unstable' : 'redpanda';
49
+
50
+ // Output for downstream consumption
51
+ console.log(`REDPANDA_VERSION=${version}`);
52
+ console.log(`REDPANDA_DOCKER_REPO=${dockerRepo}`);
53
+ };
@@ -0,0 +1,199 @@
1
+ import os
2
+ import sys
3
+ import requests
4
+ import re
5
+ import json
6
+ import logging
7
+
8
+ '''
9
+ ## How it works
10
+
11
+ Fetches metrics from the brokers and parses out the `# HELP` lines, creating:
12
+
13
+ - `metrics.json`
14
+ - `metrics.adoc`
15
+
16
+ These output files are stored in a versioned folder under `docs/autogenerated/<version>/metrics`, based on the major.minor version provided as the first argument.
17
+
18
+ ## Prerequisites
19
+
20
+ - **Python 3** & **pip** on your system.
21
+ - A Redpanda cluster running with the `public_metrics` and `metrics` endpoints exposed at http://localhost:19644/
22
+ '''
23
+
24
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
25
+
26
+ def fetch_metrics(url):
27
+ """Fetch metrics from the given URL."""
28
+ try:
29
+ response = requests.get(url)
30
+ response.raise_for_status()
31
+ return response.text
32
+ except requests.RequestException as e:
33
+ logging.error(f"Error fetching metrics from {url}: {e}")
34
+ return None
35
+
36
+ def parse_metrics(metrics_text):
37
+ """
38
+ Parse Prometheus exposition text into a dict:
39
+ metric_name → { description, type, unit, labels: [<label_keys>] }
40
+
41
+ - Strips empty `{}` on unlabelled samples
42
+ - Propagates HELP/TYPE from base metrics onto _bucket, _count, _sum
43
+ - Works regardless of # HELP / # TYPE order
44
+ - Captures # UNIT metadata if present
45
+ """
46
+
47
+ lines = metrics_text.splitlines()
48
+
49
+ # Gather HELP/TYPE metadata in any order
50
+ # Gather HELP/TYPE metadata in any order
51
+ meta = {} # name → { 'description': str, 'type': str, 'unit': str }
52
+ for line in lines:
53
+ if line.startswith("# HELP"):
54
+ m = re.match(r"# HELP\s+(\S+)\s+(.+)", line)
55
+ if m:
56
+ name, desc = m.groups()
57
+ meta.setdefault(name, {})['description'] = desc
58
+ elif line.startswith("# TYPE"):
59
+ m = re.match(r"# TYPE\s+(\S+)\s+(\S+)", line)
60
+ if m:
61
+ name, mtype = m.groups()
62
+ meta.setdefault(name, {})['type'] = mtype
63
+ elif line.startswith("# UNIT"):
64
+ m = re.match(r"# UNIT\s+(\S+)\s+(.+)", line)
65
+ if m:
66
+ name, unit = m.groups()
67
+ meta.setdefault(name, {})['unit'] = unit
68
+ # Collect label keys from _every_ sample line
69
+ label_map = {} # name → set(label_keys)
70
+ for line in lines:
71
+ if line.startswith("#"):
72
+ continue
73
+
74
+ # labelled: foo{a="1",b="2"} 42
75
+ m_lbl = re.match(r"^(\S+)\{(.+?)\}\s+(.+)", line)
76
+ if m_lbl:
77
+ name, labels_str, _ = m_lbl.groups()
78
+ keys = [kv.split("=",1)[0] for kv in labels_str.split(",")]
79
+ else:
80
+ # unlabelled, maybe with stray {}: foo{} 42 or just foo 42
81
+ m_unlbl = re.match(r"^(\S+?)(?:\{\})?\s+(.+)", line)
82
+ if not m_unlbl:
83
+ continue
84
+ name, _ = m_unlbl.groups()
85
+ keys = []
86
+
87
+ label_map.setdefault(name, set()).update(keys)
88
+
89
+ # Propagate HELP/TYPE from base histograms/summaries
90
+ for series in list(label_map):
91
+ for suffix in ("_bucket", "_count", "_sum"):
92
+ if series.endswith(suffix):
93
+ base = series[:-len(suffix)]
94
+ if base in meta:
95
+ meta.setdefault(series, {}).update(meta[base])
96
+ break
97
+
98
+ # Merge into final metrics dict, with warnings
99
+ metrics = {}
100
+ all_names = set(meta) | set(label_map)
101
+ for name in sorted(all_names):
102
+ desc = meta.get(name, {}).get("description")
103
+ mtype = meta.get(name, {}).get("type")
104
+ unit = meta.get(name, {}).get("unit")
105
+ labels = sorted(label_map.get(name, []))
106
+
107
+ if desc is None:
108
+ logging.warning(f"Metric '{name}' has samples but no # HELP.")
109
+ desc = ""
110
+ if mtype is None:
111
+ logging.warning(f"Metric '{name}' has no # TYPE entry.")
112
+
113
+ metrics[name] = {
114
+ "description": desc,
115
+ "type": mtype,
116
+ "unit": unit,
117
+ "labels": labels
118
+ }
119
+
120
+ logging.info(f"Extracted {len(metrics)} metrics.")
121
+ return metrics
122
+
123
+ def output_asciidoc(metrics, adoc_file):
124
+ """Output metrics as AsciiDoc."""
125
+ with open(adoc_file, "w") as f:
126
+ for name, data in metrics.items():
127
+ f.write(f"=== {name}\n\n")
128
+ f.write(f"{data['description']}\n\n")
129
+ f.write(f"*Type*: {data['type']}")
130
+ if data.get("unit"):
131
+ f.write(f"\n\n*Unit*: {data['unit']}")
132
+ if data["labels"]:
133
+ f.write("\n\n*Labels*:\n")
134
+ for label in data["labels"]:
135
+ f.write(f"\n- `{label}`")
136
+ f.write("\n\n---\n\n")
137
+ logging.info(f"AsciiDoc output written to {adoc_file}")
138
+
139
+ def output_json(metrics, json_file):
140
+ """Output metrics as JSON."""
141
+ with open(json_file, "w") as f:
142
+ json.dump(metrics, f, indent=4)
143
+ logging.info(f"JSON output written to {json_file}")
144
+
145
+ def ensure_directory_exists(directory):
146
+ """Ensure the given directory exists."""
147
+ if not os.path.exists(directory):
148
+ os.makedirs(directory)
149
+
150
+ if __name__ == "__main__":
151
+ # Expect the major.minor version to be provided as the first argument.
152
+ if len(sys.argv) < 2:
153
+ logging.error("Major.minor version must be provided as the first argument. Exiting.")
154
+ sys.exit(1)
155
+
156
+ tag_modified = sys.argv[1].strip()
157
+
158
+ # Resolve the base autogenerated folder at the repo root
159
+ repo_root = os.getcwd()
160
+ gen_path = os.path.join(repo_root, "autogenerated")
161
+ if not os.path.isdir(gen_path):
162
+ logging.error(f"autogenerated folder not found at: {gen_path}")
163
+ sys.exit(1)
164
+
165
+ # Build the output directory using the already provided tag_modified.
166
+ output_dir = os.path.join(gen_path, tag_modified, "metrics")
167
+ ensure_directory_exists(output_dir)
168
+
169
+ METRICS_URL = "http://localhost:19644/public_metrics/"
170
+ metrics_text = fetch_metrics(METRICS_URL)
171
+ if not metrics_text:
172
+ logging.error("No public metrics retrieved. Exiting.")
173
+ sys.exit(1)
174
+
175
+ public_metrics = parse_metrics(metrics_text)
176
+
177
+ # Fetch internal metrics if available.
178
+ INTERNAL_METRICS_URL = "http://localhost:19644/metrics/"
179
+ internal_metrics_text = fetch_metrics(INTERNAL_METRICS_URL)
180
+ if internal_metrics_text:
181
+ internal_metrics = parse_metrics(internal_metrics_text)
182
+ else:
183
+ logging.error("No internal metrics retrieved.")
184
+ internal_metrics = {}
185
+
186
+ # Merge public and internal metrics.
187
+ merged_metrics = {
188
+ "public": public_metrics,
189
+ "internal": internal_metrics
190
+ }
191
+
192
+ # Define output file paths.
193
+ JSON_OUTPUT_FILE = os.path.join(output_dir, "metrics.json")
194
+ ASCIIDOC_OUTPUT_FILE = os.path.join(output_dir, "metrics.adoc")
195
+ INTERNAL_ASCIIDOC_OUTPUT_FILE = os.path.join(output_dir, "internal-metrics.adoc")
196
+
197
+ output_json(merged_metrics, JSON_OUTPUT_FILE)
198
+ output_asciidoc(public_metrics, ASCIIDOC_OUTPUT_FILE)
199
+ output_asciidoc(internal_metrics, INTERNAL_ASCIIDOC_OUTPUT_FILE)
@@ -0,0 +1 @@
1
+ requests==2.32.3
@@ -0,0 +1,99 @@
1
+ .PHONY: build venv clean redpanda-git treesitter generate-docs check
2
+
3
+ # Default tag (can be overridden via `make TAG=v25.1.1`)
4
+ TAG ?= dev
5
+
6
+ # Derive a “major.minor” or rc identifier from TAG for folder naming
7
+ VERSION := $(shell \
8
+ if echo "$(TAG)" | grep -qE '^v?[0-9]+\.[0-9]+'; then \
9
+ echo "$(TAG)" \
10
+ | sed -E 's/^v?([0-9]+\.[0-9]+)(\.[0-9]+)?(-rc[0-9]+)?.*/\1\3/' \
11
+ | sed 's/-rc/rc/'; \
12
+ else \
13
+ echo "$(TAG)"; \
14
+ fi)
15
+
16
+ # Paths
17
+ REPO_ROOT := $(shell git rev-parse --show-toplevel)
18
+ MODULE_ROOT := $(shell cd "$(dir $(realpath $(lastword $(MAKEFILE_LIST))))"/../.. && pwd)
19
+ TOOL_ROOT := $(MODULE_ROOT)/tools/property-extractor
20
+ TMP_ROOT := $(TOOL_ROOT)/tmp
21
+ REDPANDA_SRC := $(TMP_ROOT)/redpanda
22
+ TREESITTER_DIR:= $(TOOL_ROOT)/tree-sitter/tree-sitter-cpp
23
+ VENV := $(TOOL_ROOT)/tmp/redpanda-property-extractor-venv
24
+ PYTHON := $(VENV)/bin/python
25
+ OUTPUT_DIR := $(REPO_ROOT)/autogenerated/$(TAG)/properties
26
+ TREE_SITTER := npx tree-sitter
27
+
28
+ # --- Main build: venv, fetch code, build parser, extract & docgen ---
29
+ build: venv redpanda-git treesitter
30
+ @echo "🔧 Building with Redpanda tag: $(TAG)"
31
+ @mkdir -p $(TOOL_ROOT)/gen
32
+ @cd $(TOOL_ROOT) && \
33
+ $(PYTHON) -W ignore::FutureWarning property_extractor.py \
34
+ --recursive \
35
+ --path $(REDPANDA_SRC) \
36
+ --output gen/properties-output.json
37
+ @echo "✅ JSON generated at $(TOOL_ROOT)/gen/properties-output.json"
38
+ @$(MAKE) generate-docs
39
+
40
+ # --- Ensure Python venv & dependencies ---
41
+ venv: $(TOOL_ROOT)/requirements.txt
42
+ @if [ ! -d "$(VENV)" ]; then \
43
+ echo "🐍 Creating virtual environment in $(VENV)..."; \
44
+ python3 -m venv $(VENV); \
45
+ $(VENV)/bin/pip install --upgrade pip --quiet; \
46
+ $(VENV)/bin/pip install --no-cache-dir -r $<; \
47
+ else \
48
+ echo "🐍 Virtual environment already exists at $(VENV)"; \
49
+ fi
50
+
51
+ # --- Clean out all generated state ---
52
+ clean:
53
+ @echo "🧹 Cleaning up…"
54
+ @rm -rf $(VENV) $(TMP_ROOT) $(REPO_ROOT)/autogenerated
55
+
56
+ # --- Clone or update Redpanda, checkout TAG or default branch ---
57
+ redpanda-git:
58
+ @mkdir -p "$(TMP_ROOT)"
59
+ @echo "🔄 Cloning/updating Redpanda into $(REDPANDA_SRC)…"
60
+ @if [ -d "$(REDPANDA_SRC)" ]; then \
61
+ git -C "$(REDPANDA_SRC)" fetch --all --tags -q; \
62
+ else \
63
+ git clone -q https://github.com/redpanda-data/redpanda.git "$(REDPANDA_SRC)"; \
64
+ fi; \
65
+ if git -C "$(REDPANDA_SRC)" rev-parse --verify -q "$(TAG)" >/dev/null; then \
66
+ echo "🔖 Checking out '$(TAG)'"; \
67
+ git -C "$(REDPANDA_SRC)" checkout -q "$(TAG)"; \
68
+ else \
69
+ DEFAULT_BRANCH=$$(git -C "$(REDPANDA_SRC)" symbolic-ref --short refs/remotes/origin/HEAD); \
70
+ echo "⚠️ Tag '$(TAG)' not found; falling back to '$${DEFAULT_BRANCH}'"; \
71
+ git -C "$(REDPANDA_SRC)" checkout -q "$${DEFAULT_BRANCH}"; \
72
+ fi
73
+
74
+ # --- Clone Tree-sitter grammar & generate parser ---
75
+ treesitter:
76
+ @echo "🌲 Ensuring tree-sitter-cpp grammar…"
77
+ @if [ ! -d "$(TREESITTER_DIR)" ]; then \
78
+ git clone https://github.com/tree-sitter/tree-sitter-cpp.git "$(TREESITTER_DIR)"; \
79
+ fi
80
+ @echo "🔧 Generating parser in $(TREESITTER_DIR)…"
81
+ @cd "$(TREESITTER_DIR)" && npm install --silent && $(TREE_SITTER) generate
82
+
83
+ # --- Turn the JSON into AsciiDoc pages under autogen/<version>/properties ---
84
+ generate-docs:
85
+ @echo "📝 Generating AsciiDoc pages in $(OUTPUT_DIR)…"
86
+ @mkdir -p "$(OUTPUT_DIR)"
87
+ @cd $(TOOL_ROOT) && \
88
+ $(PYTHON) json-to-asciidoc/generate_docs.py --output-dir "$(OUTPUT_DIR)"
89
+ @echo "✅ Docs generated at $(OUTPUT_DIR)"
90
+
91
+ # --- Debug helper to print all the key paths/vars ---
92
+ check:
93
+ @echo "MODULE_ROOT: $(MODULE_ROOT)"
94
+ @echo "TOOL_ROOT: $(TOOL_ROOT)"
95
+ @echo "REDPANDA_SRC: $(REDPANDA_SRC)"
96
+ @echo "TREESITTER: $(TREESITTER_DIR)"
97
+ @echo "VENV: $(VENV)"
98
+ @echo "PYTHON: $(PYTHON)"
99
+ @echo "OUTPUT_DIR: $(OUTPUT_DIR)"
@@ -0,0 +1,206 @@
1
+ = Redpanda Property Generator
2
+
3
+ The Redpanda Property Generator is a CLI tool designed to extract properties from Redpanda's source code and generate a JSON output with their definitions as well as Asciidoc pages.
4
+
5
+ == Prerequisites
6
+
7
+ Ensure the following prerequisites are installed on your system:
8
+
9
+ - https://www.python.org/downloads/[Python 3.10 or higher]
10
+ - A C++ compiler (such as `gcc`, `clang`)
11
+ - https://www.google.com/search?q=how+to+install+make[`make` utility] (to use the Makefile for automation)
12
+ +
13
+ To ensure `make` is available:
14
+ +
15
+ [,bash]
16
+ ----
17
+ make --version
18
+ ----
19
+
20
+ == Install
21
+
22
+ . Clone the repository:
23
+ +
24
+ [,bash]
25
+ ----
26
+ git clone https://github.com/redpanda-data/docs-extensions-and-macros.git
27
+ cd docs-extensions-and-macros
28
+ ----
29
+
30
+ == Generate properties
31
+
32
+ . Run the build process:
33
+ +
34
+ [,bash]
35
+ ----
36
+ cd tools/property-extractor
37
+ make build
38
+ ----
39
+ +
40
+ This command:
41
+ +
42
+ - Sets up the Python virtual environment (`venv`).
43
+ - Checks out the Redpanda source code to the specified branch or tag.
44
+ - Runs the extractor to generate a JSON file at `gen/properties-output.json`.
45
+ - Runs the docs generator to generate Asciidoc pages from the `properties-output.json`.
46
+
47
+ . Locate the generated files:
48
+ +
49
+ [,bash]
50
+ ----
51
+ ls gen/properties-output.json
52
+ ls output
53
+ ----
54
+
55
+ To clean the environment and generated files:
56
+
57
+ [,bash]
58
+ ----
59
+ make clean
60
+ ----
61
+
62
+ == Run the extractor manually
63
+
64
+ To run the extractor tool directly:
65
+
66
+ [,bash]
67
+ ----
68
+ ./property_extractor.py --path <path-to-redpanda-source> [options]
69
+ ----
70
+
71
+ === Command options
72
+
73
+ |===
74
+ | Option | Description
75
+
76
+ | `--path <path>`
77
+ | Path to the Redpanda source directory to extract properties from (required).
78
+ | `--recursive`
79
+ | Recursively scan the provided path for header (`*.h`) and implementation (`*.cc`) file pairs.
80
+ | `--output <output>`
81
+ | Path to the output JSON file. If not provided, the output will be printed to the console.
82
+ | `--definitions <definitions>`
83
+ | Path to the `definitions.json` file for type definitions (default: included `definitions.json`).
84
+ | `-v`, `--verbose`
85
+ | Enable verbose logging for debugging purposes.
86
+ |===
87
+
88
+ === Example command
89
+
90
+ [,bash]
91
+ ----
92
+ ./property_extractor.py --path ./tmp/redpanda --recursive --output autogenerated/properties.json
93
+ ----
94
+
95
+ === How it works
96
+
97
+ . The tool identifies pairs of header (`*.h`) and implementation (`*.cc`) files in the specified Redpanda source directory. This ensures that both the declaration and definition of properties are available.
98
+
99
+ . Tree-sitter is used to parse the C{plus}{plus} source code and create abstract syntax trees (ASTs). Both the Tree-sitter C++ library (via a Git submodule) and its Python bindings (`tree_sitter`) are required for this step.
100
+
101
+ . Custom logic in `property_extractor.py` processes the ASTs to extract property definitions from specific files like:
102
+ +
103
+ - `src/v/config/configuration.cc`
104
+ - `src/v/kafka/client/configuration.cc`
105
+
106
+ . Extracted properties are processed by a series of transformers to enrich and normalize the data. For example:
107
+ +
108
+ - `BasicInfoTransformer`: Extracts names and metadata.
109
+ - `VisibilityTransformer`: Determines visibility (e.g., public or private).
110
+ - `IsNullableTransformer`: Detects if a property is nullable.
111
+
112
+ . The `definitions.json` file is merged into the output, linking property types to their descriptions.
113
+
114
+ === JSON output
115
+
116
+ The final JSON contains:
117
+
118
+ - `properties`: Extracted properties with metadata.
119
+ - `definitions`: Type definitions, merged from `definitions.json`.
120
+
121
+ Example JSON structure:
122
+
123
+ [,json]
124
+ ----
125
+ {
126
+ "properties": {
127
+ "example_property": {
128
+ "type": "string",
129
+ "description": "An example property."
130
+ }
131
+ },
132
+ "definitions": {
133
+ "string": {
134
+ "description": "A string type."
135
+ }
136
+ }
137
+ }
138
+ ----
139
+
140
+ === Custom definitions
141
+
142
+ You can provide a custom `definitions.json` file:
143
+
144
+ [,bash]
145
+ ----
146
+ ./property_extractor.py --path ./tmp/redpanda --definitions custom-definitions.json --output autogenerated/custom-output.json
147
+ ----
148
+
149
+ === Debugging
150
+
151
+ Enable verbose logging to see detailed information:
152
+
153
+ [,bash]
154
+ ----
155
+ ./property_extractor.py --path ./tmp/redpanda --verbose
156
+ ----
157
+
158
+ == Run the docs generator manually
159
+
160
+ . Make sure you have the `autogenerated/properties-output.json` file, relative to the `Makefile` location.
161
+
162
+ . Run the script:
163
+ +
164
+ [,bash]
165
+ ----
166
+ python3 generate_docs.py
167
+ ----
168
+
169
+ The script will process the JSON and generate AsciiDoc files in the `output/pages/` directory.
170
+
171
+ === Output files
172
+
173
+ The following files will be generated:
174
+
175
+ - Broker Properties: `output/pages/broker-properties.adoc`
176
+ - Cluster Properties: `output/pages/cluster-properties.adoc`
177
+ - Object Storage Properties: `output/pages/object-storage-properties.adoc`
178
+ - Deprecated Properties: `output/pages/deprecated/partials/deprecated-properties.adoc`
179
+
180
+ === Error reports
181
+
182
+ If the script encounters issues, it will generate error files in the `output/error/` directory:
183
+
184
+ - `empty_description.txt`: Properties without descriptions.
185
+ - `empty_type.txt`: Properties without types.
186
+ - `max_without_min.txt`: Properties with a maximum value but no minimum.
187
+ - `min_without_max.txt`: Properties with a minimum value but no maximum.
188
+
189
+ The console output will summarize the errors and property statistics.
190
+
191
+ === How it works
192
+
193
+ . Input parsing:
194
+ - The script loads the JSON file from the `autogenerated/` directory.
195
+ - Properties are categorized into groups based on their `defined_in` field or specific naming conventions such as the `cloud_` prefix.
196
+
197
+ . Validation:
198
+ - Validates fields like `description`, `type`, `maximum`, and `minimum`.
199
+ - Identifies missing or inconsistent data and logs these to error files.
200
+
201
+ . Documentation generation:
202
+ - Creates AsciiDoc files with categorized properties, including metadata such as type, default value, visibility, and restart requirements.
203
+ - Appends appropriate titles, introductions, and formatting for each group.
204
+
205
+ . Error reporting: Generates error reports for easy debugging and correction of the input JSON.
206
+