@redpanda-data/docs-extensions-and-macros 3.1.4 → 3.2.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/README.adoc CHANGED
@@ -79,9 +79,11 @@ antora:
79
79
 
80
80
  === Version fetcher
81
81
 
82
- This extension fetches the latest release tag and latest release commit hash from http://github.com/redpanda-data/redpanda. These values are then assigned to the `full-version` and `latest-release-commit` attributes of the latest version of the Redpanda documentation, respectively.
82
+ This extension fetches the latest release versions from GitHub.
83
83
 
84
- It also fetches the latest version of Redpanda Console and assigns it to the `latest-console-version` attribute in the playbook so that all components have access to it.
84
+ The latest Console version is made available to all versions of the Redpanda docs (`ROOT` component.)
85
+
86
+ The latest Redpanda version and the latest Redpanda Operator version is made available to the latest version of the `ROOT` component.
85
87
 
86
88
  ==== Environment variables
87
89
 
@@ -97,6 +99,75 @@ antora:
97
99
  - '@redpanda-data/docs-extensions-and-macros/extensions/version-fetcher/set-latest-version'
98
100
  ```
99
101
 
102
+ === Validate attributes
103
+
104
+ This extension ensures the consistency and validity of page attributes, focusing on validating page categories against a predefined list of valid categories and subcategories. It automatically adds missing parent categories for any specified subcategories and removes any specified categories that are invalid. Additionally, it processes specific environment attributes, setting corresponding page-level attributes when environment conditions are met.
105
+
106
+ ==== Environment variables
107
+
108
+ This extension does not require any environment variables.
109
+
110
+ ==== Configuration options
111
+
112
+ There are no configurable options for this extension. It operates based on site attributes defined in `add-global-attributes.js` to determine valid categories and subcategories.
113
+
114
+ ==== Registration example
115
+
116
+ Register the `validate-attributes` extension in the Antora playbook under the `antora.extensions` key like so:
117
+
118
+ [source,yaml]
119
+ ----
120
+ antora:
121
+ extensions:
122
+ - require: '@redpanda-data/docs-extensions-and-macros/extensions/validate-attributes.js'
123
+ ----
124
+
125
+ === Related docs
126
+
127
+ This extension enhances the connectivity between lab exercises and relevant documentation by dynamically identifying and linking related documentation pages and other lab exercises based on shared categories and deployment types.
128
+
129
+ ==== Environment variables
130
+
131
+ This extension operates without requiring any specific environment variables.
132
+
133
+ ==== Configuration options
134
+
135
+ This extension does not offer configurable options. It uses the inherent attributes of pages to determine relationships based on `page-categories` and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).
136
+
137
+ ==== Registration example
138
+
139
+ To integrate the `related-docs-extension` into your Antora playbook, add it under the `antora.extensions` key as demonstrated below:
140
+
141
+ [source,yaml]
142
+ ----
143
+ antora:
144
+ extensions:
145
+ - require: '@redpanda-data/docs-extensions-and-macros/extensions/related-docs-extension.js'
146
+ ----
147
+
148
+ === Related labs
149
+
150
+ This extension enriches documentation pages with links to related lab exercises, facilitating a deeper understanding of the content through practical application. It dynamically assigns related labs to each documentation page based on shared categories and deployment types.
151
+
152
+ ==== Environment variables
153
+
154
+ This extension does not require any environment variables.
155
+
156
+ ==== Configuration options
157
+
158
+ The extension operates without explicit configuration options. It automatically processes documentation pages to identify and link related labs based on shared `page-categories` attributes and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).
159
+
160
+ ==== Registration example
161
+
162
+ Include the `related-labs-extension` in the Antora playbook under the `antora.extensions` key as follows:
163
+
164
+ [source,yaml]
165
+ ----
166
+ antora:
167
+ extensions:
168
+ - require: '@redpanda-data/docs-extensions-and-macros/extensions/related-labs-extension.js'
169
+ ----
170
+
100
171
  === Global attributes
101
172
 
102
173
  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.
@@ -11,31 +11,31 @@ module.exports.register = function ({ config }) {
11
11
  const _ = require('lodash');
12
12
 
13
13
  this.on('contentAggregated', ({ siteCatalog, contentAggregate }) => {
14
- let attributeFile;
15
14
  try {
16
15
  for (const component of contentAggregate) {
17
16
  if (component.name === 'shared') {
18
- attributeFile = component.files.find(file => file.path.includes('attributes.yml'));
19
- if (!attributeFile) {
20
- logger.warn("No attributes.yml file found in 'shared' component.");
17
+ const attributeFiles = component.files.filter(file => file.path.startsWith('modules/ROOT/partials/') && file.path.endsWith('.yml'));
18
+ if (!attributeFiles.length) {
19
+ logger.warn("No YAML attributes files found in 'shared' component.");
21
20
  } else {
22
- siteCatalog.attributeFile = yaml.load(attributeFile.contents.toString('utf8'));
23
- console.log(chalk.green('Loaded attributes from shared component.'));
21
+ siteCatalog.attributeFile = attributeFiles.reduce((acc, file) => {
22
+ const fileAttributes = yaml.load(file.contents.toString('utf8'));
23
+ return _.merge(acc, fileAttributes);
24
+ }, {});
25
+ console.log(chalk.green('Loaded global attributes from shared component.'));
24
26
  }
25
- break
27
+ break;
26
28
  }
27
29
  }
28
30
  } catch (error) {
29
31
  logger.error(`Error loading attributes: ${error.message}`);
30
32
  }
31
33
  })
32
- .on('contentClassified', async ({ siteCatalog,contentCatalog }) => {
34
+ .on('contentClassified', async ({ siteCatalog, contentCatalog }) => {
33
35
  const components = await contentCatalog.getComponents();
34
36
  for (let i = 0; i < components.length; i++) {
35
37
  let component = components[i];
36
- if (component.name !== 'ROOT' && component.name !== 'preview') continue
37
-
38
- component.versions.forEach(({asciidoc}) => {
38
+ component.versions.forEach(({ asciidoc }) => {
39
39
  if (siteCatalog.attributeFile) {
40
40
  asciidoc.attributes = _.merge({}, siteCatalog.attributeFile, asciidoc.attributes);
41
41
  }
@@ -27,7 +27,6 @@ function generateIndex (playbook, contentCatalog, { indexLatestOnly = false, exc
27
27
  const algolia = {}
28
28
 
29
29
  console.log(chalk.cyan('Indexing...'))
30
-
31
30
  const unixTimestamp = Math.floor(Date.now() / 1000)
32
31
 
33
32
  // Select indexable pages
@@ -176,27 +175,39 @@ function generateIndex (playbook, contentCatalog, { indexLatestOnly = false, exc
176
175
  .replace(/\s+/g, ' ')
177
176
  .trim();
178
177
 
179
- var tag = `${component.title}-${version}`
178
+ var tag = `${component.title}${version ? '-' + version : ''}`
179
+ var indexItem;
180
+ const deployment = page.asciidoc?.attributes['env-kubernetes'] ? 'Kubernetes' : page.asciidoc?.attributes['env-linux'] ? 'Linux' : page.asciidoc?.attributes['env-docker'] ? 'Docker' : page.asciidoc?.attributes['page-cloud'] ? 'Redpanda Cloud' : ''
181
+
182
+ const categories = page.asciidoc?.attributes['page-categories']
183
+ ? page.asciidoc.attributes['page-categories'].split(',').map(category => category.trim())
184
+ : []
180
185
 
181
- const indexItem = {
186
+ var indexItem = {
182
187
  title: documentTitle,
183
- product: component.title,
184
188
  version: version,
185
189
  text: text,
186
- breadcrumbs: breadcrumbs,
187
190
  intro: intro,
188
191
  objectID: urlPath + page.pub.url,
189
192
  titles: titles,
190
- keywords: keywords,
193
+ categories: categories,
191
194
  unixTimestamp: unixTimestamp,
192
- type: 'Doc',
193
- _tags: [tag, 'docs']
194
195
  }
195
196
 
197
+ if (component.name !== 'redpanda-labs') {
198
+ indexItem.product = component.title;
199
+ indexItem.breadcrumbs = breadcrumbs;
200
+ indexItem.type = 'Doc';
201
+ indexItem._tags = [tag, 'docs'];
202
+ } else {
203
+ indexItem.deployment = deployment;
204
+ indexItem.type = 'Lab';
205
+ indexItem.interactive = false;
206
+ indexItem._tags = ['labs'];
207
+ }
196
208
  algolia[cname][version].push(indexItem)
197
209
  algoliaCount++
198
210
  }
199
-
200
211
  return algolia
201
212
  }
202
213
 
@@ -114,7 +114,7 @@ function register({
114
114
  }
115
115
 
116
116
  for (const [objectID, obj] of existingObjectsMap) {
117
- if (obj.type === 'Doc' && !obj._tags.includes('apis') || !obj.type) {
117
+ if ((obj.type === 'Doc' && !obj._tags.includes('apis')) || (!obj.type) || (obj.type === 'Lab' && !obj.interactive)) {
118
118
  objectsToDelete.push(objectID)
119
119
  }
120
120
  }
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ module.exports.register = function ({ config }) {
4
+ const logger = this.getLogger('related-docs-extension');
5
+
6
+ this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
7
+ const labs = contentCatalog.findBy({ component: 'redpanda-labs', family: 'page' });
8
+ labs.forEach((labPage) => {
9
+ const relatedDocs = []
10
+ const relatedLabs = []
11
+ const sourceAttributes = labPage.asciidoc.attributes
12
+ const pageCategories = sourceAttributes['page-categories'];
13
+ if (!pageCategories) return;
14
+ const sourceCategoryList = pageCategories.split(',').map(c => c.trim());
15
+ const sourceDeploymentType = getDeploymentType(sourceAttributes)
16
+ const docs = contentCatalog.findBy({ component: 'ROOT', family: 'page' });
17
+ docs.forEach((docPage) => {
18
+ const related = findRelated(docPage, sourceCategoryList, sourceDeploymentType, logger)
19
+ related && relatedDocs.push(related)
20
+ })
21
+ labs.forEach((targetLabPage) => {
22
+ if (targetLabPage === labPage) return;
23
+
24
+ const related = findRelated(targetLabPage, sourceCategoryList, sourceDeploymentType, logger);
25
+ if (related) relatedLabs.push(related);
26
+ });
27
+
28
+ // Store related docs and labs in the lab page attributes
29
+ if (relatedDocs.length > 0) {
30
+ labPage.asciidoc.attributes['page-related-docs'] = JSON.stringify(relatedDocs);
31
+ }
32
+
33
+ if (relatedLabs.length > 0) {
34
+ labPage.asciidoc.attributes['page-related-labs'] = JSON.stringify(relatedLabs);
35
+ }
36
+
37
+ if (relatedDocs.length > 0 || relatedLabs.length > 0) {
38
+ logger.info(`Set related docs and labs attributes for ${labPage.asciidoc.doctitle}`);
39
+ }
40
+ })
41
+ })
42
+ }
43
+
44
+ function findRelated(docPage, sourceCategoryList, sourceDeploymentType, logger) {
45
+ const targetAttributes = docPage.asciidoc.attributes
46
+ const pageCategories = targetAttributes['page-categories'];
47
+ if (!pageCategories) return null;
48
+ const targetCategoryList = pageCategories.split(',').map(c => c.trim());
49
+ const targetDeploymentType = getDeploymentType(targetAttributes)
50
+ const categoryMatch = hasMatchingCategory(sourceCategoryList, targetCategoryList)
51
+ if (categoryMatch && (!targetDeploymentType ||sourceDeploymentType === targetDeploymentType)) {
52
+ return {
53
+ title: docPage.asciidoc.doctitle,
54
+ url: docPage.pub.url,
55
+ }
56
+ }
57
+ return null
58
+ }
59
+
60
+ function getDeploymentType (attributes) {
61
+ return attributes['env-kubernetes'] ? 'Kubernetes'
62
+ : attributes['env-linux'] ? 'Linux'
63
+ : attributes['env-docker'] ? 'Docker'
64
+ : attributes.cloud ? 'Redpanda Cloud'
65
+ : ''
66
+ }
67
+
68
+ function hasMatchingCategory (sourcePageCategories, targetPageCategories) {
69
+ return sourcePageCategories.every((category) => targetPageCategories.includes(category))
70
+ }
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ module.exports.register = function ({ config }) {
4
+ const logger = this.getLogger('related-labs-extension');
5
+
6
+ this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
7
+ const docs = contentCatalog.findBy({ component: 'ROOT', family: 'page' });
8
+ docs.forEach((docPage) => {
9
+ const relatedLabs = []
10
+ const sourceAttributes = docPage.asciidoc.attributes
11
+ const pageCategories = sourceAttributes['page-categories'];
12
+ if (!pageCategories) return;
13
+ const sourceCategoryList = pageCategories.split(',').map(c => c.trim());
14
+ const sourceDeploymentType = getDeploymentType(sourceAttributes)
15
+ const labs = contentCatalog.findBy({ component: 'redpanda-labs', family: 'page' });
16
+ labs.forEach((labPage) => {
17
+ const related = findRelated(labPage, sourceCategoryList, sourceDeploymentType, logger)
18
+ related && relatedLabs.push(related)
19
+ })
20
+ if (!relatedLabs.length) return
21
+ docPage.asciidoc.attributes['page-related-labs'] = JSON.stringify(relatedLabs)
22
+ logger.info(`Set page-related-labs attribute for ${docPage.asciidoc.doctitle} to ${docPage.asciidoc.attributes['page-related-labs']}`)
23
+ })
24
+ })
25
+ }
26
+
27
+ function findRelated(labPage, sourceCategoryList, sourceDeploymentType, logger) {
28
+ const targetAttributes = labPage.asciidoc.attributes
29
+ const pageCategories = targetAttributes['page-categories'];
30
+ if (!pageCategories) return null;
31
+ const targetCategoryList = pageCategories.split(',').map(c => c.trim());
32
+ const targetDeploymentType = getDeploymentType(targetAttributes)
33
+ const categoryMatch = hasMatchingCategory(sourceCategoryList, targetCategoryList)
34
+ if (categoryMatch && (!targetDeploymentType ||sourceDeploymentType === targetDeploymentType || targetDeploymentType === 'Docker')) {
35
+ return {
36
+ title: labPage.asciidoc.doctitle,
37
+ url: labPage.pub.url,
38
+ }
39
+ }
40
+ return null
41
+ }
42
+
43
+ function getDeploymentType (attributes) {
44
+ return attributes['env-kubernetes'] ? 'Kubernetes'
45
+ : attributes['env-linux'] ? 'Linux'
46
+ : attributes['env-docker'] ? 'Docker'
47
+ : attributes.cloud ? 'Redpanda Cloud' : ''
48
+ }
49
+
50
+ function hasMatchingCategory (sourcePageCategories, targetPageCategories) {
51
+ return sourcePageCategories.every((category) => targetPageCategories.includes(category))
52
+ }
@@ -4,19 +4,34 @@ module.exports.register = function ({ config }) {
4
4
 
5
5
  const sanitizeAttributeValue = (value) => String(value).replace("@", "");
6
6
 
7
- this.on('documentsConverted', ({contentCatalog}) => {
7
+ this.on('contentClassified', ({contentCatalog}) => {
8
8
  for (const { versions } of contentCatalog.getComponents()) {
9
9
  for (const { name: component, version, asciidoc } of versions) {
10
10
  const attachments = contentCatalog.findBy({ component, version, family });
11
- if (component == 'api') continue
11
+ if (component == 'api') continue;
12
12
  for (const attachment of attachments) {
13
13
  let contentString = attachment['_contents'].toString('utf8');
14
- if (!asciidoc.attributes) continue
14
+ if (!asciidoc.attributes) continue;
15
+
16
+ // Replace general attributes
15
17
  for (const key in asciidoc.attributes) {
16
18
  const placeholder = "{" + key + "}";
17
19
  const sanitizedValue = sanitizeAttributeValue(asciidoc.attributes[key]);
18
20
  contentString = contentString.replace(new RegExp(placeholder, 'g'), sanitizedValue);
19
21
  }
22
+
23
+
24
+ // Specific replacements for YAML files
25
+ if (attachment.out.path.endsWith('.yaml') || attachment.out.path.endsWith('.yml')) {
26
+ const redpandaVersionRegex = /(\$\{REDPANDA_VERSION[^\}]*\})/g;
27
+ const redpandaConsoleVersionRegex = /(\$\{REDPANDA_CONSOLE_VERSION[^\}]*\})/g;
28
+ const fullVersion = asciidoc.attributes['full-version'] ? sanitizeAttributeValue(asciidoc.attributes['full-version']) : '';
29
+ const latestConsoleVersion = asciidoc.attributes['latest-console-version'] ? sanitizeAttributeValue(asciidoc.attributes['latest-console-version']) : '';
30
+
31
+ contentString = contentString.replace(redpandaVersionRegex, fullVersion);
32
+ contentString = contentString.replace(redpandaConsoleVersionRegex, latestConsoleVersion);
33
+ }
34
+
20
35
  attachment['_contents'] = Buffer.from(contentString, "utf-8");
21
36
  }
22
37
  }
@@ -6,6 +6,7 @@ module.exports.register = function ({ config }) {
6
6
  contentCatalog.getComponents().forEach(({ versions }) => {
7
7
  versions.forEach(({ name: component, version, navigation: nav, url: defaultUrl }) => {
8
8
  if (component === 'api') return;
9
+ if (!nav) return
9
10
  const navEntriesByUrl = getNavEntriesByUrl(nav)
10
11
  const unlistedPages = contentCatalog
11
12
  .findBy({ component, version, family: 'page' })
@@ -0,0 +1,88 @@
1
+ /* Example use in the playbook
2
+ * antora:
3
+ extensions:
4
+ * - require: ./extensions/validate-attributes.js
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ module.exports.register = function ({ config }) {
10
+ const logger = this.getLogger('attribute-validation-extension');
11
+
12
+ this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
13
+ // Retrieve valid categories and subcategories from site attributes defined in add-global-attributes.js.
14
+ const validCategories = siteCatalog.attributeFile['page-valid-categories'];
15
+ const categoryMap = createCategoryMap(validCategories);
16
+ const pages = contentCatalog.findBy({ family: 'page' });
17
+ pages.forEach((page) => {
18
+ let pageCategories = page.asciidoc.attributes['page-categories'];
19
+ if (!pageCategories) return;
20
+ let pageCategoryList = pageCategories.split(',').map(c => c.trim());
21
+ const validatedCategories = validateCategories(pageCategoryList, page.asciidoc.attributes['page-relative-src-path'], categoryMap, logger);
22
+ page.asciidoc.attributes['page-categories'] = validatedCategories
23
+ processEnvironmentAttributes(page, logger);
24
+ })
25
+ })
26
+ }
27
+
28
+ function processEnvironmentAttributes(page, logger) {
29
+ const envAttributes = ['env-kubernetes', 'env-linux', 'env-docker'];
30
+ envAttributes.forEach(envAttr => {
31
+ if (page.asciidoc.attributes[envAttr]) {
32
+ // If the env attribute exists, set a corresponding page- attribute for use in the UI
33
+ const pageEnvAttr = `page-${envAttr}`;
34
+ page.asciidoc.attributes[pageEnvAttr] = true;
35
+ logger.info(`Set '${pageEnvAttr}' for ${page.asciidoc.attributes['page-relative-src-path']}`);
36
+ }
37
+ });
38
+ }
39
+
40
+ function validateCategories(pageCategoryList, pageInfo, categoryMap, logger) {
41
+ let isValid = true;
42
+ let adjustedCategories = new Set(pageCategoryList);
43
+
44
+ pageCategoryList.forEach(category => {
45
+ // Check if the current category is a subcategory
46
+ if (categoryMap.subcategories.has(category)) {
47
+ // Retrieve the parent category for the current subcategory
48
+ const parentCategory = categoryMap.parentMap.get(category);
49
+
50
+ // Check if the parent category is not already in the pageCategoryList
51
+ if (!adjustedCategories.has(parentCategory)) {
52
+ // Add the parent category since it's missing
53
+ adjustedCategories.add(parentCategory);
54
+ logger.info(`Added missing parent category '${parentCategory}' for subcategory '${category}' in ${pageInfo}`);
55
+ }
56
+ }
57
+ // Check if the current category is not a valid category or subcategory
58
+ else if (!categoryMap.categories.has(category)) {
59
+ logger.warn(`Invalid category '${category}' in ${pageInfo}`);
60
+ adjustedCategories.delete(category)
61
+ isValid = false;
62
+ }
63
+ });
64
+
65
+ if (!isValid) {
66
+ logger.warn(`Invalid categories detected. For a list of valid categories, see https://github.com/redpanda-data/docs/tree/shared/modules/ROOT/partials/valid-categories.yml`);
67
+ }
68
+ return Array.from(adjustedCategories).join(', ');
69
+ }
70
+
71
+ function createCategoryMap(validCategories) {
72
+ const categoryMap = {
73
+ categories: new Set(),
74
+ subcategories: new Set(),
75
+ parentMap: new Map()
76
+ };
77
+
78
+ validCategories.forEach(categoryInfo => {
79
+ categoryMap.categories.add(categoryInfo.category);
80
+ if (categoryInfo.subcategories) {
81
+ categoryInfo.subcategories.forEach(subcat => {
82
+ categoryMap.subcategories.add(subcat.category);
83
+ categoryMap.parentMap.set(subcat.category, categoryInfo.category);
84
+ });
85
+ }
86
+ });
87
+ return categoryMap
88
+ }
@@ -19,15 +19,12 @@ const github = new OctokitWithRetries(githubOptions);
19
19
  var latestConsoleReleaseVersion;
