@redpanda-data/docs-extensions-and-macros 4.15.6 ā 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.
- package/bin/doc-tools.js +2 -0
- package/package.json +1 -1
- package/tools/redpanda-connect/AUTOMATION.md +834 -0
- package/tools/redpanda-connect/generate-rpcn-connector-docs.js +20 -1
- package/tools/redpanda-connect/github-release-utils.js +275 -0
- package/tools/redpanda-connect/helpers/buildConfigYaml.js +13 -8
- package/tools/redpanda-connect/multi-version-summary.js +92 -0
- package/tools/redpanda-connect/parse-csv-connectors.js +1 -0
- package/tools/redpanda-connect/pr-summary-formatter.js +381 -12
- package/tools/redpanda-connect/rpcn-connector-docs-handler.js +462 -66
- package/tools/redpanda-connect/templates/connector.hbs +1 -0
|
@@ -8,6 +8,9 @@ const { getAntoraValue, setAntoraValue } = require('../../cli-utils/antora-utils
|
|
|
8
8
|
const fetchFromGithub = require('../fetch-from-github.js')
|
|
9
9
|
const { generateRpcnConnectorDocs } = require('./generate-rpcn-connector-docs.js')
|
|
10
10
|
const { getRpkConnectVersion, printDeltaReport } = require('./report-delta')
|
|
11
|
+
const { discoverIntermediateReleases } = require('./github-release-utils')
|
|
12
|
+
const parseCSVConnectors = require('./parse-csv-connectors.js')
|
|
13
|
+
const semver = require('semver')
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* Cap description to two sentences
|
|
@@ -484,6 +487,100 @@ function logCollapsed (label, filesArray, maxToShow = 10) {
|
|
|
484
487
|
console.log('')
|
|
485
488
|
}
|
|
486
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Strip augmentation fields from connector data to ensure clean comparisons
|
|
492
|
+
* Removes cloudSupported, requiresCgo, cloudOnly fields and filters out cloud-only connectors
|
|
493
|
+
* @param {object} data - Connector index data
|
|
494
|
+
* @returns {object} Clean connector data without augmentation
|
|
495
|
+
*/
|
|
496
|
+
function stripAugmentationFields(data) {
|
|
497
|
+
const cleanData = JSON.parse(JSON.stringify(data));
|
|
498
|
+
const connectorTypes = ['inputs', 'outputs', 'processors', 'caches', 'rate_limits',
|
|
499
|
+
'buffers', 'metrics', 'scanners', 'tracers', 'config', 'bloblang-methods'];
|
|
500
|
+
|
|
501
|
+
for (const type of connectorTypes) {
|
|
502
|
+
if (Array.isArray(cleanData[type])) {
|
|
503
|
+
// Remove connectors that were added by augmentation (cloudOnly or requiresCgo without OSS data)
|
|
504
|
+
cleanData[type] = cleanData[type].filter(c => {
|
|
505
|
+
// Keep if it's not marked as cloudOnly or requiresCgo
|
|
506
|
+
// OR if it has a config/fields (meaning it came from OSS, not just binary analysis)
|
|
507
|
+
return (!(c.cloudOnly || c.requiresCgo) || c.config || c.fields);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
// Remove augmentation fields
|
|
511
|
+
cleanData[type].forEach(c => {
|
|
512
|
+
delete c.cloudSupported;
|
|
513
|
+
delete c.requiresCgo;
|
|
514
|
+
delete c.cloudOnly;
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return cleanData;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Load or fetch connector data for a specific version
|
|
524
|
+
* @param {string} version - Version to load (e.g., "4.50.0")
|
|
525
|
+
* @param {string} dataDir - Directory where JSON files are stored
|
|
526
|
+
* @param {Object} options - Options for fetching if needed
|
|
527
|
+
* @returns {Promise<Object>} Parsed connector data
|
|
528
|
+
*/
|
|
529
|
+
async function loadConnectorDataForVersion(version, dataDir, options = {}) {
|
|
530
|
+
const dataFile = path.join(dataDir, `connect-${version}.json`);
|
|
531
|
+
|
|
532
|
+
// If file exists, load it
|
|
533
|
+
if (fs.existsSync(dataFile)) {
|
|
534
|
+
console.log(`ā Using existing data file: connect-${version}.json`);
|
|
535
|
+
const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'));
|
|
536
|
+
|
|
537
|
+
// Strip augmentation fields to ensure clean comparisons
|
|
538
|
+
// Augmentation adds CGO/cloud-only components that shouldn't affect version diffs
|
|
539
|
+
const cleanData = stripAugmentationFields(data);
|
|
540
|
+
return cleanData;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// If not, fetch it
|
|
544
|
+
console.log(`š„ Data file not found for ${version}, attempting to fetch...`);
|
|
545
|
+
|
|
546
|
+
try {
|
|
547
|
+
// Try installing that specific version and fetching data
|
|
548
|
+
console.log(` Installing Redpanda Connect version ${version}...`);
|
|
549
|
+
const installResult = spawnSync('rpk', ['connect', 'install', '--connect-version', version, '--force'], {
|
|
550
|
+
stdio: 'pipe'
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
if (installResult.status !== 0) {
|
|
554
|
+
throw new Error(`Failed to install Connect version ${version}`);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Fetch connector list
|
|
558
|
+
const tmpFile = path.join(dataDir, `connect-${version}.tmp.json`);
|
|
559
|
+
const fd = fs.openSync(tmpFile, 'w');
|
|
560
|
+
const listResult = spawnSync('rpk', ['connect', 'list', '--format', 'json-full'], {
|
|
561
|
+
stdio: ['ignore', fd, 'pipe']
|
|
562
|
+
});
|
|
563
|
+
fs.closeSync(fd);
|
|
564
|
+
|
|
565
|
+
if (listResult.status !== 0) {
|
|
566
|
+
throw new Error(`Failed to fetch connector list for version ${version}`);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Parse and validate
|
|
570
|
+
const rawJson = fs.readFileSync(tmpFile, 'utf8');
|
|
571
|
+
const parsed = JSON.parse(rawJson);
|
|
572
|
+
|
|
573
|
+
// Move to final location
|
|
574
|
+
fs.renameSync(tmpFile, dataFile);
|
|
575
|
+
|
|
576
|
+
console.log(`ā Successfully fetched data for version ${version}`);
|
|
577
|
+
return parsed;
|
|
578
|
+
} catch (error) {
|
|
579
|
+
console.error(`ā Failed to fetch data for version ${version}: ${error.message}`);
|
|
580
|
+
throw new Error(`Cannot process version ${version} - data unavailable`);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
487
584
|
/**
|
|
488
585
|
* Main handler for rpcn-connector-docs command
|
|
489
586
|
* @param {Object} options - Command options
|
|
@@ -500,10 +597,16 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
500
597
|
let draftsWritten = 0
|
|
501
598
|
let draftFiles = []
|
|
502
599
|
let needsAugmentation = false
|
|
600
|
+
let csvMetadata = []
|
|
503
601
|
|
|
504
602
|
if (options.fetchConnectors) {
|
|
505
603
|
try {
|
|
506
604
|
if (options.connectVersion) {
|
|
605
|
+
if (!semver.valid(options.connectVersion)) {
|
|
606
|
+
console.error(`Error: Invalid --connect-version format: ${options.connectVersion}`)
|
|
607
|
+
console.error('Expected format: X.Y.Z (e.g., 4.50.0)')
|
|
608
|
+
process.exit(1)
|
|
609
|
+
}
|
|
507
610
|
console.log(`Installing Redpanda Connect version ${options.connectVersion}...`)
|
|
508
611
|
const installResult = spawnSync('rpk', ['connect', 'install', '--connect-version', options.connectVersion, '--force'], {
|
|
509
612
|
stdio: 'inherit'
|
|
@@ -555,6 +658,16 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
555
658
|
console.warn(`Warning: Failed to fetch info.csv: ${csvErr.message}`)
|
|
556
659
|
}
|
|
557
660
|
|
|
661
|
+
// Parse CSV metadata
|
|
662
|
+
try {
|
|
663
|
+
const csvFile = path.join(dataDir, `connect-info-${newVersion}.csv`)
|
|
664
|
+
if (fs.existsSync(csvFile)) {
|
|
665
|
+
csvMetadata = await parseCSVConnectors(csvFile, console)
|
|
666
|
+
}
|
|
667
|
+
} catch (csvParseErr) {
|
|
668
|
+
console.warn(`Warning: Failed to parse info.csv: ${csvParseErr.message}`)
|
|
669
|
+
}
|
|
670
|
+
|
|
558
671
|
// Fetch Bloblang examples
|
|
559
672
|
try {
|
|
560
673
|
console.log(`Fetching Bloblang playground examples for Connect v${newVersion}...`)
|
|
@@ -601,16 +714,206 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
601
714
|
process.exit(1)
|
|
602
715
|
}
|
|
603
716
|
} else {
|
|
604
|
-
const candidates = fs.readdirSync(dataDir)
|
|
717
|
+
const candidates = fs.readdirSync(dataDir)
|
|
718
|
+
.filter(f => /^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/.test(f))
|
|
719
|
+
.map(f => {
|
|
720
|
+
const match = f.match(/^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/)
|
|
721
|
+
return match ? match[1] : null
|
|
722
|
+
})
|
|
723
|
+
.filter(v => v && semver.valid(v))
|
|
724
|
+
|
|
605
725
|
if (candidates.length === 0) {
|
|
606
|
-
console.error('Error: No connect-<version>.json found. Use --fetch-connectors.')
|
|
726
|
+
console.error('Error: No valid connect-<version>.json found. Use --fetch-connectors.')
|
|
727
|
+
process.exit(1)
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
const sortedVersions = semver.rsort(candidates)
|
|
731
|
+
newVersion = sortedVersions[0]
|
|
732
|
+
dataFile = path.join(dataDir, `connect-${newVersion}.json`)
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// ========================================================================
|
|
736
|
+
// Multi-Release Processing: Discover and process intermediate releases
|
|
737
|
+
// ========================================================================
|
|
738
|
+
|
|
739
|
+
const processIntermediate = !options.skipIntermediate && !options.oldData
|
|
740
|
+
let versionsToProcess = []
|
|
741
|
+
let intermediateProcessingResults = []
|
|
742
|
+
|
|
743
|
+
if (processIntermediate) {
|
|
744
|
+
// Determine starting version
|
|
745
|
+
let startVersion = options.fromVersion
|
|
746
|
+
|
|
747
|
+
if (startVersion && !semver.valid(startVersion)) {
|
|
748
|
+
console.error(`Error: Invalid --from-version format: ${startVersion}`)
|
|
749
|
+
console.error('Expected format: X.Y.Z (e.g., 4.50.0)')
|
|
607
750
|
process.exit(1)
|
|
608
751
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
752
|
+
|
|
753
|
+
if (!startVersion) {
|
|
754
|
+
// Try antora.yml first
|
|
755
|
+
startVersion = getAntoraValue('asciidoc.attributes.latest-connect-version')
|
|
756
|
+
|
|
757
|
+
// Fallback: check existing data files
|
|
758
|
+
if (!startVersion) {
|
|
759
|
+
const existingVersions = fs.readdirSync(dataDir)
|
|
760
|
+
.filter(f => /^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/.test(f))
|
|
761
|
+
.filter(f => f !== path.basename(dataFile))
|
|
762
|
+
.map(f => {
|
|
763
|
+
const match = f.match(/^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/)
|
|
764
|
+
return match ? match[1] : null
|
|
765
|
+
})
|
|
766
|
+
.filter(v => v && semver.valid(v))
|
|
767
|
+
|
|
768
|
+
if (existingVersions.length > 0) {
|
|
769
|
+
const sortedVersions = semver.rsort(existingVersions)
|
|
770
|
+
startVersion = sortedVersions[0]
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (startVersion && startVersion !== newVersion) {
|
|
776
|
+
console.log(`\n${'='.repeat(80)}`)
|
|
777
|
+
console.log(`š Checking for intermediate releases between ${startVersion} and ${newVersion}...`)
|
|
778
|
+
console.log('='.repeat(80))
|
|
779
|
+
|
|
780
|
+
try {
|
|
781
|
+
const intermediateReleases = await discoverIntermediateReleases(
|
|
782
|
+
startVersion,
|
|
783
|
+
newVersion,
|
|
784
|
+
{ includePrerelease: false, useCache: true }
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
versionsToProcess = intermediateReleases.map(r => r.version)
|
|
788
|
+
|
|
789
|
+
// Process all version pairs EXCEPT the last one (which will be handled by the main flow)
|
|
790
|
+
if (versionsToProcess.length > 2) {
|
|
791
|
+
console.log(`\nš¦ Processing ${versionsToProcess.length - 2} intermediate release(s)...\n`)
|
|
792
|
+
|
|
793
|
+
for (let i = 0; i < versionsToProcess.length - 2; i++) {
|
|
794
|
+
const fromVer = versionsToProcess[i]
|
|
795
|
+
const toVer = versionsToProcess[i + 1]
|
|
796
|
+
|
|
797
|
+
console.log(`\n${'ā'.repeat(80)}`)
|
|
798
|
+
console.log(`š Processing intermediate release: ${fromVer} ā ${toVer}`)
|
|
799
|
+
console.log('ā'.repeat(80) + '\n')
|
|
800
|
+
|
|
801
|
+
try {
|
|
802
|
+
// Load data for both versions
|
|
803
|
+
console.log(`Loading connector data for ${fromVer}...`)
|
|
804
|
+
const oldData = await loadConnectorDataForVersion(fromVer, dataDir)
|
|
805
|
+
|
|
806
|
+
console.log(`Loading connector data for ${toVer}...`)
|
|
807
|
+
const newData = await loadConnectorDataForVersion(toVer, dataDir)
|
|
808
|
+
|
|
809
|
+
// Determine the appropriate cloud version for this release date
|
|
810
|
+
const releaseInfo = intermediateReleases.find(r => r.version === toVer)
|
|
811
|
+
let cloudVersionForRelease = options.cloudVersion || null
|
|
812
|
+
|
|
813
|
+
if (!options.cloudVersion && releaseInfo && releaseInfo.date) {
|
|
814
|
+
const { findCloudVersionForDate } = require('./github-release-utils')
|
|
815
|
+
cloudVersionForRelease = await findCloudVersionForDate(releaseInfo.date, { useCache: true })
|
|
816
|
+
if (cloudVersionForRelease) {
|
|
817
|
+
console.log(` Using cloud version ${cloudVersionForRelease} (current at ${new Date(releaseInfo.date).toLocaleDateString()})`)
|
|
818
|
+
} else {
|
|
819
|
+
console.log(` No cloud version found for release date, using OSS version ${toVer}`)
|
|
820
|
+
cloudVersionForRelease = toVer
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Run binary analysis for the new version
|
|
825
|
+
console.log(`\nAnalyzing binaries for version ${toVer}...`)
|
|
826
|
+
const { analyzeAllBinaries } = require('./connector-binary-analyzer.js')
|
|
827
|
+
|
|
828
|
+
const analysisOptions = {
|
|
829
|
+
skipCloud: false,
|
|
830
|
+
skipCgo: false,
|
|
831
|
+
cgoVersion: options.cgoVersion || null
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const intermediateAnalysis = await analyzeAllBinaries(
|
|
835
|
+
toVer,
|
|
836
|
+
cloudVersionForRelease,
|
|
837
|
+
dataDir,
|
|
838
|
+
analysisOptions
|
|
839
|
+
)
|
|
840
|
+
|
|
841
|
+
console.log('ā Binary analysis complete:')
|
|
842
|
+
console.log(` ⢠OSS version: ${intermediateAnalysis.ossVersion}`)
|
|
843
|
+
if (intermediateAnalysis.cloudVersion) {
|
|
844
|
+
console.log(` ⢠Cloud version: ${intermediateAnalysis.cloudVersion}`)
|
|
845
|
+
}
|
|
846
|
+
if (intermediateAnalysis.comparison) {
|
|
847
|
+
console.log(` ⢠Connectors in cloud: ${intermediateAnalysis.comparison.inCloud.length}`)
|
|
848
|
+
console.log(` ⢠Self-hosted only: ${intermediateAnalysis.comparison.notInCloud.length}`)
|
|
849
|
+
if (intermediateAnalysis.comparison.cloudOnly) {
|
|
850
|
+
console.log(` ⢠Cloud-only: ${intermediateAnalysis.comparison.cloudOnly.length}`)
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Generate diff
|
|
855
|
+
console.log(`\nGenerating diff: ${fromVer} ā ${toVer}...`)
|
|
856
|
+
const { generateConnectorDiffJson } = require('./report-delta.js')
|
|
857
|
+
|
|
858
|
+
const diffData = generateConnectorDiffJson(
|
|
859
|
+
oldData,
|
|
860
|
+
newData,
|
|
861
|
+
{
|
|
862
|
+
oldVersion: fromVer,
|
|
863
|
+
newVersion: toVer,
|
|
864
|
+
timestamp,
|
|
865
|
+
binaryAnalysis: intermediateAnalysis
|
|
866
|
+
}
|
|
867
|
+
)
|
|
868
|
+
|
|
869
|
+
// Save diff
|
|
870
|
+
const diffPath = path.join(dataDir, `connect-diff-${fromVer}_to_${toVer}.json`)
|
|
871
|
+
fs.writeFileSync(diffPath, JSON.stringify(diffData, null, 2), 'utf8')
|
|
872
|
+
console.log(`ā Diff saved: ${path.basename(diffPath)}`)
|
|
873
|
+
|
|
874
|
+
// Update what's-new if requested
|
|
875
|
+
if (options.updateWhatsNew) {
|
|
876
|
+
console.log(`Updating what's-new.adoc for ${toVer}...`)
|
|
877
|
+
updateWhatsNew({ dataDir, oldVersion: fromVer, newVersion: toVer, binaryAnalysis: intermediateAnalysis })
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
intermediateProcessingResults.push({
|
|
881
|
+
fromVersion: fromVer,
|
|
882
|
+
toVersion: toVer,
|
|
883
|
+
diffPath,
|
|
884
|
+
success: true
|
|
885
|
+
})
|
|
886
|
+
|
|
887
|
+
console.log(`ā
Completed processing: ${fromVer} ā ${toVer}\n`)
|
|
888
|
+
} catch (err) {
|
|
889
|
+
console.error(`ā Error processing ${fromVer} ā ${toVer}: ${err.message}`)
|
|
890
|
+
console.error(' Continuing with next version...\n')
|
|
891
|
+
|
|
892
|
+
intermediateProcessingResults.push({
|
|
893
|
+
fromVersion: fromVer,
|
|
894
|
+
toVersion: toVer,
|
|
895
|
+
error: err.message,
|
|
896
|
+
success: false
|
|
897
|
+
})
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
console.log(`\n${'='.repeat(80)}`)
|
|
902
|
+
console.log(`ā Intermediate release processing complete`)
|
|
903
|
+
console.log(` Processed: ${intermediateProcessingResults.filter(r => r.success).length}/${intermediateProcessingResults.length} version pairs`)
|
|
904
|
+
console.log('='.repeat(80) + '\n')
|
|
905
|
+
}
|
|
906
|
+
} catch (err) {
|
|
907
|
+
console.warn(`\nā ļø Warning: Failed to discover intermediate releases: ${err.message}`)
|
|
908
|
+
console.warn(' Falling back to single version comparison...\n')
|
|
909
|
+
}
|
|
910
|
+
}
|
|
612
911
|
}
|
|
613
912
|
|
|
913
|
+
// ========================================================================
|
|
914
|
+
// Main Processing: Handle the latest version (final iteration)
|
|
915
|
+
// ========================================================================
|
|
916
|
+
|
|
614
917
|
console.log('Generating connector partials...')
|
|
615
918
|
let partialsWritten, partialFiles
|
|
616
919
|
|
|
@@ -624,7 +927,8 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
624
927
|
templateExamples: options.templateExamples,
|
|
625
928
|
templateBloblang: options.templateBloblang,
|
|
626
929
|
writeFullDrafts: false,
|
|
627
|
-
includeBloblang: !!options.includeBloblang
|
|
930
|
+
includeBloblang: !!options.includeBloblang,
|
|
931
|
+
csvMetadata
|
|
628
932
|
})
|
|
629
933
|
partialsWritten = result.partialsWritten
|
|
630
934
|
partialFiles = result.partialFiles
|
|
@@ -636,52 +940,49 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
636
940
|
let oldIndex = {}
|
|
637
941
|
let oldVersion = null
|
|
638
942
|
if (options.oldData && fs.existsSync(options.oldData)) {
|
|
639
|
-
|
|
943
|
+
// Strip augmentation fields to ensure clean comparisons
|
|
944
|
+
oldIndex = stripAugmentationFields(JSON.parse(fs.readFileSync(options.oldData, 'utf8')))
|
|
640
945
|
const m = options.oldData.match(/connect-([\d.]+)\.json$/)
|
|
641
946
|
if (m) oldVersion = m[1]
|
|
642
947
|
} else {
|
|
643
|
-
const
|
|
644
|
-
.filter(f => /^connect
|
|
948
|
+
const existingVersions = fs.readdirSync(dataDir)
|
|
949
|
+
.filter(f => /^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/.test(f))
|
|
645
950
|
.filter(f => f !== path.basename(dataFile))
|
|
646
|
-
.
|
|
951
|
+
.map(f => {
|
|
952
|
+
const match = f.match(/^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/)
|
|
953
|
+
return match ? match[1] : null
|
|
954
|
+
})
|
|
955
|
+
.filter(v => v && semver.valid(v))
|
|
647
956
|
|
|
648
|
-
if (
|
|
649
|
-
const
|
|
650
|
-
oldVersion =
|
|
957
|
+
if (existingVersions.length > 0) {
|
|
958
|
+
const sortedVersions = semver.rsort(existingVersions)
|
|
959
|
+
oldVersion = sortedVersions[0]
|
|
960
|
+
const oldFile = `connect-${oldVersion}.json`
|
|
651
961
|
const oldPath = path.join(dataDir, oldFile)
|
|
652
|
-
|
|
962
|
+
// Strip augmentation fields to ensure clean comparisons
|
|
963
|
+
oldIndex = stripAugmentationFields(JSON.parse(fs.readFileSync(oldPath, 'utf8')))
|
|
653
964
|
console.log(`š Using old version data: ${oldFile}`)
|
|
654
965
|
} else {
|
|
655
966
|
oldVersion = getAntoraValue('asciidoc.attributes.latest-connect-version')
|
|
656
967
|
if (oldVersion) {
|
|
657
968
|
const oldPath = path.join(dataDir, `connect-${oldVersion}.json`)
|
|
658
969
|
if (fs.existsSync(oldPath)) {
|
|
659
|
-
|
|
970
|
+
// Strip augmentation fields to ensure clean comparisons
|
|
971
|
+
oldIndex = stripAugmentationFields(JSON.parse(fs.readFileSync(oldPath, 'utf8')))
|
|
660
972
|
}
|
|
661
973
|
}
|
|
662
974
|
}
|
|
663
975
|
}
|
|
664
976
|
|
|
665
|
-
|
|
977
|
+
// Load and strip augmentation fields for clean comparisons
|
|
978
|
+
let newIndex = stripAugmentationFields(JSON.parse(fs.readFileSync(dataFile, 'utf8')))
|
|
666
979
|
|
|
667
980
|
// Save a clean copy of OSS data for binary analysis (before augmentation)
|
|
668
981
|
// This ensures the binary analyzer compares actual binaries, not augmented data
|
|
669
982
|
const cleanOssDataPath = path.join(dataDir, `._connect-${newVersion}-clean.json`)
|
|
670
983
|
|
|
671
|
-
//
|
|
984
|
+
// Use the already-stripped newIndex for clean data
|
|
672
985
|
const cleanData = JSON.parse(JSON.stringify(newIndex))
|
|
673
|
-
const connectorTypes = ['inputs', 'outputs', 'processors', 'caches', 'rate_limits', 'buffers', 'metrics', 'scanners', 'tracers']
|
|
674
|
-
|
|
675
|
-
for (const type of connectorTypes) {
|
|
676
|
-
if (Array.isArray(cleanData[type])) {
|
|
677
|
-
cleanData[type] = cleanData[type].filter(c => !c.cloudOnly) // Remove cloud-only connectors added by augmentation
|
|
678
|
-
cleanData[type].forEach(c => {
|
|
679
|
-
delete c.cloudSupported
|
|
680
|
-
delete c.requiresCgo
|
|
681
|
-
delete c.cloudOnly
|
|
682
|
-
})
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
986
|
|
|
686
987
|
fs.writeFileSync(cleanOssDataPath, JSON.stringify(cleanData, null, 2), 'utf8')
|
|
687
988
|
|
|
@@ -705,11 +1006,18 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
705
1006
|
const attachmentsRoot = path.resolve(process.cwd(), 'modules/components/attachments')
|
|
706
1007
|
fs.mkdirSync(attachmentsRoot, { recursive: true })
|
|
707
1008
|
|
|
708
|
-
const
|
|
709
|
-
.filter(f => /^connect
|
|
710
|
-
.
|
|
1009
|
+
const existingVersions = fs.readdirSync(attachmentsRoot)
|
|
1010
|
+
.filter(f => /^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/.test(f))
|
|
1011
|
+
.map(f => {
|
|
1012
|
+
const match = f.match(/^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/)
|
|
1013
|
+
return match ? match[1] : null
|
|
1014
|
+
})
|
|
1015
|
+
.filter(v => v && semver.valid(v))
|
|
1016
|
+
|
|
1017
|
+
const sortedVersions = semver.sort(existingVersions) // ascending order
|
|
711
1018
|
|
|
712
|
-
for (const
|
|
1019
|
+
for (const version of sortedVersions) {
|
|
1020
|
+
const oldFile = `connect-${version}.json`
|
|
713
1021
|
const oldFilePath = path.join(attachmentsRoot, oldFile)
|
|
714
1022
|
fs.unlinkSync(oldFilePath)
|
|
715
1023
|
console.log(`š§¹ Deleted old version: ${oldFile}`)
|
|
@@ -767,15 +1075,15 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
767
1075
|
}
|
|
768
1076
|
}
|
|
769
1077
|
|
|
1078
|
+
// Always use clean OSS data for comparison
|
|
1079
|
+
// Temporarily rename the file so the analyzer finds it
|
|
1080
|
+
const expectedPath = path.join(dataDir, `connect-${newVersion}.json`)
|
|
1081
|
+
let tempRenamed = false
|
|
1082
|
+
|
|
770
1083
|
try {
|
|
771
1084
|
console.log('\nAnalyzing connector binaries...')
|
|
772
1085
|
const { analyzeAllBinaries } = require('./connector-binary-analyzer.js')
|
|
773
1086
|
|
|
774
|
-
// Always use clean OSS data for comparison
|
|
775
|
-
// Temporarily rename the file so the analyzer finds it
|
|
776
|
-
const expectedPath = path.join(dataDir, `connect-${newVersion}.json`)
|
|
777
|
-
let tempRenamed = false
|
|
778
|
-
|
|
779
1087
|
if (fs.existsSync(cleanOssDataPath)) {
|
|
780
1088
|
if (fs.existsSync(expectedPath)) {
|
|
781
1089
|
fs.renameSync(expectedPath, path.join(dataDir, `._connect-${newVersion}-augmented.json.tmp`))
|
|
@@ -797,13 +1105,6 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
797
1105
|
analysisOptions
|
|
798
1106
|
)
|
|
799
1107
|
|
|
800
|
-
// Restore the augmented file
|
|
801
|
-
if (tempRenamed) {
|
|
802
|
-
const expectedPath = path.join(dataDir, `connect-${newVersion}.json`)
|
|
803
|
-
fs.unlinkSync(expectedPath)
|
|
804
|
-
fs.renameSync(path.join(dataDir, `._connect-${newVersion}-augmented.json.tmp`), expectedPath)
|
|
805
|
-
}
|
|
806
|
-
|
|
807
1108
|
console.log('Done: Binary analysis complete:')
|
|
808
1109
|
console.log(` ⢠OSS version: ${binaryAnalysis.ossVersion}`)
|
|
809
1110
|
|
|
@@ -825,6 +1126,17 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
825
1126
|
} catch (err) {
|
|
826
1127
|
console.error(`Warning: Binary analysis failed: ${err.message}`)
|
|
827
1128
|
console.error(' Continuing without binary analysis data...')
|
|
1129
|
+
} finally {
|
|
1130
|
+
// Restore the augmented file regardless of success or failure
|
|
1131
|
+
if (tempRenamed) {
|
|
1132
|
+
if (fs.existsSync(expectedPath)) {
|
|
1133
|
+
fs.unlinkSync(expectedPath)
|
|
1134
|
+
}
|
|
1135
|
+
const tmpPath = path.join(dataDir, `._connect-${newVersion}-augmented.json.tmp`)
|
|
1136
|
+
if (fs.existsSync(tmpPath)) {
|
|
1137
|
+
fs.renameSync(tmpPath, expectedPath)
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
828
1140
|
}
|
|
829
1141
|
|
|
830
1142
|
// Augment data file
|
|
@@ -905,20 +1217,42 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
905
1217
|
console.log(` ⢠Added ${addedCloudOnlyCount} cloud-only connectors to data file`)
|
|
906
1218
|
}
|
|
907
1219
|
|
|
908
|
-
// Keep only
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
.
|
|
1220
|
+
// Keep only the latest version (delete all older versions)
|
|
1221
|
+
// BUT preserve any files from intermediate processing during this run
|
|
1222
|
+
const dataVersions = fs.readdirSync(dataDir)
|
|
1223
|
+
.filter(f => /^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/.test(f))
|
|
1224
|
+
.map(f => {
|
|
1225
|
+
const match = f.match(/^connect-(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?)\.json$/)
|
|
1226
|
+
return match ? match[1] : null
|
|
1227
|
+
})
|
|
1228
|
+
.filter(v => v && semver.valid(v))
|
|
1229
|
+
|
|
1230
|
+
// Build list of versions we need to keep for this run
|
|
1231
|
+
const versionsToKeep = new Set([newVersion]); // Always keep the latest
|
|
1232
|
+
if (intermediateProcessingResults.length > 0) {
|
|
1233
|
+
// Keep intermediate versions from this run
|
|
1234
|
+
intermediateProcessingResults.forEach(r => {
|
|
1235
|
+
versionsToKeep.add(r.fromVersion);
|
|
1236
|
+
versionsToKeep.add(r.toVersion);
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
if (oldVersion) {
|
|
1240
|
+
versionsToKeep.add(oldVersion); // Keep old version for diff
|
|
1241
|
+
}
|
|
912
1242
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1243
|
+
// Delete only files that are NOT needed for this run
|
|
1244
|
+
for (const version of dataVersions) {
|
|
1245
|
+
if (!versionsToKeep.has(version)) {
|
|
1246
|
+
const dataFile = `connect-${version}.json`
|
|
1247
|
+
const dataPath = path.join(dataDir, dataFile);
|
|
1248
|
+
fs.unlinkSync(dataPath);
|
|
1249
|
+
console.log(`š§¹ Deleted old version from docs-data: ${dataFile}`);
|
|
1250
|
+
}
|
|
918
1251
|
}
|
|
919
1252
|
|
|
920
|
-
//
|
|
921
|
-
|
|
1253
|
+
// NOTE: We do NOT reload newIndex after augmentation
|
|
1254
|
+
// Diff generation should use clean OSS data to avoid false positives from CGO/cloud-only components
|
|
1255
|
+
// The augmented data is saved to disk but not used for version comparisons
|
|
922
1256
|
} catch (err) {
|
|
923
1257
|
console.error(`Warning: Failed to augment data file: ${err.message}`)
|
|
924
1258
|
}
|
|
@@ -1038,21 +1372,40 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1038
1372
|
console.log(` ⢠Includes binary analysis: OSS ${diffJson.binaryAnalysis.versions.oss}, Cloud ${diffJson.binaryAnalysis.versions.cloud || 'N/A'}, cgo ${diffJson.binaryAnalysis.versions.cgo || 'N/A'}`)
|
|
1039
1373
|
}
|
|
1040
1374
|
|
|
1041
|
-
// Cleanup
|
|
1375
|
+
// Cleanup only individual diff files from THIS run (not master diff or diffs from intermediate processing)
|
|
1376
|
+
// We keep intermediate diffs to build the master diff at the end
|
|
1042
1377
|
try {
|
|
1378
|
+
const currentRunDiffs = new Set();
|
|
1379
|
+
|
|
1380
|
+
// Collect diffs from this run
|
|
1381
|
+
if (intermediateProcessingResults.length > 0) {
|
|
1382
|
+
intermediateProcessingResults.forEach(r => {
|
|
1383
|
+
if (r.diffPath) {
|
|
1384
|
+
currentRunDiffs.add(path.basename(r.diffPath));
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
currentRunDiffs.add(path.basename(diffPath)); // Current final diff
|
|
1389
|
+
|
|
1390
|
+
// Find old diff files (not from this run, not master-diff)
|
|
1043
1391
|
const oldDiffFiles = fs.readdirSync(dataDir)
|
|
1044
|
-
.filter(f =>
|
|
1392
|
+
.filter(f =>
|
|
1393
|
+
f.startsWith('connect-diff-') &&
|
|
1394
|
+
f.endsWith('.json') &&
|
|
1395
|
+
!f.startsWith('connect-diff-master-') &&
|
|
1396
|
+
!currentRunDiffs.has(f)
|
|
1397
|
+
);
|
|
1045
1398
|
|
|
1046
1399
|
if (oldDiffFiles.length > 0) {
|
|
1047
|
-
console.log(`š§¹ Cleaning up ${oldDiffFiles.length} old diff
|
|
1400
|
+
console.log(`š§¹ Cleaning up ${oldDiffFiles.length} old diff file(s) from previous runs...`);
|
|
1048
1401
|
oldDiffFiles.forEach(f => {
|
|
1049
|
-
const oldDiffPath = path.join(dataDir, f)
|
|
1050
|
-
fs.unlinkSync(oldDiffPath)
|
|
1051
|
-
console.log(` ⢠Deleted: ${f}`)
|
|
1052
|
-
})
|
|
1402
|
+
const oldDiffPath = path.join(dataDir, f);
|
|
1403
|
+
fs.unlinkSync(oldDiffPath);
|
|
1404
|
+
console.log(` ⢠Deleted: ${f}`);
|
|
1405
|
+
});
|
|
1053
1406
|
}
|
|
1054
1407
|
} catch (err) {
|
|
1055
|
-
console.warn(`Warning: Failed to clean up old diff files: ${err.message}`)
|
|
1408
|
+
console.warn(`Warning: Failed to clean up old diff files: ${err.message}`);
|
|
1056
1409
|
}
|
|
1057
1410
|
}
|
|
1058
1411
|
|
|
@@ -1362,7 +1715,8 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1362
1715
|
templateIntro: options.templateIntro,
|
|
1363
1716
|
writeFullDrafts: true,
|
|
1364
1717
|
cgoOnly: binaryAnalysis?.cgoOnly || [],
|
|
1365
|
-
cloudOnly: binaryAnalysis?.comparison?.cloudOnly || []
|
|
1718
|
+
cloudOnly: binaryAnalysis?.comparison?.cloudOnly || [],
|
|
1719
|
+
csvMetadata
|
|
1366
1720
|
})
|
|
1367
1721
|
|
|
1368
1722
|
fs.unlinkSync(tempDataPath)
|
|
@@ -1399,14 +1753,40 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1399
1753
|
}
|
|
1400
1754
|
}
|
|
1401
1755
|
|
|
1756
|
+
// Create master diff if we processed intermediate releases
|
|
1757
|
+
let masterDiff = null
|
|
1758
|
+
if (intermediateProcessingResults.length > 0) {
|
|
1759
|
+
try {
|
|
1760
|
+
const { createMasterDiff } = require('./multi-version-summary.js')
|
|
1761
|
+
const masterDiffPath = path.join(dataDir, `connect-diff-master-${intermediateProcessingResults[0].fromVersion}_to_${newVersion}.json`)
|
|
1762
|
+
const finalDiffPath = path.join(dataDir, `connect-diff-${oldVersion}_to_${newVersion}.json`)
|
|
1763
|
+
masterDiff = createMasterDiff(intermediateProcessingResults, finalDiffPath, masterDiffPath)
|
|
1764
|
+
} catch (err) {
|
|
1765
|
+
console.error(`Warning: Failed to create master diff: ${err.message}`)
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1402
1769
|
// Generate PR summary
|
|
1403
1770
|
try {
|
|
1404
1771
|
const { printPRSummary } = require('./pr-summary-formatter.js')
|
|
1405
|
-
|
|
1772
|
+
// Use master diff if available, otherwise use single diff
|
|
1773
|
+
printPRSummary(masterDiff || diffJson, binaryAnalysis, draftFiles, masterDiff ? true : false)
|
|
1406
1774
|
} catch (err) {
|
|
1407
1775
|
console.error(`Warning: Failed to generate PR summary: ${err.message}`)
|
|
1408
1776
|
}
|
|
1409
1777
|
|
|
1778
|
+
// Check for failures in intermediate processing before updating Antora version
|
|
1779
|
+
if (intermediateProcessingResults.length > 0) {
|
|
1780
|
+
const failures = intermediateProcessingResults.filter(r => !r.success)
|
|
1781
|
+
if (failures.length > 0) {
|
|
1782
|
+
console.error(`\nā Cannot update Antora version: ${failures.length} intermediate release(s) failed to process`)
|
|
1783
|
+
failures.forEach(f => {
|
|
1784
|
+
console.error(` ⢠${f.fromVersion} ā ${f.toVersion}: ${f.error}`)
|
|
1785
|
+
})
|
|
1786
|
+
process.exit(1)
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1410
1790
|
const wrote = setAntoraValue('asciidoc.attributes.latest-connect-version', newVersion)
|
|
1411
1791
|
if (wrote) {
|
|
1412
1792
|
console.log(`Done: Updated Antora version: ${newVersion}`)
|
|
@@ -1438,6 +1818,22 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1438
1818
|
console.log('\nš Summary:')
|
|
1439
1819
|
console.log(` ⢠Run time: ${timestamp}`)
|
|
1440
1820
|
console.log(` ⢠Version used: ${newVersion}`)
|
|
1821
|
+
|
|
1822
|
+
if (intermediateProcessingResults.length > 0) {
|
|
1823
|
+
const successCount = intermediateProcessingResults.filter(r => r.success).length
|
|
1824
|
+
console.log(` ⢠Intermediate releases processed: ${successCount}/${intermediateProcessingResults.length}`)
|
|
1825
|
+
|
|
1826
|
+
if (successCount < intermediateProcessingResults.length) {
|
|
1827
|
+
console.log(' ā ļø Some intermediate releases failed:')
|
|
1828
|
+
intermediateProcessingResults.filter(r => !r.success).forEach(r => {
|
|
1829
|
+
console.log(` - ${r.fromVersion} ā ${r.toVersion}: ${r.error}`)
|
|
1830
|
+
})
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// Note: Version cleanup is handled earlier in the augmentation phase (versionsToKeep logic)
|
|
1835
|
+
// This preserves intermediate versions needed for diff generation while removing unneeded files
|
|
1836
|
+
|
|
1441
1837
|
process.exit(0)
|
|
1442
1838
|
}
|
|
1443
1839
|
|