@redpanda-data/docs-extensions-and-macros 4.17.2 → 5.0.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/extension-utils/llms-utils.js +2 -5
- package/extensions/algolia-indexer/generate-index.js +99 -54
- package/extensions/collect-bloblang-samples.js +6 -6
- package/extensions/compute-end-of-life.js +9 -4
- package/extensions/conditional-home-redirect.js +90 -0
- package/extensions/convert-to-markdown.js +23 -1
- package/extensions/find-related-docs.js +3 -3
- package/extensions/find-related-labs.js +1 -1
- package/extensions/generate-fields-only-pages.js +7 -7
- package/extensions/generate-rp-connect-categories.js +5 -5
- package/extensions/generate-rp-connect-info.js +6 -6
- package/extensions/modify-connect-tag-playbook.js +1 -1
- package/extensions/unified-navigation.js +669 -0
- package/extensions/unlisted-pages.js +5 -1
- package/extensions/unpublish-pages.js +12 -0
- package/extensions/version-fetcher/fetch-latest-docker-tag.js +7 -2
- package/extensions/version-fetcher/get-latest-connect.js +6 -2
- package/extensions/version-fetcher/get-latest-console-version.js +13 -4
- package/extensions/version-fetcher/get-latest-redpanda-helm-version-from-operator.js +31 -5
- package/extensions/version-fetcher/get-latest-redpanda-version.js +8 -3
- package/extensions/version-fetcher/retry-util.js +10 -3
- package/extensions/version-fetcher/set-latest-version.js +9 -8
- package/macros/rp-connect-components.js +62 -1
- package/package.json +3 -1
- package/tools/redpanda-connect/helpers/renderConnectFields.js +1 -1
- package/tools/redpanda-connect/rpcn-connector-docs-handler.js +133 -83
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
module.exports.register = function () {
|
|
4
|
+
const logger = this.getLogger('unpublish-pages-extension');
|
|
5
|
+
|
|
4
6
|
this.on('documentsConverted', ({ siteCatalog, contentCatalog }) => {
|
|
5
7
|
// Get all pages that have an `out` property
|
|
6
8
|
const pages = contentCatalog.getPages((page) => page.out);
|
|
@@ -14,6 +16,15 @@ module.exports.register = function () {
|
|
|
14
16
|
pageVersion = page.asciidoc?.attributes['page-component-version'];
|
|
15
17
|
const component = contentCatalog.getComponent(componentName);
|
|
16
18
|
|
|
19
|
+
// Debug logging for ANY page with publish-only-during-beta attribute
|
|
20
|
+
if (page.asciidoc?.attributes['publish-only-during-beta']) {
|
|
21
|
+
logger.debug(`Found page with publish-only-during-beta: ${page.src?.relative || page.pub?.url}`);
|
|
22
|
+
logger.debug(` - publish-only-during-beta: ${page.asciidoc?.attributes['publish-only-during-beta']}`);
|
|
23
|
+
logger.debug(` - page-component-version-is-prerelease: ${page.asciidoc?.attributes['page-component-version-is-prerelease']}`);
|
|
24
|
+
logger.debug(` - page-unpublish: ${page.asciidoc?.attributes['page-unpublish']}`);
|
|
25
|
+
logger.debug(` - component: ${componentName}, version: ${pageVersion}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
17
28
|
// Check the conditions for unpublishing the page
|
|
18
29
|
const shouldUnpublish = (
|
|
19
30
|
page.asciidoc?.attributes['page-unpublish'] ||
|
|
@@ -24,6 +35,7 @@ module.exports.register = function () {
|
|
|
24
35
|
|
|
25
36
|
// Unpublish the shouldUnpublish pages
|
|
26
37
|
if (shouldUnpublish) {
|
|
38
|
+
logger.info(`Unpublishing page: ${page.src?.relative || page.pub?.url}`);
|
|
27
39
|
siteCatalog.unpublishedPages.push(page.pub.url)
|
|
28
40
|
delete page.out;
|
|
29
41
|
}
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @param {string} dockerNamespace - The Docker Hub namespace (organization or username)
|
|
8
8
|
* @param {string} dockerRepo - The repository name on Docker Hub
|
|
9
|
+
* @param {Object} logger - Optional Antora logger instance for logging
|
|
9
10
|
* @returns {Promise<{ latestStableRelease: string|null, latestBetaRelease: string|null }>}
|
|
10
11
|
*/
|
|
11
|
-
module.exports = async (dockerNamespace, dockerRepo) => {
|
|
12
|
+
module.exports = async (dockerNamespace, dockerRepo, logger = null) => {
|
|
12
13
|
const { default: fetch } = await import('node-fetch');
|
|
13
14
|
|
|
14
15
|
try {
|
|
@@ -64,7 +65,11 @@ module.exports = async (dockerNamespace, dockerRepo) => {
|
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
} catch (error) {
|
|
67
|
-
|
|
68
|
+
if (logger) {
|
|
69
|
+
logger.error('Error fetching Docker tags:', error);
|
|
70
|
+
} else {
|
|
71
|
+
console.error('Error fetching Docker tags:', error);
|
|
72
|
+
}
|
|
68
73
|
return {
|
|
69
74
|
latestStableRelease: null,
|
|
70
75
|
latestBetaRelease: null
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
module.exports = async (github, owner, repo) => {
|
|
1
|
+
module.exports = async (github, owner, repo, logger = null) => {
|
|
2
2
|
|
|
3
3
|
try {
|
|
4
4
|
const release = await github.rest.repos.getLatestRelease({ owner, repo });
|
|
5
5
|
return release.data.tag_name
|
|
6
6
|
} catch (error) {
|
|
7
|
-
|
|
7
|
+
if (logger) {
|
|
8
|
+
logger.error(error);
|
|
9
|
+
} else {
|
|
10
|
+
console.error(error);
|
|
11
|
+
}
|
|
8
12
|
return null;
|
|
9
13
|
}
|
|
10
14
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { retryWithBackoff, isRetryableGitHubError } = require('./retry-util');
|
|
2
2
|
|
|
3
|
-
module.exports = async (github, owner, repo) => {
|
|
3
|
+
module.exports = async (github, owner, repo, logger = null) => {
|
|
4
4
|
const semver = require('semver');
|
|
5
5
|
|
|
6
6
|
return retryWithBackoff(
|
|
@@ -29,7 +29,11 @@ module.exports = async (github, owner, repo) => {
|
|
|
29
29
|
latestBetaRelease: latestBetaReleaseVersion || null
|
|
30
30
|
};
|
|
31
31
|
} else {
|
|
32
|
-
|
|
32
|
+
if (logger) {
|
|
33
|
+
logger.warn("No valid semver releases found.");
|
|
34
|
+
} else {
|
|
35
|
+
console.log("No valid semver releases found.");
|
|
36
|
+
}
|
|
33
37
|
return { latestStableRelease: null, latestBetaRelease: null };
|
|
34
38
|
}
|
|
35
39
|
},
|
|
@@ -38,9 +42,14 @@ module.exports = async (github, owner, repo) => {
|
|
|
38
42
|
initialDelay: 1000,
|
|
39
43
|
shouldRetry: isRetryableGitHubError,
|
|
40
44
|
operationName: `Fetch Console version from ${owner}/${repo}`
|
|
41
|
-
}
|
|
45
|
+
},
|
|
46
|
+
logger
|
|
42
47
|
).catch(error => {
|
|
43
|
-
|
|
48
|
+
if (logger) {
|
|
49
|
+
logger.error('Failed to fetch release information after retries:', error);
|
|
50
|
+
} else {
|
|
51
|
+
console.error('Failed to fetch release information after retries:', error);
|
|
52
|
+
}
|
|
44
53
|
return { latestStableRelease: null, latestBetaRelease: null };
|
|
45
54
|
});
|
|
46
55
|
};
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
* @param {string} repo - The repository name (redpanda-operator).
|
|
9
9
|
* @param {string} stableDockerTag - The stable docker tag in format v<major>.<minor>.<patch>.
|
|
10
10
|
* @param {string} betaDockerTag - Optional beta docker tag in format v<major>.<minor>.<patch>-beta.
|
|
11
|
+
* @param {Object} logger - Optional Antora logger instance for logging
|
|
11
12
|
* @returns {Promise<{ latestStableRelease: string|null, latestBetaRelease: string|null }>}
|
|
12
13
|
*/
|
|
13
|
-
module.exports = async (github, owner, repo, stableDockerTag, betaDockerTag) => {
|
|
14
|
+
module.exports = async (github, owner, repo, stableDockerTag, betaDockerTag, logger = null) => {
|
|
14
15
|
const yaml = require('js-yaml');
|
|
15
16
|
const path = 'charts/redpanda/chart/Chart.yaml';
|
|
16
17
|
|
|
@@ -29,7 +30,11 @@ module.exports = async (github, owner, repo, stableDockerTag, betaDockerTag) =>
|
|
|
29
30
|
const versionMatch = dockerTag.match(/^v(\d+)\.(\d+)(?:\.(\d+))?(?:-beta.*)?$/);
|
|
30
31
|
|
|
31
32
|
if (!versionMatch) {
|
|
32
|
-
|
|
33
|
+
if (logger) {
|
|
34
|
+
logger.error(`Invalid docker tag format: ${dockerTag}`);
|
|
35
|
+
} else {
|
|
36
|
+
console.error(`Invalid docker tag format: ${dockerTag}`);
|
|
37
|
+
}
|
|
33
38
|
return null;
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -55,11 +60,28 @@ module.exports = async (github, owner, repo, stableDockerTag, betaDockerTag) =>
|
|
|
55
60
|
const version = chartYaml.version || null;
|
|
56
61
|
return version;
|
|
57
62
|
} catch (error) {
|
|
58
|
-
|
|
63
|
+
if (error.status === 404) {
|
|
64
|
+
// Branch doesn't exist yet - this is expected for unreleased versions
|
|
65
|
+
if (logger) {
|
|
66
|
+
logger.warn(`Fetched operator ${dockerTag} from Docker Hub but branch ${branchName} not found in GitHub (source may not be released yet)`);
|
|
67
|
+
} else {
|
|
68
|
+
console.warn(`Fetched operator ${dockerTag} from Docker Hub but branch ${branchName} not found in GitHub (source may not be released yet)`);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
if (logger) {
|
|
72
|
+
logger.error(`Failed to fetch Chart.yaml for branch ${branchName}:`, error.message);
|
|
73
|
+
} else {
|
|
74
|
+
console.error(`Failed to fetch Chart.yaml for branch ${branchName}:`, error.message);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
59
77
|
return null;
|
|
60
78
|
}
|
|
61
79
|
} catch (error) {
|
|
62
|
-
|
|
80
|
+
if (logger) {
|
|
81
|
+
logger.error(`Error processing docker tag ${dockerTag}:`, error.message);
|
|
82
|
+
} else {
|
|
83
|
+
console.error(`Error processing docker tag ${dockerTag}:`, error.message);
|
|
84
|
+
}
|
|
63
85
|
return null;
|
|
64
86
|
}
|
|
65
87
|
};
|
|
@@ -75,7 +97,11 @@ module.exports = async (github, owner, repo, stableDockerTag, betaDockerTag) =>
|
|
|
75
97
|
latestBetaRelease: betaChartVersion
|
|
76
98
|
};
|
|
77
99
|
} catch (error) {
|
|
78
|
-
|
|
100
|
+
if (logger) {
|
|
101
|
+
logger.error('Failed to fetch chart versions:', error.message);
|
|
102
|
+
} else {
|
|
103
|
+
console.error('Failed to fetch chart versions:', error.message);
|
|
104
|
+
}
|
|
79
105
|
return {
|
|
80
106
|
latestStableRelease: null,
|
|
81
107
|
latestBetaRelease: null
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { retryWithBackoff, isRetryableGitHubError } = require('./retry-util');
|
|
2
2
|
|
|
3
|
-
module.exports = async (github, owner, repo) => {
|
|
3
|
+
module.exports = async (github, owner, repo, logger = null) => {
|
|
4
4
|
const semver = require('semver');
|
|
5
5
|
|
|
6
6
|
return retryWithBackoff(
|
|
@@ -67,9 +67,14 @@ module.exports = async (github, owner, repo) => {
|
|
|
67
67
|
initialDelay: 1000,
|
|
68
68
|
shouldRetry: isRetryableGitHubError,
|
|
69
69
|
operationName: `Fetch Redpanda version from ${owner}/${repo}`
|
|
70
|
-
}
|
|
70
|
+
},
|
|
71
|
+
logger
|
|
71
72
|
).catch(error => {
|
|
72
|
-
|
|
73
|
+
if (logger) {
|
|
74
|
+
logger.error('Failed to fetch Redpanda release information after retries:', error);
|
|
75
|
+
} else {
|
|
76
|
+
console.error('Failed to fetch Redpanda release information after retries:', error);
|
|
77
|
+
}
|
|
73
78
|
return { latestRedpandaRelease: null, latestRcRelease: null };
|
|
74
79
|
});
|
|
75
80
|
};
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
* @param {number} options.maxDelay - Maximum delay in ms (default: 10000)
|
|
9
9
|
* @param {Function} options.shouldRetry - Function to determine if error is retryable (default: all errors)
|
|
10
10
|
* @param {string} options.operationName - Name for logging
|
|
11
|
+
* @param {Object} logger - Optional Antora logger instance for logging
|
|
11
12
|
* @returns {Promise<*>} Result of the function
|
|
12
13
|
*/
|
|
13
|
-
async function retryWithBackoff(fn, options = {}) {
|
|
14
|
+
async function retryWithBackoff(fn, options = {}, logger = null) {
|
|
14
15
|
const {
|
|
15
16
|
maxRetries = 3,
|
|
16
17
|
initialDelay = 1000,
|
|
@@ -37,8 +38,14 @@ async function retryWithBackoff(fn, options = {}) {
|
|
|
37
38
|
const jitter = Math.random() * 0.3 * baseDelay; // Add up to 30% jitter
|
|
38
39
|
const delay = Math.floor(baseDelay + jitter);
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
// Log retry attempt using logger if available, otherwise fall back to console
|
|
42
|
+
if (logger) {
|
|
43
|
+
logger.warn(`${operationName} failed (attempt ${attempt + 1}/${maxRetries + 1}): ${error.message}`);
|
|
44
|
+
logger.warn(`Retrying in ${delay}ms...`);
|
|
45
|
+
} else {
|
|
46
|
+
console.error(`⚠️ ${operationName} failed (attempt ${attempt + 1}/${maxRetries + 1}): ${error.message}`);
|
|
47
|
+
console.error(` Retrying in ${delay}ms...`);
|
|
48
|
+
}
|
|
42
49
|
|
|
43
50
|
// Wait before retrying
|
|
44
51
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
@@ -37,10 +37,10 @@ module.exports.register = function ({ config }) {
|
|
|
37
37
|
latestOperatorResult,
|
|
38
38
|
latestConnectResult,
|
|
39
39
|
] = await Promise.allSettled([
|
|
40
|
-
GetLatestRedpandaVersion(github, owner, 'redpanda'),
|
|
41
|
-
GetLatestDockerTag(dockerNamespace, 'console'),
|
|
42
|
-
GetLatestDockerTag(dockerNamespace, 'redpanda-operator'),
|
|
43
|
-
GetLatestConnectVersion(github, owner, 'connect'),
|
|
40
|
+
GetLatestRedpandaVersion(github, owner, 'redpanda', logger),
|
|
41
|
+
GetLatestDockerTag(dockerNamespace, 'console', logger),
|
|
42
|
+
GetLatestDockerTag(dockerNamespace, 'redpanda-operator', logger),
|
|
43
|
+
GetLatestConnectVersion(github, owner, 'connect', logger),
|
|
44
44
|
]);
|
|
45
45
|
|
|
46
46
|
// Get the Helm chart version after we have the operator version (for both stable and beta)
|
|
@@ -49,11 +49,12 @@ module.exports.register = function ({ config }) {
|
|
|
49
49
|
if (latestOperatorResult.status === 'fulfilled') {
|
|
50
50
|
try {
|
|
51
51
|
const helmChartVersions = await GetLatestHelmChartVersionFromOperator(
|
|
52
|
-
github,
|
|
53
|
-
owner,
|
|
54
|
-
'redpanda-operator',
|
|
52
|
+
github,
|
|
53
|
+
owner,
|
|
54
|
+
'redpanda-operator',
|
|
55
55
|
latestOperatorResult.value?.latestStableRelease,
|
|
56
|
-
latestOperatorResult.value?.latestBetaRelease
|
|
56
|
+
latestOperatorResult.value?.latestBetaRelease,
|
|
57
|
+
logger
|
|
57
58
|
);
|
|
58
59
|
|
|
59
60
|
latestHelmChartResult = {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const { posix: path } = require('path')
|
|
3
|
+
|
|
2
4
|
/**
|
|
3
5
|
* Registers macros for use in Redpanda Connect contexts in the Redpanda documentation.
|
|
4
6
|
* @param {Registry} registry - The Antora registry where this block macro is registered.
|
|
@@ -1024,7 +1026,31 @@ module.exports.register = function (registry, context) {
|
|
|
1024
1026
|
// Filter for the specific connector by name
|
|
1025
1027
|
const componentRows = csvData.data.filter(row => row.connector.trim().toLowerCase() === name.trim().toLowerCase());
|
|
1026
1028
|
if (componentRows.length === 0) {
|
|
1027
|
-
console.
|
|
1029
|
+
console.warn(`No CSV data found for connector: ${name}. The connector may have been removed or renamed.`);
|
|
1030
|
+
// Build link to release notes using content catalog for proper URL resolution
|
|
1031
|
+
const isCloud = attributes['env-cloud'] !== undefined;
|
|
1032
|
+
let whatsNewUrl = isCloud
|
|
1033
|
+
? '/redpanda-cloud/develop/connect/get-started/whats-new/'
|
|
1034
|
+
: '/redpanda-connect/get-started/whats-new/';
|
|
1035
|
+
|
|
1036
|
+
// Try to resolve the page from the content catalog for accurate URLs
|
|
1037
|
+
if (context.contentCatalog && context.file) {
|
|
1038
|
+
const pageSpec = isCloud
|
|
1039
|
+
? 'redpanda-cloud:develop/connect/get-started:whats-new.adoc'
|
|
1040
|
+
: 'redpanda-connect:get-started:whats-new.adoc';
|
|
1041
|
+
const page = context.contentCatalog.resolvePage(pageSpec, context.file.src);
|
|
1042
|
+
if (page) {
|
|
1043
|
+
whatsNewUrl = path.relative(path.dirname(context.file.pub.url), page.pub.url);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// Return a notice for removed/unknown connectors
|
|
1048
|
+
return self.createBlock(parent, 'pass', `
|
|
1049
|
+
<div class="metadata-block">
|
|
1050
|
+
<div class="metadata-content">
|
|
1051
|
+
<p><strong>Available in:</strong> <em>This connector is no longer available. Check the <a href="${whatsNewUrl}">release notes</a> for migration guidance.</em></p>
|
|
1052
|
+
</div>
|
|
1053
|
+
</div>`);
|
|
1028
1054
|
}
|
|
1029
1055
|
// Process types and metadata from CSV
|
|
1030
1056
|
const types = componentRows.map(row => ({
|
|
@@ -1041,6 +1067,21 @@ module.exports.register = function (registry, context) {
|
|
|
1041
1067
|
const [currentType] = sortedTypes.splice(currentTypeIndex, 1);
|
|
1042
1068
|
sortedTypes.unshift(currentType);
|
|
1043
1069
|
}
|
|
1070
|
+
|
|
1071
|
+
// Set context-switcher attribute for UI template to render compact dropdown in sticky bar
|
|
1072
|
+
if (sortedTypes.length > 1) {
|
|
1073
|
+
const contextSwitcherData = {};
|
|
1074
|
+
sortedTypes.forEach(typeObj => {
|
|
1075
|
+
const link = (component === 'Cloud' && typeObj.redpandaCloudUrl) || typeObj.redpandaConnectUrl;
|
|
1076
|
+
contextSwitcherData[typeObj.type.toLowerCase()] = {
|
|
1077
|
+
name: capitalize(typeObj.type),
|
|
1078
|
+
to: link
|
|
1079
|
+
};
|
|
1080
|
+
});
|
|
1081
|
+
// Set as page attribute (not document attribute) so it's accessible in UI template
|
|
1082
|
+
attributes['page-context-switcher'] = JSON.stringify(contextSwitcherData);
|
|
1083
|
+
parent.getDocument().setAttribute('page-context-switcher', JSON.stringify(contextSwitcherData));
|
|
1084
|
+
}
|
|
1044
1085
|
// Check if the component requires an Enterprise license (based on support level)
|
|
1045
1086
|
let enterpriseLicenseInfo = '';
|
|
1046
1087
|
if (component !== 'Cloud') {
|
|
@@ -1051,6 +1092,26 @@ module.exports.register = function (registry, context) {
|
|
|
1051
1092
|
}
|
|
1052
1093
|
}
|
|
1053
1094
|
const isCloudSupported = componentRows.some(row => row.is_cloud_supported === 'y');
|
|
1095
|
+
|
|
1096
|
+
// Set availability attributes for UI template badges with URLs
|
|
1097
|
+
if (isCloudSupported) {
|
|
1098
|
+
const cloudUrl = sortedTypes[0].redpandaCloudUrl;
|
|
1099
|
+
const connectUrl = sortedTypes[0].redpandaConnectUrl;
|
|
1100
|
+
|
|
1101
|
+
if (component === 'Connect' && cloudUrl) {
|
|
1102
|
+
// Viewing Self-Managed, but also available in Cloud - show Cloud badge with link
|
|
1103
|
+
parent.getDocument().setAttribute('cloud-available', 'true');
|
|
1104
|
+
parent.getDocument().setAttribute('cloud-available-url', cloudUrl);
|
|
1105
|
+
} else if (component === 'Cloud' && connectUrl) {
|
|
1106
|
+
// Viewing Cloud, but also available in Self-Managed - show Self-Managed badge with link
|
|
1107
|
+
parent.getDocument().setAttribute('self-managed-available', 'true');
|
|
1108
|
+
parent.getDocument().setAttribute('self-managed-available-url', connectUrl);
|
|
1109
|
+
}
|
|
1110
|
+
} else if (!isCloudSupported && component === 'Connect') {
|
|
1111
|
+
// Only available in Self-Managed - show "Self-Managed Only" badge (no link)
|
|
1112
|
+
parent.getDocument().setAttribute('self-managed-only', 'true');
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1054
1115
|
let availableInInfo = '';
|
|
1055
1116
|
|
|
1056
1117
|
if (isCloudSupported) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redpanda-data/docs-extensions-and-macros",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Antora extensions and macros developed for Redpanda documentation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antora",
|
|
@@ -77,6 +77,8 @@
|
|
|
77
77
|
"./extensions/algolia-indexer/index": "./extensions/algolia-indexer/index.js",
|
|
78
78
|
"./extensions/aggregate-terms": "./extensions/aggregate-terms.js",
|
|
79
79
|
"./extensions/resolve-xrefs-in-attachments": "./extensions/resolve-xrefs-in-attachments.js",
|
|
80
|
+
"./extensions/unified-navigation": "./extensions/unified-navigation.js",
|
|
81
|
+
"./extensions/conditional-home-redirect": "./extensions/conditional-home-redirect.js",
|
|
80
82
|
"./macros/glossary": "./macros/glossary.js",
|
|
81
83
|
"./macros/rp-connect-components": "./macros/rp-connect-components.js",
|
|
82
84
|
"./macros/config-ref": "./macros/config-ref.js",
|
|
@@ -79,7 +79,7 @@ module.exports = function renderConnectFields(children, prefix = '') {
|
|
|
79
79
|
block += `${desc}\n\n`;
|
|
80
80
|
}
|
|
81
81
|
if (child.is_secret) {
|
|
82
|
-
block += `include::
|
|
82
|
+
block += `include::connect:components:partial$secret_warning.adoc[]\n\n`;
|
|
83
83
|
}
|
|
84
84
|
if (child.version) {
|
|
85
85
|
block += `ifndef::env-cloud[]\nRequires version ${child.version} or later.\nendif::[]\n\n`;
|
|
@@ -106,6 +106,94 @@ function stripPlatformMetadata (connectors) {
|
|
|
106
106
|
})
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Augment connector data with platform metadata from binary analysis.
|
|
111
|
+
* This adds cloudSupported/requiresCgo flags and includes CGO-only and cloud-only connectors.
|
|
112
|
+
*
|
|
113
|
+
* @param {Object} connectorData - Connector index object with arrays for each component type
|
|
114
|
+
* @param {Object} binaryAnalysis - Binary analysis results from analyzeAllBinaries()
|
|
115
|
+
* @returns {Object} Object with augmentedData, augmentedCount, addedCgoCount, addedCloudOnlyCount
|
|
116
|
+
*/
|
|
117
|
+
function augmentConnectorData (connectorData, binaryAnalysis) {
|
|
118
|
+
if (!binaryAnalysis) {
|
|
119
|
+
return { augmentedData: connectorData, augmentedCount: 0, addedCgoCount: 0, addedCloudOnlyCount: 0 }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Deep clone to avoid mutating original
|
|
123
|
+
const augmentedData = JSON.parse(JSON.stringify(connectorData))
|
|
124
|
+
|
|
125
|
+
const cloudSet = new Set(
|
|
126
|
+
(binaryAnalysis.comparison?.inCloud || []).map(c => `${c.type}:${c.name}`)
|
|
127
|
+
)
|
|
128
|
+
const cgoOnlySet = new Set(
|
|
129
|
+
(binaryAnalysis.cgoOnly || []).map(c => `${c.type}:${c.name}`)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
let augmentedCount = 0
|
|
133
|
+
let addedCgoCount = 0
|
|
134
|
+
let addedCloudOnlyCount = 0
|
|
135
|
+
|
|
136
|
+
const connectorTypes = ['inputs', 'outputs', 'processors', 'caches', 'rate_limits',
|
|
137
|
+
'buffers', 'metrics', 'scanners', 'tracers']
|
|
138
|
+
|
|
139
|
+
for (const type of connectorTypes) {
|
|
140
|
+
if (!Array.isArray(augmentedData[type])) {
|
|
141
|
+
augmentedData[type] = []
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Add cloudSupported and requiresCgo flags to existing connectors
|
|
145
|
+
for (const connector of augmentedData[type]) {
|
|
146
|
+
const key = `${type}:${connector.name}`
|
|
147
|
+
connector.cloudSupported = cloudSet.has(key)
|
|
148
|
+
connector.requiresCgo = cgoOnlySet.has(key)
|
|
149
|
+
augmentedCount++
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Add CGO-only connectors that aren't in the OSS list
|
|
153
|
+
if (binaryAnalysis.cgoOnly) {
|
|
154
|
+
for (const cgoConn of binaryAnalysis.cgoOnly) {
|
|
155
|
+
if (cgoConn.type === type) {
|
|
156
|
+
const exists = augmentedData[type].some(c => c.name === cgoConn.name)
|
|
157
|
+
if (!exists) {
|
|
158
|
+
// Singularize type for consistency with stored data (except "metrics" which stays plural)
|
|
159
|
+
const componentType = cgoConn.type === 'metrics' ? 'metrics' : cgoConn.type.replace(/s$/, '')
|
|
160
|
+
augmentedData[type].push({
|
|
161
|
+
...cgoConn,
|
|
162
|
+
type: componentType,
|
|
163
|
+
cloudSupported: false,
|
|
164
|
+
requiresCgo: true
|
|
165
|
+
})
|
|
166
|
+
addedCgoCount++
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Add cloud-only connectors that aren't in the OSS list
|
|
173
|
+
if (binaryAnalysis.comparison?.cloudOnly) {
|
|
174
|
+
for (const cloudConn of binaryAnalysis.comparison.cloudOnly) {
|
|
175
|
+
if (cloudConn.type === type) {
|
|
176
|
+
const exists = augmentedData[type].some(c => c.name === cloudConn.name)
|
|
177
|
+
if (!exists) {
|
|
178
|
+
// Singularize type for consistency with stored data (except "metrics" which stays plural)
|
|
179
|
+
const componentType = cloudConn.type === 'metrics' ? 'metrics' : cloudConn.type.replace(/s$/, '')
|
|
180
|
+
augmentedData[type].push({
|
|
181
|
+
...cloudConn,
|
|
182
|
+
type: componentType,
|
|
183
|
+
cloudSupported: true,
|
|
184
|
+
requiresCgo: false,
|
|
185
|
+
cloudOnly: true
|
|
186
|
+
})
|
|
187
|
+
addedCloudOnlyCount++
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return { augmentedData, augmentedCount, addedCgoCount, addedCloudOnlyCount }
|
|
195
|
+
}
|
|
196
|
+
|
|
109
197
|
/**
|
|
110
198
|
* Update whats-new.adoc with new release information
|
|
111
199
|
* @param {Object} params - Parameters
|
|
@@ -830,13 +918,22 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
830
918
|
}
|
|
831
919
|
}
|
|
832
920
|
|
|
921
|
+
// Augment newData with binary analysis results before generating diff
|
|
922
|
+
// This ensures CGO-only and cloud-only connectors are included and metadata is accurate
|
|
923
|
+
const { augmentedData: augmentedNewData, addedCgoCount, addedCloudOnlyCount } =
|
|
924
|
+
augmentConnectorData(newData, intermediateAnalysis)
|
|
925
|
+
|
|
926
|
+
if (addedCgoCount > 0 || addedCloudOnlyCount > 0) {
|
|
927
|
+
console.log(` • Augmented newData: +${addedCgoCount} CGO-only, +${addedCloudOnlyCount} cloud-only`)
|
|
928
|
+
}
|
|
929
|
+
|
|
833
930
|
// Generate diff
|
|
834
931
|
console.log(`\nGenerating diff: ${fromVer} → ${toVer}...`)
|
|
835
932
|
const { generateConnectorDiffJson } = require('./report-delta.js')
|
|
836
933
|
|
|
837
934
|
const diffData = generateConnectorDiffJson(
|
|
838
935
|
oldData,
|
|
839
|
-
|
|
936
|
+
augmentedNewData,
|
|
840
937
|
{
|
|
841
938
|
oldVersion: fromVer,
|
|
842
939
|
newVersion: toVer,
|
|
@@ -850,6 +947,12 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
850
947
|
fs.writeFileSync(diffPath, JSON.stringify(diffData, null, 2), 'utf8')
|
|
851
948
|
console.log(`✓ Diff saved: ${path.basename(diffPath)}`)
|
|
852
949
|
|
|
950
|
+
// Save augmented data back to file for subsequent iterations
|
|
951
|
+
// This ensures the next version pair has consistent metadata when loading this version as oldData
|
|
952
|
+
const augmentedDataPath = path.join(dataDir, `connect-${toVer}.json`)
|
|
953
|
+
fs.writeFileSync(augmentedDataPath, JSON.stringify(augmentedNewData, null, 2), 'utf8')
|
|
954
|
+
console.log(`✓ Augmented data saved: connect-${toVer}.json`)
|
|
955
|
+
|
|
853
956
|
// Update what's-new if requested
|
|
854
957
|
if (options.updateWhatsNew) {
|
|
855
958
|
console.log(`Updating what's-new.adoc for ${toVer}...`)
|
|
@@ -1097,73 +1200,10 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1097
1200
|
|
|
1098
1201
|
const connectorData = JSON.parse(fs.readFileSync(dataFile, 'utf8'))
|
|
1099
1202
|
|
|
1100
|
-
const
|
|
1101
|
-
(binaryAnalysis
|
|
1102
|
-
)
|
|
1103
|
-
const cgoOnlySet = new Set(
|
|
1104
|
-
(binaryAnalysis.cgoOnly || []).map(c => `${c.type}:${c.name}`)
|
|
1105
|
-
)
|
|
1106
|
-
|
|
1107
|
-
let augmentedCount = 0
|
|
1108
|
-
let addedCgoCount = 0
|
|
1109
|
-
let addedCloudOnlyCount = 0
|
|
1110
|
-
|
|
1111
|
-
const connectorTypes = ['inputs', 'outputs', 'processors', 'caches', 'rate_limits',
|
|
1112
|
-
'buffers', 'metrics', 'scanners', 'tracers']
|
|
1203
|
+
const { augmentedData, augmentedCount, addedCgoCount, addedCloudOnlyCount } =
|
|
1204
|
+
augmentConnectorData(connectorData, binaryAnalysis)
|
|
1113
1205
|
|
|
1114
|
-
|
|
1115
|
-
if (!Array.isArray(connectorData[type])) {
|
|
1116
|
-
connectorData[type] = []
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
for (const connector of connectorData[type]) {
|
|
1120
|
-
const key = `${type}:${connector.name}`
|
|
1121
|
-
connector.cloudSupported = cloudSet.has(key)
|
|
1122
|
-
connector.requiresCgo = cgoOnlySet.has(key)
|
|
1123
|
-
augmentedCount++
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
if (binaryAnalysis.cgoOnly) {
|
|
1127
|
-
for (const cgoConn of binaryAnalysis.cgoOnly) {
|
|
1128
|
-
if (cgoConn.type === type) {
|
|
1129
|
-
const exists = connectorData[type].some(c => c.name === cgoConn.name)
|
|
1130
|
-
if (!exists) {
|
|
1131
|
-
// Singularize type for consistency with stored data (except "metrics" which stays plural)
|
|
1132
|
-
const componentType = cgoConn.type === 'metrics' ? 'metrics' : cgoConn.type.replace(/s$/, '')
|
|
1133
|
-
connectorData[type].push({
|
|
1134
|
-
...cgoConn,
|
|
1135
|
-
type: componentType,
|
|
1136
|
-
cloudSupported: false,
|
|
1137
|
-
requiresCgo: true
|
|
1138
|
-
})
|
|
1139
|
-
addedCgoCount++
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
if (binaryAnalysis.comparison?.cloudOnly) {
|
|
1146
|
-
for (const cloudConn of binaryAnalysis.comparison.cloudOnly) {
|
|
1147
|
-
if (cloudConn.type === type) {
|
|
1148
|
-
const exists = connectorData[type].some(c => c.name === cloudConn.name)
|
|
1149
|
-
if (!exists) {
|
|
1150
|
-
// Singularize type for consistency with stored data (except "metrics" which stays plural)
|
|
1151
|
-
const componentType = cloudConn.type === 'metrics' ? 'metrics' : cloudConn.type.replace(/s$/, '')
|
|
1152
|
-
connectorData[type].push({
|
|
1153
|
-
...cloudConn,
|
|
1154
|
-
type: componentType,
|
|
1155
|
-
cloudSupported: true,
|
|
1156
|
-
requiresCgo: false,
|
|
1157
|
-
cloudOnly: true
|
|
1158
|
-
})
|
|
1159
|
-
addedCloudOnlyCount++
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
fs.writeFileSync(dataFile, JSON.stringify(connectorData, null, 2), 'utf8')
|
|
1206
|
+
fs.writeFileSync(dataFile, JSON.stringify(augmentedData, null, 2), 'utf8')
|
|
1167
1207
|
console.log(`Done: Augmented ${augmentedCount} connectors with cloud/cgo fields`)
|
|
1168
1208
|
if (addedCgoCount > 0) {
|
|
1169
1209
|
console.log(` • Added ${addedCgoCount} cgo-only connectors to data file`)
|
|
@@ -1172,8 +1212,7 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1172
1212
|
console.log(` • Added ${addedCloudOnlyCount} cloud-only connectors to data file`)
|
|
1173
1213
|
}
|
|
1174
1214
|
|
|
1175
|
-
// Keep only the latest
|
|
1176
|
-
// BUT preserve any files from intermediate processing during this run
|
|
1215
|
+
// Keep only the latest 2 versions (by semver), delete all others
|
|
1177
1216
|
const dataVersions = fs.readdirSync(dataDir)
|
|
1178
1217
|
.filter(f => /^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/.test(f))
|
|
1179
1218
|
.map(f => {
|
|
@@ -1181,21 +1220,12 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1181
1220
|
return match ? match[1] : null
|
|
1182
1221
|
})
|
|
1183
1222
|
.filter(v => v && semver.valid(v))
|
|
1223
|
+
.sort((a, b) => semver.rcompare(a, b)) // Sort descending (newest first)
|
|
1184
1224
|
|
|
1185
|
-
//
|
|
1186
|
-
const versionsToKeep = new Set(
|
|
1187
|
-
if (intermediateProcessingResults.length > 0) {
|
|
1188
|
-
// Keep intermediate versions from this run
|
|
1189
|
-
intermediateProcessingResults.forEach(r => {
|
|
1190
|
-
versionsToKeep.add(r.fromVersion);
|
|
1191
|
-
versionsToKeep.add(r.toVersion);
|
|
1192
|
-
});
|
|
1193
|
-
}
|
|
1194
|
-
if (oldVersion) {
|
|
1195
|
-
versionsToKeep.add(oldVersion); // Keep old version for diff
|
|
1196
|
-
}
|
|
1225
|
+
// Keep only the latest 2 versions
|
|
1226
|
+
const versionsToKeep = new Set(dataVersions.slice(0, 2))
|
|
1197
1227
|
|
|
1198
|
-
// Delete
|
|
1228
|
+
// Delete all older versions
|
|
1199
1229
|
for (const version of dataVersions) {
|
|
1200
1230
|
if (!versionsToKeep.has(version)) {
|
|
1201
1231
|
const dataFile = `connect-${version}.json`
|
|
@@ -1205,9 +1235,29 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1205
1235
|
}
|
|
1206
1236
|
}
|
|
1207
1237
|
|
|
1238
|
+
// Also clean up old CSV files (keep latest 2)
|
|
1239
|
+
const csvVersions = fs.readdirSync(dataDir)
|
|
1240
|
+
.filter(f => /^connect-info-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.csv$/.test(f))
|
|
1241
|
+
.map(f => {
|
|
1242
|
+
const match = f.match(/^connect-info-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.csv$/)
|
|
1243
|
+
return match ? match[1] : null
|
|
1244
|
+
})
|
|
1245
|
+
.filter(v => v && semver.valid(v))
|
|
1246
|
+
.sort((a, b) => semver.rcompare(a, b))
|
|
1247
|
+
|
|
1248
|
+
const csvToKeep = new Set(csvVersions.slice(0, 2))
|
|
1249
|
+
for (const version of csvVersions) {
|
|
1250
|
+
if (!csvToKeep.has(version)) {
|
|
1251
|
+
const csvFile = `connect-info-${version}.csv`
|
|
1252
|
+
const csvPath = path.join(dataDir, csvFile);
|
|
1253
|
+
fs.unlinkSync(csvPath);
|
|
1254
|
+
console.log(`🧹 Deleted old CSV from docs-data: ${csvFile}`);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1208
1258
|
// IMPORTANT: Reload newIndex with augmented data for unified diff
|
|
1209
1259
|
// The unified diff approach compares platform metadata to detect transitions
|
|
1210
|
-
newIndex =
|
|
1260
|
+
newIndex = augmentedData
|
|
1211
1261
|
console.log(`✓ Reloaded newIndex with augmented data for diff comparison`)
|
|
1212
1262
|
} catch (err) {
|
|
1213
1263
|
console.error(`Warning: Failed to augment data file: ${err.message}`)
|