@redpanda-data/docs-extensions-and-macros 4.2.5 → 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.
- package/README.adoc +184 -21
- package/bin/doc-tools.js +328 -0
- package/cli-utils/add-caret-external-links.py +68 -0
- package/cli-utils/beta-from-antora.js +27 -0
- package/cli-utils/generate-cluster-docs.sh +83 -0
- package/cli-utils/install-test-dependencies.sh +158 -0
- package/cli-utils/python-venv.sh +20 -0
- package/cli-utils/start-cluster.sh +53 -0
- package/docker-compose/bootstrap.yml +67 -0
- package/docker-compose/docker-compose.yml +414 -0
- package/docker-compose/generate-profiles.yaml +77 -0
- package/docker-compose/rpk-profile.yaml +24 -0
- package/docker-compose/transactions-schema.json +37 -0
- package/docker-compose/transactions.md +46 -0
- package/docker-compose/transform/README.adoc +73 -0
- package/docker-compose/transform/go.mod +5 -0
- package/docker-compose/transform/go.sum +2 -0
- package/docker-compose/transform/regex.wasm +0 -0
- package/docker-compose/transform/transform.go +122 -0
- package/docker-compose/transform/transform.yaml +33 -0
- package/extension-utils/compute-out.js +38 -0
- package/extension-utils/create-asciidoc-file.js +15 -0
- package/macros/data-template.js +591 -0
- package/package.json +21 -4
- package/tools/docusaurus-to-antora-conversion-scripts/convert-docs.sh +114 -0
- package/tools/docusaurus-to-antora-conversion-scripts/get-file-changes.sh +9 -0
- package/tools/docusaurus-to-antora-conversion-scripts/post-process-asciidoc.js +63 -0
- package/tools/docusaurus-to-antora-conversion-scripts/pre-process-markdown.js +108 -0
- package/tools/fetch-from-github.js +63 -0
- package/tools/gen-rpk-ascii.py +477 -0
- package/tools/get-console-version.js +53 -0
- package/tools/get-redpanda-version.js +53 -0
- package/tools/metrics/metrics.py +199 -0
- package/tools/metrics/requirements.txt +1 -0
- package/tools/property-extractor/Makefile +99 -0
- package/tools/property-extractor/README.adoc +206 -0
- package/tools/property-extractor/definitions.json +245 -0
- package/tools/property-extractor/file_pair.py +7 -0
- package/tools/property-extractor/json-to-asciidoc/generate_docs.py +460 -0
- package/tools/property-extractor/parser.py +224 -0
- package/tools/property-extractor/property_bag.py +4 -0
- package/tools/property-extractor/property_extractor.py +243 -0
- package/tools/property-extractor/requirements.txt +2 -0
- package/tools/property-extractor/tests/transformers_test.py +376 -0
- package/tools/property-extractor/transformers.py +397 -0
package/README.adoc
CHANGED
|
@@ -123,7 +123,7 @@ antora:
|
|
|
123
123
|
- home:ROOT:attachment$custom-file.txt
|
|
124
124
|
----
|
|
125
125
|
|
|
126
|
-
==== Registration
|
|
126
|
+
==== Registration
|
|
127
127
|
|
|
128
128
|
[source,yaml]
|
|
129
129
|
----
|
|
@@ -155,7 +155,7 @@ Any elements, classes, or IDs that you want to exclude from the index.
|
|
|
155
155
|
index-latest-only (optional)::
|
|
156
156
|
Whether to index all versions or just the latest version of a component.
|
|
157
157
|
|
|
158
|
-
==== Registration
|
|
158
|
+
==== Registration
|
|
159
159
|
|
|
160
160
|
```yaml
|
|
161
161
|
antora:
|
|
@@ -246,7 +246,7 @@ This extension does not require any environment variables.
|
|
|
246
246
|
|
|
247
247
|
There are no configurable options for this extension.
|
|
248
248
|
|
|
249
|
-
==== Registration
|
|
249
|
+
==== Registration
|
|
250
250
|
|
|
251
251
|
```yaml
|
|
252
252
|
antora:
|
|
@@ -297,7 +297,7 @@ antora:
|
|
|
297
297
|
upgrade_doc: ROOT:upgrade:index.adoc
|
|
298
298
|
----
|
|
299
299
|
|
|
300
|
-
==== Registration
|
|
300
|
+
==== Registration
|
|
301
301
|
|
|
302
302
|
You can register the extension with a customized configuration for different components in your playbook:
|
|
303
303
|
|
|
@@ -456,7 +456,7 @@ NOTE: If you don't set the environment variable, the latest version of Redpanda
|
|
|
456
456
|
|
|
457
457
|
There are no configurable options for this extension.
|
|
458
458
|
|
|
459
|
-
==== Registration
|
|
459
|
+
==== Registration
|
|
460
460
|
|
|
461
461
|
```yaml
|
|
462
462
|
antora:
|
|
@@ -488,7 +488,7 @@ The following attributes are available to the latest version of the `ROOT` compo
|
|
|
488
488
|
|
|
489
489
|
NOTE: If you don't set the environment variable, the latest versions may not be fetched. When the environment variable is not set, the extension sends unauthenticated requests to GitHub. Unauthenticated requests may result in hitting the API rate limit and cause GitHub to reject the request.
|
|
490
490
|
|
|
491
|
-
==== Registration
|
|
491
|
+
==== Registration
|
|
492
492
|
|
|
493
493
|
```yaml
|
|
494
494
|
antora:
|
|
@@ -508,7 +508,7 @@ This extension does not require any environment variables.
|
|
|
508
508
|
|
|
509
509
|
There are no configurable options for this extension. It operates based on site attributes defined in `add-global-attributes.js` to determine valid categories and subcategories.
|
|
510
510
|
|
|
511
|
-
==== Registration
|
|
511
|
+
==== Registration
|
|
512
512
|
|
|
513
513
|
Register the `validate-attributes` extension in the Antora playbook under the `antora.extensions` key like so:
|
|
514
514
|
|
|
@@ -531,7 +531,7 @@ This extension operates without requiring any specific environment variables.
|
|
|
531
531
|
|
|
532
532
|
This extension does not offer configurable options. It uses the inherent attributes of pages to determine relationships based on `page-categories` and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).
|
|
533
533
|
|
|
534
|
-
==== Registration
|
|
534
|
+
==== Registration
|
|
535
535
|
|
|
536
536
|
To integrate the `related-docs-extension` into your Antora playbook, add it under the `antora.extensions` key as demonstrated below:
|
|
537
537
|
|
|
@@ -554,7 +554,7 @@ This extension does not require any environment variables.
|
|
|
554
554
|
|
|
555
555
|
The extension operates without explicit configuration options. It automatically processes documentation pages to identify and link related labs based on shared `page-categories` attributes and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).
|
|
556
556
|
|
|
557
|
-
==== Registration
|
|
557
|
+
==== Registration
|
|
558
558
|
|
|
559
559
|
Include the `related-labs-extension` in the Antora playbook under the `antora.extensions` key as follows:
|
|
560
560
|
|
|
@@ -579,7 +579,7 @@ The extension accepts the following configuration options:
|
|
|
579
579
|
|
|
580
580
|
attributespath (optional):: Specifies the path to a local YAML file that contains global attributes. If this is provided, the extension will load attributes from this file first. If this path is not provided or no valid attributes are found in the file, the extension will fall back to loading attributes from the `shared` component.
|
|
581
581
|
|
|
582
|
-
==== Registration
|
|
582
|
+
==== Registration
|
|
583
583
|
|
|
584
584
|
```yml
|
|
585
585
|
antora:
|
|
@@ -602,7 +602,7 @@ This extension does not require any environment variables.
|
|
|
602
602
|
|
|
603
603
|
There are no configurable options for this extension.
|
|
604
604
|
|
|
605
|
-
==== Registration
|
|
605
|
+
==== Registration
|
|
606
606
|
|
|
607
607
|
```yaml
|
|
608
608
|
antora:
|
|
@@ -640,7 +640,7 @@ data.replacements (required):: An array of replacement configurations. Each conf
|
|
|
640
640
|
|
|
641
641
|
NOTE: Ensure that `file_patterns` accurately reflect the paths of the attachments you want to process. Overly broad patterns may include unintended files, while overly restrictive patterns might exclude necessary resources.
|
|
642
642
|
|
|
643
|
-
==== Registration
|
|
643
|
+
==== Registration
|
|
644
644
|
|
|
645
645
|
This is an example of how to register and configure the `replace-attributes-in-attachments` extension in your Antora playbook. This example demonstrates defining multiple replacement configurations, each targeting different components and specifying their own file patterns and custom replacements.
|
|
646
646
|
|
|
@@ -698,7 +698,7 @@ Term files should follow the following structure:
|
|
|
698
698
|
This is the detailed description of the term.
|
|
699
699
|
```
|
|
700
700
|
|
|
701
|
-
==== Registration
|
|
701
|
+
==== Registration
|
|
702
702
|
|
|
703
703
|
```yml
|
|
704
704
|
antora:
|
|
@@ -729,7 +729,7 @@ Whether to add unlisted pages to the navigation. The default is `false` (unliste
|
|
|
729
729
|
unlistedPagesHeading (optional)::
|
|
730
730
|
The heading under which to list the unlisted pages in the navigation. The default is 'Unlisted Pages'.
|
|
731
731
|
|
|
732
|
-
==== Registration
|
|
732
|
+
==== Registration
|
|
733
733
|
|
|
734
734
|
```yaml
|
|
735
735
|
antora:
|
|
@@ -749,7 +749,7 @@ IMPORTANT: Be sure to register each extension under the `asciidoc.extensions` ke
|
|
|
749
749
|
|
|
750
750
|
This extension adds the necessary classes to make line numbers and line highlighting work with Prism.js.
|
|
751
751
|
|
|
752
|
-
==== Registration
|
|
752
|
+
==== Registration
|
|
753
753
|
|
|
754
754
|
```yaml
|
|
755
755
|
antora:
|
|
@@ -763,6 +763,108 @@ This section documents the Asciidoc macros that are provided by this library and
|
|
|
763
763
|
|
|
764
764
|
IMPORTANT: Be sure to register each extension under the `asciidoc.extensions` key in the playbook, not the `antora.extensions` key.
|
|
765
765
|
|
|
766
|
+
=== data_template
|
|
767
|
+
|
|
768
|
+
The `data_template` block processor lets you render dynamic AsciiDoc content from external or local data sources (JSON, YAML, or plain text) using Handlebars templates.
|
|
769
|
+
|
|
770
|
+
This is useful for generating documentation from structured data like config fields, component metadata, or examples.
|
|
771
|
+
|
|
772
|
+
=== Usage
|
|
773
|
+
|
|
774
|
+
You can use the `data_template` block macro to dynamically generate AsciiDoc content from structured data files such as JSON or YAML. The macro uses a Handlebars template to render the data.
|
|
775
|
+
|
|
776
|
+
[source,asciidoc]
|
|
777
|
+
----
|
|
778
|
+
[data_template, ROOT:example$connect.json]
|
|
779
|
+
--
|
|
780
|
+
== Component: {{{name}}}
|
|
781
|
+
|
|
782
|
+
Summary: {{{summary}}}
|
|
783
|
+
|
|
784
|
+
{{#each fields}}
|
|
785
|
+
=== {{name}}
|
|
786
|
+
|
|
787
|
+
*Type*: `{{type}}`
|
|
788
|
+
|
|
789
|
+
{{{description}}}
|
|
790
|
+
{{/each}}
|
|
791
|
+
--
|
|
792
|
+
----
|
|
793
|
+
|
|
794
|
+
The block content is a Handlebars template. Fields from the data file are injected into this template during site build.
|
|
795
|
+
|
|
796
|
+
The macro accepts one or two positional attributes:
|
|
797
|
+
|
|
798
|
+
1. The first attribute (`dataPath`) is required and should be the resource ID of the data file.
|
|
799
|
+
2. The second attribute (`overrides`) is optional and allows you to override or merge values from a secondary file.
|
|
800
|
+
|
|
801
|
+
You can apply overrides by specifying a second file:
|
|
802
|
+
|
|
803
|
+
[source,asciidoc]
|
|
804
|
+
----
|
|
805
|
+
[data_template, ROOT:example$connect.json, ROOT:example$overrides.json]
|
|
806
|
+
--
|
|
807
|
+
...template content...
|
|
808
|
+
--
|
|
809
|
+
----
|
|
810
|
+
|
|
811
|
+
In this case:
|
|
812
|
+
|
|
813
|
+
- The macro first loads and parses `connect.json`.
|
|
814
|
+
- Then it loads `overrides.json` and **merges** its values into the base file.
|
|
815
|
+
- Arrays of objects (such as fields or processors) are merged by matching objects with the same `name` key.
|
|
816
|
+
- The result is passed into the Handlebars template.
|
|
817
|
+
|
|
818
|
+
This is useful for tweaking content (like updating a `description`) without modifying the original source file.
|
|
819
|
+
|
|
820
|
+
==== Triple mustaches
|
|
821
|
+
|
|
822
|
+
When your data contains AsciiDoc markup (like lists, admonitions, or headings), use triple curly braces:
|
|
823
|
+
|
|
824
|
+
[source,handlebars]
|
|
825
|
+
----
|
|
826
|
+
{{{description}}}
|
|
827
|
+
----
|
|
828
|
+
|
|
829
|
+
This tells Handlebars to not escape the content, so Asciidoctor can render it correctly.
|
|
830
|
+
|
|
831
|
+
==== Handlebars helpers
|
|
832
|
+
|
|
833
|
+
The following helpers are available inside templates:
|
|
834
|
+
|
|
835
|
+
* `eq`, `ne` — Equality helpers.
|
|
836
|
+
* `uppercase` — Converts text to uppercase.
|
|
837
|
+
* `renderConnectFields` — Renders config fields for Redpanda Connect.
|
|
838
|
+
* `renderConnectExamples` — Renders usage examples.
|
|
839
|
+
* `selectByJsonPath` — Selects items from the data using a JSONPath expression.
|
|
840
|
+
|
|
841
|
+
==== Registration
|
|
842
|
+
|
|
843
|
+
To use this macro, register it in your Antora playbook:
|
|
844
|
+
|
|
845
|
+
[source,yaml]
|
|
846
|
+
----
|
|
847
|
+
asciidoc:
|
|
848
|
+
extensions:
|
|
849
|
+
- '@redpanda-data/docs-extensions-and-macros/macros/data-template'
|
|
850
|
+
----
|
|
851
|
+
|
|
852
|
+
==== Example
|
|
853
|
+
|
|
854
|
+
You can use the `selectByJsonPath` helper to filter data. For example, if you want to render only the `redis` processor's fields from a JSON file, you can do it like this:
|
|
855
|
+
|
|
856
|
+
[source,asciidoc]
|
|
857
|
+
----
|
|
858
|
+
[data_template, redpanda-connect:ROOT:example$connect.json]
|
|
859
|
+
--
|
|
860
|
+
{{#selectByJsonPath this "$.processors[?(@.name=='redis')]" }}
|
|
861
|
+
{{renderConnectFields this.config.children}}
|
|
862
|
+
{{/selectByJsonPath}}
|
|
863
|
+
--
|
|
864
|
+
----
|
|
865
|
+
|
|
866
|
+
This will render only the fields for the `redis` processor.
|
|
867
|
+
|
|
766
868
|
=== config_ref
|
|
767
869
|
|
|
768
870
|
This inline macro is used to generate a reference to a configuration value in the Redpanda documentation. The macro's parameters allow for control over the generated reference's format and the type of output produced.
|
|
@@ -798,7 +900,7 @@ For example:
|
|
|
798
900
|
config_ref:example_config,true,tunable-properties[]
|
|
799
901
|
----
|
|
800
902
|
|
|
801
|
-
==== Registration
|
|
903
|
+
==== Registration
|
|
802
904
|
|
|
803
905
|
[,yaml]
|
|
804
906
|
----
|
|
@@ -807,6 +909,67 @@ asciidoc:
|
|
|
807
909
|
- '@redpanda-data/docs-extensions-and-macros/macros/config-ref'
|
|
808
910
|
----
|
|
809
911
|
|
|
912
|
+
=== data_template
|
|
913
|
+
|
|
914
|
+
The `data_template` macro provides a way to dynamically generate AsciiDoc content by combining external or local data sources with Handlebars templates. When you use the `data_template` block macro, the extension performs the following steps:
|
|
915
|
+
|
|
916
|
+
* Resolves the `dataPath` attribute to locate a data file (in JSON, YAML, or raw text format).
|
|
917
|
+
* Fetches and caches external resources or reads local files from the Antora content catalog.
|
|
918
|
+
* Parses the data file.
|
|
919
|
+
* Compiles the block's content as a Handlebars template, injecting the parsed data.
|
|
920
|
+
* Processes the resulting text as AsciiDoc using Asciidoctor to generate the final HTML output.
|
|
921
|
+
|
|
922
|
+
By default, Handlebars escapes HTML to prevent potential security issues. However, if your data includes AsciiDoc markup (such as headings, lists, or formatting directives), escaping it will prevent Asciidoctor from converting the markup correctly.
|
|
923
|
+
|
|
924
|
+
To ensure that your AsciiDoc syntax is preserved during template rendering, **use the triple curly braces syntax** in your Handlebars templates. For example, if your JSON file contains a `description` field with AsciiDoc content, reference it like this:
|
|
925
|
+
|
|
926
|
+
[source,handlebars]
|
|
927
|
+
----
|
|
928
|
+
{{{description}}}
|
|
929
|
+
----
|
|
930
|
+
|
|
931
|
+
This tells Handlebars to output the content unescaped, allowing Asciidoctor to process the raw AsciiDoc markup correctly.
|
|
932
|
+
|
|
933
|
+
==== Usage
|
|
934
|
+
|
|
935
|
+
In an AsciiDoc document, you can invoke the data template macro as follows:
|
|
936
|
+
|
|
937
|
+
[,asciidoc]
|
|
938
|
+
----
|
|
939
|
+
[data_template, ROOT:example$connect.json]
|
|
940
|
+
--
|
|
941
|
+
Version: {{{version}}}
|
|
942
|
+
|
|
943
|
+
{{#each buffers}}
|
|
944
|
+
|
|
945
|
+
=== {{{this.name}}}
|
|
946
|
+
|
|
947
|
+
Status: {{{this.status}}}
|
|
948
|
+
|
|
949
|
+
{{#if (eq this.name 'memory')}}
|
|
950
|
+
This is a custom description for the memory buffer.
|
|
951
|
+
{{else}}
|
|
952
|
+
{{{this.summary}}}
|
|
953
|
+
{{/if}}
|
|
954
|
+
|
|
955
|
+
{{/each}}
|
|
956
|
+
|
|
957
|
+
--
|
|
958
|
+
----
|
|
959
|
+
|
|
960
|
+
==== Registration
|
|
961
|
+
|
|
962
|
+
Register the macro in your Antora playbook under the `asciidoc.extensions` key:
|
|
963
|
+
|
|
964
|
+
[source,yaml]
|
|
965
|
+
----
|
|
966
|
+
asciidoc:
|
|
967
|
+
extensions:
|
|
968
|
+
- require: '@redpanda-data/docs-extensions-and-macros/macros/data-template'
|
|
969
|
+
----
|
|
970
|
+
|
|
971
|
+
This configuration ensures that during the build process, the data template macro is executed to fetch, parse, and render data as part of your docs.
|
|
972
|
+
|
|
810
973
|
=== glossterm
|
|
811
974
|
|
|
812
975
|
The `glossterm` inline macro provides a way to define and reference glossary terms in your AsciiDoc documents.
|
|
@@ -855,7 +1018,7 @@ Whether to enable tooltips for the defined terms. Valid values are:
|
|
|
855
1018
|
|
|
856
1019
|
The last two options are intended to support js/css tooltip solutions such as tippy.js.
|
|
857
1020
|
|
|
858
|
-
==== Registration
|
|
1021
|
+
==== Registration
|
|
859
1022
|
|
|
860
1023
|
[,yaml]
|
|
861
1024
|
----
|
|
@@ -897,7 +1060,7 @@ For default values and documentation for configuration options, see the https://
|
|
|
897
1060
|
|
|
898
1061
|
If you do not specify a Helm reference value, the macro generates a link without specifying a path.
|
|
899
1062
|
|
|
900
|
-
==== Registration
|
|
1063
|
+
==== Registration
|
|
901
1064
|
|
|
902
1065
|
[,yaml]
|
|
903
1066
|
----
|
|
@@ -918,7 +1081,7 @@ The categories are fetched from the `connectCategoriesData` that's generated in
|
|
|
918
1081
|
components_by_category::[<type>]
|
|
919
1082
|
```
|
|
920
1083
|
|
|
921
|
-
==== Registration
|
|
1084
|
+
==== Registration
|
|
922
1085
|
|
|
923
1086
|
```yaml
|
|
924
1087
|
asciidoc:
|
|
@@ -938,7 +1101,7 @@ The types are fetched from the `flatComponentsData` that's generated in the <<Co
|
|
|
938
1101
|
component_table::[]
|
|
939
1102
|
```
|
|
940
1103
|
|
|
941
|
-
==== Registration
|
|
1104
|
+
==== Registration
|
|
942
1105
|
|
|
943
1106
|
```yaml
|
|
944
1107
|
asciidoc:
|
|
@@ -958,7 +1121,7 @@ The types are fetched from the `flatComponentsData` that's generated in the <<Co
|
|
|
958
1121
|
component_type_dropdown::[]
|
|
959
1122
|
```
|
|
960
1123
|
|
|
961
|
-
==== Registration
|
|
1124
|
+
==== Registration
|
|
962
1125
|
|
|
963
1126
|
```yaml
|
|
964
1127
|
asciidoc:
|
package/bin/doc-tools.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync, spawnSync } = require('child_process');
|
|
4
|
+
const { Command } = require('commander');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
// --------------------------------------------------------------------
|
|
9
|
+
// Dependency check functions
|
|
10
|
+
// --------------------------------------------------------------------
|
|
11
|
+
function checkDependency(command, versionArg, name, helpURL) {
|
|
12
|
+
try {
|
|
13
|
+
execSync(`${command} ${versionArg}`, { stdio: 'ignore' });
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.error(`Error: ${name} is required but not found or not working properly.
|
|
16
|
+
Please install ${name} and try again.
|
|
17
|
+
For more info, see: ${helpURL}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function checkCommandExists(command) {
|
|
23
|
+
try {
|
|
24
|
+
execSync(`which ${command}`, { stdio: 'ignore' });
|
|
25
|
+
return true;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(`Error: \`${command}\` is required but not found. Please install \`${command}\` and try again.`);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function checkMake() {
|
|
33
|
+
if (!checkCommandExists('make')) {
|
|
34
|
+
console.error('Error: `make` is required but not found. Please install `make` to use the automation Makefile. For help, see: https://www.google.com/search?q=how+to+install+make');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function checkPython() {
|
|
40
|
+
const candidates = ['python3', 'python'];
|
|
41
|
+
let found = false;
|
|
42
|
+
|
|
43
|
+
for (const cmd of candidates) {
|
|
44
|
+
try {
|
|
45
|
+
const versionOutput = execSync(`${cmd} --version`, {
|
|
46
|
+
encoding: 'utf8',
|
|
47
|
+
stdio: ['pipe', 'pipe', 'ignore']
|
|
48
|
+
}).trim();
|
|
49
|
+
// versionOutput looks like "Python 3.x.y"
|
|
50
|
+
const versionString = versionOutput.split(' ')[1];
|
|
51
|
+
const [major, minor] = versionString.split('.').map(Number);
|
|
52
|
+
if (major > 3 || (major === 3 && minor >= 10)) {
|
|
53
|
+
found = true;
|
|
54
|
+
break;
|
|
55
|
+
} else {
|
|
56
|
+
console.error(`Error: Python 3.10 or higher is required. Detected version: ${versionString}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
// this candidate didn’t exist or errored—try the next one
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!found) {
|
|
64
|
+
console.error('Error: Python 3.10 or higher is required but not found.\nPlease install Python and ensure `python3 --version` or `python --version` returns at least 3.10: https://www.geeksforgeeks.org/how-to-install-python-on-mac/');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function checkCompiler() {
|
|
70
|
+
const gccInstalled = checkCommandExists('gcc');
|
|
71
|
+
const clangInstalled = checkCommandExists('clang');
|
|
72
|
+
if (!gccInstalled && !clangInstalled) {
|
|
73
|
+
console.error('Error: A C++ compiler (such as gcc or clang) is required but not found. Please install one: https://osxdaily.com/2023/05/02/how-install-gcc-mac/');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function checkDocker() {
|
|
79
|
+
checkDependency('docker', '--version', 'Docker', 'https://docs.docker.com/get-docker/');
|
|
80
|
+
try {
|
|
81
|
+
execSync('docker info', { stdio: 'ignore' });
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('Error: Docker daemon appears to be not running. Please start Docker.');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function verifyPropertyDependencies() {
|
|
89
|
+
checkMake();
|
|
90
|
+
checkPython();
|
|
91
|
+
checkCompiler();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function verifyMetricsDependencies() {
|
|
95
|
+
checkPython();
|
|
96
|
+
if (!checkCommandExists('curl') || !checkCommandExists('tar')) {
|
|
97
|
+
// `checkCommandExists` already prints a helpful message.
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
checkDocker();
|
|
101
|
+
}
|
|
102
|
+
// --------------------------------------------------------------------
|
|
103
|
+
// Main CLI Definition
|
|
104
|
+
// --------------------------------------------------------------------
|
|
105
|
+
const programCli = new Command();
|
|
106
|
+
|
|
107
|
+
programCli
|
|
108
|
+
.name('doc-tools')
|
|
109
|
+
.description('Redpanda Document Automation CLI')
|
|
110
|
+
.version('1.0.0');
|
|
111
|
+
|
|
112
|
+
// Top-level commands.
|
|
113
|
+
programCli
|
|
114
|
+
.command('install-test-dependencies')
|
|
115
|
+
.description('Install packages for doc test workflows')
|
|
116
|
+
.action(() => {
|
|
117
|
+
const scriptPath = path.join(__dirname, '../cli-utils/install-test-dependencies.sh');
|
|
118
|
+
const result = spawnSync(scriptPath, { stdio: 'inherit', shell: true });
|
|
119
|
+
process.exit(result.status);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
programCli
|
|
123
|
+
.command('get-redpanda-version')
|
|
124
|
+
.description('Print the latest Redpanda version')
|
|
125
|
+
.option('--beta', 'Return the latest RC (beta) version if available')
|
|
126
|
+
.option('--from-antora', 'Read prerelease flag from local antora.yml')
|
|
127
|
+
.action(async (options) => {
|
|
128
|
+
try {
|
|
129
|
+
await require('../tools/get-redpanda-version.js')(options);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
console.error(err);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
programCli
|
|
137
|
+
.command('get-console-version')
|
|
138
|
+
.description('Print the latest Console version')
|
|
139
|
+
.option('--beta', 'Return the latest beta version if available')
|
|
140
|
+
.option('--from-antora', 'Read prerelease flag from local antora.yml')
|
|
141
|
+
.action(async (options) => {
|
|
142
|
+
try {
|
|
143
|
+
await require('../tools/get-console-version.js')(options);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error(err);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Create an "automation" subcommand group.
|
|
151
|
+
const automation = new Command('generate')
|
|
152
|
+
.description('Run docs automations (properties, metrics, and rpk docs generation)');
|
|
153
|
+
|
|
154
|
+
// --------------------------------------------------------------------
|
|
155
|
+
// Automation Subcommands: Delegate to a unified Bash script internally.
|
|
156
|
+
// --------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
// Common options for both automation tasks.
|
|
159
|
+
const commonOptions = {
|
|
160
|
+
tag: 'latest',
|
|
161
|
+
dockerRepo: 'redpanda',
|
|
162
|
+
consoleTag: 'latest',
|
|
163
|
+
consoleDockerRepo: 'console'
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
function runClusterDocs(mode, tag, options) {
|
|
167
|
+
const script = path.join(__dirname, '../cli-utils/generate-cluster-docs.sh');
|
|
168
|
+
const args = [ mode, tag, options.dockerRepo, options.consoleTag, options.consoleDockerRepo ];
|
|
169
|
+
console.log(`Running ${script} with arguments: ${args.join(' ')}`);
|
|
170
|
+
const r = spawnSync('bash', [ script, ...args ], { stdio: 'inherit', shell: true });
|
|
171
|
+
if (r.status !== 0) process.exit(r.status);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// helper to diff two autogenerated directories
|
|
175
|
+
function diffDirs(kind, oldTag, newTag) {
|
|
176
|
+
const oldDir = path.join('autogenerated', oldTag, kind);
|
|
177
|
+
const newDir = path.join('autogenerated', newTag, kind);
|
|
178
|
+
const diffDir = path.join('autogenerated', 'diffs', kind, `${oldTag}_to_${newTag}`);
|
|
179
|
+
const patch = path.join(diffDir, 'changes.patch');
|
|
180
|
+
|
|
181
|
+
if (!fs.existsSync(oldDir)) {
|
|
182
|
+
console.error(`❌ Cannot diff: missing ${oldDir}`);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
if (!fs.existsSync(newDir)) {
|
|
186
|
+
console.error(`❌ Cannot diff: missing ${newDir}`);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
fs.mkdirSync(diffDir, { recursive: true });
|
|
191
|
+
|
|
192
|
+
const cmd = `diff -ru "${oldDir}" "${newDir}" > "${patch}" || true`;
|
|
193
|
+
const res = spawnSync(cmd, { stdio: 'inherit', shell: true });
|
|
194
|
+
|
|
195
|
+
if (res.error) {
|
|
196
|
+
console.error(`❌ diff failed: ${res.error.message}`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
console.log(`✅ Wrote patch: ${patch}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
automation
|
|
203
|
+
.command('metrics-docs')
|
|
204
|
+
.description('Extract Redpanda metrics and generate JSON/AsciiDoc docs')
|
|
205
|
+
.option('--tag <tag>', 'Redpanda tag (default: latest)', commonOptions.tag)
|
|
206
|
+
.option('--docker-repo <repo>', '...', commonOptions.dockerRepo)
|
|
207
|
+
.option('--console-tag <tag>', '...', commonOptions.consoleTag)
|
|
208
|
+
.option('--console-docker-repo <repo>', '...', commonOptions.consoleDockerRepo)
|
|
209
|
+
.option('--diff <oldTag>', 'Also diff autogenerated metrics from <oldTag> → <tag>')
|
|
210
|
+
.action((options) => {
|
|
211
|
+
verifyMetricsDependencies();
|
|
212
|
+
|
|
213
|
+
const newTag = options.tag;
|
|
214
|
+
const oldTag = options.diff;
|
|
215
|
+
|
|
216
|
+
if (oldTag) {
|
|
217
|
+
const oldDir = path.join('autogenerated', oldTag, 'metrics');
|
|
218
|
+
if (!fs.existsSync(oldDir)) {
|
|
219
|
+
console.log(`⏳ Generating metrics docs for old tag ${oldTag}…`);
|
|
220
|
+
runClusterDocs('metrics', oldTag, options);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log(`⏳ Generating metrics docs for new tag ${newTag}…`);
|
|
225
|
+
runClusterDocs('metrics', newTag, options);
|
|
226
|
+
|
|
227
|
+
if (oldTag) {
|
|
228
|
+
diffDirs('metrics', oldTag, newTag);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
process.exit(0);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
automation
|
|
235
|
+
.command('property-docs')
|
|
236
|
+
.description('Extract properties from Redpanda source')
|
|
237
|
+
.option('--tag <tag>', 'Git tag or branch to extract from (default: dev)', 'dev')
|
|
238
|
+
.option('--diff <oldTag>', 'Also diff autogenerated properties from <oldTag> → <tag>')
|
|
239
|
+
.action((options) => {
|
|
240
|
+
verifyPropertyDependencies();
|
|
241
|
+
|
|
242
|
+
const newTag = options.tag;
|
|
243
|
+
const oldTag = options.diff;
|
|
244
|
+
const cwd = path.resolve(__dirname, '../tools/property-extractor');
|
|
245
|
+
const make = (tag) => {
|
|
246
|
+
console.log(`⏳ Building property docs for ${tag}…`);
|
|
247
|
+
const r = spawnSync('make', ['build', `TAG=${tag}`], { cwd, stdio: 'inherit' });
|
|
248
|
+
if (r.error ) { console.error(r.error); process.exit(1); }
|
|
249
|
+
if (r.status !== 0) process.exit(r.status);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
if (oldTag) {
|
|
253
|
+
const oldDir = path.join('autogenerated', oldTag, 'properties');
|
|
254
|
+
if (!fs.existsSync(oldDir)) make(oldTag);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
make(newTag);
|
|
258
|
+
|
|
259
|
+
if (oldTag) {
|
|
260
|
+
diffDirs('properties', oldTag, newTag);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
process.exit(0);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
automation
|
|
267
|
+
.command('rpk-docs')
|
|
268
|
+
.description('Generate documentation for rpk commands')
|
|
269
|
+
.option('--tag <tag>', 'Redpanda tag (default: latest)', commonOptions.tag)
|
|
270
|
+
.option('--docker-repo <repo>', '...', commonOptions.dockerRepo)
|
|
271
|
+
.option('--console-tag <tag>', '...', commonOptions.consoleTag)
|
|
272
|
+
.option('--console-docker-repo <repo>', '...', commonOptions.consoleDockerRepo)
|
|
273
|
+
.option('--diff <oldTag>', 'Also diff autogenerated rpk docs from <oldTag> → <tag>')
|
|
274
|
+
.action((options) => {
|
|
275
|
+
verifyMetricsDependencies();
|
|
276
|
+
|
|
277
|
+
const newTag = options.tag;
|
|
278
|
+
const oldTag = options.diff;
|
|
279
|
+
|
|
280
|
+
if (oldTag) {
|
|
281
|
+
const oldDir = path.join('autogenerated', oldTag, 'rpk');
|
|
282
|
+
if (!fs.existsSync(oldDir)) {
|
|
283
|
+
console.log(`⏳ Generating rpk docs for old tag ${oldTag}…`);
|
|
284
|
+
runClusterDocs('rpk', oldTag, options);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
console.log(`⏳ Generating rpk docs for new tag ${newTag}…`);
|
|
289
|
+
runClusterDocs('rpk', newTag, options);
|
|
290
|
+
|
|
291
|
+
if (oldTag) {
|
|
292
|
+
diffDirs('rpk', oldTag, newTag);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
process.exit(0);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
programCli
|
|
299
|
+
.command('fetch')
|
|
300
|
+
.description('Fetch a file or directory from GitHub and save locally')
|
|
301
|
+
.requiredOption('-o, --owner <owner>', 'GitHub repo owner or org')
|
|
302
|
+
.requiredOption('-r, --repo <repo>', 'GitHub repo name')
|
|
303
|
+
.requiredOption('-p, --remote-path <path>', 'Path in the repo to fetch')
|
|
304
|
+
.requiredOption('-d, --save-dir <dir>', 'Local directory to save into')
|
|
305
|
+
.option('-f, --filename <name>', 'Custom filename to save as')
|
|
306
|
+
.action(async (options) => {
|
|
307
|
+
try {
|
|
308
|
+
const fetchFromGithub = await require('../tools/fetch-from-github.js');
|
|
309
|
+
// options.owner, options.repo, options.remotePath, options.saveDir, options.filename
|
|
310
|
+
await fetchFromGithub(
|
|
311
|
+
options.owner,
|
|
312
|
+
options.repo,
|
|
313
|
+
options.remotePath,
|
|
314
|
+
options.saveDir,
|
|
315
|
+
options.filename
|
|
316
|
+
);
|
|
317
|
+
} catch (err) {
|
|
318
|
+
console.error('❌', err.message);
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
// Attach the automation group to the main program.
|
|
325
|
+
programCli.addCommand(automation);
|
|
326
|
+
|
|
327
|
+
programCli.parse(process.argv);
|
|
328
|
+
|