@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.
Files changed (45) hide show
  1. package/README.adoc +184 -21
  2. package/bin/doc-tools.js +328 -0
  3. package/cli-utils/add-caret-external-links.py +68 -0
  4. package/cli-utils/beta-from-antora.js +27 -0
  5. package/cli-utils/generate-cluster-docs.sh +83 -0
  6. package/cli-utils/install-test-dependencies.sh +158 -0
  7. package/cli-utils/python-venv.sh +20 -0
  8. package/cli-utils/start-cluster.sh +53 -0
  9. package/docker-compose/bootstrap.yml +67 -0
  10. package/docker-compose/docker-compose.yml +414 -0
  11. package/docker-compose/generate-profiles.yaml +77 -0
  12. package/docker-compose/rpk-profile.yaml +24 -0
  13. package/docker-compose/transactions-schema.json +37 -0
  14. package/docker-compose/transactions.md +46 -0
  15. package/docker-compose/transform/README.adoc +73 -0
  16. package/docker-compose/transform/go.mod +5 -0
  17. package/docker-compose/transform/go.sum +2 -0
  18. package/docker-compose/transform/regex.wasm +0 -0
  19. package/docker-compose/transform/transform.go +122 -0
  20. package/docker-compose/transform/transform.yaml +33 -0
  21. package/extension-utils/compute-out.js +38 -0
  22. package/extension-utils/create-asciidoc-file.js +15 -0
  23. package/macros/data-template.js +591 -0
  24. package/package.json +21 -4
  25. package/tools/docusaurus-to-antora-conversion-scripts/convert-docs.sh +114 -0
  26. package/tools/docusaurus-to-antora-conversion-scripts/get-file-changes.sh +9 -0
  27. package/tools/docusaurus-to-antora-conversion-scripts/post-process-asciidoc.js +63 -0
  28. package/tools/docusaurus-to-antora-conversion-scripts/pre-process-markdown.js +108 -0
  29. package/tools/fetch-from-github.js +63 -0
  30. package/tools/gen-rpk-ascii.py +477 -0
  31. package/tools/get-console-version.js +53 -0
  32. package/tools/get-redpanda-version.js +53 -0
  33. package/tools/metrics/metrics.py +199 -0
  34. package/tools/metrics/requirements.txt +1 -0
  35. package/tools/property-extractor/Makefile +99 -0
  36. package/tools/property-extractor/README.adoc +206 -0
  37. package/tools/property-extractor/definitions.json +245 -0
  38. package/tools/property-extractor/file_pair.py +7 -0
  39. package/tools/property-extractor/json-to-asciidoc/generate_docs.py +460 -0
  40. package/tools/property-extractor/parser.py +224 -0
  41. package/tools/property-extractor/property_bag.py +4 -0
  42. package/tools/property-extractor/property_extractor.py +243 -0
  43. package/tools/property-extractor/requirements.txt +2 -0
  44. package/tools/property-extractor/tests/transformers_test.py +376 -0
  45. package/tools/property-extractor/transformers.py +397 -0
