@redpanda-data/docs-extensions-and-macros 4.8.1 → 4.9.1

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
@@ -546,6 +676,7 @@ automation
546
676
  .description('Generate RPCN connector docs and diff changes since the last version')
547
677
  .option('-d, --data-dir <path>', 'Directory where versioned connect JSON files live', path.resolve(process.cwd(), 'docs-data'))
548
678
  .option('--old-data <path>', 'Optional override for old data file (for diff)')
679
+ .option('--update-whats-new', 'Update whats-new.adoc with new section from diff JSON')
549
680
  .option('-f, --fetch-connectors', 'Fetch latest connector data using rpk')
550
681
  .option('-m, --draft-missing', 'Generate full-doc drafts for connectors missing in output')
551
682
  .option('--csv <path>', 'Path to connector metadata CSV file', 'internal/plugins/info.csv')
@@ -553,7 +684,9 @@ automation
553
684
  .option('--template-intro <path>', 'Intro section partial template', path.resolve(__dirname, '../tools/redpanda-connect/templates/intro.hbs'))
554
685
  .option('--template-fields <path>', 'Fields section partial template', path.resolve(__dirname, '../tools/redpanda-connect/templates/fields-partials.hbs'))
555
686
  .option('--template-examples <path>', 'Examples section partial template', path.resolve(__dirname, '../tools/redpanda-connect/templates/examples-partials.hbs'))
687
+ .option('--template-bloblang <path>', 'Custom Handlebars template for bloblang function/method partials')
556
688
  .option('--overrides <path>', 'Optional JSON file with overrides')
