@apistudio/apim-cli
Version:
CLI for API Management Products
214 lines (213 loc) • 9.14 kB
JavaScript
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());
};