@redpanda-data/docs-extensions-and-macros 4.12.5 → 4.13.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 (62) hide show
  1. package/README.adoc +33 -1064
  2. package/bin/doc-tools-mcp.js +720 -0
  3. package/bin/doc-tools.js +1050 -50
  4. package/bin/mcp-tools/antora.js +153 -0
  5. package/bin/mcp-tools/cache.js +89 -0
  6. package/bin/mcp-tools/cloud-regions.js +127 -0
  7. package/bin/mcp-tools/content-review.js +196 -0
  8. package/bin/mcp-tools/crd-docs.js +153 -0
  9. package/bin/mcp-tools/frontmatter.js +138 -0
  10. package/bin/mcp-tools/generated-docs-review.js +887 -0
  11. package/bin/mcp-tools/helm-docs.js +152 -0
  12. package/bin/mcp-tools/index.js +245 -0
  13. package/bin/mcp-tools/job-queue.js +468 -0
  14. package/bin/mcp-tools/mcp-validation.js +266 -0
  15. package/bin/mcp-tools/metrics-docs.js +146 -0
  16. package/bin/mcp-tools/openapi.js +174 -0
  17. package/bin/mcp-tools/prompt-discovery.js +283 -0
  18. package/bin/mcp-tools/property-docs.js +157 -0
  19. package/bin/mcp-tools/rpcn-docs.js +113 -0
  20. package/bin/mcp-tools/rpk-docs.js +141 -0
  21. package/bin/mcp-tools/telemetry.js +211 -0
  22. package/bin/mcp-tools/utils.js +131 -0
  23. package/bin/mcp-tools/versions.js +168 -0
  24. package/cli-utils/convert-doc-links.js +1 -1
  25. package/cli-utils/github-token.js +58 -0
  26. package/cli-utils/self-managed-docs-branch.js +2 -2
  27. package/cli-utils/setup-mcp.js +313 -0
  28. package/docker-compose/25.1/transactions.md +1 -1
  29. package/docker-compose/transactions.md +1 -1
  30. package/extensions/DEVELOPMENT.adoc +464 -0
  31. package/extensions/README.adoc +124 -0
  32. package/extensions/REFERENCE.adoc +768 -0
  33. package/extensions/USER_GUIDE.adoc +339 -0
  34. package/extensions/generate-rp-connect-info.js +3 -4
  35. package/extensions/version-fetcher/get-latest-console-version.js +38 -27
  36. package/extensions/version-fetcher/get-latest-redpanda-helm-version-from-operator.js +1 -1
  37. package/extensions/version-fetcher/get-latest-redpanda-version.js +65 -54
  38. package/extensions/version-fetcher/retry-util.js +88 -0
  39. package/extensions/version-fetcher/set-latest-version.js +6 -3
  40. package/macros/DEVELOPMENT.adoc +377 -0
  41. package/macros/README.adoc +105 -0
  42. package/macros/REFERENCE.adoc +222 -0
  43. package/macros/USER_GUIDE.adoc +220 -0
  44. package/macros/rp-connect-components.js +6 -6
  45. package/package.json +12 -3
  46. package/tools/bundle-openapi.js +20 -10
  47. package/tools/cloud-regions/generate-cloud-regions.js +1 -1
  48. package/tools/fetch-from-github.js +18 -4
  49. package/tools/gen-rpk-ascii.py +3 -1
  50. package/tools/generate-cli-docs.js +325 -0
  51. package/tools/get-console-version.js +4 -2
  52. package/tools/get-redpanda-version.js +4 -2
  53. package/tools/metrics/metrics.py +19 -7
  54. package/tools/property-extractor/Makefile +7 -1
  55. package/tools/property-extractor/cloud_config.py +4 -4
  56. package/tools/property-extractor/constant_resolver.py +11 -11
  57. package/tools/property-extractor/property_extractor.py +18 -16
  58. package/tools/property-extractor/topic_property_extractor.py +2 -2
  59. package/tools/property-extractor/transformers.py +7 -7
  60. package/tools/property-extractor/type_definition_extractor.py +4 -4
  61. package/tools/redpanda-connect/README.adoc +1 -1
  62. package/tools/redpanda-connect/generate-rpcn-connector-docs.js +5 -3
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Usage Telemetry and Statistics
3
+ *
4
+ * Tracks usage of prompts, resources, and tools to provide insights
5
+ * into adoption and identify unused features.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ /**
12
+ * Usage statistics tracker
13
+ */
14
+ class UsageStats {
15
+ constructor() {
16
+ this.prompts = new Map(); // name count
17
+ this.resources = new Map(); // uri count
18
+ this.tools = new Map(); // name count
19
+ this.startTime = new Date();
20
+ this.lastReportTime = new Date();
21
+ }
22
+
23
+ /**
24
+ * Record prompt usage
25
+ * @param {string} name - Prompt name
26
+ */
27
+ recordPrompt(name) {
28
+ const count = this.prompts.get(name) || 0;
29
+ this.prompts.set(name, count + 1);
30
+ }
31
+
32
+ /**
33
+ * Record resource usage
34
+ * @param {string} uri - Resource URI
35
+ */
36
+ recordResource(uri) {
37
+ const count = this.resources.get(uri) || 0;
38
+ this.resources.set(uri, count + 1);
39
+ }
40
+
41
+ /**
42
+ * Record tool usage
43
+ * @param {string} name - Tool name
44
+ */
45
+ recordTool(name) {
46
+ const count = this.tools.get(name) || 0;
47
+ this.tools.set(name, count + 1);
48
+ }
49
+
50
+ /**
51
+ * Get stats summary
52
+ * @returns {Object} Statistics summary
53
+ */
54
+ getSummary() {
55
+ const now = new Date();
56
+ const uptime = Math.floor((now - this.startTime) / 1000); // seconds
57
+ const timeSinceLastReport = Math.floor((now - this.lastReportTime) / 1000);
58
+
59
+ return {
60
+ uptime,
61
+ timeSinceLastReport,
62
+ promptCount: this.prompts.size,
63
+ resourceCount: this.resources.size,
64
+ toolCount: this.tools.size,
65
+ totalPromptCalls: Array.from(this.prompts.values()).reduce((a, b) => a + b, 0),
66
+ totalResourceCalls: Array.from(this.resources.values()).reduce((a, b) => a + b, 0),
67
+ totalToolCalls: Array.from(this.tools.values()).reduce((a, b) => a + b, 0),
68
+ prompts: Object.fromEntries(this.prompts),
69
+ resources: Object.fromEntries(this.resources),
70
+ tools: Object.fromEntries(this.tools)
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Get top N most used items
76
+ * @param {Map} map - Map to get top from
77
+ * @param {number} n - Number of items
78
+ * @returns {Array} Top N items as [name, count] pairs
79
+ */
80
+ getTopN(map, n = 5) {
81
+ return Array.from(map.entries())
82
+ .sort((a, b) => b[1] - a[1])
83
+ .slice(0, n);
84
+ }
85
+
86
+ /**
87
+ * Format stats for display
88
+ * @returns {string} Formatted stats
89
+ */
90
+ format() {
91
+ const summary = this.getSummary();
92
+ const lines = [];
93
+
94
+ lines.push('MCP Server Usage Statistics');
95
+ lines.push('='.repeat(60));
96
+ lines.push('');
97
+
98
+ // Uptime
99
+ const hours = Math.floor(summary.uptime / 3600);
100
+ const minutes = Math.floor((summary.uptime % 3600) / 60);
101
+ lines.push(`Uptime: ${hours}h ${minutes}m`);
102
+ lines.push('');
103
+
104
+ // Totals
105
+ lines.push(`Total calls:`);
106
+ lines.push(` Prompts: ${summary.totalPromptCalls}`);
107
+ lines.push(` Resources: ${summary.totalResourceCalls}`);
108
+ lines.push(` Tools: ${summary.totalToolCalls}`);
109
+ lines.push('');
110
+
111
+ // Top prompts
112
+ if (this.prompts.size > 0) {
113
+ lines.push('Most used prompts:');
114
+ const topPrompts = this.getTopN(this.prompts, 5);
115
+ topPrompts.forEach(([name, count]) => {
116
+ lines.push(` ${name}: ${count} calls`);
117
+ });
118
+ lines.push('');
119
+ }
120
+
121
+ // Top resources
122
+ if (this.resources.size > 0) {
123
+ lines.push('Most used resources:');
124
+ const topResources = this.getTopN(this.resources, 5);
125
+ topResources.forEach(([uri, count]) => {
126
+ lines.push(` ${uri}: ${count} calls`);
127
+ });
128
+ lines.push('');
129
+ }
130
+
131
+ // Top tools
132
+ if (this.tools.size > 0) {
133
+ lines.push('Most used tools:');
134
+ const topTools = this.getTopN(this.tools, 5);
135
+ topTools.forEach(([name, count]) => {
136
+ lines.push(` ${name}: ${count} calls`);
137
+ });
138
+ lines.push('');
139
+ }
140
+
141
+ return lines.join('\n');
142
+ }
143
+
144
+ /**
145
+ * Export stats to JSON file
146
+ * @param {string} filepath - Path to export to
147
+ */
148
+ exportToFile(filepath) {
149
+ const summary = this.getSummary();
150
+ summary.exportedAt = new Date().toISOString();
151
+
152
+ fs.writeFileSync(filepath, JSON.stringify(summary, null, 2), 'utf8');
153
+ }
154
+
155
+ /**
156
+ * Reset stats (for periodic reporting)
157
+ */
158
+ reset() {
159
+ this.lastReportTime = new Date();
160
+ // Don't reset the maps - keep cumulative stats
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Create a periodic reporter
166
+ * @param {UsageStats} stats - Stats instance
167
+ * @param {number} intervalMs - Interval in milliseconds
168
+ * @returns {NodeJS.Timeout} Interval handle
169
+ */
170
+ function createPeriodicReporter(stats, intervalMs = 3600000) {
171
+ return setInterval(() => {
172
+ const output = stats.format();
173
+ console.error('\n' + output);
174
+ stats.reset();
175
+ }, intervalMs);
176
+ }
177
+
178
+ /**
179
+ * Create a shutdown handler to export stats
180
+ * @param {UsageStats} stats - Stats instance
181
+ * @param {string} baseDir - Base directory for export
182
+ */
183
+ function createShutdownHandler(stats, baseDir) {
184
+ const handler = () => {
185
+ const exportPath = path.join(baseDir, 'mcp-usage-stats.json');
186
+ try {
187
+ stats.exportToFile(exportPath);
188
+ console.error(`\nUsage stats exported to: ${exportPath}`);
189
+ } catch (err) {
190
+ console.error(`Failed to export usage stats: ${err.message}`);
191
+ }
192
+ };
193
+
194
+ process.on('SIGINT', () => {
195
+ handler();
196
+ process.exit(0);
197
+ });
198
+
199
+ process.on('SIGTERM', () => {
200
+ handler();
201
+ process.exit(0);
202
+ });
203
+
204
+ return handler;
205
+ }
206
+
207
+ module.exports = {
208
+ UsageStats,
209
+ createPeriodicReporter,
210
+ createShutdownHandler
211
+ };
@@ -0,0 +1,131 @@
1
+ /**
2
+ * MCP Tools - Shared Utilities
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const { spawnSync } = require('child_process');
8
+
9
+ // Constants
10
+ const MAX_RECURSION_DEPTH = 3;
11
+ const MAX_EXEC_BUFFER_SIZE = 50 * 1024 * 1024; // 50MB
12
+ const DEFAULT_COMMAND_TIMEOUT = 10 * 60 * 1000; // 10 minutes
13
+ const DEFAULT_SKIP_DIRS = ['node_modules', '.git', 'venv', '__pycache__', '.pytest_cache'];
14
+ const PLAYBOOK_NAMES = [
15
+ 'local-antora-playbook.yml',
16
+ 'antora-playbook.yml',
17
+ 'docs-playbook.yml'
18
+ ];
19
+
20
+ /**
21
+ * Find the repository root from current working directory
22
+ * @param {string} [start=process.cwd()] - Starting directory for search
23
+ * @returns {{ root: string, detected: boolean, type: string|null }} Repository information
24
+ */
25
+ function findRepoRoot(start = process.cwd()) {
26
+ let dir = start;
27
+ while (dir !== path.parse(dir).root) {
28
+ if (fs.existsSync(path.join(dir, '.git'))) {
29
+ return { root: dir, detected: true, type: 'git' };
30
+ }
31
+ if (fs.existsSync(path.join(dir, 'package.json'))) {
32
+ return { root: dir, detected: true, type: 'npm' };
33
+ }
34
+ dir = path.dirname(dir);
35
+ }
36
+ return { root: start, detected: false, type: null };
37
+ }
38
+
39
+ /**
40
+ * Get the doc-tools command and arguments
41
+ * Handles both development mode (source repo) and installed mode (npm package)
42
+ * @param {Object} repoRoot - Repository root information from findRepoRoot()
43
+ * @returns {{ program: string, getArgs: function }} Command configuration
44
+ */
45
+ function getDocToolsCommand(repoRoot) {
46
+ // Check if we're in the source repository (development mode)
47
+ const localDocTools = path.join(repoRoot.root, 'bin', 'doc-tools.js');
48
+ if (fs.existsSync(localDocTools)) {
49
+ return {
50
+ program: 'node',
51
+ getArgs: (cmdArgs) => [localDocTools, ...cmdArgs]
52
+ };
53
+ }
54
+
55
+ // Otherwise use npx, which will find the installed package in node_modules
56
+ return {
57
+ program: 'npx',
58
+ getArgs: (cmdArgs) => ['doc-tools', ...cmdArgs]
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Execute a command safely using spawnSync (no shell)
64
+ * @param {string} program - Program to execute (for example, 'npx')
65
+ * @param {string[]} args - Array of arguments (for example, ['doc-tools', 'generate', 'property-docs'])
66
+ * @param {Object} options - Execution options
67
+ * @returns {string} Command output (stdout)
68
+ * @throws {Error} Error with stdout, stderr, and status properties on failure
69
+ */
70
+ function executeCommand(program, args, options = {}) {
71
+ const defaultOptions = {
72
+ encoding: 'utf8',
73
+ maxBuffer: MAX_EXEC_BUFFER_SIZE,
74
+ timeout: DEFAULT_COMMAND_TIMEOUT,
75
+ stdio: 'pipe'
76
+ };
77
+
78
+ const result = spawnSync(program, args, { ...defaultOptions, ...options });
79
+
80
+ // Check for spawn errors
81
+ if (result.error) {
82
+ const err = new Error(`Failed to execute command: ${result.error.message}`);
83
+ err.stdout = result.stdout || '';
84
+ err.stderr = result.stderr || '';
85
+ err.status = result.status;
86
+ throw err;
87
+ }
88
+
89
+ // Check for non-zero exit codes
90
+ if (result.status !== 0) {
91
+ const errorMsg = result.stderr || `Command failed with exit code ${result.status}`;
92
+ const err = new Error(errorMsg);
93
+ err.stdout = result.stdout || '';
94
+ err.stderr = result.stderr || '';
95
+ err.status = result.status;
96
+ throw err;
97
+ }
98
+
99
+ return result.stdout;
100
+ }
101
+
102
+ /**
103
+ * Normalize version string (remove 'v' prefix if present)
104
+ * @param {string} version - Version string
105
+ * @returns {string} Normalized version
106
+ */
107
+ function normalizeVersion(version) {
108
+ return version.startsWith('v') ? version.substring(1) : version;
109
+ }
110
+
111
+ /**
112
+ * Format date as YYYY-MM-DD
113
+ * @param {Date} date - Date to format
114
+ * @returns {string} Formatted date string
115
+ */
116
+ function formatDate(date = new Date()) {
117
+ return date.toISOString().split('T')[0];
118
+ }
119
+
120
+ module.exports = {
121
+ MAX_RECURSION_DEPTH,
122
+ MAX_EXEC_BUFFER_SIZE,
123
+ DEFAULT_COMMAND_TIMEOUT,
124
+ DEFAULT_SKIP_DIRS,
125
+ PLAYBOOK_NAMES,
126
+ findRepoRoot,
127
+ getDocToolsCommand,
128
+ executeCommand,
129
+ normalizeVersion,
130
+ formatDate
131
+ };
@@ -0,0 +1,168 @@
1
+ /**
2
+ * MCP Tools - Version Information
3
+ *
4
+ * OPTIMIZATION: This tool calls CLI and caches results.
5
+ * - Caches version info for 5 minutes (rarely changes)
6
+ * - No model recommendation (CLI tool)
7
+ * - Recommended model: haiku (if LLM processing needed)
8
+ */
9
+
10
+ const { spawnSync } = require('child_process');
11
+ const { findRepoRoot, getDocToolsCommand } = require('./utils');
12
+ const cache = require('./cache');
13
+
14
+ /**
15
+ * Get the latest Redpanda version information
16
+ * @param {Object} args - Arguments
17
+ * @param {boolean} [args.beta] - Whether to get beta/RC version
18
+ * @returns {Object} Version information
19
+ */
20
+ function getRedpandaVersion(args = {}) {
21
+ // Check cache first (5 minute TTL)
22
+ const cacheKey = `redpanda-version:${args.beta ? 'beta' : 'stable'}`;
23
+ const cached = cache.get(cacheKey);
24
+ if (cached) {
25
+ return { ...cached, _cached: true };
26
+ }
27
+
28
+ try {
29
+ // Get doc-tools command (handles both local and installed)
30
+ const repoRoot = findRepoRoot();
31
+ const docTools = getDocToolsCommand(repoRoot);
32
+
33
+ // Build command arguments array
34
+ const baseArgs = ['get-redpanda-version'];
35
+ if (args.beta) {
36
+ baseArgs.push('--beta');
37
+ }
38
+
39
+ const cmdResult = spawnSync(docTools.program, docTools.getArgs(baseArgs), {
40
+ encoding: 'utf8',
41
+ stdio: 'pipe',
42
+ timeout: 30000
43
+ });
44
+
45
+ // Check for errors
46
+ if (cmdResult.error) {
47
+ throw new Error(`Failed to execute command: ${cmdResult.error.message}`);
48
+ }
49
+
50
+ if (cmdResult.status !== 0) {
51
+ const errorMsg = cmdResult.stderr || `Command failed with exit code ${cmdResult.status}`;
52
+ throw new Error(errorMsg);
53
+ }
54
+
55
+ const output = cmdResult.stdout;
56
+
57
+ // Parse the output (format: REDPANDA_VERSION=vX.Y.Z\nREDPANDA_DOCKER_REPO=redpanda)
58
+ const lines = output.trim().split('\n');
59
+ const versionLine = lines.find(l => l.startsWith('REDPANDA_VERSION='));
60
+ const dockerLine = lines.find(l => l.startsWith('REDPANDA_DOCKER_REPO='));
61
+
62
+ if (!versionLine) {
63
+ return {
64
+ success: false,
65
+ error: 'Failed to parse version from output'
66
+ };
67
+ }
68
+
69
+ const version = versionLine.split('=')[1];
70
+ const dockerRepo = dockerLine ? dockerLine.split('=')[1] : 'redpanda';
71
+
72
+ const result = {
73
+ success: true,
74
+ version,
75
+ docker_tag: `docker.redpanda.com/redpandadata/${dockerRepo}:${version}`,
76
+ is_beta: args.beta || false,
77
+ notes_url: `https://github.com/redpanda-data/redpanda/releases/tag/${version}`,
78
+ _modelRecommendation: 'haiku'
79
+ };
80
+
81
+ // Cache for 5 minutes
82
+ cache.set(cacheKey, result, 5 * 60 * 1000);
83
+
84
+ return result;
85
+ } catch (err) {
86
+ return {
87
+ success: false,
88
+ error: err.message,
89
+ suggestion: 'Make sure you have network access to fetch version information from GitHub'
90
+ };
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Get the latest Redpanda Console version information
96
+ * @returns {Object} Version information
97
+ */
98
+ function getConsoleVersion() {
99
+ // Check cache first (5 minute TTL)
100
+ const cacheKey = 'console-version';
101
+ const cached = cache.get(cacheKey);
102
+ if (cached) {
103
+ return { ...cached, _cached: true };
104
+ }
105
+
106
+ try {
107
+ // Get doc-tools command (handles both local and installed)
108
+ const repoRoot = findRepoRoot();
109
+ const docTools = getDocToolsCommand(repoRoot);
110
+
111
+ const cmdResult = spawnSync(docTools.program, docTools.getArgs(['get-console-version']), {
112
+ encoding: 'utf8',
113
+ stdio: 'pipe',
114
+ timeout: 30000
115
+ });
116
+
117
+ // Check for errors
118
+ if (cmdResult.error) {
119
+ throw new Error(`Failed to execute command: ${cmdResult.error.message}`);
120
+ }
121
+
122
+ if (cmdResult.status !== 0) {
123
+ const errorMsg = cmdResult.stderr || `Command failed with exit code ${cmdResult.status}`;
124
+ throw new Error(errorMsg);
125
+ }
126
+
127
+ const output = cmdResult.stdout;
128
+
129
+ // Parse the output (format: CONSOLE_VERSION=vX.Y.Z\nCONSOLE_DOCKER_REPO=console)
130
+ const lines = output.trim().split('\n');
131
+ const versionLine = lines.find(l => l.startsWith('CONSOLE_VERSION='));
132
+ const dockerLine = lines.find(l => l.startsWith('CONSOLE_DOCKER_REPO='));
133
+
134
+ if (!versionLine) {
135
+ return {
136
+ success: false,
137
+ error: 'Failed to parse version from output'
138
+ };
139
+ }
140
+
141
+ const version = versionLine.split('=')[1];
142
+ const dockerRepo = dockerLine ? dockerLine.split('=')[1] : 'console';
143
+
144
+ const result = {
145
+ success: true,
146
+ version,
147
+ docker_tag: `docker.redpanda.com/redpandadata/${dockerRepo}:${version}`,
148
+ notes_url: `https://github.com/redpanda-data/console/releases/tag/${version}`,
149
+ _modelRecommendation: 'haiku'
150
+ };
151
+
152
+ // Cache for 5 minutes
153
+ cache.set(cacheKey, result, 5 * 60 * 1000);
154
+
155
+ return result;
156
+ } catch (err) {
157
+ return {
158
+ success: false,
159
+ error: err.message,
160
+ suggestion: 'Make sure you have network access to fetch version information from GitHub'
161
+ };
162
+ }
163
+ }
164
+
165
+ module.exports = {
166
+ getRedpandaVersion,
167
+ getConsoleVersion
168
+ };
@@ -3,7 +3,7 @@ const { URL } = require('url');
3
3
  /**
4
4
  * Converts a docs.redpanda.com URL, optionally suffixed with a label in brackets, into an Antora xref resource ID string.
5
5
  *
6
- * If the input includes a label in square brackets (e.g., `[Label]`), the label is preserved and appended to the resulting xref.
6
+ * If the input includes a label in square brackets (for example, `[Label]`), the label is preserved and appended to the resulting xref.
7
7
  *
8
8
  * @param {string} input - A docs.redpanda.com URL, optionally followed by a label in square brackets.
9
9
  * @returns {string} The corresponding Antora xref resource ID, with the label preserved if present.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * GitHub Token Utility
3
+ *
4
+ * Provides a consistent way to retrieve GitHub tokens from environment variables.
5
+ * Supports multiple common token variable names with priority order.
6
+ */
7
+
8
+ /**
9
+ * Get GitHub token from environment variables
10
+ * Checks multiple common variable names in priority order:
11
+ * 1. REDPANDA_GITHUB_TOKEN - Custom Redpanda token
12
+ * 2. GITHUB_TOKEN - GitHub Actions default
13
+ * 3. GH_TOKEN - GitHub CLI default
14
+ *
15
+ * @returns {string|null} GitHub token or null if not found
16
+ */
17
+ function getGitHubToken() {
18
+ return process.env.REDPANDA_GITHUB_TOKEN ||
19
+ process.env.GITHUB_TOKEN ||
20
+ process.env.GH_TOKEN ||
21
+ null;
22
+ }
23
+
24
+ /**
25
+ * Get an authenticated GitHub URL by injecting the token
26
+ * @param {string} url - The GitHub HTTPS URL (for example, https://github.com/owner/repo.git)
27
+ * @returns {string} Authenticated URL with token, or original URL if no token available
28
+ */
29
+ function getAuthenticatedGitHubUrl(url) {
30
+ const token = getGitHubToken();
31
+
32
+ if (!token || !url.includes('github.com')) {
33
+ return url;
34
+ }
35
+
36
+ try {
37
+ const urlObj = new URL(url);
38
+ urlObj.username = token;
39
+ return urlObj.toString();
40
+ } catch (err) {
41
+ // If URL parsing fails, return original
42
+ return url;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Check if a GitHub token is available
48
+ * @returns {boolean} True if a token is available
49
+ */
50
+ function hasGitHubToken() {
51
+ return getGitHubToken() !== null;
52
+ }
53
+
54
+ module.exports = {
55
+ getGitHubToken,
56
+ getAuthenticatedGitHubUrl,
57
+ hasGitHubToken
58
+ };
@@ -5,7 +5,7 @@ const { spawnSync } = require('child_process');
5
5
  /**
6
6
  * Retrieves the current Self-Managed documentation version from the remote antora.yml file.
7
7
  *
8
- * @returns {Promise<string>} Resolves with the version string (e.g., "25.1").
8
+ * @returns {Promise<string>} Resolves with the version string (for example, "25.1").
9
9
  *
10
10
  * @throws {Error} If the antora.yml file cannot be fetched, parsed, or if the version field is missing.
11
11
  */
@@ -39,7 +39,7 @@ function fetchRemoteAntoraVersion() {
39
39
  *
40
40
  * Normalizes the input tag, extracts the major.minor version, and applies version-specific logic to select the correct branch. Verifies that the chosen branch exists in the remote repository.
41
41
  *
42
- * @param {string} operatorTag - The operator tag to evaluate (e.g., "operator/v25.1.2" or "v25.1.2").
42
+ * @param {string} operatorTag - The operator tag to evaluate (for example, "operator/v25.1.2" or "v25.1.2").
43
43
  * @returns {Promise<string>} The name of the documentation branch to use.
44
44
  *
45
45
  * @throws {Error} If the tag cannot be parsed or if the determined branch does not exist in the remote repository.