20
20
 
21
21
  module.exports = async () => {
22
- await github.rest.repos.getLatestRelease({
23
- owner,
24
- repo,
25
- }).then((release => {
26
- const tag = release.data.tag_name;
27
- latestConsoleReleaseVersion = tag.replace('v','');
28
- })).catch((error => {
29
- console.error(error)
30
- return null
31
- }))
32
- return latestConsoleReleaseVersion;
22
+ try {
23
+ const release = await github.rest.repos.getLatestRelease({ owner, repo });
24
+ latestConsoleReleaseVersion = release.data.tag_name.replace('v','');
25
+ return latestConsoleReleaseVersion;
26
+ } catch (error) {
27
+ console.error(error);
28
+ return null;
29
+ }
33
30
  };
@@ -0,0 +1,28 @@
1
+ // Fetch the latest release version from GitHub
2
+ const { Octokit } = require("@octokit/rest");
3
+ const { retry } = require("@octokit/plugin-retry");
4
+ const OctokitWithRetries = Octokit.plugin(retry);
5
+ const owner = 'redpanda-data';
6
+ const repo = 'redpanda-operator';
7
+
8
+ let githubOptions = {
9
+ userAgent: 'Redpanda Docs',
10
+ baseUrl: 'https://api.github.com',
11
+ };
12
+
13
+ if (process.env.REDPANDA_GITHUB_TOKEN) {
14
+ githubOptions.auth = process.env.REDPANDA_GITHUB_TOKEN;
15
+ }
16
+
17
+ const github = new OctokitWithRetries(githubOptions);
18
+
19
+ module.exports = async () => {
20
+ try {
21
+ const release = await github.rest.repos.getLatestRelease({ owner, repo });
22
+ latestOperatorReleaseVersion = release.data.tag_name;
23
+ return latestOperatorReleaseVersion;
24
+ } catch (error) {
25
+ console.error(error);
26
+ return null;
27
+ }
28
+ };
@@ -0,0 +1,39 @@
1
+ // Fetch the latest release version from GitHub
2
+ const { Octokit } = require("@octokit/rest");
3
+ const { retry } = require("@octokit/plugin-retry");
4
+ const OctokitWithRetries = Octokit.plugin(retry);
5
+ const owner = 'redpanda-data';
6
+ const repo = 'redpanda';
7
+
8
+ let githubOptions = {
9
+ userAgent: 'Redpanda Docs',
10
+ baseUrl: 'https://api.github.com',
11
+ };
12
+
13
+ if (process.env.REDPANDA_GITHUB_TOKEN) {
14
+ githubOptions.auth = process.env.REDPANDA_GITHUB_TOKEN;
15
+ }
16
+
17
+ const github = new OctokitWithRetries(githubOptions);
18
+
19
+ module.exports = async () => {
20
+ try {
21
+ // Fetch the latest release
22
+ const release = await github.rest.repos.getLatestRelease({ owner, repo });
23
+ const tag = release.data.tag_name;
24
+ latestRedpandaReleaseVersion = tag.replace('v', '');
25
+
26
+ // Get reference of the tag
27
+ const tagRef = await github.rest.git.getRef({ owner, repo, ref: `tags/${tag}` });
28
+ const releaseSha = tagRef.data.object.sha;
29
+
30
+ // Get the tag object to extract the commit hash
31
+ const tagData = await github.rest.git.getTag({ owner, repo, tag_sha: releaseSha });
32
+ latestRedpandaReleaseCommitHash = tagData.data.object.sha.substring(0, 7);
33
+
34
+ return [latestRedpandaReleaseVersion, latestRedpandaReleaseCommitHash];
35
+ } catch (error) {
36
+ console.error(error);
37
+ return [null, null];
38
+ }
39
+ };
@@ -4,8 +4,9 @@ antora:
4
4
  - require: ./extensions/setLatestVersion.js
5
5
  */
6
6
 
7
- const GetLatestRedpandaVersion = require('./getLatestRedpandaVersion');
8
- const GetLatestConsoleVersion = require('./getLatestConsoleVersion');
7
+ const GetLatestRedpandaVersion = require('./get-latest-redpanda-version');
8
+ const GetLatestConsoleVersion = require('./get-latest-console-version');
9
+ const GetLatestOperatorVersion = require('./get-latest-operator-version');
9
10
  const chalk = require('chalk')
10
11
 
11
12
 
@@ -15,25 +16,28 @@ module.exports.register = function ({ config }) {
15
16
  logger.warn('REDPANDA_GITHUB_TOKEN environment variable not set. Attempting unauthenticated request.');
16
17
  }
17
18
  this
18
- .on('contentClassified', async ({ siteCatalog,contentCatalog }) => {
19
+ .on('contentClassified', async ({ contentCatalog }) => {
19
20
  try {
20
21
  const LatestRedpandaVersion = await GetLatestRedpandaVersion();
21
22
  const LatestConsoleVersion = await GetLatestConsoleVersion();
23
+ const LatestOperatorVersion = await GetLatestOperatorVersion();
22
24
  if (LatestRedpandaVersion.length !== 2 || !LatestRedpandaVersion[0]) {
23
25
  logger.warn('Failed to get the latest Redpanda version - using defaults');
24
26
  }
25
27
  if (!LatestConsoleVersion) {
26
28
  logger.warn(`Failed to get latest Console version from GitHub - using default`)
27
29
  }
30
+ if (!LatestOperatorVersion) {
31
+ logger.warn(`Failed to get latest Operator version from GitHub - using default`)
32
+ }
28
33
  const components = await contentCatalog.getComponents();
29
34
  for (let i = 0; i < components.length; i++) {
30
35
  let component = components[i];
31
- if (component.name !== 'ROOT' && component.name !== 'preview') continue
32
36
 
33
37
  component.versions.forEach(({name, version, asciidoc}) => {
34
38
  if (LatestConsoleVersion) {
35
39
  asciidoc.attributes['latest-console-version'] = `${LatestConsoleVersion}`;
36
- console.log(`${chalk.green('Set Redpanda Console version to')} ${chalk.bold(LatestConsoleVersion)} in ${name} ${version}`);
40
+ logger.info(`Set Redpanda Console version to')} ${LatestConsoleVersion} in ${name} ${version}`);
37
41
  }
38
42
  })
39
43
 
@@ -49,8 +53,16 @@ module.exports.register = function ({ config }) {
49
53
 
50
54
  component.latest.asciidoc.attributes['full-version'] = `${LatestRedpandaVersion[0]}`;
51
55
  component.latest.asciidoc.attributes['latest-release-commit'] = `${LatestRedpandaVersion[1]}`;
52
- console.log(`${chalk.green('Set the latest Redpanda version to')} ${chalk.bold(LatestRedpandaVersion[0])} ${chalk.bold(LatestRedpandaVersion[1])}`)
56
+ logger.info(`Set the latest Redpanda version to ${LatestRedpandaVersion[0]} ${LatestRedpandaVersion[1]}`)
57
+
58
+ if (!LatestOperatorVersion) continue;
59
+
60
+ component.latest.asciidoc.attributes['latest-operator-version'] = `${LatestOperatorVersion}`;
61
+ logger.info(`Set the latest Redpanda Operator version to ${LatestOperatorVersion}`)
53
62
  }
63
+ console.log(`${chalk.green('Set Redpanda Console version to')} ${chalk.bold(LatestConsoleVersion)}`);
64
+ console.log(`${chalk.green('Set the latest Redpanda version to')} ${chalk.bold(LatestRedpandaVersion[0])} ${chalk.bold(LatestRedpandaVersion[1])}`)
65
+ console.log(`${chalk.green('Set the latest Redpanda Operator version to')} ${chalk.bold(LatestOperatorVersion)}`)
54
66
  } catch(error) {
55
67
  logger.warn(error)
56
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redpanda-data/docs-extensions-and-macros",
3
- "version": "3.1.4",
3
+ "version": "3.2.0",
4
4
  "description": "Antora extensions and macros developed for Redpanda documentation.",
5
5
  "keywords": [
6
6
  "antora",
@@ -1,46 +0,0 @@
1
- // Fetch the latest release version from GitHub
2
- const { Octokit } = require("@octokit/rest");
3
- const { retry } = require("@octokit/plugin-retry");
4
- const OctokitWithRetries = Octokit.plugin(retry);
5
- const owner = 'redpanda-data';
6
- const repo = 'redpanda';
7
-
8
- let githubOptions = {
9
- userAgent: 'Redpanda Docs',
10
- baseUrl: 'https://api.github.com',
11
- };
12
-
13
- if (process.env.REDPANDA_GITHUB_TOKEN) {
14
- githubOptions.auth = process.env.REDPANDA_GITHUB_TOKEN;
15
- }
16
-
17
- const github = new OctokitWithRetries(githubOptions);
18
-
19
- var latestRedpandaReleaseVersion;
20
- var latestRedpandaReleaseCommitHash;
21
-
22
- module.exports = async () => {
23
- await github.rest.repos.getLatestRelease({
24
- owner,
25
- repo,
26
- }).then(async function(release) {
27
- const tag = release.data.tag_name;
28
- latestRedpandaReleaseVersion = tag.replace('v','');
29
- await github.rest.git.getRef({
30
- owner,
31
- repo,
32
- ref: `/tags/${tag}`,
33
- }).then(async function(tagRef) {
34
- const releaseSha = tagRef.data.object.sha;
35
- await github.rest.git.getTag({
36
- owner,
37
- repo,
38
- tag_sha: releaseSha,
39
- }).then((tag => latestRedpandaReleaseCommitHash = tag.data.object.sha.substring(0, 7)))
40
- })
41
- }).catch((error => {
42
- console.error(error)
43
- return null
44
- }))
45
- return [latestRedpandaReleaseVersion, latestRedpandaReleaseCommitHash];
46
- };