@redpanda-data/docs-extensions-and-macros 4.8.1 → 4.9.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 CHANGED
@@ -459,18 +459,120 @@ const commonOptions = {
459
459
  consoleDockerRepo: 'console',
460
460
  };
461
461
 
462
+ /**
463
+ * Run the cluster documentation generator script for a specific release/tag.
464
+ *
465
+ * Invokes the external `generate-cluster-docs.sh` script with the provided mode, tag,
466
+ * and Docker-related options. The script's stdout/stderr are forwarded to the current
467
+ * process; if the script exits with a non-zero status, this function will terminate
468
+ * the Node.js process with that status code.
469
+ *
470
+ * @param {string} mode - Operation mode passed to the script (e.g., "generate" or "clean").
471
+ * @param {string} tag - Release tag or version to generate docs for.
472
+ * @param {Object} options - Runtime options.
473
+ * @param {string} options.dockerRepo - Docker repository used by the script.
474
+ * @param {string} options.consoleTag - Console image tag passed to the script.
475
+ * @param {string} options.consoleDockerRepo - Console Docker repository used by the script.
476
+ */
462
477
  function runClusterDocs(mode, tag, options) {
463
478
  const script = path.join(__dirname, '../cli-utils/generate-cluster-docs.sh');
464
479
  const args = [mode, tag, options.dockerRepo, options.consoleTag, options.consoleDockerRepo];
465
480
  console.log(`ā³ Running ${script} with arguments: ${args.join(' ')}`);
466
- const r = spawnSync('bash', [script, ...args], { stdio: 'inherit', shell: true });
481
+ const r = spawnSync('bash', [script, ...args], { stdio: 'inherit' });
467
482
  if (r.status !== 0) process.exit(r.status);
468
483
  }
469
484
 
