From 9eacbab93f755c46daee592ae15bd9cbb88c051e Mon Sep 17 00:00:00 2001 From: Leah Bush Date: Mon, 5 May 2025 14:17:58 -0500 Subject: [PATCH] feat: add nav-data support to compare-api-responses script --- app/utils/productConfig.mjs | 10 +- scripts/compare-api-responses/index.mjs | 197 +++++++++++++----------- 2 files changed, 118 insertions(+), 89 deletions(-) diff --git a/app/utils/productConfig.mjs b/app/utils/productConfig.mjs index c59726c654..1224efde4a 100644 --- a/app/utils/productConfig.mjs +++ b/app/utils/productConfig.mjs @@ -54,12 +54,13 @@ import semver from 'semver' * basePaths: paths where content may exist on the website for the product, used for rewrite-internal-links script. Not required for all products * contentDir: directory where content lives in the product repo, used for migration script and all-docs-paths api route * dataDir: directory where nav data lives in the product repo, used for migration script + * navDataPath: path used as a prefix for the nav data in the product repo, used for api compare tool * productSlug: product that is associated with the product repo, used for all-docs-paths api route * semverCoerce: a function that coerces a version string into a semver version object, used for migration scripts * versionedDocs: a boolean that indicates whether the product has versioned docs * websiteDir: directory where all docs content folders live in the product repo, used for migration script * - * @type Record + * @type Record */ export const PRODUCT_CONFIG = { @@ -251,6 +252,7 @@ export const PRODUCT_CONFIG = { basePaths: ['cdktf'], contentDir: 'docs', dataDir: 'data', + navDataPath: 'cdktf', productSlug: 'terraform', semverCoerce: semver.coerce, versionedDocs: true, @@ -270,6 +272,7 @@ export const PRODUCT_CONFIG = { basePaths: ['cloud-docs/agents'], contentDir: 'docs', dataDir: 'data', + navDataPath: 'cloud-docs-agents', productSlug: 'terraform', semverCoerce: semver.coerce, versionedDocs: true, @@ -313,6 +316,7 @@ export const PRODUCT_CONFIG = { basePaths: ['plugin/framework'], contentDir: 'docs', dataDir: 'data', + navDataPath: 'plugin-framework', productSlug: 'terraform', semverCoerce: semver.coerce, versionedDocs: true, @@ -326,6 +330,7 @@ export const PRODUCT_CONFIG = { basePaths: ['plugin/log'], contentDir: 'docs', dataDir: 'data', + navDataPath: 'plugin-log', productSlug: 'terraform', semverCoerce: semver.coerce, versionedDocs: true, @@ -347,6 +352,7 @@ export const PRODUCT_CONFIG = { basePaths: ['plugin/mux'], contentDir: 'docs', dataDir: 'data', + navDataPath: 'plugin-mux', productSlug: 'terraform', semverCoerce: semver.coerce, versionedDocs: true, @@ -368,6 +374,7 @@ export const PRODUCT_CONFIG = { basePaths: ['plugin/sdkv2'], contentDir: 'docs', dataDir: 'data', + navDataPath: 'plugin-sdkv2', productSlug: 'terraform', semverCoerce: semver.coerce, versionedDocs: true, @@ -388,6 +395,7 @@ export const PRODUCT_CONFIG = { basePaths: ['plugin/testing'], contentDir: 'docs', dataDir: 'data', + navDataPath: 'plugin-testing', productSlug: 'terraform', semverCoerce: semver.coerce, versionedDocs: true, diff --git a/scripts/compare-api-responses/index.mjs b/scripts/compare-api-responses/index.mjs index 73ebb3ba95..a5bc4ec74b 100644 --- a/scripts/compare-api-responses/index.mjs +++ b/scripts/compare-api-responses/index.mjs @@ -90,40 +90,9 @@ function saveTestOutputIfSelected(outputString, newApiURL) { } } -async function fetchApiTypeVersionAndNav(options, product, versionMetadata) { - let newApiURL - let oldApiURL - - if (options.api === 'version-metadata') { - newApiURL = `${options.newApiUrl}/api/content/${product}/version-metadata` - oldApiURL = `${options.oldApiUrl}/api/content/${product}/version-metadata?partial=true` - } else if (options.api === 'nav-data') { - newApiURL = `${options.newApiUrl}/api/content/${product}/nav-data/${versionMetadata.version}` - oldApiURL = `${options.oldApiUrl}/api/content/${product}/nav-data/${versionMetadata.version}` - } - - const newApiResponse = await fetch(newApiURL) - const oldApiResponse = await fetch(oldApiURL) - - const newApiData = await newApiResponse.json() - const oldApiData = await oldApiResponse.json() - - const newApiDataStrings = JSON.stringify( - sortObjectByKeys(newApiData.result), - null, - 2, - ).split('\n') - const oldApiDataStrings = JSON.stringify( - sortObjectByKeys(oldApiData.result), - null, - 2, - ).split('\n') - - return { newApiDataStrings, oldApiDataStrings, newApiURL } -} - const testsPassed = [] const testsFailed = [] +const totalTests = [] for (const [product, versions] of Object.entries(versionMetadata)) { if (options.product && options.product !== product) { continue @@ -134,9 +103,26 @@ for (const [product, versions] of Object.entries(versionMetadata)) { continue } - if (options.api === 'version-metadata' || options.api === 'nav-data') { - const { newApiDataStrings, oldApiDataStrings, newApiURL } = - await fetchApiTypeVersionAndNav(options, product, versionMetadata) + if (options.api === 'version-metadata') { + const newApiURL = `${options.newApiUrl}/api/content/${product}/version-metadata` + const oldApiURL = `${options.oldApiUrl}/api/content/${product}/version-metadata?partial=true` + + const newApiResponse = await fetch(newApiURL) + const oldApiResponse = await fetch(oldApiURL) + + const newApiData = await newApiResponse.json() + const oldApiData = await oldApiResponse.json() + + const newApiDataStrings = JSON.stringify( + sortObjectByKeys(newApiData.result), + null, + 2, + ).split('\n') + const oldApiDataStrings = JSON.stringify( + sortObjectByKeys(oldApiData.result), + null, + 2, + ).split('\n') const diffOptions = { contextLines: 1, @@ -154,6 +140,39 @@ for (const [product, versions] of Object.entries(versionMetadata)) { saveTestOutputIfSelected(outputString, newApiURL) break + } else if (options.api === 'nav-data') { + const newApiURL = `${options.newApiUrl}/api/content/${product}/nav-data/${versionMetadata.version}/${contentDirMap[product].navDataPath}` + const oldApiURL = `${options.oldApiUrl}/api/content/${product}/nav-data/${versionMetadata.version}/${contentDirMap[product].navDataPath}` + + const newApiResponse = await fetch(newApiURL) + const oldApiResponse = await fetch(oldApiURL) + + const newApiData = await newApiResponse.json() + const oldApiData = await oldApiResponse.json() + + const newDataToCompare = newApiData.result?.navData + const oldDataToCompare = oldApiData.result?.navData + + const diffOptions = { + contextLines: 1, + expand: false, + } + + const difference = diff(oldDataToCompare, newDataToCompare, diffOptions) + + const outputString = `Testing API URL:\n${newApiURL}\n${difference}` + console.log(outputString) + + if (difference.includes('Compared values have no visual difference.')) { + testsPassed.push(newApiURL) + console.log('✅ No visual difference found.\n') + } else { + testsFailed.push(newApiURL) + console.log(`${difference}\n`) + } + + totalTests.push(newApiURL) + saveTestOutputIfSelected(outputString, newApiURL) } else if (options.api === 'content') { const productContentDir = contentDirMap[product].contentDir const isVersionedProduct = contentDirMap[product].versionedDocs @@ -246,73 +265,75 @@ for (const [product, versions] of Object.entries(versionMetadata)) { console.log(`${difference}\n`) } + totalTests.push(i + 1) saveTestOutputIfSelected(outputString, newApiURL) } - } else if (options.api === 'content-versions') { - const newApiURL = new URL(options.newApiUrl) - const oldApiURL = new URL(options.oldApiUrl) - - let newApiResponse, oldApiResponse - try { - newApiResponse = await fetch(newApiURL) - oldApiResponse = await fetch(oldApiURL) - - if (!newApiResponse.ok) { - console.log( - `Error fetching API response:\n${newApiURL}\n${newApiResponse.statusText}`, - ) - continue - } - if (!oldApiResponse.ok) { - console.log( - `Error fetching API response:\n${oldApiURL}\n${oldApiResponse.statusText}`, - ) - continue - } - } catch (error) { - console.log(`Error fetching API response\n${error}`) - continue - } + } + } +} - let newApiData, oldApiData - try { - newApiData = await newApiResponse.json() - oldApiData = await oldApiResponse.json() - } catch (error) { - console.log(`Error decoding JSON\n${error}`) - continue - } +if (options.api === 'content-versions') { + const newApiURL = new URL(options.newApiUrl) + const oldApiURL = new URL(options.oldApiUrl) + + let newApiResponse, oldApiResponse + try { + newApiResponse = await fetch(newApiURL) + oldApiResponse = await fetch(oldApiURL) - // sort the versions to normalize the responses because the APIs return content versions in different orders - const newSortedVersions = newApiData.versions.sort() - const oldSortedVersions = oldApiData.versions.sort() + if (!newApiResponse.ok) { + console.log( + `Error fetching API response:\n${newApiURL}\n${newApiResponse.statusText}`, + ) + } + if (!oldApiResponse.ok) { + console.log( + `Error fetching API response:\n${oldApiURL}\n${oldApiResponse.statusText}`, + ) + } + } catch (error) { + console.log(`Error fetching API response\n${error}`) + } - const difference = diff(newSortedVersions, oldSortedVersions) + let newApiData, oldApiData + try { + newApiData = await newApiResponse.json() + oldApiData = await oldApiResponse.json() + } catch (error) { + console.log(`Error decoding JSON\n${error}`) + } - const outputString = `Testing API URL\n${difference}` - console.log(outputString) + // sort the versions to normalize the responses because the APIs return content versions in different orders + const newSortedVersions = newApiData.versions.sort() + const oldSortedVersions = oldApiData.versions.sort() - if (difference.includes('Compared values have no visual difference.')) { - testsPassed.push(newApiURL) - console.log('✅ No visual difference found.\n') - } else { - testsFailed.push(newApiURL) - console.log(`${difference}\n`) - } + const difference = diff(newSortedVersions, oldSortedVersions) - saveTestOutputIfSelected(outputString, newApiURL) - } + const outputString = `Testing API URL\n${difference}` + console.log(outputString) - break + if (difference.includes('Compared values have no visual difference.')) { + testsPassed.push(newApiURL) + console.log('✅ No visual difference found.\n') + } else { + testsFailed.push(newApiURL) + console.log(`${difference}\n`) } - break + totalTests.push(newApiURL) + saveTestOutputIfSelected(outputString, newApiURL) } -if (options.api === 'content') { +if ( + options.api === 'content' || + options.api === 'nav-data' || + options.api === 'content-versions' +) { console.log( - `Tests passed: ${testsPassed.length} of ${options.numOfTests} ${ - testsPassed.length === options.numOfTests ? '🎉' : '' + `Tests passed: ${testsPassed.length} of ${options.numOfTests ?? totalTests.length} ${ + testsPassed.length === (options.numOfTests ?? totalTests.length) + ? '🎉' + : '' }`, ) }