@redpanda-data/docs-extensions-and-macros
Version:
Antora extensions and macros developed for Redpanda documentation.
177 lines (155 loc) • 8.99 kB
JavaScript
;
module.exports.register = function ({ config }) {
const GetLatestRedpandaVersion = require('./get-latest-redpanda-version');
const GetLatestConsoleVersion = require('./get-latest-console-version');
const GetLatestDockerTag = require('./fetch-latest-docker-tag');
const GetLatestHelmChartVersionFromOperator = require('./get-latest-redpanda-helm-version-from-operator');
const GetLatestConnectVersion = require('./get-latest-connect');
const logger = this.getLogger('set-latest-version-extension');
const { getGitHubToken } = require('../../cli-utils/github-token');
const token = getGitHubToken();
if (!token) {
logger.warn('GitHub token not set (REDPANDA_GITHUB_TOKEN, GITHUB_TOKEN, or GH_TOKEN). Attempting unauthenticated request.');
}
this.on('contentClassified', async ({ contentCatalog }) => {
const { Octokit } = await import("@octokit/rest");
const { retry } = await import("@octokit/plugin-retry");
const semver = await import("semver");
const OctokitWithRetries = Octokit.plugin(retry);
const owner = 'redpanda-data';
const githubOptions = {
userAgent: 'Redpanda Docs',
baseUrl: 'https://api.github.com',
auth: token || undefined,
};
const github = new OctokitWithRetries(githubOptions);
const dockerNamespace = 'redpandadata'
try {
const [
latestRedpandaResult,
latestConsoleResult,
latestOperatorResult,
latestConnectResult,
] = await Promise.allSettled([
GetLatestRedpandaVersion(github, owner, 'redpanda', logger),
GetLatestDockerTag(dockerNamespace, 'console', logger),
GetLatestDockerTag(dockerNamespace, 'redpanda-operator', logger),
GetLatestConnectVersion(github, owner, 'connect', logger),
]);
// Get the Helm chart version after we have the operator version (for both stable and beta)
let latestHelmChartResult = { status: 'rejected', reason: 'Operator result not fulfilled' };
if (latestOperatorResult.status === 'fulfilled') {
try {
const helmChartVersions = await GetLatestHelmChartVersionFromOperator(
github,
owner,
'redpanda-operator',
latestOperatorResult.value?.latestStableRelease,
latestOperatorResult.value?.latestBetaRelease,
logger
);
latestHelmChartResult = {
status: 'fulfilled',
value: helmChartVersions
};
} catch (error) {
latestHelmChartResult = {
status: 'rejected',
reason: error.message || 'Unknown error fetching Helm chart version'
};
logger.error(`Helm chart lookup failed: ${error.message || error}`);
}
} else {
logger.error(`Helm chart lookup failed: Operator version not available`);
}
const latestVersions = {
redpanda: latestRedpandaResult.status === 'fulfilled' ? latestRedpandaResult.value : {},
console: latestConsoleResult.status === 'fulfilled' ? latestConsoleResult.value : undefined,
operator: latestOperatorResult.status === 'fulfilled' ? latestOperatorResult.value : undefined,
helmChart: latestHelmChartResult.status === 'fulfilled' ? latestHelmChartResult.value : undefined,
connect: latestConnectResult.status === 'fulfilled' ? latestConnectResult.value : undefined,
};
const components = await contentCatalog.getComponents();
components.forEach(component => {
const prerelease = component.latestPrerelease;
component.versions.forEach(({ name, version, asciidoc }) => {
if (prerelease?.version === version) {
asciidoc.attributes['page-component-version-is-prerelease'] = 'true';
}
// Set operator and helm chart attributes via helper function
updateAttributes(asciidoc, [
{ condition: latestVersions.operator, key: 'latest-operator-version', value: latestVersions.operator?.latestStableRelease },
{ condition: latestVersions.helmChart, key: 'latest-redpanda-helm-chart-version', value: latestVersions.helmChart?.latestStableRelease }
]);
// Set attributes for console and connect versions
[
{ condition: latestVersions.console, baseName: 'latest-console', value: latestVersions.console?.latestStableRelease },
{ condition: latestVersions.connect, baseName: 'latest-connect', value: latestVersions.connect }
].forEach(mapping => {
if (mapping.condition && mapping.value) {
setVersionAndTagAttributes(asciidoc, mapping.baseName, mapping.value, name, version);
}
});
// Special handling for Redpanda RC versions if in beta
if (latestVersions.redpanda?.latestRcRelease?.version) {
setVersionAndTagAttributes(asciidoc, 'redpanda-beta', latestVersions.redpanda.latestRcRelease.version, name, version);
asciidoc.attributes['redpanda-beta-commit'] = latestVersions.redpanda.latestRcRelease.commitHash;
}
if (latestVersions.console?.latestBetaRelease) {
setVersionAndTagAttributes(asciidoc, 'console-beta', latestVersions.console.latestBetaRelease, name, version);
}
if (latestVersions.operator?.latestBetaRelease) {
setVersionAndTagAttributes(asciidoc, 'operator-beta', latestVersions.operator.latestBetaRelease, name, version);
}
if (latestVersions.helmChart?.latestBetaRelease) {
setVersionAndTagAttributes(asciidoc, 'helm-beta', latestVersions.helmChart.latestBetaRelease, name, version);
}
});
if (!component.latest.asciidoc) component.latest.asciidoc = { attributes: {} };
// For Redpanda GA version, set both latest-redpanda-version and latest-redpanda-tag if available
if (semver.valid(latestVersions.redpanda?.latestRedpandaRelease?.version)) {
const currentVersion = component.latest.asciidoc.attributes['full-version'] || '0.0.0';
if (semver.gt(latestVersions.redpanda.latestRedpandaRelease.version, currentVersion)) {
// Required for backwards compatibility. Some docs still use full-version
component.latest.asciidoc.attributes['full-version'] = sanitizeVersion(latestVersions.redpanda.latestRedpandaRelease.version);
setVersionAndTagAttributes(component.latest.asciidoc, 'latest-redpanda', latestVersions.redpanda.latestRedpandaRelease.version, component.latest.name, component.latest.version);
component.latest.asciidoc.attributes['latest-release-commit'] = latestVersions.redpanda.latestRedpandaRelease.commitHash;
}
}
});
logger.info('Updated Redpanda documentation versions successfully:');
logger.info(`- Redpanda: ${latestVersions.redpanda.latestRedpandaRelease.version}${latestVersions.redpanda.latestRcRelease ? ', beta: ' + latestVersions.redpanda.latestRcRelease.version : ''}`);
logger.info(`- Connect: ${latestVersions.connect}`);
logger.info(`- Console: ${latestVersions.console.latestStableRelease}${latestVersions.console.latestBetaRelease ? ', beta: ' + latestVersions.console.latestBetaRelease : ''}`);
logger.info(`- Operator: ${latestVersions.operator?.latestStableRelease || 'unknown'}${latestVersions.operator?.latestBetaRelease ? ', beta: ' + latestVersions.operator.latestBetaRelease : ''}`);
logger.info(`- Helm chart: ${latestVersions.helmChart?.latestStableRelease || 'unknown'}${latestVersions.helmChart?.latestBetaRelease ? ', beta: ' + latestVersions.helmChart.latestBetaRelease : ''}`);
} catch (error) {
logger.error(`Error updating versions: ${error}`);
}
});
// Helper function to set both latest-*version and latest-*tag attributes
function setVersionAndTagAttributes(asciidoc, baseName, versionData, name = '', version = '') {
if (versionData) {
const versionWithoutPrefix = sanitizeVersion(versionData);
asciidoc.attributes[`${baseName}-version`] = versionWithoutPrefix; // Without "v" prefix
asciidoc.attributes[`${baseName}-tag`] = `${versionData}`;
if (name && version) {
logger.debug(`Set ${baseName}-version to ${versionWithoutPrefix} and ${baseName}-tag to ${versionData} in ${name} ${version}`);
} else {
logger.debug(`Updated ${baseName}-version to ${versionWithoutPrefix} and ${baseName}-tag to ${versionData}`);
}
}
}
// Helper function to sanitize version by removing "v" prefix
function sanitizeVersion(version) {
return version.replace(/^v/, '');
}
// Helper function to update multiple attributes based on a list of mappings
function updateAttributes(asciidoc, mappings) {
mappings.forEach(({ condition, key, value }) => {
if (condition) {
asciidoc.attributes[key] = value;
}
});
}
};