@redpanda-data/docs-extensions-and-macros 3.3.3 → 3.4.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 CHANGED
@@ -44,13 +44,13 @@ To use the development version instead, refer to the <<development-quickstart,De
44
44
 
45
45
  This section documents the Antora extensions that are provided by this library and how to configure them.
46
46
 
47
- IMPORTANT: Be sure to register each extension under the `antora.extensions` key in the playbook, not the `asciidoc.extensions` key.
47
+ IMPORTANT: Ensure you register each extension under the `antora.extensions` key in the playbook, not the `asciidoc.extensions` key.
48
48
 
49
49
  === Algolia indexer
50
50
 
51
51
  This extension generates an Algolia index for each version of each component. The index entries are then saved to Algolia using the `saveObjects()` method, and also saved as JSON files in the site catalog. JSON files are published to the site root using the following template: `algolia-<component>-<version>.json`.
52
52
 
53
- NOTE: Only pages that include an `<article>` element with the `doc` class are indexed. Pages marked as "noindex" for "robots" are skipped.
53
+ NOTE: Only pages that include an `<article>` element with the `doc` class are indexed.
54
54
 
55
55
  ==== Environment variables
56
56
 
@@ -85,6 +85,14 @@ This extension maps Redpanda Connect component data into a structured format:
85
85
  - Populates `connectCategoriesData` and `flatComponentsData` attributes.
86
86
  - Skips deprecated components.
87
87
 
88
+ ==== Environment variables
89
+
90
+ This extension does not require any environment variables.
91
+
92
+ ==== Configuration options
93
+
94
+ There are no configurable options for this extension.
95
+
88
96
  ==== Registration Example
89
97
 
90
98
  ```yaml
@@ -93,19 +101,41 @@ antora:
93
101
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/generate-rp-connect-categories'
94
102
  ```
95
103
 
104
+ === Redpanda Connect tag modifier
105
+
106
+ This extension updates the playbook to use the latest release tag for the Redpanda Connect documentation. It ensures that the Redpanda Connect documentation is always pulled from the latest release tag available on GitHub.
107
+
108
+ ==== Environment variables
109
+
110
+ - `REDPANDA_GITHUB_TOKEN` (optional): A Personal access token (PAT) that has `repo` permissions for the `redpanda-data` GitHub organization.
111
+
112
+ NOTE: If you don't set the environment variable, the latest version of Redpanda Connect may not be fetched. When the environment variable is not set, the extension sends unauthenticated requests to GitHub. Unauthenticated requests may result in hitting the API rate limit and cause GitHub to reject the request. In this case the fallback version is used. This version is defined in the playbook where the extension is registered.
113
+
114
+ ==== Configuration options
115
+
116
+ There are no configurable options for this extension.
117
+
118
+ ==== Registration Example
119
+
120
+ ```yaml
121
+ antora:
122
+ extensions:
123
+ - require: '@redpanda-data/docs-extensions-and-macros/extensions/modify-connect-tag-playbook'
124
+ ```
125
+
96
126
  === Version fetcher
97
127
 
98
128
  This extension fetches the latest release versions from GitHub.
99
129
 
100
- The latest Console version is made available to all versions of the Redpanda docs (`ROOT` component.)
130
+ The latest versions of Redpanda Console and Redpanda Connect are made available to all versions of all Antora components.
101
131
 
102
- The latest Redpanda version and the latest Redpanda Operator version is made available to the latest version of the `ROOT` component.
132
+ The latest Redpanda version and the latest Redpanda Operator version are made available to the latest version of the `ROOT` component (Redpanda docs).
103
133
 
104
134
  ==== Environment variables
105
135
 
106
136
  - `REDPANDA_GITHUB_TOKEN` (optional): A Personal access token (PAT) that has `repo` permissions for the `redpanda-data` GitHub organization.
107
137
 
108
- NOTE: If you don't set the environment variable, the latest versions may not be made available to your build. When the environment variable is not set, the extension sends unauthenticated requests to GitHub. Unauthenticated requests may result in hitting the API rate limit and cause GitHub to reject the request.
138
+ NOTE: If you don't set the environment variable, the latest versions may not be fetched. When the environment variable is not set, the extension sends unauthenticated requests to GitHub. Unauthenticated requests may result in hitting the API rate limit and cause GitHub to reject the request.
109
139
 