470
- // helper to diff two temporary directories
485
+ /**
486
+ * Generate a detailed JSON report describing property changes between two releases.
487
+ *
488
+ * Looks for `<oldTag>-properties.json` and `<newTag>-properties.json` in
489
+ * `modules/reference/examples`. If both files exist, invokes the external
490
+ * property comparison tool to produce `property-changes-<oldTag>-to-<newTag>.json`
491
+ * in the provided output directory.
492
+ *
493
+ * If either input JSON is missing the function logs a message and returns without
494
+ * error. Any errors from the comparison tool are logged; the function does not
495
+ * throw.
496
+ *
497
+ * @param {string} oldTag - Release tag or identifier for the "old" properties set.
498
+ * @param {string} newTag - Release tag or identifier for the "new" properties set.
499
+ * @param {string} outputDir - Directory where the comparison report will be written.
500
+ */
501
+ function generatePropertyComparisonReport(oldTag, newTag, outputDir) {
502
+ try {
503
+ console.log(`\nšŸ“Š Generating detailed property comparison report...`);
504
+
505
+ // Look for the property JSON files in modules/reference/examples
506
+ const repoRoot = findRepoRoot();
507
+ const examplesDir = path.join(repoRoot, 'modules', 'reference', 'examples');
508
+ const oldJsonPath = path.join(examplesDir, `${oldTag}-properties.json`);
509
+ const newJsonPath = path.join(examplesDir, `${newTag}-properties.json`);
510
+
511
+ // Check if JSON files exist
512
+ if (!fs.existsSync(oldJsonPath)) {
513
+ console.log(`āš ļø Old properties JSON not found at: ${oldJsonPath}`);
514
+ console.log(` Skipping detailed property comparison.`);
515
+ return;
516
+ }
517
+
518
+ if (!fs.existsSync(newJsonPath)) {
519
+ console.log(`āš ļø New properties JSON not found at: ${newJsonPath}`);
520
+ console.log(` Skipping detailed property comparison.`);
521
+ return;
522
+ }
523
+
524
+ // Ensure output directory exists (use absolute path)
525
+ const absoluteOutputDir = path.resolve(outputDir);
526
+ fs.mkdirSync(absoluteOutputDir, { recursive: true });
527
+
528
+ // Run the property comparison tool with descriptive filename
529
+ const propertyExtractorDir = path.resolve(__dirname, '../tools/property-extractor');
530
+ const compareScript = path.join(propertyExtractorDir, 'compare-properties.js');
531
+ const reportFilename = `property-changes-${oldTag}-to-${newTag}.json`;
532
+ const reportPath = path.join(absoluteOutputDir, reportFilename);
533
+ const args = [compareScript, oldJsonPath, newJsonPath, oldTag, newTag, absoluteOutputDir, reportFilename];
534
+
535
+ const result = spawnSync('node', args, {
536
+ stdio: 'inherit',
537
+ cwd: propertyExtractorDir
538
+ });
539
+
540
+ if (result.error) {
541
+ console.error(`āŒ Property comparison failed: ${result.error.message}`);
542
+ } else if (result.status !== 0) {
543
+ console.error(`āŒ Property comparison exited with code: ${result.status}`);
544
+ } else {
545
+ console.log(`āœ… Property comparison report saved to: ${reportPath}`);
546
+ }
547
+ } catch (error) {
548
+ console.error(`āŒ Error generating property comparison: ${error.message}`);
549
+ }
550
+ }
551
+
552
+ /**
553
+ * Create a unified diff patch between two temporary directories and clean them up.
554
+ *
555
+ * Ensures both source directories exist, writes a recursive unified diff
556
+ * (changes.patch) to tmp/diffs/<kind>/<oldTag>_to_<newTag>/, and removes the
557
+ * provided temporary directories. On missing inputs or if the diff subprocess
558
+ * fails to spawn, the process exits with a non-zero status.
559
+ *
560
+ * @param {string} kind - Logical category for the diff (e.g., "metrics" or "rpk"); used in the output path.
561
+ * @param {string} oldTag - Identifier for the "old" version (used in the output path).
562
+ * @param {string} newTag - Identifier for the "new" version (used in the output path).
563
+ * @param {string} oldTempDir - Path to the existing temporary directory containing the old output; must exist.
564
+ * @param {string} newTempDir - Path to the existing temporary directory containing the new output; must exist.
565
+ */
471
566
  function diffDirs(kind, oldTag, newTag, oldTempDir, newTempDir) {
567
+ // Backwards compatibility: if temp directories not provided, use autogenerated paths
568
+ if (!oldTempDir) {
569
+ oldTempDir = path.join('autogenerated', oldTag, kind);
570
+ }
571
+ if (!newTempDir) {
572
+ newTempDir = path.join('autogenerated', newTag, kind);
573
+ }
574
+
472
575
  const diffDir = path.join('tmp', 'diffs', kind, `${oldTag}_to_${newTag}`);
473
- const patch = path.join(diffDir, 'changes.patch');
474
576
 
475
577
  if (!fs.existsSync(oldTempDir)) {
476
578
  console.error(`āŒ Cannot diff: missing ${oldTempDir}`);
@@ -483,6 +585,8 @@ function diffDirs(kind, oldTag, newTag, oldTempDir, newTempDir) {
483
585
 
484
586
  fs.mkdirSync(diffDir, { recursive: true });
485
587
 
588
+ // Generate traditional patch for metrics and rpk
589
+ const patch = path.join(diffDir, 'changes.patch');
486
590
  const cmd = `diff -ru "${oldTempDir}" "${newTempDir}" > "${patch}" || true`;
487
591
  const res = spawnSync(cmd, { stdio: 'inherit', shell: true });
488
592
 
@@ -492,9 +596,35 @@ function diffDirs(kind, oldTag, newTag, oldTempDir, newTempDir) {
492
596
  }
493
597
  console.log(`āœ… Wrote patch: ${patch}`);
494
598
 
495
- // Clean up temporary directories
496
- fs.rmSync(oldTempDir, { recursive: true, force: true });
497
- fs.rmSync(newTempDir, { recursive: true, force: true });
599
+ // Safety guard: only clean up directories that are explicitly passed as temp directories
600
+ // For backwards compatibility with autogenerated paths, don't clean up automatically
601
+ const tmpRoot = path.resolve('tmp') + path.sep;
602
+ const workspaceRoot = path.resolve('.') + path.sep;
603
+
604
+ // Only clean up if directories were explicitly provided as temp directories
605
+ // (indicated by having all 5 parameters) and they're in the tmp/ directory
606
+ const explicitTempDirs = arguments.length >= 5;
607
+
608
+ if (explicitTempDirs) {
609
+ [oldTempDir, newTempDir].forEach(dirPath => {
610
+ const resolvedPath = path.resolve(dirPath) + path.sep;
611
+ const isInTmp = resolvedPath.startsWith(tmpRoot);
612
+ const isInWorkspace = resolvedPath.startsWith(workspaceRoot);
613
+
614
+ if (isInWorkspace && isInTmp) {
615
+ try {
616
+ fs.rmSync(dirPath, { recursive: true, force: true });
617
+ console.log(`🧹 Cleaned up temporary directory: ${dirPath}`);
618
+ } catch (err) {
619
+ console.warn(`āš ļø Warning: Could not clean up directory ${dirPath}: ${err.message}`);
620
+ }
621
+ } else {
622
+ console.log(`ā„¹ļø Skipping cleanup of directory outside tmp/: ${dirPath}`);
623
+ }
624
+ });
625
+ } else {
626
+ console.log(`ā„¹ļø Using autogenerated directories - skipping cleanup for safety`);
627
+ }
498
628
  }
499
629
 
500
630
  automation
@@ -755,20 +885,47 @@ automation
755
885
  .option('--diff <oldTag>', 'Also diff autogenerated properties from <oldTag> → <tag>')
756
886
  .option('--overrides <path>', 'Optional JSON file with property description overrides')
757
887
  .option('--output-dir <dir>', 'Where to write all generated files', 'modules/reference')
888
+ .option('--cloud-support', 'Enable cloud support metadata by fetching configuration from the cloudv2 repository (requires GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN)')
758
889
  .option('--template-property-page <path>', 'Custom Handlebars template for property page layout')
759
890
  .option('--template-property <path>', 'Custom Handlebars template for individual property sections')
891
+ .option('--template-topic-property <path>', 'Custom Handlebars template for individual topic property sections')
760
892
  .option('--template-deprecated <path>', 'Custom Handlebars template for deprecated properties page')
761
893
  .option('--template-deprecated-property <path>', 'Custom Handlebars template for individual deprecated property sections')
762
894
  .action((options) => {
763
895
  verifyPropertyDependencies();
764
896
 
897
+ // Validate cloud support dependencies if requested
898
+ if (options.cloudSupport) {
899
+ console.log('šŸ” Validating cloud support dependencies...');
900
+
901
+ // Check for GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN
902
+ const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || process.env.REDPANDA_GITHUB_TOKEN;
903
+ if (!token) {
904
+ console.error('āŒ Cloud support requires GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN environment variable');
905
+ console.error(' Set up GitHub token:');
906
+ console.error(' 1. Go to https://github.com/settings/tokens');
907
+ console.error(' 2. Generate token with "repo" scope');
908
+ console.error(' 3. Set: export GITHUB_TOKEN=your_token_here');
909
+ console.error(' Or: export GH_TOKEN=your_token_here');
910
+ console.error(' Or: export REDPANDA_GITHUB_TOKEN=your_token_here');
911
+ process.exit(1);
912
+ }
913
+
914
+ console.log('šŸ“¦ Cloud support enabled - Python dependencies will be validated during execution');
915
+ if (process.env.VIRTUAL_ENV) {
916
+ console.log(` Using virtual environment: ${process.env.VIRTUAL_ENV}`);
917
+ }
918
+ console.log(' Required packages: pyyaml, requests');
919
+ console.log('āœ… GitHub token validated');
920
+ }
921
+
765
922
  const newTag = options.tag;
766
923
  const oldTag = options.diff;
767
924
  const overridesPath = options.overrides;
768
925
  const outputDir = options.outputDir;
769
926
  const cwd = path.resolve(__dirname, '../tools/property-extractor');
770
927
 
771
- const make = (tag, overrides, templates = {}, outputDir = 'modules/reference/', tempDir = null) => {
928
+ const make = (tag, overrides, templates = {}, outputDir = 'modules/reference/', tempDir = null, cloudSupport = false) => {
772
929
  console.log(`ā³ Building property docs for ${tag}${tempDir ? ' (for diff)' : ''}…`);
773
930
  const args = ['build', `TAG=${tag}`];
774
931
 
@@ -777,12 +934,18 @@ automation
777
934
  if (overrides) {
778
935
  env.OVERRIDES = path.resolve(overrides);
779
936
  }
937
+ if (cloudSupport) {
938
+ env.CLOUD_SUPPORT = '1';
939
+ }
780
940
  if (templates.propertyPage) {
781
941
  env.TEMPLATE_PROPERTY_PAGE = path.resolve(templates.propertyPage);
782
942
  }
783
943
  if (templates.property) {
784
944
  env.TEMPLATE_PROPERTY = path.resolve(templates.property);
785
945
  }
946
+ if (templates.topicProperty) {
947
+ env.TEMPLATE_TOPIC_PROPERTY = path.resolve(templates.topicProperty);
948
+ }
786
949
  if (templates.deprecated) {
787
950
  env.TEMPLATE_DEPRECATED = path.resolve(templates.deprecated);
788
951
  }
@@ -791,13 +954,9 @@ automation
791
954
  }
792
955
 
793
956
  if (tempDir) {
794
- // For diff purposes, generate to temporary directory
795
- env.OUTPUT_ASCIIDOC_DIR = path.resolve(tempDir);
796
957
  env.OUTPUT_JSON_DIR = path.resolve(tempDir, 'examples');
797
958
  env.OUTPUT_AUTOGENERATED_DIR = path.resolve(tempDir);
798
959
  } else {
799
- // Normal generation - go directly to final destination
800
- // Let Makefile calculate OUTPUT_ASCIIDOC_DIR as OUTPUT_AUTOGENERATED_DIR/pages
801
960
  env.OUTPUT_JSON_DIR = path.resolve(outputDir, 'examples');
802
961
  env.OUTPUT_AUTOGENERATED_DIR = path.resolve(outputDir);
803
962
  }
@@ -814,34 +973,22 @@ automation
814
973
  const templates = {
815
974
  propertyPage: options.templatePropertyPage,
816
975
  property: options.templateProperty,
976
+ topicProperty: options.templateTopicProperty,
817
977
  deprecated: options.templateDeprecated,
818
978
  deprecatedProperty: options.templateDeprecatedProperty
819
979
  };
820
980
 
821
- let oldTempDir = null;
822
- let newTempDir = null;
823
-
824
981
  if (oldTag) {
825
- // Generate old version to temporary directory for diff
826
- oldTempDir = path.join('tmp', 'diff', `${oldTag}-properties`);
827
- fs.mkdirSync(oldTempDir, { recursive: true });
828
- make(oldTag, overridesPath, templates, outputDir, oldTempDir);
982
+ // Generate old version directly to final destination so its JSON is available for comparison
983
+ make(oldTag, overridesPath, templates, outputDir, null, options.cloudSupport);
829
984
  }
830
985
 
986
+ // Generate new version to final destination
987
+ make(newTag, overridesPath, templates, outputDir, null, options.cloudSupport);
988
+
831
989
  if (oldTag) {
832
- // Generate new version to temporary directory for diff
833
- newTempDir = path.join('tmp', 'diff', `${newTag}-properties`);
834
- fs.mkdirSync(newTempDir, { recursive: true });
835
- make(newTag, overridesPath, templates, outputDir, newTempDir);
836
-
837
- // Then generate new version to final destination
838
- make(newTag, overridesPath, templates, outputDir);
839
-
840
- // Compare the temporary directories
841
- diffDirs('properties', oldTag, newTag, oldTempDir, newTempDir);
842
- } else {
843
- // No diff requested, just generate to final destination
844
- make(newTag, overridesPath, templates, outputDir);
990
+ // Generate property comparison report using the JSON files now in modules/reference/examples
991
+ generatePropertyComparisonReport(oldTag, newTag, 'modules/reference');
845
992
  }
846
993
 
847
994
  process.exit(0);
@@ -1050,9 +1197,9 @@ automation
1050
1197
  const { generateCloudRegions } = require('../tools/cloud-regions/generate-cloud-regions.js');
1051
1198
 
1052
1199
  try {
1053
- const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
1200
+ const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || process.env.REDPANDA_GITHUB_TOKEN;
1054
1201
  if (!token) {
1055
- throw new Error('GITHUB_TOKEN environment variable is required to fetch from private cloudv2-infra repo.');
1202
+ throw new Error('GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN environment variable is required to fetch from private cloudv2-infra repo.');
1056
1203
  }
1057
1204
  const fmt = (options.format || 'md').toLowerCase();
1058
1205
  let templatePath = undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redpanda-data/docs-extensions-and-macros",
3
- "version": "4.8.1",
3
+ "version": "4.9.0",
4
4
  "description": "Antora extensions and macros developed for Redpanda documentation.",
5
5
  "keywords": [
6
6
  "antora",
@@ -1,17 +1,5 @@
1
1
  .PHONY: build venv clean redpanda-git treesitter generate-docs check
2
2
 
3
- # --- Main build: venv, fetch code, build parser, extract & docgen ---
4
- build: venv redpanda-git treesitter
5
- @echo "šŸ”§ Building with Redpanda tag: $(TAG)"
6
- @mkdir -p $(TOOL_ROOT)/gen
7
- @cd $(TOOL_ROOT) && \
8
- $(PYTHON) -W ignore::FutureWarning property_extractor.py \
9
- --recursive \
10
- --path $(REDPANDA_SRC) \
11
- --output gen/properties-output.json
12
- @echo "āœ… Cluster properties JSON generated at $(TOOL_ROOT)/gen/properties-output.json"
13
- @$(MAKE) generate-docs
14
-
15
3
  # Default tag (can be overridden via `make TAG=v25.1.1`)
16
4
  TAG ?= dev
17
5
 
@@ -51,12 +39,13 @@ build: venv redpanda-git treesitter
51
39
  exit 1; \
52
40
  fi
53
41
  @cd $(TOOL_ROOT) && \
54
- $(PYTHON) -W ignore::FutureWarning property_extractor.py \
42
+ $(PYTHON) -W ignore property_extractor.py \
55
43
  --recursive \
56
44
  --path $(REDPANDA_SRC) \
57
45
  --output gen/properties-output.json \
58
46
  --enhanced-output gen/$(TAG)-properties.json \
59
- $(if $(OVERRIDES),$(if $(shell [ -f "$(OVERRIDES)" ] && echo exists),--overrides $(OVERRIDES),),)
47
+ $(if $(OVERRIDES),$(if $(shell [ -f "$(OVERRIDES)" ] && echo exists),--overrides $(OVERRIDES),),) \
48
+ $(if $(CLOUD_SUPPORT),--cloud-support,)
60
49
  @echo "āœ… JSON generated at $(TOOL_ROOT)/gen/properties-output.json"
61
50
  @echo "āœ… Enhanced JSON (with overrides) generated at $(TOOL_ROOT)/gen/$(TAG)-properties.json"
62
51
  @$(MAKE) generate-docs
@@ -66,11 +55,12 @@ venv: $(TOOL_ROOT)/requirements.txt
66
55
  @if [ ! -d "$(VENV)" ]; then \
67
56
  echo "šŸ Creating virtual environment in $(VENV)..."; \
68
57
  python3 -m venv $(VENV); \
69
- $(VENV)/bin/pip install --upgrade pip --quiet; \
70
- $(VENV)/bin/pip install --no-cache-dir -r $<; \
71
58
  else \
72
59
  echo "šŸ Virtual environment already exists at $(VENV)"; \
73
- fi
60
+ fi; \
61
+ echo "šŸ”„ Upgrading pip and installing requirements..."; \
62
+ $(VENV)/bin/pip install --upgrade pip --quiet; \
63
+ $(VENV)/bin/pip install --no-cache-dir -r $<;
74
64
 
75
65
  # --- Clean out all generated state ---
76
66
  clean:
@@ -106,7 +96,7 @@ treesitter:
106
96
  git fetch --tags -q && \
107
97
  git checkout -q v0.20.5
108
98
  @echo "šŸ”§ Generating parser in $(TREESITTER_DIR)…"
109
- @cd "$(TREESITTER_DIR)" && npm install --silent && $(TREE_SITTER) generate
99
+ @cd "$(TREESITTER_DIR)" && export CFLAGS="-Wno-unused-but-set-variable" && npm install --silent && export CFLAGS="-Wno-unused-but-set-variable" && $(TREE_SITTER) generate
110
100
 
111
101
  # --- Install Node.js dependencies for Handlebars ---
112
102
  node-deps: