UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

214 lines (213 loc) 9.14 kB
import path from 'path'; import AdmZip from 'adm-zip'; import { showError, showInfo } from '../common/message-helper.js'; import { readMultiYaml } from '../common/yaml-helper.js'; import { readFile } from '../common/fs-helper.js'; import { searchAssetByKind } from './asset-searchByKind-helper.js'; import { getAllProjectNames } from './root-dir-helper.js'; import Table from 'cli-table3'; import { INVALID_OR_EMPTY_DEPLOYMENT_RESPONSES, ADDING_ENDPOINT_FILE_FAILED, TESTING_LIST_ALL_PROJECTS, CHECKING_ALL_PROJECTS, IDENTIFIED_PROJECTS, FAILED_TO_BUILD_TEST_ASSETS, ERROR_IN_COMBINING_TEST_ASSET, LINE, TEST_STARTED, PROCESS_ENDPOINT_RESPONSE, PROCESS_GATEWAY_RESPONSE, PROCESS_ENDPOINT_RESPONSE_SUCCESS, ENDPOINT_TEST, COMBINING_TEST_ZIP, COMBINING_TEST_ZIP_SUCCESS, BUILDING_TEST, BUILDING_TEST_SUCCESS, JSON_FILE_MISSING, UPDATE_ENDPOINT_FAILED, ASSETS_BUILD_FAILED, APIENDPOINTS, } from '../../constants/message-constants.js'; import { ENDPOINT_FILE, TEST } from '../../constants/app-constants.js'; import { executeBuildTestAssets } from '../../testers/project/projects-asset-testers.js'; import { DebugManager } from '../../debug/debug-manager.js'; import { KindEnums } from '@apic/api-model/common/StudioEnums.js'; import { buildAssets } from '../../actions/helpers/build-action-helper.js'; import { executeDeployment } from '../../deployers/project/projects-deployer.js'; const constructJSON = (jsonObject, key, value) => { jsonObject[key] = value; }; export const constructKey = (response) => { return `${response.namespace}:${response.assetName}:${response.version}`; }; export const createJSONBuffer = (apiGatewayEndpoints) => { return Buffer.from(JSON.stringify(apiGatewayEndpoints, null, 2), 'utf-8'); }; export const getAPIRefToBuild = (testFilePath) => { const apiReferences = []; const parentDirPath = path.dirname(testFilePath); const testFileName = path.basename(testFilePath); const yamlContent = readFile(parentDirPath, testFileName); const parsedYamls = readMultiYaml(testFileName, yamlContent); parsedYamls.forEach((parsedYaml) => { const ref = parsedYaml?.spec?.api?.$ref; if (parsedYaml.kind?.toLowerCase() === TEST && ref) { apiReferences.push(ref); } }); return apiReferences; }; export const processEndpointFromResponse = (responses) => { const apiGatewayEndpoints = {}; if (DebugManager.getInstance().isDebugEnabled()) { showInfo(PROCESS_ENDPOINT_RESPONSE); } if (!Array.isArray(responses) || responses.length === 0) { showError(INVALID_OR_EMPTY_DEPLOYMENT_RESPONSES); throw new Error(INVALID_OR_EMPTY_DEPLOYMENT_RESPONSES); } responses.forEach((response) => { if (DebugManager.getInstance().isDebugEnabled()) { showInfo(`${PROCESS_GATEWAY_RESPONSE}${response.name}`); } const key = constructKey(response); if (apiGatewayEndpoints[key]) { apiGatewayEndpoints[key] = [ ...new Set([...apiGatewayEndpoints[key], ...response.gatewayEndpoints]), ]; } else { constructJSON(apiGatewayEndpoints, key, response.gatewayEndpoints); } }); if (DebugManager.getInstance().isDebugEnabled()) { showInfo(PROCESS_ENDPOINT_RESPONSE_SUCCESS); } return createJSONBuffer(apiGatewayEndpoints); }; export const addEndpointToZip = (testZipBuffer, endpointFile) => { try { if (DebugManager.getInstance().isDebugEnabled()) { showInfo(ENDPOINT_TEST); } const testZipBufferWithEndpoint = new AdmZip(testZipBuffer); testZipBufferWithEndpoint.addFile(ENDPOINT_FILE, endpointFile); return testZipBufferWithEndpoint.toBuffer(); } catch (error) { showError(ADDING_ENDPOINT_FILE_FAILED); throw new Error(`${ADDING_ENDPOINT_FILE_FAILED} ${error.message}`); } }; const addFileToZip = (combinedZip, entry) => { if (!combinedZip.getEntry(entry.entryName)) { combinedZip.addFile(entry.entryName, entry.getData()); } }; const displayErrorMessage = (result, project) => { if (!result || !result.zipBuffer) { showError(`${FAILED_TO_BUILD_TEST_ASSETS} ${project}`); throw new Error(`${FAILED_TO_BUILD_TEST_ASSETS} ${project}`); } }; export const updateEndpointZip = async (finalZipBuffer, newEndpoints) => { try { const zip = new AdmZip(finalZipBuffer); const jsonEntry = zip.getEntry(ENDPOINT_FILE); if (!jsonEntry) { throw new Error(JSON_FILE_MISSING); } const existingEndpointsBuffer = jsonEntry.getData(); const existingEndpoints = JSON.parse(existingEndpointsBuffer.toString('utf-8')); const newEndpointsData = JSON.parse(newEndpoints.toString('utf-8')); const updatedEndpoints = { ...existingEndpoints, ...newEndpointsData }; const updatedEndpointsBuffer = createJSONBuffer(updatedEndpoints); zip.updateFile(ENDPOINT_FILE, updatedEndpointsBuffer); return zip.toBuffer(); } catch (error) { showError(`${UPDATE_ENDPOINT_FAILED} ${error.message}`); throw new Error(`${UPDATE_ENDPOINT_FAILED} ${error.message}`); } }; export const combineTestAsset = async (rootDir, assetsToTest) => { try { if (DebugManager.getInstance().isDebugEnabled()) { showInfo(COMBINING_TEST_ZIP); } const combinedZip = new AdmZip(); const apiReferences = {}; for (const project in assetsToTest) { if (Object.prototype.hasOwnProperty.call(assetsToTest, project)) { if (DebugManager.getInstance().isDebugEnabled()) { showInfo(`${BUILDING_TEST} ${project}`); } const metadata = assetsToTest[project]; const result = await testAssets(rootDir, project, metadata); displayErrorMessage(result, project); if (DebugManager.getInstance().isDebugEnabled()) { showInfo(`${BUILDING_TEST_SUCCESS} ${project}`); } const projectZip = new AdmZip(result.zipBuffer); projectZip.getEntries().forEach((entry) => { addFileToZip(combinedZip, entry); }); apiReferences[project] = result.apiReference; } } if (DebugManager.getInstance().isDebugEnabled()) { showInfo(COMBINING_TEST_ZIP_SUCCESS); } return { zipBuffer: combinedZip.toBuffer(), apiReference: apiReferences }; } catch (error) { showError(`${ERROR_IN_COMBINING_TEST_ASSET} ${error.message}`); throw error; } }; export const findProjectForApi = (apiReference, notFoundApisList) => { const apiReferenceMap = {}; for (const [project, reference] of Object.entries(apiReference)) { const apiList = reference.split(',').map(api => api.trim()); for (const api of notFoundApisList) { if (apiList.includes(api)) { apiReferenceMap[project] = apiReferenceMap[project] ? `${apiReferenceMap[project]},${api}` : api; } } } return apiReferenceMap; }; export const buildAndDeployAssets = async (localDir, assetsToBuildAndDeploy, gatewayJson) => { const combinedZip = new AdmZip(); for (const [project, metadata] of Object.entries(assetsToBuildAndDeploy)) { try { const resultBuffer = await buildAssets(metadata, localDir, project); const projectZip = new AdmZip(resultBuffer); projectZip.getEntries().forEach((entry) => { combinedZip.addFile(entry.entryName, entry.getData()); }); } catch (error) { showError(`${ASSETS_BUILD_FAILED} ${project}: ${error.message}`); } } const combinedZipBuffer = combinedZip.toBuffer(); const deploymentResult = await executeDeployment(gatewayJson, combinedZipBuffer); return { buildBuffer: combinedZipBuffer, deploymentResult }; }; export const testProjects = async (all, rootDir, projects) => { if (all) { showInfo(TESTING_LIST_ALL_PROJECTS + rootDir); showInfo(CHECKING_ALL_PROJECTS + rootDir); projects = getAllProjectNames(rootDir); showInfo(IDENTIFIED_PROJECTS + projects); } return searchAssetByKind(KindEnums.Test, rootDir, projects); }; export const testAssets = (rootDir, projects, assets) => { showInfo(LINE); showInfo(TEST_STARTED); showInfo(LINE); return executeBuildTestAssets(rootDir, projects, assets); }; export const formattedEndpoints = (endpoints) => { const endPointsTable = new Table({ head: ['APIs', 'Gateway Endpoints'], style: { head: ['blue'], border: ['yellow'], }, }); Object.entries(endpoints).forEach(([api, urls]) => { endPointsTable.push([api, urls.join('\n')]); }); showInfo(APIENDPOINTS); console.log(endPointsTable.toString()); };