110
140
  ==== Registration example
111
141
 
@@ -188,6 +218,14 @@ antora:
188
218
 
189
219
  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.
190
220
 
221
+ ==== Environment variables
222
+
223
+ This extension does not require any environment variables.
224
+
225
+ ==== Configuration options
226
+
227
+ There are no configurable options for this extension.
228
+
191
229
  ==== Registration example
192
230
 
193
231
  ```yaml
@@ -200,6 +238,14 @@ antora:
200
238
 
201
239
  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.
202
240
 
241
+ ==== Environment variables
242
+
243
+ This extension does not require any environment variables.
244
+
245
+ ==== Configuration options
246
+
247
+ There are no configurable options for this extension.
248
+
203
249
  ==== Registration example
204
250
 
205
251
  ```yaml
@@ -219,6 +265,14 @@ This extension replaces AsciiDoc attribute placeholders with their respective va
219
265
  - If the same attribute placeholder is used multiple times within a file, all instances will be replaced with the attribute's value.
220
266
  ====
221
267
 
268
+ ==== Environment variables
269
+
270
+ This extension does not require any environment variables.
271
+
272
+ ==== Configuration options
273
+
274
+ There are no configurable options for this extension.
275
+
222
276
  ==== Registration example
223
277
 
224
278
  ```yaml
@@ -235,6 +289,14 @@ This extension aggregates all term pages from the {url-playbook}[`shared` compon
235
289
  - Looks for glossary pages named `reference:glossary.adoc` in all versions of all components and appends the contents of each term file to the glossary in alphabetical order.
236
290
  - If a glossary page is found, sets the `glossary-page` attribute of the <<glossterm, `glossterm` macro>> to `reference:glossary.adoc` so that terms can be linked to the glossary page.
237
291
 
292
+ ==== Environment variables
293
+
294
+ This extension does not require any environment variables.
295
+
296
+ ==== Configuration options
297
+
298
+ There are no configurable options for this extension.
299
+
238
300
  ==== Registration example
239
301
 
240
302
  ```yaml
@@ -249,6 +311,10 @@ This extension identifies and logs any pages that aren't listed in the navigatio
249
311
 
250
312
  IMPORTANT: By default, this extension excludes components named 'api'. This behavior is hardcoded and cannot be changed in the configuration.
251
313
 
314
+ ==== Environment variables
315
+
316
+ This extension does not require any environment variables.
317
+
252
318
  ==== Configuration options
253
319
 
254
320
  This extension accepts the following configuration options:
@@ -4,67 +4,86 @@ module.exports.register = function ({ config }) {
4
4
  const logger = this.getLogger('related-docs-extension');
5
5
 
6
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
7
+ // Find the latest version of each component
8
+ const latestVersions = {};
9
+ contentCatalog.getComponents().forEach(component => {
10
+ latestVersions[component.name] = component.latest.version;
11
+ });
12
+
13
+ // Retrieve all documents and labs from the latest versions of each component
14
+ const allDocs = [];
15
+ const allLabs = contentCatalog.findBy({ component: 'redpanda-labs', family: 'page', version: latestVersions['redpanda-labs'] });
16
+
17
+ Object.keys(latestVersions).forEach(component => {
18
+ if (component === 'redpanda-labs') return;
19
+ allDocs.push(...contentCatalog.findBy({ component, family: 'page', version: latestVersions[component] }));
20
+ });
21
+ allLabs.forEach((labPage) => {
22
+ const relatedDocs = new Set();
23
+ const relatedLabs = new Set();
24
+ const sourceAttributes = labPage.asciidoc.attributes;
12
25
  const pageCategories = sourceAttributes['page-categories'];
13
26
  if (!pageCategories) return;
14
27
  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) => {
28
+ const sourceDeploymentType = getDeploymentType(sourceAttributes);
29
+ const docs = contentCatalog.findBy({ component: 'ROOT', family: 'page', version: latestVersions['ROOT'] });
30
+
31
+ allDocs.forEach((docPage) => {
32
+ const related = findRelated(docPage, sourceCategoryList, sourceDeploymentType, logger);
33
+ if (related) relatedDocs.add(JSON.stringify(related));
34
+ });
35
+
36
+ allLabs.forEach((targetLabPage) => {
22
37
  if (targetLabPage === labPage) return;
23
38
 
24
39
  const related = findRelated(targetLabPage, sourceCategoryList, sourceDeploymentType, logger);
25
- if (related) relatedLabs.push(related);
40
+ if (related) relatedLabs.add(JSON.stringify(related));
26
41
  });
27
42
 
43
+ // Convert Sets back to arrays and remove duplicates
44
+ const uniqueRelatedDocs = Array.from(relatedDocs).map(item => JSON.parse(item));
45
+ const uniqueRelatedLabs = Array.from(relatedLabs).map(item => JSON.parse(item));
46
+
28
47
  // 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);
48
+ if (uniqueRelatedDocs.length > 0) {
49
+ labPage.asciidoc.attributes['page-related-docs'] = JSON.stringify(uniqueRelatedDocs);
31
50
  }
32
51
 
33
- if (relatedLabs.length > 0) {
34
- labPage.asciidoc.attributes['page-related-labs'] = JSON.stringify(relatedLabs);
52
+ if (uniqueRelatedLabs.length > 0) {
53
+ labPage.asciidoc.attributes['page-related-labs'] = JSON.stringify(uniqueRelatedLabs);
35
54
  }
36
55
 
37
- if (relatedDocs.length > 0 || relatedLabs.length > 0) {
56
+ if (uniqueRelatedDocs.length > 0 || uniqueRelatedLabs.length > 0) {
38
57
  logger.info(`Set related docs and labs attributes for ${labPage.asciidoc.doctitle}`);
39
58
  }
40
- })
41
- })
42
- }
59
+ });
60
+ });
61
+ };
43
62
 
44
63
  function findRelated(docPage, sourceCategoryList, sourceDeploymentType, logger) {
45
- const targetAttributes = docPage.asciidoc.attributes
64
+ const targetAttributes = docPage.asciidoc.attributes;
46
65
  const pageCategories = targetAttributes['page-categories'];
47
66
  if (!pageCategories) return null;
48
67
  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)) {
68
+ const targetDeploymentType = getDeploymentType(targetAttributes);
69
+ const categoryMatch = hasMatchingCategory(sourceCategoryList, targetCategoryList);
70
+ if (categoryMatch && (!targetDeploymentType || sourceDeploymentType === targetDeploymentType)) {
52
71
  return {
53
72
  title: docPage.asciidoc.doctitle,
54
73
  url: docPage.pub.url,
55
- }
74
+ };
56
75
  }
57
- return null
76
+ return null;
58
77
  }
59
78
 
60
- function getDeploymentType (attributes) {
79
+ function getDeploymentType(attributes) {
61
80
  return attributes['env-kubernetes'] ? 'Kubernetes'
62
81
  : attributes['env-linux'] ? 'Linux'
63
82
  : attributes['env-docker'] ? 'Docker'
64
- : attributes.cloud ? 'Redpanda Cloud'
65
- : ''
83
+ : attributes.cloud ? 'Redpanda Cloud'
84
+ : '';
66
85
  }
67
86
 
68
- function hasMatchingCategory (sourcePageCategories, targetPageCategories) {
69
- return sourcePageCategories.every((category) => targetPageCategories.includes(category))
70
- }
87
+ function hasMatchingCategory(sourcePageCategories, targetPageCategories) {
88
+ return sourcePageCategories.every(category => targetPageCategories.includes(category));
89
+ }
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ const GetLatestConnectTag = require('./version-fetcher/get-latest-connect');
4
+
5
+ module.exports.register = function ({ config }) {
6
+ const logger = this.getLogger('modify-connect-tag-playbook-extension');
7
+
8
+ this.on('contextStarted', async ({ playbook }) => {
9
+ try {
10
+ // Fetch the latest release tag for redpanda-data/connect
11
+ const sourceUrl = 'https://github.com/redpanda-data/connect';
12
+ if (playbook && playbook.content && playbook.content.sources) {
13
+ const source = playbook.content.sources.find(source => source.url === sourceUrl);
14
+ if (source) {
15
+ const latestTag = await GetLatestConnectTag();
16
+ if (latestTag) {
17
+ source.tags[0] = latestTag;
18
+ this.updateVariables({ playbook });
19
+ }
20
+ }
21
+ }
22
+ } catch (error) {
23
+ console.error('Failed to update playbook with the latest Redpanda Connect tag:', error);
24
+ }
25
+ });
26
+ }
@@ -1,54 +1,68 @@
1
+ 'use strict';
2
+
1
3
  module.exports.register = function ({ config }) {
2
- const { addToNavigation, unlistedPagesHeading = 'Unlisted Pages' } = config
3
- const logger = this.getLogger('unlisted-pages-extension')
4
- this
5
- .on('navigationBuilt', ({ navigationCatalog, contentCatalog }) => {
6
- contentCatalog.getComponents().forEach(({ versions }) => {
7
- versions.forEach(({ name: component, version, navigation: nav, url: defaultUrl }) => {
8
- if (component === 'api') return;
9
- if (!nav) return
10
- const navEntriesByUrl = getNavEntriesByUrl(nav)
11
- const unlistedPages = contentCatalog
12
- .findBy({ component, version, family: 'page' })
13
- .filter((page) => page.out)
14
- .reduce((collector, page) => {
15
- if ((page.pub.url in navEntriesByUrl) || page.pub.url === defaultUrl) return collector
16
- logger.warn({ file: page.src, source: page.src.origin }, 'detected unlisted page')
17
- return collector.concat(page)
18
- }, [])
19
- if (unlistedPages.length && component === 'redpanda-connect') {
20
- // Some component pages for Redpanda Connect are autogenerated. This function tries to add unlisted component pages to the nav in case a new one gets created without updating the nav.
21
- addRedpandaConnectPagesToNav(nav[0].items, unlistedPages)
22
- } else if (unlistedPages.length && addToNavigation) {
23
- nav.push({
24
- content: unlistedPagesHeading,
25
- items: unlistedPages.map((page) => {
26
- return { content: page.asciidoc.navtitle, url: page.pub.url, urlType: 'internal' }
27
- }),
28
- root: true,
29
- })
30
- }
31
- })
32
- })
33
- })
34
- }
4
+ const { addToNavigation, unlistedPagesHeading = 'Unlisted Pages' } = config;
5
+ const logger = this.getLogger('unlisted-pages-extension');
6
+
7
+ this.on('navigationBuilt', ({ siteCatalog, contentCatalog }) => {
8
+ contentCatalog.getComponents().forEach(({ versions }) => {
9
+ versions.forEach(({ name: component, version, navigation: nav, url: defaultUrl }) => {
10
+ if (component === 'api') return;
11
+ if (!nav) return;
12
+ const currentComponent = contentCatalog.getComponent(component);
13
+ const prerelease = currentComponent && currentComponent.latestPrerelease ? currentComponent.latestPrerelease : false;
14
+
15
+ const navEntriesByUrl = getNavEntriesByUrl(nav);
16
+ const unlistedPages = contentCatalog
17
+ .findBy({ component, version, family: 'page' })
18
+ .reduce((collector, page) => {
19
+ if (siteCatalog.unpublishedPages.includes(page.pub.url)) {
20
+ logger.info({ file: page.src, source: page.src.origin }, 'removing unpublished page from nav tree');
21
+ removePageFromNav(nav, page.pub.url); // Remove the page from navigationCatalog
22
+ return collector; // Skip adding this page to the collector
23
+ }
35
24
 
36
- function getNavEntriesByUrl (items = [], accum = {}) {
25
+ if (!(page.pub.url in navEntriesByUrl) && page.pub.url !== defaultUrl) {
26
+ logger.warn({ file: page.src, source: page.src.origin }, 'detected unlisted page');
27
+ return collector.concat(page);
28
+ }
29
+
30
+ return collector;
31
+ }, []);
32
+
33
+ if (unlistedPages.length && component === 'redpanda-connect') {
34
+ // Some component pages for Redpanda Connect are autogenerated. This function tries to add unlisted component pages to the nav in case a new one gets created without updating the nav.
35
+ addRedpandaConnectPagesToNav(nav[0].items, unlistedPages);
36
+ } else if (unlistedPages.length && addToNavigation) {
37
+ nav.push({
38
+ content: unlistedPagesHeading,
39
+ items: unlistedPages.map((page) => {
40
+ return { content: page.asciidoc.navtitle, url: page.pub.url, urlType: 'internal' };
41
+ }),
42
+ root: true,
43
+ });
44
+ }
45
+ });
46
+ });
47
+ });
48
+ };
49
+
50
+ function getNavEntriesByUrl(items = [], accum = {}) {
37
51
  items.forEach((item) => {
38
- if (item.urlType === 'internal') accum[item.url.split('#')[0]] = item
39
- getNavEntriesByUrl(item.items, accum)
40
- })
41
- return accum
52
+ if (item.urlType === 'internal') accum[item.url.split('#')[0]] = item;
53
+ getNavEntriesByUrl(item.items, accum);
54
+ });
55
+ return accum;
42
56
  }
43
57
 
44
58
  function addRedpandaConnectPagesToNav(navItems, pages) {
45
59
  // get the Components nav section
46
60
  let componentsSection = navItems.find(item => item.content === 'Components');
47
- if (!componentsSection) return
61
+ if (!componentsSection) return;
48
62
 
49
63
  pages.forEach(page => {
50
64
  const dirname = page.out.dirname;
51
- if (!dirname.includes('/components/')) return
65
+ if (!dirname.includes('/components/')) return;
52
66
  const heading = page.asciidoc.attributes.doctitle;
53
67
  const pathParts = dirname.split('/').slice(2); // Get the type
54
68
  // get existing nav items inside the Components tree
@@ -66,4 +80,16 @@ function addRedpandaConnectPagesToNav(navItems, pages) {
66
80
 
67
81
  currentLevel.push({ content: page.asciidoc.navtitle || page.src.stem, url: page.pub.url, urlType: 'internal' });
68
82
  });
69
- }
83
+ }
84
+
85
+ function removePageFromNav(navItems, urlToRemove) {
86
+ // Remove the page from the navigation items
87
+ for (let i = navItems.length - 1; i >= 0; i--) {
88
+ const item = navItems[i];
89
+ if (item.url === urlToRemove) {
90
+ navItems.splice(i, 1);
91
+ } else if (item.items && item.items.length > 0) {
92
+ removePageFromNav(item.items, urlToRemove);
93
+ }
94
+ }
95
+ }
@@ -1,9 +1,34 @@
1
+ 'use strict';
2
+
1
3
  module.exports.register = function () {
2
- this.on('documentsConverted', ({ contentCatalog }) => {
3
- contentCatalog.getPages((page) => page.out).forEach((page) => {
4
- if (page.asciidoc?.attributes['page-unpublish'] != null || page.asciidoc?.attributes['page-layout'] === 'api-partial') {
5
- delete page.out
4
+ this.on('documentsConverted', ({ siteCatalog, contentCatalog }) => {
5
+ // Get all pages that have an `out` property
6
+ const pages = contentCatalog.getPages((page) => page.out);
7
+ let componentName;
8
+ siteCatalog.unpublishedPages = []
9
+
10
+ // Iterate over each page
11
+ pages.forEach((page) => {
12
+ // Retrieve the component associated with the page
13
+ componentName = page.asciidoc?.attributes['page-component-name'];
14
+ const component = contentCatalog.getComponent(componentName);
15
+
16
+ // Check if the component has a latest prerelease
17
+ const prerelease = component && component.latestPrerelease ? component.latestPrerelease : false;
18
+
19
+ // Check the conditions for unpublishing the page
20
+ const shouldUnpublish = (
21
+ page.asciidoc?.attributes['page-unpublish'] ||
22
+ (page.asciidoc?.attributes['publish-only-during-beta']
23
+ && !prerelease // No beta version available, meaning the beta period has ended
24
+ )
25
+ );
26
+
27
+ // If any condition is met, unpublish the page
28
+ if (shouldUnpublish) {
29
+ siteCatalog.unpublishedPages.push(page.pub.url)
30
+ delete page.out;
6
31
  }
7
- })
8
- })
9
- }
32
+ });
33
+ });
34
+ };
@@ -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 = 'connect';
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
+ tag = release.data.tag_name;
23
+ return tag;
24
+ } catch (error) {
25
+ console.error(error);
26
+ return null;
27
+ }
28
+ };
@@ -27,15 +27,17 @@ module.exports = async () => {
27
27
  per_page: 50
28
28
  });
29
29
 
30
- // Filter valid semver tags and sort them to find the highest version
30
+ // Filter valid semver tags, exclude drafts, and sort them to find the highest version
31
31
  const sortedReleases = releases.data
32
+ .filter(release => !release.draft)
32
33
  .map(release => release.tag_name.replace(/^v/, ''))
33
- .filter(tag => semver.valid(tag) && !tag.match(/rc\d+$/)) // Exclude 'rc-{number}' suffixes
34
+ .filter(tag => semver.valid(tag))
34
35
  // Sort in descending order to get the highest version first
35
36
  .sort(semver.rcompare);
36
37
 
37
38
  if (sortedReleases.length > 0) {
38
- const latestRedpandaReleaseVersion = sortedReleases[0];
39
+ const latestRedpandaReleaseVersion = sortedReleases.find(tag => !tag.includes('rc'));
40
+ const latestRcReleaseVersion = sortedReleases.find(tag => tag.includes('rc'));
39
41
 
40
42
  // Get the commit hash for the highest version tag
41
43
  const commitData = await github.rest.git.getRef({
@@ -45,13 +47,32 @@ module.exports = async () => {
45
47
  });
46
48
  const latestRedpandaReleaseCommitHash = commitData.data.object.sha;
47
49
 
48
- return [latestRedpandaReleaseVersion, latestRedpandaReleaseCommitHash.substring(0, 7)];
50
+ let latestRcReleaseCommitHash = null;
51
+ if (latestRcReleaseVersion) {
52
+ const rcCommitData = await github.rest.git.getRef({
53
+ owner,
54
+ repo,
55
+ ref: `tags/v${latestRcReleaseVersion}`
56
+ });
57
+ latestRcReleaseCommitHash = rcCommitData.data.object.sha;
58
+ }
59
+
60
+ return {
61
+ latestRedpandaRelease: {
62
+ version: latestRedpandaReleaseVersion,
63
+ commitHash: latestRedpandaReleaseCommitHash.substring(0, 7)
64
+ },
65
+ latestRcRelease: latestRcReleaseVersion ? {
66
+ version: latestRcReleaseVersion,
67
+ commitHash: latestRcReleaseCommitHash.substring(0, 7)
68
+ } : null
69
+ };
49
70
  } else {
50
71
  console.log("No valid semver releases found for Redpanda.");
51
- return [null, null];
72
+ return { latestRedpandaRelease: null, latestRcRelease: null };
52
73
  }
53
74
  } catch (error) {
54
75
  console.error('Failed to fetch Redpanda release information:', error);
55
- return [null, null];
76
+ return { latestRedpandaRelease: null, latestRcRelease: null };
56
77
  }
57
78
  };
@@ -2,6 +2,7 @@ const GetLatestRedpandaVersion = require('./get-latest-redpanda-version')
2
2
  const GetLatestConsoleVersion = require('./get-latest-console-version')
3
3
  const GetLatestOperatorVersion = require('./get-latest-operator-version')
4
4
  const GetLatestHelmChartVersion = require('./get-latest-redpanda-helm-version')
5
+ const GetLatestConnectVersion = require('./get-latest-connect')
5
6
  const chalk = require('chalk')
6
7
  const semver = require('semver')
7
8
 
@@ -17,13 +18,15 @@ module.exports.register = function ({ config }) {
17
18
  GetLatestRedpandaVersion(),
18
19
  GetLatestConsoleVersion(),
19
20
  GetLatestOperatorVersion(),
20
- GetLatestHelmChartVersion()
21
+ GetLatestHelmChartVersion(),
22
+ GetLatestConnectVersion()
21
23
  ])
22
24
 
23
25
  const LatestRedpandaVersion = results[0].status === 'fulfilled' ? results[0].value : null
24
26
  const LatestConsoleVersion = results[1].status === 'fulfilled' ? results[1].value : null
25
27
  const LatestOperatorVersion = results[2].status === 'fulfilled' ? results[2].value : null
