@redpanda-data/docs-extensions-and-macros 3.6.6 → 3.7.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 +28 -6
- package/extensions/add-global-attributes.js +68 -18
- package/extensions/aggregate-terms.js +82 -15
- package/extensions/generate-rp-connect-info.js +109 -32
- package/extensions/validate-attributes.js +2 -0
- package/macros/rp-connect-components.js +676 -262
- package/package.json +1 -1
package/README.adoc
CHANGED
|
@@ -226,7 +226,7 @@ antora:
|
|
|
226
226
|
|
|
227
227
|
=== Global attributes
|
|
228
228
|
|
|
229
|
-
This extension collects Asciidoc attributes from the {url-playbook}[`shared` component] and makes them available to all component versions. Having global attributes is useful for consistent configuration of local and production builds.
|
|
229
|
+
This extension collects Asciidoc attributes from the {url-playbook}[`shared` component] or a local YAML file and makes them available to all component versions. Having global attributes is useful for consistent configuration of local and production builds.
|
|
230
230
|
|
|
231
231
|
==== Environment variables
|
|
232
232
|
|
|
@@ -234,16 +234,21 @@ This extension does not require any environment variables.
|
|
|
234
234
|
|
|
235
235
|
==== Configuration options
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
The extension accepts the following configuration options:
|
|
238
|
+
|
|
239
|
+
attributespath (optional):: Specifies the path to a local YAML file that contains global attributes. If this is provided, the extension will load attributes from this file first. If this path is not provided or no valid attributes are found in the file, the extension will fall back to loading attributes from the `shared` component.
|
|
238
240
|
|
|
239
241
|
==== Registration example
|
|
240
242
|
|
|
241
|
-
```
|
|
243
|
+
```yml
|
|
242
244
|
antora:
|
|
243
245
|
extensions:
|
|
244
246
|
- require: '@redpanda-data/docs-extensions-and-macros/extensions/add-global-attributes'
|
|
247
|
+
attributespath: './local-attributes.yml'
|
|
245
248
|
```
|
|
246
249
|
|
|
250
|
+
In this example, the `attributespath` option points to a local YAML file (`./local-attributes.yml`), which contains the global attributes. The extension will load attributes from this file first before falling back to the `shared` component.
|
|
251
|
+
|
|
247
252
|
=== Produce redirects (customization of core Antora)
|
|
248
253
|
|
|
249
254
|
This extension replaces the default https://gitlab.com/antora/antora/-/tree/v3.1.x/packages/redirect-producer[`produceRedirects()` function] in Antora to handle redirect loops caused by https://docs.antora.org/antora/latest/page/page-aliases/[page aliases]. Normally, page aliases in Antora are used to resolve outdated links without causing issues. However, with https://docs.antora.org/antora/latest/playbook/urls-html-extension-style/#html-extension-style-key[`indexify`], the same URL may inadvertently be used for both the source and target of a redirect, leading to loops. This problem is https://antora.zulipchat.com/#narrow/stream/282400-users/topic/Redirect.20Loop.20Issue.20with.20Page.20Renaming.20and.20Indexify/near/433691700[recognized as a bug] in core Antora. For example, creating a page alias for `modules/manage/security/authorization.adoc` to point to `modules/manage/security/authorization/index.adoc' can lead to a redirect loop where `manage/security/authorization/` points to `manage/security/authorization/`. Furthermore, omitting the alias would lead to `xref not found` errors because Antora relies on the alias to resolve the old xrefs. This extension is necessary until such behaviors are natively supported or fixed in Antora core.
|
|
@@ -305,16 +310,33 @@ This extension does not require any environment variables.
|
|
|
305
310
|
|
|
306
311
|
==== Configuration options
|
|
307
312
|
|
|
308
|
-
|
|
313
|
+
The extension accepts the following configuration options:
|
|
314
|
+
|
|
315
|
+
termspath (optional):: Specifies the path to a local directory containing term files (in `.adoc` format). If this path is provided, the extension will attempt to load terms from this directory first. If this path is not provided or no valid terms are found in the specified directory, the extension will fall back to loading terms from the `shared` component.
|
|
316
|
+
|
|
317
|
+
Term files should follow the following structure:
|
|
318
|
+
|
|
319
|
+
```asciidoc
|
|
320
|
+
:category: Documentation
|
|
321
|
+
:hover-text: This is a description of the term.
|
|
322
|
+
:link: https://example.com
|
|
323
|
+
|
|
324
|
+
== Term Title
|
|
325
|
+
|
|
326
|
+
This is the detailed description of the term.
|
|
327
|
+
```
|
|
309
328
|
|
|
310
329
|
==== Registration example
|
|
311
330
|
|
|
312
|
-
```
|
|
331
|
+
```yml
|
|
313
332
|
antora:
|
|
314
333
|
extensions:
|
|
315
|
-
- '@redpanda-data/docs-extensions-and-macros/extensions/aggregate-terms'
|
|
334
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/aggregate-terms'
|
|
335
|
+
termspath: './local-terms/'
|
|
316
336
|
```
|
|
317
337
|
|
|
338
|
+
In this example, the `termspath` option points to a local directory (./local-terms/), where the term files are stored. The extension will load terms from this directory first before falling back to the `shared` component.
|
|
339
|
+
|
|
318
340
|
=== Unlisted pages
|
|
319
341
|
|
|
320
342
|
This extension identifies and logs any pages that aren't listed in the navigation (nav) file of each version of each component. It then optionally adds these unlisted pages to the end of the navigation tree under a configurable heading.
|
|
@@ -4,33 +4,83 @@
|
|
|
4
4
|
* - require: ./extensions/add-global-attributes.js
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const yaml = require('js-yaml');
|
|
10
|
+
const _ = require('lodash');
|
|
11
|
+
|
|
12
|
+
const ATTRIBUTES_PATH = 'modules/ROOT/partials/'; // Default path within the 'shared' component
|
|
13
|
+
|
|
7
14
|
module.exports.register = function ({ config }) {
|
|
8
|
-
const yaml = require('js-yaml');
|
|
9
15
|
const logger = this.getLogger('global-attributes-extension');
|
|
10
|
-
const chalk = require('chalk')
|
|
11
|
-
|
|
16
|
+
const chalk = require('chalk');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Load global attributes from a specified local file if provided.
|
|
20
|
+
*/
|
|
21
|
+
function loadLocalAttributes(siteCatalog, localAttributesFile) {
|
|
22
|
+
try {
|
|
23
|
+
const resolvedPath = path.resolve(localAttributesFile);
|
|
24
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
25
|
+
logger.warn(`Local attributes file "${localAttributesFile}" does not exist.`);
|
|
26
|
+
return false; // Return false if the local file doesn't exist
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const fileContents = fs.readFileSync(resolvedPath, 'utf8');
|
|
30
|
+
const fileAttributes = yaml.load(fileContents);
|
|
31
|
+
|
|
32
|
+
siteCatalog.attributeFile = _.merge({}, fileAttributes);
|
|
33
|
+
console.log(chalk.green(`Loaded global attributes from local file "${localAttributesFile}".`));
|
|
34
|
+
return true; // Return true if the local attributes were successfully loaded
|
|
35
|
+
|
|
36
|
+
} catch (error) {
|
|
37
|
+
logger.error(`Error loading local attributes from "${localAttributesFile}": ${error.message}`);
|
|
38
|
+
return false; // Return false if an error occurs
|
|
39
|
+
}
|
|
40
|
+
}
|
|
12
41
|
|
|
13
42
|
this.on('contentAggregated', ({ siteCatalog, contentAggregate }) => {
|
|
14
43
|
try {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
let attributesLoaded = false;
|
|
45
|
+
|
|
46
|
+
// Try to load attributes from the local file if provided
|
|
47
|
+
if (config.attributespath) {
|
|
48
|
+
attributesLoaded = loadLocalAttributes(siteCatalog, config.attributespath);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// If no local attributes were loaded, fallback to the 'shared' component
|
|
52
|
+
if (!attributesLoaded) {
|
|
53
|
+
let sharedComponentFound = false;
|
|
54
|
+
|
|
55
|
+
for (const component of contentAggregate) {
|
|
56
|
+
if (component.name === 'shared') {
|
|
57
|
+
sharedComponentFound = true;
|
|
58
|
+
const attributeFiles = component.files.filter(file => (file.path.startsWith(ATTRIBUTES_PATH) && (file.path.endsWith('.yml') || file.path.endsWith('.yaml'))));
|
|
59
|
+
|
|
60
|
+
if (!attributeFiles.length) {
|
|
61
|
+
logger.warn(`No YAML attributes files found in 'shared' component in ${ATTRIBUTES_PATH}.`);
|
|
62
|
+
} else {
|
|
63
|
+
siteCatalog.attributeFile = attributeFiles.reduce((acc, file) => {
|
|
64
|
+
const fileAttributes = yaml.load(file.contents.toString('utf8'));
|
|
65
|
+
return _.merge(acc, fileAttributes);
|
|
66
|
+
}, {});
|
|
67
|
+
console.log(chalk.green('Loaded global attributes from shared component.'));
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
26
70
|
}
|
|
27
|
-
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// If no 'shared' component is found, log a warning
|
|
74
|
+
if (!sharedComponentFound) {
|
|
75
|
+
logger.warn("No component named 'shared' found in the content and no valid local attributes file provided. Global attributes will not be available. You may see Asciidoc warnings about missing attributes and some behavior may not work as expected.");
|
|
28
76
|
}
|
|
29
77
|
}
|
|
78
|
+
|
|
30
79
|
} catch (error) {
|
|
31
80
|
logger.error(`Error loading attributes: ${error.message}`);
|
|
32
81
|
}
|
|
33
82
|
})
|
|
83
|
+
|
|
34
84
|
.on('contentClassified', async ({ siteCatalog, contentCatalog }) => {
|
|
35
85
|
const components = await contentCatalog.getComponents();
|
|
36
86
|
for (let i = 0; i < components.length; i++) {
|
|
@@ -39,7 +89,7 @@ module.exports.register = function ({ config }) {
|
|
|
39
89
|
if (siteCatalog.attributeFile) {
|
|
40
90
|
asciidoc.attributes = _.merge({}, siteCatalog.attributeFile, asciidoc.attributes);
|
|
41
91
|
}
|
|
42
|
-
})
|
|
92
|
+
});
|
|
43
93
|
}
|
|
44
|
-
})
|
|
45
|
-
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
@@ -4,10 +4,18 @@
|
|
|
4
4
|
* - require: ./extensions/aggregate-terms.js
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const TERMS_PATH = 'modules/terms/partials/'; // Default path within the 'shared' component
|
|
11
|
+
|
|
7
12
|
module.exports.register = function ({ config }) {
|
|
8
13
|
const logger = this.getLogger('term-aggregation-extension');
|
|
9
14
|
const chalk = require('chalk');
|
|
10
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Function to process term content, extracting hover text and links.
|
|
18
|
+
*/
|
|
11
19
|
function processTermContent(termContent) {
|
|
12
20
|
const hoverTextMatch = termContent.match(/:hover-text: (.*)/);
|
|
13
21
|
const hoverText = hoverTextMatch ? hoverTextMatch[1] : '';
|
|
@@ -27,32 +35,91 @@ module.exports.register = function ({ config }) {
|
|
|
27
35
|
return termContent;
|
|
28
36
|
}
|
|
29
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Load terms from a specified local path if provided.
|
|
40
|
+
*/
|
|
41
|
+
function loadLocalTerms(siteCatalog, termsPath) {
|
|
42
|
+
try {
|
|
43
|
+
const resolvedPath = path.resolve(termsPath);
|
|
44
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
45
|
+
logger.warn(`Local terms path "${termsPath}" does not exist.`);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const termFiles = fs.readdirSync(resolvedPath).filter(file => file.endsWith('.adoc'));
|
|
50
|
+
if (!termFiles.length) {
|
|
51
|
+
logger.warn(`No term files found in local path "${termsPath}".`);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
termFiles.forEach(file => {
|
|
56
|
+
const filePath = path.join(resolvedPath, file);
|
|
57
|
+
const termContent = fs.readFileSync(filePath, 'utf8');
|
|
58
|
+
const categoryMatch = /:category: (.*)/.exec(termContent);
|
|
59
|
+
const category = categoryMatch ? categoryMatch[1] : 'Miscellaneous';
|
|
60
|
+
|
|
61
|
+
const formattedCategory = category.charAt(0).toUpperCase() + category.slice(1);
|
|
62
|
+
|
|
63
|
+
if (!siteCatalog.termsByCategory[formattedCategory]) {
|
|
64
|
+
siteCatalog.termsByCategory[formattedCategory] = [];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
siteCatalog.termsByCategory[formattedCategory].push({ name: file, content: termContent });
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
console.log(chalk.green(`Categorized terms from local terms path "${termsPath}".`));
|
|
71
|
+
return true;
|
|
72
|
+
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logger.error(`Error loading local terms from "${termsPath}": ${error.message}`);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
30
79
|
this.on('contentAggregated', ({ siteCatalog, contentAggregate }) => {
|
|
31
80
|
try {
|
|
32
81
|
siteCatalog.termsByCategory = {};
|
|
82
|
+
let termsLoaded = false;
|
|
83
|
+
|
|
84
|
+
// Try to load terms from the local path if provided
|
|
85
|
+
if (config.termspath) {
|
|
86
|
+
termsLoaded = loadLocalTerms(siteCatalog, config.termspath);
|
|
87
|
+
}
|
|
33
88
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
89
|
+
// If no local terms were loaded, fallback to the 'shared' component
|
|
90
|
+
if (!termsLoaded) {
|
|
91
|
+
let sharedComponentFound = false;
|
|
37
92
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
93
|
+
for (const component of contentAggregate) {
|
|
94
|
+
if (component.name === 'shared') {
|
|
95
|
+
sharedComponentFound = true;
|
|
96
|
+
const termFiles = component.files.filter(file => file.path.includes(TERMS_PATH));
|
|
42
97
|
|
|
43
|
-
|
|
98
|
+
termFiles.forEach(file => {
|
|
99
|
+
const termContent = file.contents.toString('utf8');
|
|
100
|
+
const categoryMatch = /:category: (.*)/.exec(termContent);
|
|
101
|
+
const category = categoryMatch ? categoryMatch[1] : 'Miscellaneous';
|
|
44
102
|
|
|
45
|
-
|
|
46
|
-
siteCatalog.termsByCategory[category] = [];
|
|
47
|
-
}
|
|
103
|
+
const formattedCategory = category.charAt(0).toUpperCase() + category.slice(1);
|
|
48
104
|
|
|
49
|
-
|
|
50
|
-
|
|
105
|
+
if (!siteCatalog.termsByCategory[formattedCategory]) {
|
|
106
|
+
siteCatalog.termsByCategory[formattedCategory] = [];
|
|
107
|
+
}
|
|
51
108
|
|
|
52
|
-
|
|
53
|
-
|
|
109
|
+
siteCatalog.termsByCategory[formattedCategory].push({ name: file.basename, content: termContent });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
console.log(chalk.green('Categorized terms from shared component.'));
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// If no 'shared' component is found, log a warning
|
|
118
|
+
if (!sharedComponentFound) {
|
|
119
|
+
logger.warn(`No component named 'shared' found in the content and no valid local terms path provided. Terms will not be added to the glossary.`);
|
|
54
120
|
}
|
|
55
121
|
}
|
|
122
|
+
|
|
56
123
|
} catch (error) {
|
|
57
124
|
logger.error(`Error categorizing terms: ${error.message}`);
|
|
58
125
|
}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
const
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
3
4
|
const Papa = require('papaparse');
|
|
4
5
|
|
|
5
|
-
const CSV_PATH = '
|
|
6
|
+
const CSV_PATH = 'internal/plugins/info.csv'
|
|
6
7
|
const GITHUB_OWNER = 'redpanda-data'
|
|
7
|
-
const GITHUB_REPO = '
|
|
8
|
+
const GITHUB_REPO = 'connect'
|
|
8
9
|
const GITHUB_REF = 'main'
|
|
9
|
-
/* const csvUrl = 'https://localhost:3000/csv';
|
|
10
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; */
|
|
11
10
|
|
|
12
|
-
module.exports.register = function ({ config
|
|
13
|
-
|
|
11
|
+
module.exports.register = function ({ config }) {
|
|
12
|
+
const logger = this.getLogger('redpanda-connect-info-extension');
|
|
14
13
|
|
|
15
14
|
async function loadOctokit() {
|
|
16
15
|
const { Octokit } = await import('@octokit/rest');
|
|
@@ -20,21 +19,30 @@ module.exports.register = function ({ config,contentCatalog }) {
|
|
|
20
19
|
});
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
this.once('contentClassified', async ({
|
|
24
|
-
const redpandaConnect = contentCatalog.getComponents().find(component => component.name === 'redpanda-connect')
|
|
25
|
-
const redpandaCloud = contentCatalog.getComponents().find(component => component.name === 'redpanda-cloud')
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
this.once('contentClassified', async ({ contentCatalog }) => {
|
|
23
|
+
const redpandaConnect = contentCatalog.getComponents().find(component => component.name === 'redpanda-connect');
|
|
24
|
+
const redpandaCloud = contentCatalog.getComponents().find(component => component.name === 'redpanda-cloud');
|
|
25
|
+
const preview = contentCatalog.getComponents().find(component => component.name === 'preview');
|
|
26
|
+
if (!redpandaConnect) return;
|
|
27
|
+
const pages = contentCatalog.getPages();
|
|
28
|
+
|
|
28
29
|
try {
|
|
29
|
-
// Fetch CSV data
|
|
30
|
-
const csvData = await fetchCSV();
|
|
30
|
+
// Fetch CSV data (either from local file or GitHub)
|
|
31
|
+
const csvData = await fetchCSV(config.csvpath);
|
|
31
32
|
const parsedData = Papa.parse(csvData, { header: true, skipEmptyLines: true });
|
|
32
|
-
const enrichedData =
|
|
33
|
-
parsedData.data = enrichedData
|
|
34
|
-
|
|
33
|
+
const enrichedData = translateCsvData(parsedData, pages, logger);
|
|
34
|
+
parsedData.data = enrichedData;
|
|
35
|
+
|
|
36
|
+
if (redpandaConnect) {
|
|
35
37
|
redpandaConnect.latest.asciidoc.attributes.csvData = parsedData;
|
|
36
|
-
|
|
38
|
+
}
|
|
39
|
+
if (redpandaCloud) {
|
|
37
40
|
redpandaCloud.latest.asciidoc.attributes.csvData = parsedData;
|
|
41
|
+
}
|
|
42
|
+
// For previewing the data on our extensions site
|
|
43
|
+
if (preview) {
|
|
44
|
+
preview.latest.asciidoc.attributes.csvData = parsedData;
|
|
45
|
+
}
|
|
38
46
|
|
|
39
47
|
} catch (error) {
|
|
40
48
|
logger.error('Error fetching or parsing CSV data:', error.message);
|
|
@@ -42,7 +50,22 @@ module.exports.register = function ({ config,contentCatalog }) {
|
|
|
42
50
|
}
|
|
43
51
|
});
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
// Check for local CSV file first. If not found, fetch from GitHub
|
|
54
|
+
async function fetchCSV(localCsvPath) {
|
|
55
|
+
if (localCsvPath && fs.existsSync(localCsvPath)) {
|
|
56
|
+
if (path.extname(localCsvPath).toLowerCase() !== '.csv') {
|
|
57
|
+
throw new Error(`Invalid file type: ${localCsvPath}. Expected a CSV file.`);
|
|
58
|
+
}
|
|
59
|
+
logger.info(`Loading CSV data from local file: ${localCsvPath}`);
|
|
60
|
+
return fs.readFileSync(localCsvPath, 'utf8');
|
|
61
|
+
} else {
|
|
62
|
+
logger.info('Local CSV file not found. Fetching from GitHub...');
|
|
63
|
+
return await fetchCsvFromGitHub();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Fetch CSV data from GitHub
|
|
68
|
+
async function fetchCsvFromGitHub() {
|
|
46
69
|
const octokit = await loadOctokit();
|
|
47
70
|
try {
|
|
48
71
|
const { data: fileContent } = await octokit.rest.repos.getContent({
|
|
@@ -54,33 +77,87 @@ module.exports.register = function ({ config,contentCatalog }) {
|
|
|
54
77
|
return Buffer.from(fileContent.content, 'base64').toString('utf8');
|
|
55
78
|
} catch (error) {
|
|
56
79
|
console.error('Error fetching Redpanda Connect catalog from GitHub:', error);
|
|
57
|
-
return
|
|
80
|
+
return '';
|
|
58
81
|
}
|
|
59
82
|
}
|
|
60
83
|
|
|
61
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Translates the parsed CSV data into our expected format.
|
|
86
|
+
* If "enterprise" is found in the `support` column, it is replaced with "certified" in the output.
|
|
87
|
+
*
|
|
88
|
+
* @param {object} parsedData - The CSV data parsed into an object.
|
|
89
|
+
* @param {array} pages - The list of pages to map the URLs (used for enrichment with URLs).
|
|
90
|
+
* @param {object} logger - The logger used for error handling.
|
|
91
|
+
*
|
|
92
|
+
* @returns {array} - The translated and enriched data.
|
|
93
|
+
*/
|
|
94
|
+
function translateCsvData(parsedData, pages, logger) {
|
|
62
95
|
return parsedData.data.map(row => {
|
|
63
96
|
// Create a new object with trimmed keys and values
|
|
64
97
|
const trimmedRow = Object.fromEntries(
|
|
65
98
|
Object.entries(row).map(([key, value]) => [key.trim(), value.trim()])
|
|
66
99
|
);
|
|
67
|
-
|
|
100
|
+
|
|
101
|
+
// Map fields from the trimmed row to the desired output
|
|
102
|
+
const connector = trimmedRow.name;
|
|
68
103
|
const type = trimmedRow.type;
|
|
69
|
-
|
|
70
|
-
|
|
104
|
+
const commercial_name = trimmedRow.commercial_name;
|
|
105
|
+
const available_connect_version = trimmedRow.version;
|
|
106
|
+
const deprecated = trimmedRow.deprecated.toLowerCase() === 'y' ? 'y' : 'n';
|
|
107
|
+
const is_cloud_supported = trimmedRow.cloud.toLowerCase() === 'y' ? 'y' : 'n';
|
|
108
|
+
const cloud_ai = trimmedRow.cloud_with_gpu.toLowerCase() === 'y' ? 'y' : 'n';
|
|
109
|
+
// Handle enterprise to certified conversion and set enterprise license flag
|
|
110
|
+
const originalSupport = trimmedRow.support.toLowerCase();
|
|
111
|
+
const support_level = originalSupport === 'enterprise' ? 'certified' : originalSupport;
|
|
112
|
+
const is_licensed = originalSupport === 'enterprise' ? 'Yes' : 'No';
|
|
113
|
+
|
|
114
|
+
// Redpanda Connect and Cloud enrichment URLs
|
|
115
|
+
let redpandaConnectUrl = '';
|
|
116
|
+
let redpandaCloudUrl = '';
|
|
117
|
+
|
|
118
|
+
// Look for both Redpanda Connect and Cloud URLs
|
|
119
|
+
for (const file of pages) {
|
|
120
|
+
const component = file.src.component;
|
|
71
121
|
const filePath = file.path;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
122
|
+
|
|
123
|
+
if (
|
|
124
|
+
component === 'redpanda-connect' &&
|
|
125
|
+
filePath.endsWith(`/${connector}.adoc`) &&
|
|
126
|
+
filePath.includes(`pages/${type}s/`)
|
|
127
|
+
) {
|
|
128
|
+
redpandaConnectUrl = file.pub.url;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Only check for Redpanda Cloud URLs if cloud is supported
|
|
132
|
+
if (
|
|
133
|
+
is_cloud_supported === 'y' &&
|
|
134
|
+
component === 'redpanda-cloud' &&
|
|
135
|
+
filePath.endsWith(`/${connector}.adoc`) &&
|
|
136
|
+
filePath.includes(`${type}s/`)
|
|
137
|
+
) {
|
|
138
|
+
redpandaCloudUrl = file.pub.url;
|
|
75
139
|
}
|
|
76
140
|
}
|
|
77
|
-
|
|
78
|
-
|
|
141
|
+
|
|
142
|
+
// Log a warning if neither URL was found (only warn for missing cloud if it should support cloud)
|
|
143
|
+
if (!redpandaConnectUrl && (!redpandaCloudUrl && is_cloud_supported === 'y')) {
|
|
144
|
+
logger.info(`Docs missing for: ${connector} of type: ${type}`);
|
|
79
145
|
}
|
|
146
|
+
|
|
147
|
+
// Return the translated and enriched row
|
|
80
148
|
return {
|
|
81
|
-
|
|
82
|
-
|
|
149
|
+
connector,
|
|
150
|
+
type,
|
|
151
|
+
commercial_name,
|
|
152
|
+
available_connect_version,
|
|
153
|
+
support_level, // "enterprise" is replaced with "certified"
|
|
154
|
+
deprecated,
|
|
155
|
+
is_cloud_supported,
|
|
156
|
+
cloud_ai,
|
|
157
|
+
is_licensed, // "Yes" if the original support level was "enterprise"
|
|
158
|
+
redpandaConnectUrl,
|
|
159
|
+
redpandaCloudUrl,
|
|
83
160
|
};
|
|
84
161
|
});
|
|
85
162
|
}
|
|
86
|
-
}
|
|
163
|
+
}
|
|
@@ -11,7 +11,9 @@ module.exports.register = function ({ config }) {
|
|
|
11
11
|
|
|
12
12
|
this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
|
|
13
13
|
// Retrieve valid categories and subcategories from site attributes defined in add-global-attributes.js.
|
|
14
|
+
if (!siteCatalog.attributeFile) return logger.warn('No global attributes file available - skipping attribute validation. Check global-attributes-extension for errors')
|
|
14
15
|
const validCategories = siteCatalog.attributeFile['page-valid-categories'];
|
|
16
|
+
if (!validCategories) return logger.warn('No page-valid-categories attribute found - skipping attribute validation')
|
|
15
17
|
const categoryMap = createCategoryMap(validCategories);
|
|
16
18
|
const pages = contentCatalog.findBy({ family: 'page' });
|
|
17
19
|
pages.forEach((page) => {
|