@@ -0,0 +1,477 @@
1
+ import subprocess
2
+ import re
3
+ import json
4
+ import os
5
+ import filecmp
6
+ import difflib
7
+ import sys
8
+
9
+ suggestedReadings = """
10
+
11
+ ---
12
+
13
+ <SuggestedReading/>
14
+
15
+ - [Introducing rpk container](https://redpanda.com/blog/rpk-container/)
16
+ - [Getting started with rpk commands](https://redpanda.com/blog/getting-started-rpk/)
17
+ """
18
+
19
+
20
+ cmd_dict = {}
21
+ basic_commands_docker = ["docker","exec","-it"]
22
+ basic_commands_docker.append("redpanda-1")
23
+ rpk_basic_command = ["rpk"]
24
+
25
+ def assert_period(s):return s if s.endswith('.') else s + '.'
26
+
27
+ def escape_chars(s):
28
+
29
+ s = s.replace("./<timestamp>-bundle.zip", "./&lt;timestamp&gt;-bundle.zip")
30
+ return s
31
+
32
+ def cmp_rpk_ascii(dir1, dir2, outdir=""):
33
+ if outdir:
34
+ for root1, _, files1 in os.walk(dir1):
35
+ for file1 in files1:
36
+ for root2, _, files2 in os.walk(dir2):
37
+ for file2 in files2:
38
+ if file1 == file2:
39
+ file_path1 = os.path.join(root1, file1)
40
+ file_path2 = os.path.join(root2, file2)
41
+ if not filecmp.cmp(file_path1, file_path2, shallow=False):
42
+ with open(file_path1, "r") as f1, open(file_path2, "r") as f2:
43
+ lines1 = f1.readlines()
44
+ lines2 = f2.readlines()
45
+ diff = difflib.unified_diff(lines1, lines2, file_path1, file_path2)
46
+ outfile = outdir + "/diff_" + os.path.basename(file_path1)
47
+ with open(outfile, "w") as fo:
48
+ fo.write("\n".join(diff))
49
+ print("Wrote " + outfile)
50
+
51
+ class Flag:
52
+ def __init__(self, value: str, flag_type: str, explanation: str):
53
+ self.value = value
54
+ self.flag_type = flag_type
55
+ self.explanation = explanation
56
+
57
+
58
+ # Execute a subprocess inside a Linux machine. If the command is multi level (such as rpk acl create) it generates a bigger list
59
+ def execute_process(commands):
60
+ if len(commands) > 0:
61
+ commands = commands[0].split(" ")
62
+ commands_to_execute = basic_commands_docker + rpk_basic_command + commands
63
+ commands_to_execute.append("-h")
64
+ try:
65
+ process = subprocess.run(
66
+ commands_to_execute,
67
+ stdout=subprocess.PIPE,
68
+ stderr=subprocess.PIPE,
69
+ check=True,
70
+ )
71
+ return process.stdout.decode("utf-8")
72
+ except subprocess.CalledProcessError as e:
73
+ print(f"Error executing command: {' '.join(commands_to_execute)}")
74
+ print(f"Error message: {e.stderr.decode('utf-8')}")
75
+ sys.exit(1)
76
+
77
+
78
+ # Get the explanation written before the usage. Example:
79
+ """ # rpk is the Redpanda CLI & toolbox.
80
+ # Usage:
81
+ # rpk [command] """
82
+
83
+
84
+ def get_explanation(process_line):
85
+ explanation_line = process_line[: process_line.find("Usage")].rstrip("\n").strip()
86
+ explanation_line = explanation_line.replace("redpanda.yaml","`redpanda.yaml`")
87
+ return explanation_line
88
+
89
+
90
+ # Get the usage of the command. If it's an initial command, look for available commands. If it's a final command, then look for flags. Finally if neither are present, extract the usage. Example:
91
+ """ Usage:
92
+ rpk [command]
93
+
94
+ Available Commands:
95
+ acl Manage ACLs and SASL users.
96
+ cluster Interact with a Redpanda cluster.
97
+ container Manage a local container cluster.
98
+ debug Debug the local Redpanda process.
99
+ generate Generate a configuration template for related services.
100
+ group Describe, list, and delete consumer groups and manage their offsets.
101
+ help Help about any command
102
+ iotune Measure filesystem performance and create IO configuration file.
103
+ plugin List, download, update, and remove rpk plugins.
104
+ redpanda Interact with a local Redpanda process
105
+ topic Create, delete, produce to and consume from Redpanda topics.
106
+ version Check the current version.
107
+ wasm Deploy and remove inline WASM engine scripts. """
108
+
109
+
110
+ def get_usage(process_line):
111
+ if process_line.find("Available Commands:") != -1:
112
+ return process_line[
113
+ process_line.find("Usage") : process_line.find("Available Commands:")
114
+ ].rstrip("\n")
115
+ elif process_line.find("Flags:") != -1:
116
+ return process_line[
117
+ process_line.find("Usage") : process_line.find("Flags:")
118
+ ].rstrip("\n")
119
+ else:
120
+ return process_line[process_line.find("Usage") :].rstrip("\n")
121
+
122
+
123
+ # Get lines for possible available commands. Example:
124
+ """ Usage:
125
+ rpk [command]
126
+
127
+ Available Commands:
128
+ acl Manage ACLs and SASL users.
129
+ cluster Interact with a Redpanda cluster.
130
+ container Manage a local container cluster.
131
+ debug Debug the local Redpanda process.
132
+ generate Generate a configuration template for related services.
133
+ group Describe, list, and delete consumer groups and manage their offsets.
134
+ help Help about any command
135
+ iotune Measure filesystem performance and create IO configuration file.
136
+ plugin List, download, update, and remove rpk plugins.
137
+ redpanda Interact with a local Redpanda process
138
+ topic Create, delete, produce to and consume from Redpanda topics.
139
+ version Check the current version.
140
+ wasm Deploy and remove inline WASM engine scripts. """
141
+
142
+
143
+ def get_commands(process_line):
144
+ if process_line.find('Use "rpk') != -1:
145
+ full_command = process_line[
146
+ process_line.find("Available Commands:") : process_line.find('Use "rpk')
147
+ ]
148
+ else:
149
+ full_command = process_line[process_line.find("Available Commands:") :]
150
+ commands = full_command[: full_command.find("Flags:")]
151
+ prefix = "Available Commands:"
152
+ return commands[len(prefix):] if commands.startswith(prefix) else commands
153
+
154
+ # Extract lines for the flags from a command. Example:
155
+ """ Available Commands:
156
+ acl Manage ACLs and SASL users.
157
+ cluster Interact with a Redpanda cluster.
158
+ container Manage a local container cluster.
159
+ debug Debug the local Redpanda process.
160
+ generate Generate a configuration template for related services.
161
+ group Describe, list, and delete consumer groups and manage their offsets.
162
+ help Help about any command
163
+ iotune Measure filesystem performance and create IO configuration file.
164
+ plugin List, download, update, and remove rpk plugins.
165
+ redpanda Interact with a local Redpanda process
166
+ topic Create, delete, produce to and consume from Redpanda topics.
167
+ version Check the current version.
168
+ wasm Deploy and remove inline WASM engine scripts.
169
+
170
+ Flags:
171
+ -h, --help help for rpk
172
+ -v, --verbose Enable verbose logging (default: false).
173
+
174
+ Use "rpk [command] --help" for more information about a command. """
175
+
176
+
177
+ def extract_flags(process_line):
178
+ if process_line.find('Use "rpk') != -1:
179
+ flag_line = process_line[process_line.find("Flags:") : process_line.find('Use "rpk')]
180
+ else:
181
+ flag_line = process_line[process_line.find("Flags:") :]
182
+ flag_line = flag_line.replace("\"/var/lib/redpanda/.config/rpk/rpk.yaml\"","`/var/lib/redpanda/.config/rpk/rpk.yaml`")
183
+ flag_line = flag_line.replace("$PWD/redpanda.yaml","`$PWD/redpanda.yaml`")
184
+ flag_line = flag_line.replace("/etc/redpanda/redpanda.yaml","`/etc/redpanda/redpanda.yaml`")
185
+ return flag_line
186
+
187
+
188
+ # Extract new commands (multilevel) or flags from the available ones. Example:
189
+ """ deploy Deploy inline WASM function.
190
+ generate Create an npm template project for inline WASM engine.
191
+ remove Remove inline WASM function. """
192
+ # or
193
+ """ --brokers strings Comma-separated list of broker ip:port pairs (e.g. --brokers '192.168.78.34:9092,192.168.78.35:9092,192.179.23.54:9092' ). Alternatively, you may set the REDPANDA_BROKERS environment variable with the comma-separated list of broker addresses.
194
+ --config string Redpanda config file, if not set the file will be searched for in the default locations
195
+ -h, --help help for wasm
196
+ --password string SASL password to be used for authentication.
197
+ --sasl-mechanism string The authentication mechanism to use. Supported values: SCRAM-SHA-256, SCRAM-SHA-512.
198
+ --tls-cert string The certificate to be used for TLS authentication with the broker.
199
+ --tls-enabled Enable TLS for the Kafka API (not necessary if specifying custom certs).
200
+ --tls-key string The certificate key to be used for TLS authentication with the broker.
201
+ --tls-truststore string The truststore to be used for TLS communication with the broker.
202
+ --user string SASL user to be used for authentication. """
203
+
204
+
205
+ def extract_new_commands(available, is_flag):
206
+ iterable_commands = []
207
+ mline = ""
208
+
209
+ for line in available.splitlines():
210
+ if not line:
211
+ if mline:
212
+ mline = mline.strip()
213
+ iterable_commands.append(mline)
214
+ mline = ""
215
+ continue
216
+ if not is_flag:
217
+ if mline:
218
+ mline = mline.strip()
219
+ iterable_commands.append(mline)
220
+ mline = ""
221
+ iterable_commands.append(line.split(" ")[2])
222
+ else:
223
+ if line.strip().startswith("-"):
224
+ if mline:
225
+ mline = mline.strip()
226
+ iterable_commands.append(mline)
227
+ mline = ""
228
+ mline = line[line.find("-") :].strip()
229
+ continue
230
+ elif line[0] != " ":
231
+ if mline:
232
+ mline = mline.strip()
233
+ iterable_commands.append(mline)
234
+ mline = ""
235
+ continue
236
+ else:
237
+ mline += " " + line.strip()
238
+ continue
239
+
240
+ if mline:
241
+ mline = mline.strip()
242
+ iterable_commands.append(mline.strip())
243
+
244
+ return iterable_commands
245
+
246
+
247
+ # Extract flag value, explanation and type from a flag line. Example:
248
+ """--user string SASL user to be used for authentication. """
249
+
250
+
251
+ def extract_all_flag(line):
252
+ flag_set = []
253
+ for flag in line:
254
+ value = flag[: flag.find(" ")]
255
+ explanation = flag[flag.find(" ") :]
256
+ if value.find(",") != -1:
257
+ explanation = explanation.lstrip(" ")
258
+ value = value + " " + (explanation[: explanation.find(" ")])
259
+ explanation = explanation[explanation.find(" ") :]
260
+
261
+ if re.search(r"\bstring\b", explanation):
262
+ flag_type = "string"
263
+ explanation = re.sub(r"\bstring\b", "", explanation)
264
+ elif re.search(r"\bstrings\b", flag):
265
+ flag_type = "strings"
266
+ explanation = re.sub(r"\bstrings\b", "", explanation)
267
+ elif re.search(r"\bstringArray\b", flag):
268
+ flag_type = "stringArray"
269
+ explanation = re.sub(r"\bstringArray\b", "", explanation)
270
+ elif re.search(r"\bint\b", flag):
271
+ flag_type = "int"
272
+ explanation = re.sub(r"\bint\b", "", explanation)
273
+ elif re.search(r"\bint16\b", flag):
274
+ flag_type = "int16"
275
+ explanation = re.sub(r"\bint16\b", "", explanation)
276
+ elif re.search(r"\bint32\b", flag):
277
+ flag_type = "int32"
278
+ explanation = re.sub(r"\bint32\b", "", explanation)
279
+ elif re.search(r"\bint32Slice\b", flag):
280
+ flag_type = "int32"
281
+ explanation = re.sub(r"\bint32Array\b", "", explanation)
282
+ elif re.search(r"\bduration\b", flag):
283
+ flag_type = "duration"
284
+ explanation = re.sub(r"\bduration\b", "", explanation)
285
+ else:
286
+ flag_type = "-"
287
+ explanation = assert_period(explanation.strip())
288
+ flag_set.append(Flag(value, flag_type, explanation))
289
+ return flag_set
290
+
291
+ # Build dictionary of commands
292
+ def build_dict(cmd_dict, executed_command, explanation, usage, it_flags, flag_list):
293
+
294
+ cmd = {"description" : explanation, "usage" : usage, "flags" : {} }
295
+
296
+ if it_flags:
297
+ for flag in flag_list:
298
+ cmd['flags'][flag.value] = { "type" : flag.flag_type.strip(), "description" : flag.explanation}
299
+
300
+ cmd_dict[executed_command] = cmd
301
+ return cmd_dict
302
+
303
+
304
+ def build_ascii(ascii_result, executed_command, explanation, usage, it_flags, flag_list, separate_files):
305
+ # Determine the version passed as argument or default to "latest"
306
+ tag_modified = sys.argv[1] if len(sys.argv) > 1 else "latest"
307
+ # Build the output directory as "autogenerated/<tag_modified>/rpk"
308
+ rpk_gen_dir = os.path.join("autogenerated", tag_modified, "rpk")
309
+ if not os.path.exists(rpk_gen_dir):
310
+ os.makedirs(rpk_gen_dir)
311
+
312
+ # Construct the asciidoc content
313
+ ascii_result += "= " + executed_command
314
+ ascii_result += "\n:description: " + executed_command
315
+ ascii_result += "\n\n" + explanation
316
+
317
+ usage_val_start = usage.find("Usage:") + len("Usage:")
318
+ aliases_start = usage.find("Aliases:")
319
+ aliases_val_start = usage.find("Aliases:") + len("Aliases:")
320
+
321
+ usage_val = usage[usage_val_start:aliases_start] if aliases_start >= 0 else usage[usage_val_start:]
322
+ ascii_result += "\n\n== Usage"
323
+ ascii_result += "\n\n[,bash]\n"
324
+ ascii_result += "----\n"
325
+ ascii_result += usage_val.strip()
326
+ ascii_result += "\n----"
327
+
328
+ if aliases_start >= 0:
329
+ ascii_result += "\n\n== Aliases"
330
+ ascii_result += "\n\n[,bash]\n"
331
+ ascii_result += "----\n"
332
+ ascii_result += usage[aliases_val_start:].strip()
333
+ ascii_result += "\n----"
334
+
335
+ if it_flags:
336
+ ascii_result += "\n\n== Flags"
337
+ ascii_result += "\n\n[cols=\"1m,1a,2a\"]"
338
+ ascii_result += "\n|==="
339
+ ascii_result += "\n|*Value* |*Type* |*Description*"
340
+
341
+ for flag in flag_list:
342
+ ascii_result += "\n\n"
343
+ ascii_result += "|" + flag.value + " |"
344
+ ascii_result += flag.flag_type + " |"
345
+ ascii_result += flag.explanation
346
+
347
+ ascii_result += "\n|==="
348
+
349
+ # Build filename using os.path.join rather than string concatenation.
350
+ filename = os.path.join(rpk_gen_dir, executed_command.replace(" ", "-") + ".adoc")
351
+
352
+ # If the file exists, delete it.
353
+ if os.path.exists(filename):
354
+ os.remove(filename)
355
+
356
+ # Write the ASCII content to the file with the necessary escaping.
357
+ with open(filename, "w", encoding="utf-8") as filetowrite:
358
+ ascii_result = escape_chars(ascii_result)
359
+ filetowrite.write(ascii_result)
360
+
361
+ return ascii_result
362
+
363
+ ## run basic command first
364
+ first_command = basic_commands_docker + rpk_basic_command + ["version"]
365
+ result = subprocess.run(first_command, stdout=subprocess.PIPE)
366
+ rpk_version = result.stdout.decode('utf-8').strip(" \n")
367
+
368
+ result = execute_process([])
369
+
370
+ explanation = get_explanation(result)
371
+
372
+ usage = get_usage(result)
373
+
374
+ full_command = get_commands(result)
375
+
376
+ commands = full_command[: full_command.find("Flags:")]
377
+
378
+ available_commmands = commands.lstrip("Available Commands:")
379
+ it_commands = extract_new_commands(available_commmands, False)
380
+
381
+ flags = extract_flags(result)
382
+ available_flags = flags.lstrip("Flags:")
383
+
384
+ it_flags = extract_new_commands(available_flags, True)
385
+ flag_list = extract_all_flag(it_flags)
386
+
387
+ md_result = """---
388
+ title: rpk commands
389
+ rpk_version: """ + rpk_version + """
390
+ ---
391
+
392
+ `rpk` is Redpanda's command line interface (CLI) utility. rpk commands allow you to configure and manage Redpanda clusters, tune them for better performance, manage topics and groups, manage access control lists (ACLs).
393
+
394
+ This section lists each rpk command in alphabetical order, along with a table of flags for that command. All descriptions are from the output of the `rpk <command> -–help` command.
395
+
396
+ """
397
+
398
+ executed_command = "rpk"
399
+ quantity =0
400
+
401
+ for command in it_commands:
402
+ quantity+=1
403
+
404
+ result = execute_process([command])
405
+ executed_command = "rpk " + command
406
+
407
+ explanation = get_explanation(result)
408
+
409
+ usage = get_usage(result)
410
+
411
+ full_command = get_commands(result)
412
+
413
+ commands = full_command[: full_command.find("Flags:")]
414
+
415
+ available_commmands = commands.lstrip("Available Commands:")
416
+ new_commands = extract_new_commands(available_commmands, False)
417
+
418
+ flags = extract_flags(result)
419
+ available_flags = flags.lstrip("Flags:")
420
+
421
+ it_flags = extract_new_commands(available_flags, True)
422
+
423
+ flag_list = extract_all_flag(it_flags)
424
+
425
+ cmd_dict = build_dict(cmd_dict, executed_command, explanation, usage, it_flags, flag_list);
426
+
427
+ md_result = build_ascii(
428
+ "", executed_command, explanation, usage, it_flags, flag_list, True
429
+ )
430
+
431
+ index = it_commands.index(command) + 1
432
+ for new_command in new_commands:
433
+ it_commands.insert(index, command + " " + new_command)
434
+ index += 1
435
+
436
+ if(quantity%20==0):
437
+ print(f"{quantity}/{len(it_commands)} files written in disk.")
438
+
439
+ cmd_dict['rpk_version'] = rpk_version
440
+ json_object = json.dumps(cmd_dict, indent = 4)
441
+
442
+ md_result = md_result.replace(
443
+ """ rpk-<name>
444
+ rpk.ac-<name>""",
445
+ """```bash
446
+ rpk-<name>
447
+ rpk.ac-<name>
448
+ ```
449
+ """,
450
+ )
451
+
452
+
453
+
454
+ md_result = md_result + suggestedReadings
455
+
456
+ # Get the version from command-line arguments, defaulting to "latest" if not provided.
457
+ tag_modified = sys.argv[1] if len(sys.argv) > 1 else "latest"
458
+
459
+ # Build a common base directory using the version.
460
+ base_dir = os.path.join("autogenerated", tag_modified, "rpk")
461
+
462
+ # Write the JSON file into a JSON subdirectory within the same base directory.
463
+ json_path = os.path.join(base_dir, "json")
464
+ if not os.path.exists(json_path):
465
+ os.makedirs(json_path)
466
+
467
+ json_file = os.path.join(json_path, "rpk-commands.json")
468
+ try:
469
+ with open(json_file, "w") as filetowrite:
470
+ filetowrite.write(json_object)
471
+ print("The rpk commands have been successfully generated at", json_file)
472
+ except Exception as e:
473
+ print("Error generating the rpk commands file " + str(e))
474
+
475
+ # Define the directories for comparison.
476
+ dir1 = os.path.join("docs", "reference", "rpk")
477
+ dir2 = base_dir # Using the common base directory
@@ -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
+ };