@redpanda-data/docs-extensions-and-macros 4.12.6 → 4.13.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/README.adoc +33 -1064
- package/bin/doc-tools-mcp.js +720 -0
- package/bin/doc-tools.js +1050 -50
- package/bin/mcp-tools/antora.js +153 -0
- package/bin/mcp-tools/cache.js +89 -0
- package/bin/mcp-tools/cloud-regions.js +127 -0
- package/bin/mcp-tools/content-review.js +196 -0
- package/bin/mcp-tools/crd-docs.js +153 -0
- package/bin/mcp-tools/frontmatter.js +138 -0
- package/bin/mcp-tools/generated-docs-review.js +887 -0
- package/bin/mcp-tools/helm-docs.js +152 -0
- package/bin/mcp-tools/index.js +245 -0
- package/bin/mcp-tools/job-queue.js +468 -0
- package/bin/mcp-tools/mcp-validation.js +266 -0
- package/bin/mcp-tools/metrics-docs.js +146 -0
- package/bin/mcp-tools/openapi.js +174 -0
- package/bin/mcp-tools/prompt-discovery.js +283 -0
- package/bin/mcp-tools/property-docs.js +157 -0
- package/bin/mcp-tools/rpcn-docs.js +113 -0
- package/bin/mcp-tools/rpk-docs.js +141 -0
- package/bin/mcp-tools/telemetry.js +211 -0
- package/bin/mcp-tools/utils.js +131 -0
- package/bin/mcp-tools/versions.js +168 -0
- package/cli-utils/convert-doc-links.js +1 -1
- package/cli-utils/github-token.js +58 -0
- package/cli-utils/self-managed-docs-branch.js +2 -2
- package/cli-utils/setup-mcp.js +313 -0
- package/docker-compose/25.1/transactions.md +1 -1
- package/docker-compose/transactions.md +1 -1
- package/extensions/DEVELOPMENT.adoc +464 -0
- package/extensions/README.adoc +124 -0
- package/extensions/REFERENCE.adoc +768 -0
- package/extensions/USER_GUIDE.adoc +339 -0
- package/extensions/generate-rp-connect-info.js +3 -4
- package/extensions/version-fetcher/get-latest-console-version.js +38 -27
- package/extensions/version-fetcher/get-latest-redpanda-version.js +65 -54
- package/extensions/version-fetcher/retry-util.js +88 -0
- package/extensions/version-fetcher/set-latest-version.js +6 -3
- package/macros/DEVELOPMENT.adoc +377 -0
- package/macros/README.adoc +105 -0
- package/macros/REFERENCE.adoc +222 -0
- package/macros/USER_GUIDE.adoc +220 -0
- package/macros/rp-connect-components.js +6 -6
- package/mcp/CLI_INTERFACE.adoc +384 -0
- package/mcp/COSTS.adoc +167 -0
- package/mcp/DEVELOPMENT.adoc +726 -0
- package/mcp/README.adoc +172 -0
- package/mcp/USER_GUIDE.adoc +1392 -0
- package/mcp/WRITER_EXTENSION_GUIDE.adoc +814 -0
- package/mcp/prompts/README.adoc +183 -0
- package/mcp/prompts/property-docs-guide.md +283 -0
- package/mcp/prompts/review-for-style.md +128 -0
- package/mcp/prompts/rpcn-connector-docs-guide.md +126 -0
- package/mcp/prompts/write-new-guide.md +222 -0
- package/mcp/team-standards/style-guide.md +321 -0
- package/mcp/templates/README.adoc +212 -0
- package/mcp/templates/prompt-review-template.md +80 -0
- package/mcp/templates/prompt-write-template.md +110 -0
- package/mcp/templates/resource-template.md +76 -0
- package/package.json +16 -5
- package/tools/bundle-openapi.js +20 -10
- package/tools/cloud-regions/generate-cloud-regions.js +1 -1
- package/tools/fetch-from-github.js +18 -4
- package/tools/gen-rpk-ascii.py +3 -1
- package/tools/generate-cli-docs.js +325 -0
- package/tools/get-console-version.js +4 -2
- package/tools/get-redpanda-version.js +4 -2
- package/tools/metrics/metrics.py +19 -7
- package/tools/property-extractor/Makefile +7 -1
- package/tools/property-extractor/cloud_config.py +4 -4
- package/tools/property-extractor/constant_resolver.py +11 -11
- package/tools/property-extractor/property_extractor.py +18 -16
- package/tools/property-extractor/topic_property_extractor.py +2 -2
- package/tools/property-extractor/transformers.py +7 -7
- package/tools/property-extractor/type_definition_extractor.py +4 -4
- package/tools/redpanda-connect/README.adoc +1 -1
- 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 (
|
|
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 (
|
|
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 (
|
|
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.
|