689
+ .option('--include-bloblang', 'Include Bloblang functions and methods in generation')
557
690
  .action(async (options) => {
558
691
  requireTool('rpk', {
559
692
  versionFlag: '--version',
@@ -614,7 +747,9 @@ automation
614
747
  templateIntro: options.templateIntro,
615
748
  templateFields: options.templateFields,
616
749
  templateExamples: options.templateExamples,
617
- writeFullDrafts: false
750
+ templateBloblang: options.templateBloblang,
751
+ writeFullDrafts: false,
752
+ includeBloblang: !!options.includeBloblang
618
753
  });
619
754
  partialsWritten = result.partialsWritten;
620
755
  partialFiles = result.partialFiles;
@@ -696,10 +831,13 @@ automation
696
831
  }
697
832
 
698
833
  let oldIndex = {};
834
+ let oldVersion = null;
699
835
  if (options.oldData && fs.existsSync(options.oldData)) {
700
836
  oldIndex = JSON.parse(fs.readFileSync(options.oldData, 'utf8'));
837
+ const m = options.oldData.match(/connect-([\d.]+)\.json$/);
838
+ if (m) oldVersion = m[1];
701
839
  } else {
702
- const oldVersion = getAntoraValue('asciidoc.attributes.latest-connect-version');
840
+ oldVersion = getAntoraValue('asciidoc.attributes.latest-connect-version');
703
841
  if (oldVersion) {
704
842
  const oldPath = path.join(dataDir, `connect-${oldVersion}.json`);
705
843
  if (fs.existsSync(oldPath)) {
@@ -711,6 +849,21 @@ automation
711
849
  const newIndex = JSON.parse(fs.readFileSync(dataFile, 'utf8'));
712
850
  printDeltaReport(oldIndex, newIndex);
713
851
 
852
+ // Generate JSON diff file for whats-new.adoc
853
+ const { generateConnectorDiffJson } = require('../tools/redpanda-connect/report-delta.js');
854
+ const diffJson = generateConnectorDiffJson(
855
+ oldIndex,
856
+ newIndex,
857
+ {
858
+ oldVersion: oldVersion || '',
859
+ newVersion,
860
+ timestamp
861
+ }
862
+ );
863
+ const diffPath = path.join(dataDir, `connect-diff-${(oldVersion || 'unknown')}_to_${newVersion}.json`);
864
+ fs.writeFileSync(diffPath, JSON.stringify(diffJson, null, 2), 'utf8');
865
+ console.log(`āœ… Connector diff JSON written to: ${diffPath}`);
866
+
714
867
  function logCollapsed(label, filesArray, maxToShow = 10) {
715
868
  console.log(` • ${label}: ${filesArray.length} total`);
716
869
  const sample = filesArray.slice(0, maxToShow);
@@ -742,6 +895,135 @@ automation
742
895
  logCollapsed('Draft files', draftFiles, 5);
743
896
  }
744
897
 
898
+ // Optionally update whats-new.adoc
899
+ if (options.updateWhatsNew) {
900
+ try {
901
+ const whatsNewPath = path.join(findRepoRoot(), 'modules/get-started/pages/whats-new.adoc');
902
+ if (!fs.existsSync(whatsNewPath)) {
903
+ console.error(`āŒ Unable to update release notes: 'whats-new.adoc' was not found at: ${whatsNewPath}\nPlease ensure this file exists and is tracked in your repository.`);
904
+ return;
905
+ }
906
+ // Find the diff JSON file we just wrote
907
+ const diffPath = path.join(dataDir, `connect-diff-${(oldVersion || 'unknown')}_to_${newVersion}.json`);
908
+ if (!fs.existsSync(diffPath)) {
909
+ console.error(`āŒ Unable to update release notes: The connector diff JSON was not found at: ${diffPath}\nPlease ensure the diff was generated successfully before updating release notes.`);
910
+ return;
911
+ }
912
+ let diff;
913
+ try {
914
+ diff = JSON.parse(fs.readFileSync(diffPath, 'utf8'));
915
+ } catch (jsonErr) {
916
+ console.error(`āŒ Unable to parse connector diff JSON at ${diffPath}: ${jsonErr.message}\nPlease check the file for syntax errors or corruption.`);
917
+ return;
918
+ }
919
+ let whatsNewContent;
920
+ try {
921
+ whatsNewContent = fs.readFileSync(whatsNewPath, 'utf8');
922
+ } catch (readErr) {
923
+ console.error(`āŒ Unable to read whats-new.adoc at ${whatsNewPath}: ${readErr.message}\nPlease check file permissions and try again.`);
924
+ return;
925
+ }
926
+ const whatsNew = whatsNewContent;
927
+ // Regex to find section for this version
928
+ const versionTitle = `== Version ${diff.comparison.newVersion}`;
929
+ const versionRe = new RegExp(`^== Version ${diff.comparison.newVersion.replace(/[-.]/g, '\\$&')}(?:\\r?\\n|$)`, 'm');
930
+ const match = versionRe.exec(whatsNew);
931
+ let startIdx = match ? match.index : -1;
932
+ let endIdx = -1;
933
+ if (startIdx !== -1) {
934
+ // Find the start of the next version section
935
+ const rest = whatsNew.slice(startIdx + 1);
936
+ const nextMatch = /^== Version /m.exec(rest);
937
+ endIdx = nextMatch ? startIdx + 1 + nextMatch.index : whatsNew.length;
938
+ }
939
+ // Compose new section
940
+ let section = `\n== Version ${diff.comparison.newVersion}\n\n=== Component updates\n\n`;
941
+ // Add link to full release notes for this connector version after version heading and before component updates
942
+ let releaseNotesLink = '';
943
+ if (diff.comparison && diff.comparison.newVersion) {
944
+ releaseNotesLink = `link:https://github.com/redpanda-data/connect/releases/tag/v${diff.comparison.newVersion}[See the full release notes^].\n\n`;
945
+ }
946
+ section = `\n== Version ${diff.comparison.newVersion}\n\n${releaseNotesLink}=== Component updates\n\n`;
947
+ // New components
948
+ if (diff.details.newComponents && diff.details.newComponents.length) {
949
+ section += 'This release adds the following new components:\n\n';
950
+ // Group by type
951
+ const byType = {};
952
+ for (const comp of diff.details.newComponents) {
953
+ if (!byType[comp.type]) byType[comp.type] = [];
954
+ byType[comp.type].push(comp);
955
+ }
956
+ for (const [type, comps] of Object.entries(byType)) {
957
+ section += `* ${type.charAt(0).toUpperCase() + type.slice(1)}:\n`;
958
+ for (const comp of comps) {
959
+ section += `** xref:components:${type}/${comp.name}.adoc[\`${comp.name}\`]`;
960
+ if (comp.status) section += ` (${comp.status})`;
961
+ if (comp.description) section += `: ${comp.description}`;
962
+ section += '\n';
963
+ }
964
+ }
965
+ }
966
+
967
+ // New fields
968
+ if (diff.details.newFields && diff.details.newFields.length) {
969
+ section += '\nThis release adds support for the following new fields:\n\n';
970
+ // Group new fields by component type
971
+ const fieldsByType = {};
972
+ for (const field of diff.details.newFields) {
973
+ // component: "inputs:kafka", field: "timely_nacks_maximum_wait"
974
+ const [type, compName] = field.component.split(':');
975
+ if (!fieldsByType[type]) fieldsByType[type] = [];
976
+ fieldsByType[type].push({
977
+ compName,
978
+ field: field.field,
979
+ description: field.description || '',
980
+ });
981
+ }
982
+ for (const [type, fields] of Object.entries(fieldsByType)) {
983
+ section += `* ${type.charAt(0).toUpperCase() + type.slice(1)} components\n`;
984
+ // Group by component name
985
+ const byComp = {};
986
+ for (const f of fields) {
987
+ if (!byComp[f.compName]) byComp[f.compName] = [];
988
+ byComp[f.compName].push(f);
989
+ }
990
+ for (const [comp, compFields] of Object.entries(byComp)) {
991
+ section += `** xref:components:${type}/${comp}.adoc['${comp}']`;
992
+ if (compFields.length === 1) {
993
+ const f = compFields[0];
994
+ section += `: xref:components:${type}/${comp}.adoc#${f.field}['${f.field}']`;
995
+ if (f.description) section += ` - ${f.description}`;
996
+ section += '\n';
997
+ } else {
998
+ section += '\n';
999
+ for (const f of compFields) {
1000
+ section += `*** xref:components:${type}/${comp}.adoc#${f.field}['${f.field}']`;
1001
+ if (f.description) section += ` - ${f.description}`;
1002
+ section += '\n';
1003
+ }
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+ let updated;
1009
+ if (startIdx !== -1) {
1010
+ // Replace the existing section
1011
+ updated = whatsNew.slice(0, startIdx) + section + '\n' + whatsNew.slice(endIdx);
1012
+ console.log(`ā™»ļø whats-new.adoc: replaced section for Version ${diff.comparison.newVersion}`);
1013
+ } else {
1014
+ // Insert above first version heading
1015
+ const versionHeading = /^== Version /m;
1016
+ const firstMatch = versionHeading.exec(whatsNew);
1017
+ let insertIdx = firstMatch ? firstMatch.index : 0;
1018
+ updated = whatsNew.slice(0, insertIdx) + section + '\n' + whatsNew.slice(insertIdx);
1019
+ console.log(`āœ… whats-new.adoc updated with Version ${diff.comparison.newVersion}`);
1020
+ }
1021
+ fs.writeFileSync(whatsNewPath, updated, 'utf8');
1022
+ } catch (err) {
1023
+ console.error(`āŒ Failed to update whats-new.adoc: ${err.message}`);
1024
+ }
1025
+ }
1026
+
745
1027
  console.log('\nšŸ“„ Summary:');
746
1028
  console.log(` • Run time: ${timestamp}`);
747
1029
  console.log(` • Version used: ${newVersion}`);
@@ -755,20 +1037,47 @@ automation
755
1037
  .option('--diff <oldTag>', 'Also diff autogenerated properties from <oldTag> → <tag>')
756
1038
  .option('--overrides <path>', 'Optional JSON file with property description overrides')
757
1039
  .option('--output-dir <dir>', 'Where to write all generated files', 'modules/reference')
1040
+ .option('--cloud-support', 'Enable cloud support metadata by fetching configuration from the cloudv2 repository (requires GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN)')
758
1041
  .option('--template-property-page <path>', 'Custom Handlebars template for property page layout')
759
1042
  .option('--template-property <path>', 'Custom Handlebars template for individual property sections')
1043
+ .option('--template-topic-property <path>', 'Custom Handlebars template for individual topic property sections')
760
1044
  .option('--template-deprecated <path>', 'Custom Handlebars template for deprecated properties page')
761
1045
  .option('--template-deprecated-property <path>', 'Custom Handlebars template for individual deprecated property sections')
762
1046
  .action((options) => {
763
1047
  verifyPropertyDependencies();
764
1048
 
1049
+ // Validate cloud support dependencies if requested
1050
+ if (options.cloudSupport) {
1051
+ console.log('šŸ” Validating cloud support dependencies...');
1052
+
1053
+ // Check for GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN
1054
+ const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || process.env.REDPANDA_GITHUB_TOKEN;
1055
+ if (!token) {
1056
+ console.error('āŒ Cloud support requires GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN environment variable');
1057
+ console.error(' Set up GitHub token:');
1058
+ console.error(' 1. Go to https://github.com/settings/tokens');
1059
+ console.error(' 2. Generate token with "repo" scope');
1060
+ console.error(' 3. Set: export GITHUB_TOKEN=your_token_here');
1061
+ console.error(' Or: export GH_TOKEN=your_token_here');
1062
+ console.error(' Or: export REDPANDA_GITHUB_TOKEN=your_token_here');
1063
+ process.exit(1);
1064
+ }
1065
+
1066
+ console.log('šŸ“¦ Cloud support enabled - Python dependencies will be validated during execution');
1067
+ if (process.env.VIRTUAL_ENV) {
1068
+ console.log(` Using virtual environment: ${process.env.VIRTUAL_ENV}`);
1069
+ }
1070
+ console.log(' Required packages: pyyaml, requests');
1071
+ console.log('āœ… GitHub token validated');
1072
+ }
1073
+
765
1074
  const newTag = options.tag;
766
1075
  const oldTag = options.diff;
767
1076
  const overridesPath = options.overrides;
768
1077
  const outputDir = options.outputDir;
769
1078
  const cwd = path.resolve(__dirname, '../tools/property-extractor');
770
1079
 
771
- const make = (tag, overrides, templates = {}, outputDir = 'modules/reference/', tempDir = null) => {
1080
+ const make = (tag, overrides, templates = {}, outputDir = 'modules/reference/', tempDir = null, cloudSupport = false) => {
772
1081
  console.log(`ā³ Building property docs for ${tag}${tempDir ? ' (for diff)' : ''}…`);
773
1082
  const args = ['build', `TAG=${tag}`];
774
1083
 
@@ -777,12 +1086,18 @@ automation
777
1086
  if (overrides) {
778
1087
  env.OVERRIDES = path.resolve(overrides);
779
1088
  }
1089
+ if (cloudSupport) {
1090
+ env.CLOUD_SUPPORT = '1';
1091
+ }
780
1092
  if (templates.propertyPage) {
781
1093
  env.TEMPLATE_PROPERTY_PAGE = path.resolve(templates.propertyPage);
782
1094
  }
783
1095
  if (templates.property) {
784
1096
  env.TEMPLATE_PROPERTY = path.resolve(templates.property);
785
1097
  }
1098
+ if (templates.topicProperty) {
1099
+ env.TEMPLATE_TOPIC_PROPERTY = path.resolve(templates.topicProperty);
1100
+ }
786
1101
  if (templates.deprecated) {
787
1102
  env.TEMPLATE_DEPRECATED = path.resolve(templates.deprecated);
788
1103
  }
@@ -791,13 +1106,9 @@ automation
791
1106
  }
792
1107
 
793
1108
  if (tempDir) {
794
- // For diff purposes, generate to temporary directory
795
- env.OUTPUT_ASCIIDOC_DIR = path.resolve(tempDir);
796
1109
  env.OUTPUT_JSON_DIR = path.resolve(tempDir, 'examples');
797
1110
  env.OUTPUT_AUTOGENERATED_DIR = path.resolve(tempDir);
798
1111
  } else {
799
- // Normal generation - go directly to final destination
800
- // Let Makefile calculate OUTPUT_ASCIIDOC_DIR as OUTPUT_AUTOGENERATED_DIR/pages
801
1112
  env.OUTPUT_JSON_DIR = path.resolve(outputDir, 'examples');
802
1113
  env.OUTPUT_AUTOGENERATED_DIR = path.resolve(outputDir);
803
1114
  }
@@ -814,34 +1125,22 @@ automation
814
1125
  const templates = {
815
1126
  propertyPage: options.templatePropertyPage,
816
1127
  property: options.templateProperty,
1128
+ topicProperty: options.templateTopicProperty,
817
1129
  deprecated: options.templateDeprecated,
818
1130
  deprecatedProperty: options.templateDeprecatedProperty
819
1131
  };
820
1132
 
821
- let oldTempDir = null;
822
- let newTempDir = null;
823
-
824
1133
  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);
1134
+ // Generate old version directly to final destination so its JSON is available for comparison
1135
+ make(oldTag, overridesPath, templates, outputDir, null, options.cloudSupport);
829
1136
  }
830
1137
 
1138
+ // Generate new version to final destination
1139
+ make(newTag, overridesPath, templates, outputDir, null, options.cloudSupport);
1140
+
831
1141
  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);
1142
+ // Generate property comparison report using the JSON files now in modules/reference/examples
1143
+ generatePropertyComparisonReport(oldTag, newTag, 'modules/reference');
845
1144
  }
846
1145
 
847
1146
  process.exit(0);
@@ -1050,9 +1349,9 @@ automation
1050
1349
  const { generateCloudRegions } = require('../tools/cloud-regions/generate-cloud-regions.js');
1051
1350
 
1052
1351
  try {
1053
- const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
1352
+ const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || process.env.REDPANDA_GITHUB_TOKEN;
1054
1353
  if (!token) {
1055
- throw new Error('GITHUB_TOKEN environment variable is required to fetch from private cloudv2-infra repo.');
1354
+ throw new Error('GITHUB_TOKEN, GH_TOKEN, or REDPANDA_GITHUB_TOKEN environment variable is required to fetch from private cloudv2-infra repo.');
1056
1355
  }
1057
1356
  const fmt = (options.format || 'md').toLowerCase();
1058
1357
  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.1",
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: