@redpanda-data/docs-extensions-and-macros 4.15.5 → 4.15.7

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.
@@ -3,20 +3,370 @@
3
3
  * Outputs a console-parseable format for GitHub Actions
4
4
  */
5
5
 
6
+ /**
7
+ * Generate PR summary for multiple releases
8
+ * @param {object} masterDiff - Master diff with releases array
9
+ * @param {object} binaryAnalysis - Cloud support data (from latest release)
10
+ * @param {array} draftedConnectors - Array of newly drafted connectors
11
+ * @returns {string} Formatted summary
12
+ */
13
+ function generateMultiVersionPRSummary(masterDiff, binaryAnalysis = null, draftedConnectors = null) {
14
+ const lines = [];
15
+
16
+ // Defensive: ensure metadata exists
17
+ const metadata = masterDiff?.metadata || {};
18
+ const startVersion = metadata.startVersion || 'unknown';
19
+ const endVersion = metadata.endVersion || 'unknown';
20
+ const processedReleases = metadata.processedReleases || 0;
21
+
22
+ lines.push('<!-- PR_SUMMARY_START -->');
23
+ lines.push('');
24
+ lines.push('## 📊 Redpanda Connect Documentation Update');
25
+ lines.push('');
26
+ lines.push(`**📦 Multi-Release Update:** ${startVersion} → ${endVersion}`);
27
+ lines.push(`**Releases Processed:** ${processedReleases}`);
28
+
29
+ if (binaryAnalysis) {
30
+ lines.push(`**Cloud Version:** ${binaryAnalysis.cloudVersion}`);
31
+ }
32
+
33
+ lines.push('');
34
+
35
+ // Total summary across all releases
36
+ lines.push('### Total Changes Across All Releases');
37
+ lines.push('');
38
+ const total = masterDiff?.totalSummary || {};
39
+
40
+ if (total.newComponents > 0) {
41
+ lines.push(`- **${total.newComponents}** new connectors`);
42
+ }
43
+ if (total.newFields > 0) {
44
+ lines.push(`- **${total.newFields}** new fields across ${total.releaseCount || 0} release(s)`);
45
+ }
46
+ if (total.removedComponents > 0) {
47
+ lines.push(`- **${total.removedComponents}** removed connectors ⚠️`);
48
+ }
49
+ if (total.removedFields > 0) {
50
+ lines.push(`- **${total.removedFields}** removed fields ⚠️`);
51
+ }
52
+ if (total.deprecatedComponents > 0) {
53
+ lines.push(`- **${total.deprecatedComponents}** deprecated connectors`);
54
+ }
55
+ if (total.deprecatedFields > 0) {
56
+ lines.push(`- **${total.deprecatedFields}** deprecated fields`);
57
+ }
58
+ if (total.changedDefaults > 0) {
59
+ lines.push(`- **${total.changedDefaults}** changed default values ⚠️`);
60
+ }
61
+
62
+ lines.push('');
63
+
64
+ // Guard: ensure releases array exists
65
+ const releases = masterDiff?.releases || [];
66
+ if (releases.length === 0) {
67
+ lines.push('_No releases to process_');
68
+ lines.push('');
69
+ lines.push('<!-- PR_SUMMARY_END -->');
70
+ return lines.join('\n');
71
+ }
72
+
73
+ // Per-release detailed breakdown
74
+ lines.push('### Changes Per Release');
75
+ lines.push('');
76
+
77
+ for (const release of releases) {
78
+ const releaseNotesUrl = `https://github.com/redpanda-data/connect/releases/tag/v${release.toVersion}`;
79
+ lines.push(`#### 🔖 Version ${release.toVersion}`);
80
+ lines.push(`> [Release notes](${releaseNotesUrl})`);
81
+ lines.push('');
82
+
83
+ const summary = release.summary || {};
84
+ const details = release.details || {};
85
+ const hasChanges = Object.values(summary).some(v => v > 0);
86
+
87
+ if (!hasChanges) {
88
+ lines.push('_No documentation changes in this release_');
89
+ lines.push('');
90
+ continue;
91
+ }
92
+
93
+ // New connectors with descriptions
94
+ const newComponents = details.newComponents || [];
95
+ if (summary.newComponents > 0 && newComponents.length > 0) {
96
+ lines.push(`**New Connectors (${summary.newComponents}):**`);
97
+ lines.push('');
98
+ const inCloud = release.binaryAnalysis?.comparison?.inCloud || [];
99
+ const cloudOnly = release.binaryAnalysis?.comparison?.cloudOnly || [];
100
+ const notInCloud = release.binaryAnalysis?.comparison?.notInCloud || [];
101
+ const cgoOnly = release.binaryAnalysis?.cgoOnly || [];
102
+
103
+ newComponents.forEach(comp => {
104
+ const isInCloud = inCloud.some(c => c.type === comp.type && c.name === comp.name) ||
105
+ cloudOnly.some(c => c.type === comp.type && c.name === comp.name);
106
+ const isSelfHostedOnly = notInCloud.some(c => c.type === comp.type && c.name === comp.name);
107
+ const isCgoOnly = cgoOnly.some(c => c.type === comp.type && c.name === comp.name);
108
+
109
+ let platformIndicator = '';
110
+ if (isInCloud) platformIndicator = ' ☁️';
111
+ else if (isSelfHostedOnly) platformIndicator = ' 🖥️';
112
+ if (isCgoOnly) platformIndicator += ' 🔧';
113
+
114
+ lines.push(`##### \`${comp.name}\` (${comp.type}, ${comp.status})${platformIndicator}`);
115
+
116
+ // Add description (truncated to 2 sentences)
117
+ if (comp.description) {
118
+ const shortDesc = truncateToSentence(comp.description, 2);
119
+ lines.push(`> ${shortDesc}`);
120
+ }
121
+ lines.push('');
122
+ });
123
+ }
124
+
125
+ // New fields with details
126
+ const newFields = details.newFields || [];
127
+ if (summary.newFields > 0 && newFields.length > 0) {
128
+ lines.push(`**New Fields (${summary.newFields}):**`);
129
+ lines.push('');
130
+ lines.push('| Component | Field | Description |');
131
+ lines.push('|-----------|-------|-------------|');
132
+
133
+ newFields.forEach(field => {
134
+ const desc = field.description ? truncateToSentence(field.description, 1).replace(/\|/g, '\\|') : '_No description_';
135
+ lines.push(`| \`${field.component}\` | \`${field.field}\` | ${desc} |`);
136
+ });
137
+ lines.push('');
138
+ }
139
+
140
+ // Removed components
141
+ const removedComponents = details.removedComponents || [];
142
+ if (summary.removedComponents > 0 && removedComponents.length > 0) {
143
+ lines.push(`**⚠️ Removed Connectors (${summary.removedComponents}):**`);
144
+ lines.push('');
145
+ removedComponents.forEach(comp => {
146
+ lines.push(`- \`${comp.name}\` (${comp.type})`);
147
+ });
148
+ lines.push('');
149
+ }
150
+
151
+ // Removed fields
152
+ const removedFields = details.removedFields || [];
153
+ if (summary.removedFields > 0 && removedFields.length > 0) {
154
+ lines.push(`**⚠️ Removed Fields (${summary.removedFields}):**`);
155
+ lines.push('');
156
+ lines.push('| Component | Field |');
157
+ lines.push('|-----------|-------|');
158
+ removedFields.forEach(field => {
159
+ lines.push(`| \`${field.component}\` | \`${field.field}\` |`);
160
+ });
161
+ lines.push('');
162
+ }
163
+
164
+ // Deprecated fields with migration guidance
165
+ const deprecatedFields = details.deprecatedFields || [];
166
+ if (summary.deprecatedFields > 0 && deprecatedFields.length > 0) {
167
+ lines.push(`**Deprecated Fields (${summary.deprecatedFields}):**`);
168
+ lines.push('');
169
+ deprecatedFields.forEach(field => {
170
+ const guidance = field.description ? ` — ${truncateToSentence(field.description, 1)}` : '';
171
+ lines.push(`- \`${field.component}.${field.field}\`${guidance}`);
172
+ });
173
+ lines.push('');
174
+ }
175
+
176
+ // Changed defaults
177
+ const changedDefaults = details.changedDefaults || [];
178
+ if (summary.changedDefaults > 0 && changedDefaults.length > 0) {
179
+ lines.push(`**⚠️ Changed Defaults (${summary.changedDefaults}):**`);
180
+ lines.push('');
181
+ lines.push('| Component | Field | Old Default | New Default |');
182
+ lines.push('|-----------|-------|-------------|-------------|');
183
+ changedDefaults.forEach(change => {
184
+ const oldVal = change.oldDefault !== undefined ? `\`${JSON.stringify(change.oldDefault)}\`` : '_none_';
185
+ const newVal = change.newDefault !== undefined ? `\`${JSON.stringify(change.newDefault)}\`` : '_none_';
186
+ lines.push(`| \`${change.component}\` | \`${change.field}\` | ${oldVal} | ${newVal} |`);
187
+ });
188
+ lines.push('');
189
+ }
190
+ }
191
+
192
+ // Writer action items (aggregate)
193
+ lines.push('---');
194
+ lines.push('');
195
+ lines.push('### ✍️ Writer Action Items');
196
+ lines.push('');
197
+
198
+ // Collect all new connectors across all releases with full details
199
+ const allNewConnectors = [];
200
+ const allRemovedConnectors = [];
201
+ const allDeprecatedFields = [];
202
+ const allChangedDefaults = [];
203
+
204
+ releases.forEach(release => {
205
+ const details = release.details || {};
206
+ const releaseInCloud = release.binaryAnalysis?.comparison?.inCloud || [];
207
+ const releaseCloudOnly = release.binaryAnalysis?.comparison?.cloudOnly || [];
208
+ const releaseNotInCloud = release.binaryAnalysis?.comparison?.notInCloud || [];
209
+
210
+ // New connectors
211
+ (details.newComponents || []).forEach(comp => {
212
+ const isCloud = releaseInCloud.some(c => c.type === comp.type && c.name === comp.name) ||
213
+ releaseCloudOnly.some(c => c.type === comp.type && c.name === comp.name);
214
+ const isSelfHostedOnly = releaseNotInCloud.some(c => c.type === comp.type && c.name === comp.name);
215
+
216
+ allNewConnectors.push({
217
+ name: comp.name,
218
+ type: comp.type,
219
+ status: comp.status,
220
+ description: comp.description,
221
+ version: release.toVersion,
222
+ isCloud,
223
+ isSelfHostedOnly
224
+ });
225
+ });
226
+
227
+ // Removed connectors
228
+ (details.removedComponents || []).forEach(comp => {
229
+ allRemovedConnectors.push({
230
+ name: comp.name,
231
+ type: comp.type,
232
+ version: release.toVersion
233
+ });
234
+ });
235
+
236
+ // Deprecated fields
237
+ (details.deprecatedFields || []).forEach(field => {
238
+ allDeprecatedFields.push({
239
+ component: field.component,
240
+ field: field.field,
241
+ description: field.description,
242
+ version: release.toVersion
243
+ });
244
+ });
245
+
246
+ // Changed defaults
247
+ (details.changedDefaults || []).forEach(change => {
248
+ allChangedDefaults.push({
249
+ component: change.component,
250
+ field: change.field,
251
+ oldDefault: change.oldDefault,
252
+ newDefault: change.newDefault,
253
+ version: release.toVersion
254
+ });
255
+ });
256
+ });
257
+
258
+ // Priority 1: New connectors needing documentation
259
+ if (allNewConnectors.length > 0) {
260
+ lines.push('**📝 Document New Connectors:**');
261
+ lines.push('');
262
+
263
+ // Group by cloud vs self-hosted
264
+ const cloudConnectors = allNewConnectors.filter(c => c.isCloud);
265
+ const selfHostedConnectors = allNewConnectors.filter(c => c.isSelfHostedOnly);
266
+ const otherConnectors = allNewConnectors.filter(c => !c.isCloud && !c.isSelfHostedOnly);
267
+
268
+ if (cloudConnectors.length > 0) {
269
+ lines.push('_Cloud-supported (higher priority):_');
270
+ cloudConnectors.forEach(conn => {
271
+ lines.push(`- [ ] \`${conn.name}\` ${conn.type} ☁️ — introduced in **${conn.version}**`);
272
+ });
273
+ lines.push('');
274
+ }
275
+
276
+ if (selfHostedConnectors.length > 0) {
277
+ lines.push('_Self-hosted only:_');
278
+ selfHostedConnectors.forEach(conn => {
279
+ lines.push(`- [ ] \`${conn.name}\` ${conn.type} 🖥️ — introduced in **${conn.version}**`);
280
+ });
281
+ lines.push('');
282
+ }
283
+
284
+ if (otherConnectors.length > 0) {
285
+ lines.push('_Other connectors:_');
286
+ otherConnectors.forEach(conn => {
287
+ lines.push(`- [ ] \`${conn.name}\` ${conn.type} — introduced in **${conn.version}**`);
288
+ });
289
+ lines.push('');
290
+ }
291
+ }
292
+
293
+ // Priority 2: Removed connectors needing migration docs
294
+ if (allRemovedConnectors.length > 0) {
295
+ lines.push('**⚠️ Update Migration Guide for Removed Connectors:**');
296
+ lines.push('');
297
+ allRemovedConnectors.forEach(conn => {
298
+ lines.push(`- [ ] \`${conn.name}\` ${conn.type} — removed in **${conn.version}**`);
299
+ });
300
+ lines.push('');
301
+ }
302
+
303
+ // Priority 3: Deprecated fields needing docs update
304
+ if (allDeprecatedFields.length > 0) {
305
+ lines.push('**📋 Update Docs for Deprecated Fields:**');
306
+ lines.push('');
307
+ allDeprecatedFields.forEach(field => {
308
+ const guidance = field.description ? ` (${truncateToSentence(field.description, 1)})` : '';
309
+ lines.push(`- [ ] \`${field.component}.${field.field}\`${guidance} — deprecated in **${field.version}**`);
310
+ });
311
+ lines.push('');
312
+ }
313
+
314
+ // Priority 4: Changed defaults that may affect users
315
+ if (allChangedDefaults.length > 0) {
316
+ lines.push('**⚠️ Review Changed Defaults for Breaking Changes:**');
317
+ lines.push('');
318
+ allChangedDefaults.forEach(change => {
319
+ const oldVal = change.oldDefault !== undefined ? JSON.stringify(change.oldDefault) : 'none';
320
+ const newVal = change.newDefault !== undefined ? JSON.stringify(change.newDefault) : 'none';
321
+ lines.push(`- [ ] \`${change.component}.${change.field}\`: \`${oldVal}\` → \`${newVal}\` — changed in **${change.version}**`);
322
+ });
323
+ lines.push('');
324
+ }
325
+
326
+ // Add commercial name reminder if there are new connectors
327
+ if (allNewConnectors.length > 0) {
328
+ lines.push('---');
329
+ lines.push('');
330
+ lines.push('**💡 Reminder:** For each new connector, add the `:page-commercial-names:` attribute:');
331
+ lines.push('');
332
+ lines.push('```asciidoc');
333
+ lines.push('= Connector Name');
334
+ lines.push(':type: input');
335
+ lines.push(':page-commercial-names: Commercial Name, Alternative Name');
336
+ lines.push('```');
337
+ lines.push('');
338
+ }
339
+
340
+ lines.push('<!-- PR_SUMMARY_END -->');
341
+ return lines.join('\n');
342
+ }
343
+
6
344
  /**
7
345
  * Generate a PR-friendly summary for connector changes
8
- * @param {object} diffData - Diff data from generateConnectorDiffJson
346
+ * @param {object} diffData - Diff data from generateConnectorDiffJson OR master diff with multiple releases
9
347
  * @param {object} binaryAnalysis - Cloud support data from getCloudSupport
10
348
  * @param {array} draftedConnectors - Array of newly drafted connectors
349
+ * @param {boolean} isMultiVersion - Whether diffData is a master diff with multiple releases
11
350
  * @returns {string} Formatted summary
12
351
  */
13
- function generatePRSummary(diffData, binaryAnalysis = null, draftedConnectors = null) {
352
+ function generatePRSummary(diffData, binaryAnalysis = null, draftedConnectors = null, isMultiVersion = false) {
14
353
  const lines = [];
15
354
 
16
355
  // Header with delimiters for GitHub Action parsing
17
356
  lines.push('<!-- PR_SUMMARY_START -->');
18
357
  lines.push('');
19
358
 
359
+ // Detect if this is a master diff
360
+ if (!isMultiVersion && diffData.releases && diffData.totalSummary) {
361
+ isMultiVersion = true;
362
+ }
363
+
364
+ if (isMultiVersion) {
365
+ // Multi-version format
366
+ return generateMultiVersionPRSummary(diffData, binaryAnalysis, draftedConnectors);
367
+ }
368
+
369
+ // Single version format (original logic)
20
370
  // Quick Summary Section
21
371
  lines.push('## 📊 Redpanda Connect Documentation Update');
22
372
  lines.push('');
@@ -45,11 +395,13 @@ function generatePRSummary(diffData, binaryAnalysis = null, draftedConnectors =
45
395
  if (stats.newComponents > 0) {
46
396
  lines.push(`- **${stats.newComponents}** new connector${stats.newComponents !== 1 ? 's' : ''}`);
47
397
 
48
- if (binaryAnalysis) {
398
+ if (binaryAnalysis && binaryAnalysis.comparison) {
49
399
  const newConnectorKeys = diffData.details.newComponents.map(c => `${c.type}:${c.name}`);
50
400
  const cloudSupported = newConnectorKeys.filter(key => {
51
401
  const inCloud = binaryAnalysis.comparison.inCloud.some(c => `${c.type}:${c.name}` === key);
52
- return inCloud;
402
+ const cloudOnly = binaryAnalysis.comparison.cloudOnly &&
403
+ binaryAnalysis.comparison.cloudOnly.some(c => `${c.type}:${c.name}` === key);
404
+ return inCloud || cloudOnly;
53
405
  }).length;
54
406
 
55
407
  const needsCloudDocs = cloudSupported;
@@ -199,9 +551,15 @@ function generatePRSummary(diffData, binaryAnalysis = null, draftedConnectors =
199
551
  Object.entries(draftsByType).forEach(([type, drafts]) => {
200
552
  lines.push(`**${type}:**`);
201
553
  drafts.forEach(draft => {
202
- const cloudIndicator = binaryAnalysis?.comparison.inCloud.some(c =>
554
+ // Check both inCloud (OSS+Cloud) and cloudOnly (Cloud-only)
555
+ const isInCloud = binaryAnalysis?.comparison.inCloud.some(c =>
203
556
  c.type === type && c.name === draft.name
204
- ) ? ' ☁️' : '';
557
+ );
558
+ const isCloudOnly = binaryAnalysis?.comparison.cloudOnly &&
559
+ binaryAnalysis.comparison.cloudOnly.some(c =>
560
+ c.type === type && c.name === draft.name
561
+ );
562
+ const cloudIndicator = (isInCloud || isCloudOnly) ? ' ☁️' : '';
205
563
  const cgoIndicator = draft.requiresCgo ? ' 🔧' : '';
206
564
  const statusBadge = draft.status && draft.status !== 'stable' ? ` (${draft.status})` : '';
207
565
  lines.push(`- \`${draft.name}\`${statusBadge}${cloudIndicator}${cgoIndicator} → \`${draft.path}\``);
@@ -304,13 +662,16 @@ function generatePRSummary(diffData, binaryAnalysis = null, draftedConnectors =
304
662
  });
305
663
  }
306
664
 
307
- // New connectors without cloud support
308
- if (stats.newComponents > 0) {
665
+ // New connectors without cloud support (self-hosted only)
666
+ if (binaryAnalysis && stats.newComponents > 0) {
309
667
  diffData.details.newComponents.forEach(connector => {
310
668
  const key = `${connector.type}:${connector.name}`;
311
- const inCloud = binaryAnalysis?.comparison.inCloud.some(c => `${c.type}:${c.name}` === key);
312
669
 
313
- if (!inCloud) {
670
+ // Check if it's explicitly in the self-hosted only list
671
+ const isSelfHostedOnly = binaryAnalysis.comparison.notInCloud &&
672
+ binaryAnalysis.comparison.notInCloud.some(c => `${c.type}:${c.name}` === key);
673
+
674
+ if (isSelfHostedOnly) {
314
675
  actionItems.push({
315
676
  priority: 2,
316
677
  text: `Document new \`${connector.name}\` ${connector.type} (self-hosted only)`
@@ -376,7 +737,13 @@ function generatePRSummary(diffData, binaryAnalysis = null, draftedConnectors =
376
737
 
377
738
  diffData.details.newComponents.forEach(connector => {
378
739
  const key = `${connector.type}:${connector.name}`;
740
+
741
+ // Check explicit categories
379
742
  const inCloud = binaryAnalysis.comparison.inCloud.some(c => `${c.type}:${c.name}` === key);
743
+ const isSelfHostedOnly = binaryAnalysis.comparison.notInCloud &&
744
+ binaryAnalysis.comparison.notInCloud.some(c => `${c.type}:${c.name}` === key);
745
+ const isCloudOnly = binaryAnalysis.comparison.cloudOnly &&
746
+ binaryAnalysis.comparison.cloudOnly.some(c => `${c.type}:${c.name}` === key);
380
747
 
381
748
  const entry = {
382
749
  name: connector.name,
@@ -385,9 +752,10 @@ function generatePRSummary(diffData, binaryAnalysis = null, draftedConnectors =
385
752
  description: connector.description
386
753
  };
387
754
 
388
- if (inCloud) {
755
+ // Use explicit positive checks instead of !inCloud
756
+ if (inCloud || isCloudOnly) {
389
757
  cloudSupportedNew.push(entry);
390
- } else {
758
+ } else if (isSelfHostedOnly) {
391
759
  selfHostedOnlyNew.push(entry);
392
760
  }
393
761
  });
@@ -661,6 +1029,7 @@ function printPRSummary(diffData, binaryAnalysis = null, draftedConnectors = nul
661
1029
 
662
1030
  module.exports = {
663
1031
  generatePRSummary,
1032
+ generateMultiVersionPRSummary,
664
1033
  printPRSummary,
665
1034
  truncateToSentence
666
1035
  };