@apistudio/apim-cli
Version:
CLI for API Management Products
457 lines (387 loc) • 16 kB
text/typescript
import { TestOptionsModel } from '../../model/studio/command-options/test-options-model.js';
import { executeDeployment, prepareGatewayJson } from '../../deployers/project/projects-deployer.js';
import { showError, showWarning, showInfo } from '../../helpers/common/message-helper.js';
import { buildAssets } from './build-action-helper.js';
import { processEndpointFromResponse,
addEndpointToZip,
testAssets,
testProjects,
combineTestAsset,
createJSONBuffer,
findProjectForApi,
buildAndDeployAssets,
updateEndpointZip,
formattedEndpoints,
APIEndpoints,
} from '../../helpers/apim/test-helper.js';
import { MULTIPLE_PROJECTS_NOT_ALLOWED,
IGNORE_PROJECT_ARG,
IGNORE_NAMES_OPT,
ENDPOINT_TEST_SUCCESS,
CREATED_TEST_ZIP,
API_DETAILS_MISSING,
RETRY_TEST_COMMAND,
DEPLOYMENT_DETAILS_NOT_IDENTIFIED_LOCALLY,
DEPLOYMENT_DOESNOT_OVERWRITE,
ERROR_PROCESSING_ENDPOINT,
ENDPOINT_ARGUMENT_NOT_AVAILABLE,
NO_VALID_ENDPOINT_FOUND,
MISMATCH_IN_API_AND_ENDPOINT,
CREATED_BUILD_ZIP
} from '../../constants/message-constants.js';
import { BUILD, COMMA, TEST } from '../../constants/app-constants.js';
import { GatewaysJson } from '@apic/studio-shared';
import { getGatewayEndpoints } from '../../configure/endpoints/config.js';
import { createBuildZip } from '../../helpers/common/fs-helper.js';
import {getOutputPath} from './../helpers/build-action-helper.js';
import validateEndpoint from '../../validators/endpoint-validator.js'
import { TestOutputBuffers } from '../../model/studio/test-response-model.js';
export const getGatewayJson = async (options: TestOptionsModel, gatewayPassword: string): Promise<GatewaysJson> => {
const overwriteFlag = options.deploy;
let is_mcsp_enabled=false;
if(options.authToken)
{
is_mcsp_enabled=true;
}
return prepareGatewayJson(options.target, options.username, gatewayPassword, overwriteFlag,is_mcsp_enabled);
};
export const handleTestWarnings = (projects: string, options: TestOptionsModel) => {
if (projects && options.all) {
showWarning(IGNORE_PROJECT_ARG);
}
if (options.names && options.all) {
showWarning(IGNORE_NAMES_OPT);
}
};
const handleMultipleProjectsError = (projects: string): boolean => {
const projectList = projects.split(COMMA);
if (projectList.length > 1) {
showError(MULTIPLE_PROJECTS_NOT_ALLOWED);
return true;
}
return false;
};
const displayGatewayError = () => {
showError(API_DETAILS_MISSING);
showError(RETRY_TEST_COMMAND);
};
const displayDeploymentWarning = () => {
showWarning(DEPLOYMENT_DETAILS_NOT_IDENTIFIED_LOCALLY);
showWarning(DEPLOYMENT_DOESNOT_OVERWRITE);
};
const handleNotFoundApisForProjects = async (
notFoundApis: string,
apiReference: Record<string, string>,
localDir: string,
gatewayJson: GatewaysJson,
finalZipBuffer: Buffer
): Promise<TestOutputBuffers>=> {
const notFoundApisList = notFoundApis.split(',').map(api => api.trim());
const projectApisMap = findProjectForApi(apiReference, notFoundApisList);
const {buildBuffer, deploymentResult} = await buildAndDeployAssets(localDir, projectApisMap, gatewayJson);
const newEndpointFile = processEndpointFromResponse(deploymentResult);
const testBuffer = await updateEndpointZip(finalZipBuffer, newEndpointFile);
return { testZipBuffer: testBuffer, buildZipBuffer: buildBuffer };
};
const handleNotFoundApisForAssets = async (
notFoundApis: string,
localDir: string,
projects: string,
gatewayJson: GatewaysJson,
finalZipBuffer: Buffer
): Promise<TestOutputBuffers>=> {
const zipBufferToBuild = await buildAssets(notFoundApis, localDir, projects);
const deployResponses = await executeDeployment(gatewayJson, zipBufferToBuild);
const newEndpointFile = processEndpointFromResponse(deployResponses);
const testBuffer = await updateEndpointZip(finalZipBuffer, newEndpointFile);
return { testZipBuffer: testBuffer, buildZipBuffer: zipBufferToBuild };
};
const deployAndAddEndpointForProjects = async (
gatewayJson: GatewaysJson,
localDir: string,
finalZipBuffer: Buffer,
ApiReference: Record<string, string>
): Promise<TestOutputBuffers>=> {
const {buildBuffer, deploymentResult} = await buildAndDeployAssets(localDir,ApiReference,gatewayJson);
const endpointFile = processEndpointFromResponse(deploymentResult);
const testBuffer= addEndpointToZip(finalZipBuffer, endpointFile);
return { testZipBuffer: testBuffer, buildZipBuffer: buildBuffer };
};
const deployAndAddEndpointForAssets = async (
gatewayJson: GatewaysJson,
localDir: string,
apiReference: string,
projects: string,
testZipBuffer: Buffer
): Promise<TestOutputBuffers>=> {
const zipBufferToBuild = await buildAssets(apiReference, localDir, projects);
const deployResponses = await executeDeployment(gatewayJson, zipBufferToBuild);
const endpointFile = processEndpointFromResponse(deployResponses);
const testBuffer= addEndpointToZip(testZipBuffer, endpointFile);
return { testZipBuffer: testBuffer, buildZipBuffer: zipBufferToBuild };
};
const handleFoundEndpoints = async (
foundEndpoints: Record<string, any>,
finalZipBuffer: Buffer
): Promise<TestOutputBuffers> => {
const endpointFile = createJSONBuffer(foundEndpoints);
const testBuffer = addEndpointToZip(finalZipBuffer, endpointFile);
return { testZipBuffer: testBuffer, buildZipBuffer: undefined};
};
const hasGatewayDetails = (options: TestOptionsModel): boolean => {
return Boolean(options.target && options.username && options.password);
};
export const handleDeploymentForProjects = async (
options: TestOptionsModel,
gatewayJson: GatewaysJson,
localDir: string,
finalZipBuffer: Buffer,
ApiReference: Record<string, string>,
): Promise<TestOutputBuffers> => {
if (!hasGatewayDetails(options)) {
displayGatewayError();
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
return deployAndAddEndpointForProjects(gatewayJson, localDir,finalZipBuffer,ApiReference);
};
export const handleDeploymentWarning = (options: TestOptionsModel): TestOutputBuffers | null => {
displayDeploymentWarning();
if (!hasGatewayDetails(options)) {
displayGatewayError();
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
return null;
};
const handleMissingEndpoints = async (
options: TestOptionsModel,
gatewayJson: GatewaysJson,
localDir: string,
outputBuffers: TestOutputBuffers,
apiReference: any,
projects?: string
): Promise<TestOutputBuffers> => {
const warningResult = handleDeploymentWarning(options);
if (warningResult)
{
return warningResult;
}
if (outputBuffers.testZipBuffer) {
if (projects) {
outputBuffers = await deployAndAddEndpointForAssets(gatewayJson, localDir, apiReference, projects, outputBuffers.testZipBuffer);
} else {
outputBuffers = await deployAndAddEndpointForProjects(gatewayJson, localDir, outputBuffers.testZipBuffer, apiReference);
}
}
return outputBuffers;
};
async function processNotFoundApisForProjects(
notFoundApis: string,
apiReferencesString: string,
gatewayJson: GatewaysJson,
localDir: string,
testZipBuffer: Buffer,
apiReference: any
): Promise<TestOutputBuffers> {
return (notFoundApis === apiReferencesString)
? deployAndAddEndpointForProjects(gatewayJson, localDir, testZipBuffer, apiReference)
: handleNotFoundApisForProjects(notFoundApis, apiReference, localDir, gatewayJson, testZipBuffer);
}
export const handleNonDeploymentForProjects = async (
apiReferencesString: string,
options: TestOptionsModel,
gatewayJson: GatewaysJson,
localDir: string,
finalZipBuffer: Buffer,
apiReference: any,
): Promise<TestOutputBuffers> => {
const result = await getGatewayEndpoints(apiReferencesString);
let outputBuffers: TestOutputBuffers = { testZipBuffer: finalZipBuffer, buildZipBuffer: undefined };
if (result) {
const { foundEndpoints, notFoundApis } = result;
if (Object.keys(foundEndpoints).length > 0 && outputBuffers.testZipBuffer) {
formattedEndpoints(foundEndpoints);
outputBuffers = await handleFoundEndpoints(foundEndpoints, outputBuffers.testZipBuffer);
}
if (notFoundApis.length > 0) {
const warningResult = handleDeploymentWarning(options);
if (warningResult)
{
return warningResult;
}
if (outputBuffers.testZipBuffer) {
outputBuffers = await processNotFoundApisForProjects(
notFoundApis,
apiReferencesString,
gatewayJson,
localDir,
outputBuffers.testZipBuffer,
apiReference
);
}
}
} else {
outputBuffers = await handleMissingEndpoints(options, gatewayJson, localDir, outputBuffers, apiReference);
}
return outputBuffers;
};
async function processNotFoundApisForAssets(
notFoundApis: string,
apiReference: string,
gatewayJson: GatewaysJson,
localDir: string,
projects: string,
testZipBuffer: Buffer
): Promise<TestOutputBuffers> {
return (notFoundApis === apiReference)
? deployAndAddEndpointForAssets(gatewayJson, localDir, apiReference, projects, testZipBuffer)
: handleNotFoundApisForAssets(notFoundApis, localDir, projects, gatewayJson, testZipBuffer);
}
export const handleNonDeploymentForAssets = async (
apiReference: string,
options: TestOptionsModel,
gatewayJson: GatewaysJson,
localDir: string,
projects: string,
testZipBuffer: Buffer
): Promise<TestOutputBuffers> => {
const result = await getGatewayEndpoints(apiReference);
let outputBuffers: TestOutputBuffers = { testZipBuffer, buildZipBuffer: undefined };
if (result) {
const { foundEndpoints, notFoundApis } = result;
if (Object.keys(foundEndpoints).length > 0 && outputBuffers.testZipBuffer) {
formattedEndpoints(foundEndpoints);
outputBuffers = await handleFoundEndpoints(foundEndpoints, testZipBuffer);
}
if (notFoundApis.length > 0) {
const warningResult = handleDeploymentWarning(options);
if (warningResult)
{
return warningResult;
}
if (outputBuffers.testZipBuffer) {
outputBuffers = await processNotFoundApisForAssets(
notFoundApis,
apiReference,
gatewayJson,
localDir,
projects,
outputBuffers.testZipBuffer
);
}
}
} else {
outputBuffers = await handleMissingEndpoints(options, gatewayJson, localDir, outputBuffers, apiReference, projects);
}
return outputBuffers;
};
export const handleDeploymentForAssets = async (
options: TestOptionsModel,
gatewayJson: GatewaysJson,
localDir: string,
apiReference: any,
projects: string,
testZipBuffer: Buffer
): Promise<TestOutputBuffers> => {
if (!hasGatewayDetails(options)) {
displayGatewayError();
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
return deployAndAddEndpointForAssets(gatewayJson, localDir, apiReference, projects, testZipBuffer);
};
export const handleTestAssets = async (options: TestOptionsModel, projects: string, localDir: string, gatewayJson: GatewaysJson): Promise<TestOutputBuffers>=> {
if (handleMultipleProjectsError(projects)) {
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
const { zipBuffer, apiReference } = await testAssets(localDir, projects, options.names);
const testZipBuffer = zipBuffer;
if (options.deploy) {
return handleDeploymentForAssets(options, gatewayJson, localDir, apiReference, projects, testZipBuffer);
} else {
return handleNonDeploymentForAssets(apiReference, options, gatewayJson, localDir, projects, testZipBuffer);
}
};
export const handleTestProjects = async (
options: TestOptionsModel,
projects: string,
localDir: string,
gatewayJson: GatewaysJson
): Promise<TestOutputBuffers> => {
const testProject = await testProjects(options.all, localDir, projects);
const { zipBuffer: testZipBuffer, apiReference } = await combineTestAsset(localDir, testProject);
const apiReferencesString = Object.values(apiReference).join(',');
const finalZipBuffer = testZipBuffer;
if (options.deploy) {
const { testZipBuffer: finalTestZipBuffer, buildZipBuffer: finalBuildZipBuffer } =
await handleDeploymentForProjects(options, gatewayJson, localDir, finalZipBuffer, apiReference);
return { testZipBuffer: finalTestZipBuffer, buildZipBuffer: finalBuildZipBuffer };
} else {
const { testZipBuffer: finalTestZipBuffer, buildZipBuffer: finalBuildZipBuffer } =
await handleNonDeploymentForProjects(apiReferencesString, options, gatewayJson, localDir, finalZipBuffer, apiReference);
return { testZipBuffer: finalTestZipBuffer, buildZipBuffer: finalBuildZipBuffer };
}
};
const mapEndpoints = (apiReference: string, endpoints: string[]): APIEndpoints => {
const apiReferences = apiReference.split(COMMA).map(ref => ref.trim());
const mapped: APIEndpoints = {};
// 1-1 mapping
if (apiReferences.length === endpoints.length) {
apiReferences.forEach((reference, index) => {
mapped[reference] = [endpoints[index]];
});
}
// n:1 mapping
else if (endpoints.length === 1) {
apiReferences.forEach(reference => {
mapped[reference] = [endpoints[0]];
});
}
// case n:m mapping - throw an error for mismatch
else {
throw new Error(MISMATCH_IN_API_AND_ENDPOINT);
}
return mapped;
};
export const validateEndpointOptions = (options: TestOptionsModel) => {
if (options.endpoints && !options.names) {
showError(ENDPOINT_ARGUMENT_NOT_AVAILABLE);
return false;
}
return true;
};
export const testAssetsForEndpoint = async ( options: TestOptionsModel,project: string,localDir: string): Promise<TestOutputBuffers> => {
if (handleMultipleProjectsError(project)) {
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
const { zipBuffer, apiReference } = await testAssets(localDir, project, options.names);
const testZipBuffer = zipBuffer;
try {
const processedEndpoints = await validateEndpoint(options.endpoints);
if (processedEndpoints === false) {
throw new Error(NO_VALID_ENDPOINT_FOUND);
}
const mappedEndpoints = mapEndpoints(apiReference, processedEndpoints);
if (Object.keys(mappedEndpoints).length === 0) {
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
const endpointBuffer = createJSONBuffer(mappedEndpoints);
if (!endpointBuffer || endpointBuffer.length === 0) {
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
const testBuffer = addEndpointToZip(testZipBuffer, endpointBuffer);
return { testZipBuffer: testBuffer, buildZipBuffer: undefined };
} catch (error) {
showError(` ${ERROR_PROCESSING_ENDPOINT} ${(error as Error).message}`);
return { testZipBuffer: undefined, buildZipBuffer: undefined };
}
};
export const writeArchive = async (projects: string, all: boolean, names: string, testZipBuffer: Buffer, buildZipBuffer: Buffer| undefined) => {
showInfo(ENDPOINT_TEST_SUCCESS);
const buildZipFileName = await getOutputPath(projects, all, names, BUILD);
const testZipFileName = await getOutputPath(projects, all, names, TEST);
createBuildZip(testZipBuffer, testZipFileName);
showInfo(CREATED_TEST_ZIP + testZipFileName);
if(buildZipBuffer){
createBuildZip(buildZipBuffer, buildZipFileName);
showInfo(CREATED_BUILD_ZIP + buildZipFileName);
}
};