26
28
  const LatestHelmChartVersion = results[3].status === 'fulfilled' ? results[3].value : null
29
+ const LatestConnectVersion = results[4].status === 'fulfilled' ? results[4].value : null
27
30
 
28
31
  const components = await contentCatalog.getComponents()
29
32
  components.forEach(component => {
@@ -32,18 +35,27 @@ module.exports.register = function ({ config }) {
32
35
  asciidoc.attributes['latest-console-version'] = `${LatestConsoleVersion}@`
33
36
  logger.info(`Set Redpanda Console version to ${LatestConsoleVersion} in ${name} ${version}`)
34
37
  }
38
+ if (LatestConnectVersion) {
39
+ asciidoc.attributes['latest-connect-version'] = `${LatestConnectVersion}@`
40
+ logger.info(`Set Redpanda Connect version to ${LatestConnectVersion} in ${name} ${version}`)
41
+ }
42
+ if (LatestRedpandaVersion && LatestRedpandaVersion.latestRcRelease) {
43
+ asciidoc.attributes['redpanda-beta-version'] = `${LatestRedpandaVersion.latestRcRelease.version}@`
44
+ asciidoc.attributes['redpanda-beta-commit'] = `${LatestRedpandaVersion.latestRcRelease.commitHash}@`
45
+ logger.info(`Updated to latest Redpanda RC version: ${LatestRedpandaVersion.latestRcRelease.version} with commit: ${LatestRedpandaVersion.latestRcRelease.commitHash}`)
46
+ }
35
47
  })
36
48
 
37
49
  if (!component.latest.asciidoc) {
38
50
  component.latest.asciidoc = { attributes: {} }
39
51
  }
40
52
 
41
- if (LatestRedpandaVersion && semver.valid(LatestRedpandaVersion[0])) {
53
+ if (LatestRedpandaVersion && semver.valid(LatestRedpandaVersion.latestRedpandaRelease.version)) {
42
54
  let currentVersion = component.latest.asciidoc.attributes['full-version'] || '0.0.0'
43
- if (semver.gt(LatestRedpandaVersion[0], currentVersion)) {
44
- component.latest.asciidoc.attributes['full-version'] = `${LatestRedpandaVersion[0]}@`
45
- component.latest.asciidoc.attributes['latest-release-commit'] = `${LatestRedpandaVersion[1]}@`
46
- logger.info(`Updated to latest Redpanda version: ${LatestRedpandaVersion[0]} with commit: ${LatestRedpandaVersion[1]}`)
55
+ if (semver.gt(LatestRedpandaVersion.latestRedpandaRelease.version, currentVersion)) {
56
+ component.latest.asciidoc.attributes['full-version'] = `${LatestRedpandaVersion.latestRedpandaRelease.version}@`
57
+ component.latest.asciidoc.attributes['latest-release-commit'] = `${LatestRedpandaVersion.latestRedpandaRelease.commitHash}@`
58
+ logger.info(`Updated to latest Redpanda version: ${LatestRedpandaVersion.latestRedpandaRelease.version} with commit: ${LatestRedpandaVersion.latestRedpandaRelease.commitHash}`)
47
59
  }
48
60
  }
49
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redpanda-data/docs-extensions-and-macros",
3
- "version": "3.3.3",
3
+ "version": "3.4.1",
4
4
  "description": "Antora extensions and macros developed for Redpanda documentation.",
5
5
  "keywords": [
6
6
  "antora",
@@ -33,6 +33,7 @@
33
33
  "./extensions/generate-rp-connect-categories": "./extensions/generate-rp-connect-categories.js",
34
34
  "./extensions/add-global-attributes": "./extensions/add-global-attributes.js",
35
35
  "./extensions/version-fetcher/set-latest-version": "./extensions/version-fetcher/set-latest-version.js",
36
+ "./extensions/modify-connect-tag-playbook": "./extensions/modify-connect-tag-playbook.js",
36
37
  "./extensions/validate-attributes": "./extensions/validate-attributes.js",
37
38
  "./extensions/find-related-docs": "./extensions/find-related-docs.js",
38
39
  "./extensions/unpublish-pages": "./extensions/unpublish-pages.js",