@broadcom/endevor-bridge-for-git-for-zowe-cli
Version:
Endevor Bridge for Git plug-in for Zowe CLI
875 lines (874 loc) • 72.5 kB
JavaScript
"use strict";
/*
* Copyright (c) 2019 Broadcom. All Rights Reserved. The term
* "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
* This software and all information contained therein is
* confidential and proprietary and shall not be duplicated,
* used, disclosed, or disseminated in any way except as
* authorized by the applicable license agreement, without the
* express written permission of Broadcom. All authorized
* reproductions must be marked with this language.
*
* EXCEPT AS SET FORTH IN THE APPLICABLE LICENSE AGREEMENT, TO
* THE EXTENT PERMITTED BY APPLICABLE LAW, BROADCOM PROVIDES THIS
* SOFTWARE WITHOUT WARRANTY OF ANY KIND, INCLUDING WITHOUT
* LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL BROADCOM
* BE LIABLE TO THE END USER OR ANY THIRD PARTY FOR ANY LOSS OR
* DAMAGE, DIRECT OR INDIRECT, FROM THE USE OF THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, LOST PROFITS, BUSINESS
* INTERRUPTION, GOODWILL, OR LOST DATA, EVEN IF BROADCOM IS
* EXPRESSLY ADVISED OF SUCH LOSS OR DAMAGE.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BuildExecute = void 0;
const child_process_1 = require("child_process");
const imperative_1 = require("@zowe/imperative");
const api_1 = require("@broadcom/endevor-for-zowe-cli/lib/api");
const BuildUtils_1 = require("../../utils/BuildUtils");
const EndevorService_1 = require("../../service/EndevorService");
const zos_jobs_for_zowe_sdk_1 = require("@zowe/zos-jobs-for-zowe-sdk");
const EBGConstants_1 = require("../../constants/EBGConstants");
const MappingMetadata_1 = require("../../utils/MappingMetadata");
const ChangeValidator_1 = require("../../utils/ChangeValidator");
const BridgeMetadataUtils_1 = require("../../utils/BridgeMetadataUtils");
const endevor_for_zowe_cli_1 = require("@broadcom/endevor-for-zowe-cli");
const path = require("path");
const fs = require("fs");
const _ = require("lodash");
const object_1 = require("../../../utils/object");
// tslint:disable: no-magic-numbers
function hashObj(obj) {
const str = JSON.stringify(obj);
let h = 0;
for (let i = 0; i < str.length; i++) {
// tslint:disable-next-line: no-bitwise
h = Math.imul(31, h) + str.charCodeAt(i) | 0;
}
return h;
}
function process_WorkAreaMapping_IntoMap(workArea) {
const workAreaMap = new Map();
workArea.systems.forEach((systemMapping) => {
systemMapping.subsystems.forEach((subsystemMapping) => {
workAreaMap.set(hashObj({ fromSys: systemMapping.from, fromSubsys: subsystemMapping.from }), { toSystem: systemMapping.to, toSubsystem: subsystemMapping.to });
});
});
return workAreaMap;
}
// tslint:disable: no-magic-numbers
// tslint:disable: member-ordering
class BuildExecute {
constructor(endevorSession, instance, gitLocation, forceClean, listingDir, listingRC, currWorkAreaID, currBuildSub, zosmfBuild) {
this.endvWrkDir = path.join(".", ".git", "endvWrk");
this.endvWrkTempDir = path.join(".", ".git", "endvWrk", "temp");
this.endvReportsDir = EBGConstants_1.EBGConstants.getEndevorReportsDir();
this.currWorkAreaMap = new Map();
this.reusePrev = false;
this.prevElmsInWorkArea = [];
this.ccid = "gitBridge";
this.comment = "GIT_BRIDGE_DEVELOPER_BUILD";
this.toBeUploadToWorkArea = new Map();
this.toBeDeletedFromWorkArea = [];
this.gitDeletedElement = [];
this.workAreaEntryStage = 1;
this.gitBridgeExt = {}; // type-file extension of gitBridge mapped system
this.sysSubWithoutToMap = new Map();
this.elmsFailedUpload = [];
this.listingRC = 0;
this.zosmfBuild = {
iszosmf: false,
jclSkeletonPath: "",
autogen: "",
zosmfSession: new imperative_1.Session({ hostname: "host", port: 8080, protocol: "http" })
};
/**
* Initialize all the variables for the current build
*/
this.endevorSession = endevorSession;
this.instance = instance;
this.endvWrkDir = path.join(gitLocation, ".git", "endvWrk");
this.endvWrkTempDir = path.join(gitLocation, ".git", "endvWrk", "temp");
if (fs.existsSync(this.endvWrkTempDir)) { // clean the temp directory left from previous build
fs.readdirSync(this.endvWrkTempDir).forEach((file) => {
const filePath = path.join(this.endvWrkTempDir, file);
// delete all the files inside;
// no need to check if there's subdirectory, because we only use the temp directory to temporarily store files from retrieving element
fs.unlinkSync(filePath);
});
}
EndevorService_1.EndevorService.mkdirSyncRecursive(this.endvWrkTempDir);
this.endvReportsDir = EBGConstants_1.EBGConstants.getEndevorReportsDir(gitLocation);
EndevorService_1.EndevorService.mkdirSyncRecursive(this.endvReportsDir);
// set ccid from branch name
try {
const workingBranch = (0, child_process_1.execSync)("git rev-parse --abbrev-ref HEAD", { cwd: gitLocation }).toString().trim();
this.ccid = workingBranch.substring(0, workingBranch.length > 12 ? 12 : workingBranch.length);
}
catch (err) {
throw new imperative_1.ImperativeError({
msg: `GIT bash not present: ${err}`,
});
}
if ((0, object_1.isNotNil)(currWorkAreaID)) {
const mappingMetadata = BuildUtils_1.BuildUtils.readMappingMetadata(gitLocation);
const branchMetadata = MappingMetadata_1.MappingMetadata.getSynchronizedBranch(mappingMetadata);
const workArea = BuildUtils_1.BuildUtils.getWorkAreaByIDFromFile(gitLocation, currWorkAreaID);
if (branchMetadata.environment === workArea.environment) {
throw new imperative_1.ImperativeError({
msg: "Build subsystem cannot have the same environment as the mapping." +
" It must be mapped under the mapping's environment"
});
}
this.currBuildDetails = {
mappingMetadata,
workArea,
gitLocation,
elmsInWorkArea: []
};
}
else if ((0, object_1.isNotNil)(currBuildSub)) {
// Only for single system/subsystem mappings
const mappingMetadata = BuildUtils_1.BuildUtils.readMappingMetadata(gitLocation);
const branchMetadata = MappingMetadata_1.MappingMetadata.getSynchronizedBranch(mappingMetadata);
if ((0, object_1.isNil)(branchMetadata)) {
throw new imperative_1.ImperativeError({
msg: `Branch '${mappingMetadata.git.branch}' not found in the mapping metadata`
});
}
else if (MappingMetadata_1.MappingMetadata.isMultiSystem(branchMetadata)) {
throw new imperative_1.ImperativeError({
msg: "Work area ID is required to build Multi-System mappings"
});
}
else if (branchMetadata.environment === currBuildSub.env) {
throw new imperative_1.ImperativeError({
msg: "Build subsystem cannot have the same environment as the mapping." +
" It must be mapped under the mapping's environment"
});
}
this.currBuildDetails = {
mappingMetadata,
workArea: {
id: "",
lockElement: {
name: "",
type: "",
environment: "",
system: "",
subsystem: ""
},
environment: currBuildSub.env,
systems: [{
from: branchMetadata.systems[0].name,
to: currBuildSub.sys,
subsystems: [{
from: branchMetadata.systems[0].subsystems[0].name,
to: currBuildSub.sub
}]
}]
},
gitLocation,
elmsInWorkArea: []
};
}
else {
throw new imperative_1.ImperativeError({
msg: `Work area ID or build subsystem must be specified`,
});
}
this.currWorkAreaMap = process_WorkAreaMapping_IntoMap(this.currBuildDetails.workArea);
if ((0, object_1.isNotNil)(listingDir)) {
EndevorService_1.EndevorService.mkdirSyncRecursive(listingDir);
this.listingDir = listingDir;
}
if ((0, object_1.isNotNil)(listingRC)) {
this.listingRC = listingRC;
}
if ((0, object_1.isNotNil)(zosmfBuild) && zosmfBuild.iszosmf) {
this.zosmfBuild = zosmfBuild;
}
this.reusePrev = false;
this.prevElmsInWorkArea = [];
if (forceClean) {
return;
}
/**
* Initialize all the variables related to previous build
*/
// read previous build's IGBBuildDetails, and check if it's same condition as current build
let prevBuildDetails;
try {
const prevBuildDetailsPath = path.join(this.endvWrkDir, "developerBuildDetails.json");
imperative_1.Logger.getAppLogger().trace(`DeveloperBuild - Reading prev build developerBuildDetails.json file from: ${prevBuildDetailsPath}`);
const prevBuildDetailsFile = fs.readFileSync(prevBuildDetailsPath, "utf8"); // read with default encoding
imperative_1.Logger.getAppLogger().trace(`DeveloperBuild - Get prev build developerBuildDetails.json file content: \n${prevBuildDetailsFile}`);
prevBuildDetails = JSON.parse(prevBuildDetailsFile);
}
catch (err) {
return;
}
if (_.isEqual(prevBuildDetails.mappingMetadata, this.currBuildDetails.mappingMetadata) &&
_.isEqual(prevBuildDetails.workArea, this.currBuildDetails.workArea)) {
const normalizePathForCmp = ((inputPath) => {
const outputPath = path.normalize(inputPath);
if (outputPath.endsWith(path.sep)) {
return outputPath;
}
else {
return outputPath + path.sep;
}
});
if (normalizePathForCmp(prevBuildDetails.gitLocation) === normalizePathForCmp(this.currBuildDetails.gitLocation)) {
this.reusePrev = true;
this.prevElmsInWorkArea = prevBuildDetails.elmsInWorkArea;
}
}
}
/**
* NOTE: This class uses the mapping metadata when gitBridge hasn't implement multi-system support.
* When they do, the whole mapping metadata is going to look different.
* Therefore, function getGitDiffElements here that relies on mapping metadata being a single system, should later be wrapped in loop.
*/
buildDriver(commandResponse) {
return __awaiter(this, void 0, void 0, function* () {
const task = {
percentComplete: 0,
statusMessage: "Analysing the changed elements",
stageName: imperative_1.TaskStage.IN_PROGRESS
};
commandResponse.progress.startBar({ task });
EndevorService_1.EndevorService.cleanAllReportFiles(); // clean all the reports from previous build before performing this build
yield this.getGitDiffElements();
task.statusMessage = "Getting entry stage for build environment";
task.percentComplete = 10;
yield this.getEntryStage();
if (this.reusePrev) {
task.statusMessage = "Previous build detected, preparing build subsystem(s)";
task.percentComplete = 15;
yield this.prepareWorkAreaWhenReusePrev();
}
else {
task.statusMessage = "No previous build with the same specifications detected, cleaning up build subsystem(s)";
task.percentComplete = 15;
yield this.cleanWorkAreaWhenNOTreusePrev();
task.statusMessage = "Getting source up the map for deleted elements";
task.percentComplete = 30;
yield this.prepareWorkAreaWhenNOTreusePrev();
}
task.statusMessage = "Uploading elements";
task.percentComplete = 50;
yield this.uploadElmsToBeUploadToWorkArea();
if (this.elmsFailedUpload.length > 0) { // upload wasn't successful for all elements
// first print the warning for sys/sub that has no to mapping
if (this.sysSubWithoutToMap.size > 0) {
commandResponse.console.log("[WARN] No \"to\" mapping found for the system/subsystem:");
this.sysSubWithoutToMap.forEach((sysSub) => {
commandResponse.console.log(`${sysSub.system}/${sysSub.subsystem}`);
});
}
// save the current build details
this.writecurrBuildDetailsToFile();
task.percentComplete = 100;
commandResponse.progress.endBar();
// print upload error to console
commandResponse.console.log("Error during the uploading of the elements below:");
commandResponse.format.output({
output: this.elmsFailedUpload,
format: "table",
header: true
});
throw new imperative_1.ImperativeError({
msg: "Build can't be finished"
});
}
// upload successful, generate elements
if (this.zosmfBuild.iszosmf) {
task.statusMessage = "Preparing zosmf job for generating elements";
task.percentComplete = 70;
yield this.generateWorkAreaZosmf();
// first print the warning for sys/sub that has no to mapping
if (this.sysSubWithoutToMap.size > 0) {
commandResponse.console.log("[WARN] No to mapping found for the system/subsystem:");
this.sysSubWithoutToMap.forEach((sysSub) => {
commandResponse.console.log(`${sysSub.system}/${sysSub.subsystem}`);
});
}
// save the current build details
this.writecurrBuildDetailsToFile();
task.percentComplete = 100;
commandResponse.progress.endBar();
if ((0, object_1.isNotNil)(this.currBuildDetails.jobDetails)) {
commandResponse.console.log("Job is submitted to compile:" +
"\n jobname: " + this.currBuildDetails.jobDetails.jobname +
"\n jobid: " + this.currBuildDetails.jobDetails.jobid +
"\n jobstatus: " + this.currBuildDetails.jobDetails.status);
}
else {
throw new imperative_1.ImperativeError({
msg: `Error submitting generate batch job: no job details returned from zosmf.`,
});
}
}
else {
if ((0, object_1.isNotNil)(this.listingDir)) {
task.statusMessage = "Generating elements and getting their output";
}
else {
task.statusMessage = "Generating elements";
}
task.percentComplete = 70;
const now = new Date();
const fileDateTime = api_1.EndevorUtils.formatDate(now, false) + "-" + api_1.EndevorUtils.formatTime(now, true, "");
const genC1MSGFileName = path.join(this.endvReportsDir, "Generate-C1MSG1-" + fileDateTime + ".txt");
const genC2MSGFileName = path.join(this.endvReportsDir, "Generate-C1MSG2-" + fileDateTime + ".txt");
const generateResult = yield this.generateWorkArea(genC1MSGFileName, genC2MSGFileName);
const generatedElms = generateResult.generatedElms;
// first print the warning for sys/sub that has no to mapping
if (this.sysSubWithoutToMap.size > 0) {
commandResponse.console.log("[WARN] No to mapping found for the system/subsystem:");
this.sysSubWithoutToMap.forEach((sysSub) => {
commandResponse.console.log(`${sysSub.system}/${sysSub.subsystem}`);
});
}
// save the current build details
this.writecurrBuildDetailsToFile();
task.percentComplete = 100;
commandResponse.progress.endBar();
// print geenrate result to console
if (generatedElms.length === 0) {
commandResponse.console.log("No element generated");
}
else {
commandResponse.format.output({
output: generatedElms,
format: "table",
header: true
});
}
if (generateResult.generateResult.body.returnCode >= 16) {
commandResponse.console.errorHeader("\nError during generating elements");
commandResponse.console.log("\t" + generateResult.generateResult.body.messages);
}
commandResponse.console.log("\nBuild Report:");
commandResponse.console.log("\tC1MSG1: " + genC1MSGFileName);
commandResponse.console.log("\tC1MSG2: " + genC2MSGFileName);
}
});
}
writecurrBuildDetailsToFile() {
const filePath = path.join(this.endvWrkDir, "developerBuildDetails.json");
api_1.EndevorUtils.generalWriteFile(filePath, JSON.stringify(this.currBuildDetails, null, 4));
}
getGitDiffElements() {
return __awaiter(this, void 0, void 0, function* () {
/**
* First get a list of changes from git commands
*/
let changed;
let untracked;
let synchronizedBranch;
try {
synchronizedBranch = MappingMetadata_1.MappingMetadata.getSynchronizedBranch(this.currBuildDetails.mappingMetadata);
changed = (((0, child_process_1.execSync)("git diff --name-status origin/" + synchronizedBranch.name, { cwd: this.currBuildDetails.gitLocation }).toString()).split(/\r?\n/)).filter(String);
untracked = (((0, child_process_1.execSync)("git ls-files --others --exclude-standard", { cwd: this.currBuildDetails.gitLocation }).toString()).split(/\r?\n/)).filter(String);
}
catch (err) {
throw new imperative_1.ImperativeError({
msg: `Error getting changed elements: ${err}`,
});
}
/**
* Prepare everything needed for parsing the git commands output
*/
// get {typename, file extension} information
this.gitBridgeExt = yield this.getTypeFileExt();
// A function to:
// 1. set toSystem toSubsystem for element
// 2. check if element has file extension. If so extract only the filename without extension (the real element name)
const elmsWithoutToMap = [];
const setToLocAndRealElementName = (elementDetail) => {
// get to location from work area
const toMap = this.currWorkAreaMap.get(hashObj({ fromSys: elementDetail.fromSys, fromSubsys: elementDetail.fromSubsys }));
if ((0, object_1.isNil)(toMap)) {
elmsWithoutToMap.push(elementDetail);
}
else {
elementDetail.toSystem = toMap.toSystem;
elementDetail.toSubsystem = toMap.toSubsystem;
}
if (!(elementDetail.type in this.gitBridgeExt)) {
throw new imperative_1.ImperativeError({
msg: `Undefined type ${elementDetail.type} for element ${elementDetail.name}`,
});
}
const fileSplit = elementDetail.name.split(".");
if (fileSplit.length > 1) {
const fileExt = this.gitBridgeExt[elementDetail.type.toUpperCase()];
if ((0, object_1.isNotNil)(fileExt)) { // only check for types with file extension defined
if (fileExt === fileSplit[fileSplit.length - 1]) {
// file extension match
elementDetail.name = elementDetail.name.substr(0, elementDetail.name.lastIndexOf("."));
}
else {
throw new imperative_1.ImperativeError({
msg: `element ${elementDetail.name} under type ${elementDetail.type} folder must have extension ${fileExt}`,
});
}
}
}
return elementDetail;
};
/**
* Process each changed element into this.toBeUploadToWorkArea and deletedElement
*/
const mappingMetadata = BuildUtils_1.BuildUtils.readMappingMetadata(this.currBuildDetails.gitLocation);
const exemptions = [EBGConstants_1.EBGConstants.GITKEEP_FILENAME, EBGConstants_1.EBGConstants.GITIGNORE_FILENAME];
changed.filter(change => !exemptions.some(e => change.includes(e))).forEach(entry => {
// example changed:
// M ESCM180/XUEYU010/ISPM/LOCK2
// R100 ESCM180/XUEYU010/ISPM/TESTADD2 ESCM180/XUEYU010/ISPM/REN
// D ESCM180/XUEYU010/ISPM/TESTADD3
// A ESCM180/XUEYU010/ISPM/test
const items = entry.split(/\s+/);
if (items.length <= 1) {
return;
}
if (items[0].startsWith("R") && items.length === 3) {
const matchResult1 = ChangeValidator_1.ChangeValidator.validateAndGetPathComponents(items[1], mappingMetadata);
const matchResult2 = ChangeValidator_1.ChangeValidator.validateAndGetPathComponents(items[2], mappingMetadata);
if ((0, object_1.isNil)(matchResult1) || (0, object_1.isNil)((matchResult2)) ||
matchResult1[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX] === EBGConstants_1.EBGConstants.BRIDGE_METATDATA_FILENAME) {
return;
}
const bridgeMetadata = BridgeMetadataUtils_1.BridgeMetadataUtils.readBridgeMetadataFile(this.currBuildDetails.gitLocation, matchResult2[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX], matchResult2[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX], matchResult2[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX], false);
let procGrpName;
if ((0, object_1.isNotNil)(bridgeMetadata)) {
procGrpName = this.getProcGrpName(matchResult2, bridgeMetadata);
}
const bridgeMetadataForDelete = BridgeMetadataUtils_1.BridgeMetadataUtils.readBridgeMetadataFile(this.currBuildDetails.gitLocation, matchResult2[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX], matchResult2[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX], matchResult2[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX], false);
let procGrpNameForDelete;
if ((0, object_1.isNotNil)(bridgeMetadata)) {
procGrpNameForDelete = this.getProcGrpName(matchResult1, bridgeMetadataForDelete);
}
const deletedElmDetail = this.elementsToBeDeleted(matchResult1, procGrpNameForDelete);
this.gitDeletedElement.push(setToLocAndRealElementName(deletedElmDetail));
// process rename dest
const pathToSourceFile = path.join(this.currBuildDetails.gitLocation, items[2]);
let addedElmDetail = this.addElementForUpload(matchResult2, procGrpName, pathToSourceFile);
addedElmDetail = setToLocAndRealElementName(addedElmDetail);
this.toBeUploadToWorkArea.set(hashObj(addedElmDetail), addedElmDetail);
}
else if ((items[0].startsWith("A") || items[0].startsWith("M")) && items.length === 2) {
const matchResult = ChangeValidator_1.ChangeValidator.validateAndGetPathComponents(items[1], mappingMetadata);
if ((0, object_1.isNil)(matchResult)) {
return;
}
if (matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX] === EBGConstants_1.EBGConstants.BRIDGE_METATDATA_FILENAME) {
// if the file changed is a .bridge.json, find the element for which processor group has changed
const remoteBridgeMetadata = (0, child_process_1.execSync)("git show origin/" + synchronizedBranch.name + ":" + matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX] + "/" +
matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX] + "/" + matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX] + "/" +
EBGConstants_1.EBGConstants.BRIDGE_METATDATA_FILENAME, { cwd: this.currBuildDetails.gitLocation }).toString();
const remoteBridgeMetadataObject = JSON.parse(remoteBridgeMetadata);
const bridgeMetadataObject = BridgeMetadataUtils_1.BridgeMetadataUtils.readBridgeMetadataFile(this.currBuildDetails.gitLocation, matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX], false);
if ((0, object_1.isNil)(bridgeMetadataObject.defaultProcessorGroup) ||
(0, object_1.isNil)(bridgeMetadataObject.definedProcessorGroups)) {
throw new imperative_1.ImperativeError({
msg: `\t${items[1]} does not contain a valid .bridge.json file. `,
});
}
const definedProcList = [bridgeMetadataObject.defaultProcessorGroup];
for (const procGroup of bridgeMetadataObject.definedProcessorGroups) {
if (procGroup.name === bridgeMetadataObject.defaultProcessorGroup) {
continue;
}
definedProcList.push(procGroup.name);
}
for (const key in bridgeMetadataObject.elements) {
if (!bridgeMetadataObject.elements.hasOwnProperty(key)) {
continue;
}
if (!definedProcList.includes(bridgeMetadataObject.elements[key].processorGroup)) {
throw new imperative_1.ImperativeError({
msg: `\tThe processor group ${bridgeMetadataObject.elements[key].processorGroup} specified for ${key} is not defined for the type ${matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX]} at the mapped Endevor location.`,
});
}
for (const prevKey in remoteBridgeMetadataObject.elements) {
if (!remoteBridgeMetadataObject.elements.hasOwnProperty(prevKey)) {
continue;
}
if (key === prevKey &&
bridgeMetadataObject.elements[key].processorGroup !== remoteBridgeMetadataObject.elements[key].processorGroup) {
try {
const pathToUpdatedSourceFile = path.join(this.currBuildDetails.gitLocation, matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX], key);
let addedElmDetail = {
fromSys: matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX],
fromSubsys: matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX],
toSystem: "",
toSubsystem: "",
type: matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX],
name: key,
fingerprint: "",
timestamp: (fs.statSync(pathToUpdatedSourceFile)).mtime.valueOf(),
pathToSourceFile: pathToUpdatedSourceFile,
procGrpName: bridgeMetadataObject.elements[key].processorGroup
};
addedElmDetail = setToLocAndRealElementName(addedElmDetail);
this.toBeUploadToWorkArea.set(hashObj(addedElmDetail), addedElmDetail);
}
catch (e) {
imperative_1.Logger.getAppLogger().trace(`No such file or directory: \n${e}`);
}
}
}
}
}
else {
// if the file changed is an element check what processor group is defined for it in .bridge.json.
// If nothing is defined then take the default processor group for its type
const bridgeMetadata = BridgeMetadataUtils_1.BridgeMetadataUtils.readBridgeMetadataFile(this.currBuildDetails.gitLocation, matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX], false);
let procGrpName;
if ((0, object_1.isNotNil)(bridgeMetadata)) {
procGrpName = this.getProcGrpName(matchResult, bridgeMetadata);
}
const pathToSourceFile = path.join(this.currBuildDetails.gitLocation, items[1]);
let addedElmDetail = this.addElementForUpload(matchResult, procGrpName, pathToSourceFile);
addedElmDetail = setToLocAndRealElementName(addedElmDetail);
this.toBeUploadToWorkArea.set(hashObj(addedElmDetail), addedElmDetail);
}
}
else if (items[0].startsWith("D") && items.length === 2) {
const matchResult = ChangeValidator_1.ChangeValidator.validateAndGetPathComponents(items[1], mappingMetadata);
if ((0, object_1.isNil)(matchResult) ||
matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX] === EBGConstants_1.EBGConstants.BRIDGE_METATDATA_FILENAME) {
return;
}
const bridgeMetadata = BridgeMetadataUtils_1.BridgeMetadataUtils.readBridgeMetadataFile(this.currBuildDetails.gitLocation, matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX], false);
let procGrpName;
if ((0, object_1.isNotNil)(bridgeMetadata)) {
procGrpName = this.getProcGrpName(matchResult, bridgeMetadata);
}
const deletedElmDetail = this.elementsToBeDeleted(matchResult, procGrpName);
this.gitDeletedElement.push(setToLocAndRealElementName(deletedElmDetail));
}
});
/**
* Process each untracked element into this.toBeUploadToWorkArea
*/
untracked.filter(v => !exemptions.some(e => v.includes(e))).forEach(entry => {
// example untracked:
// ESCM180/XUEYU010/ISPM/NEW
const matchResult = ChangeValidator_1.ChangeValidator.validateAndGetPathComponents(entry, mappingMetadata);
if ((0, object_1.isNil)(matchResult) ||
matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX] === EBGConstants_1.EBGConstants.BRIDGE_METATDATA_FILENAME) {
return;
}
const bridgeMetadata = BridgeMetadataUtils_1.BridgeMetadataUtils.readBridgeMetadataFile(this.currBuildDetails.gitLocation, matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX], matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX], false);
let procGrpName;
if ((0, object_1.isNotNil)(bridgeMetadata)) {
procGrpName = this.getProcGrpName(matchResult, bridgeMetadata);
}
const pathToSourceFile = path.join(this.currBuildDetails.gitLocation, entry);
let addedElmDetail = this.addElementForUpload(matchResult, procGrpName, pathToSourceFile);
addedElmDetail = setToLocAndRealElementName(addedElmDetail);
this.toBeUploadToWorkArea.set(hashObj(addedElmDetail), addedElmDetail);
});
/**
* Record all sys/sub that has no to map
*/
elmsWithoutToMap.forEach((elm) => {
const sysSub = {
system: elm.fromSys,
subsystem: elm.fromSubsys
};
this.sysSubWithoutToMap.set(hashObj(sysSub), sysSub);
});
});
}
getProcGrpName(matchResult, bridgeMetadata) {
let procGrpName;
for (const key in bridgeMetadata.elements) {
if (!bridgeMetadata.elements.hasOwnProperty(key)) {
continue;
}
if (matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX] === key) {
procGrpName = bridgeMetadata.elements[key].processorGroup;
break;
}
else {
procGrpName = bridgeMetadata.defaultProcessorGroup;
}
}
return procGrpName;
}
addElementForUpload(matchResult, procGrpName, pathToSourceFile) {
let addedElmDetail;
if ((0, object_1.isNotNil)(procGrpName)) {
addedElmDetail = {
fromSys: matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX],
fromSubsys: matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX],
toSystem: "",
toSubsystem: "",
type: matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX],
name: matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX],
fingerprint: "",
timestamp: (fs.statSync(pathToSourceFile)).mtime.valueOf(),
pathToSourceFile,
procGrpName
};
}
else {
addedElmDetail = {
fromSys: matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX],
fromSubsys: matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX],
toSystem: "",
toSubsystem: "",
type: matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX],
name: matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX],
fingerprint: "",
timestamp: (fs.statSync(pathToSourceFile)).mtime.valueOf(),
pathToSourceFile
};
}
return addedElmDetail;
}
elementsToBeDeleted(matchResult, procGrpName) {
let deletedElmDetail;
if ((0, object_1.isNotNil)(procGrpName)) {
deletedElmDetail = {
fromSys: matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX],
fromSubsys: matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX],
toSystem: "",
toSubsystem: "",
type: matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX],
name: matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX],
fingerprint: "",
timestamp: BuildExecute.DELETETIMESTAMP,
procGrpName
};
}
else {
deletedElmDetail = {
fromSys: matchResult[EBGConstants_1.EBGConstants.SYSTEM_DIR_INDEX],
fromSubsys: matchResult[EBGConstants_1.EBGConstants.SUBSYSTEM_DIR_INDEX],
toSystem: "",
toSubsystem: "",
type: matchResult[EBGConstants_1.EBGConstants.TYPE_DIR_INDEX],
name: matchResult[EBGConstants_1.EBGConstants.ELEMENT_NAME_INDEX],
fingerprint: "",
timestamp: BuildExecute.DELETETIMESTAMP,
};
}
return deletedElmDetail;
}
getTypeFileExt() {
return __awaiter(this, void 0, void 0, function* () {
let gitBridgeExt = {};
const gitBridgeExtPath = path.join(this.endvWrkDir, "gitBridgeFileExt.json");
/**
* First check if we can reuse from previous build, without doing list type
*/
if (this.reusePrev) { // reuse previous run's type-fileExt definition file if it exist
try {
const fileContent = fs.readFileSync(gitBridgeExtPath, "utf8");
if ((0, object_1.isNotNil)(fileContent) && fileContent.length > 0) {
gitBridgeExt = JSON.parse(fileContent);
return gitBridgeExt;
}
}
catch (e) {
// file doesn't exist or invalid, perform list type to get type-fileExt
}
}
const synchronizedBranch = MappingMetadata_1.MappingMetadata.getSynchronizedBranch(this.currBuildDetails.mappingMetadata);
/**
* List type is needed.
* Perform list type to get file extension, store it as JSON format {typeName:fileExt} in gitBridgeExtPath
*/
const listTypeResult = [];
for (const system of synchronizedBranch.systems) {
const typeDef = {
element: "",
environment: synchronizedBranch.environment,
stageNumber: synchronizedBranch.stageNumber.toString(),
system: system.name,
subsystem: "",
type: "*",
instance: "" // not used in listType
};
const systemTypes = yield EndevorService_1.EndevorService.listTypeToGetFileExtension(this.endevorSession, this.instance, typeDef);
listTypeResult.push(...systemTypes);
}
listTypeResult.forEach((entry) => {
if ((0, object_1.isNotNil)(entry.typeName)) {
gitBridgeExt[entry.typeName.toUpperCase()] = entry.fileExt;
}
});
// async write in endevor work directory
api_1.EndevorUtils.generalWriteFile(gitBridgeExtPath, JSON.stringify(gitBridgeExt, null, 4));
return gitBridgeExt;
});
}
getEntryStage() {
return __awaiter(this, void 0, void 0, function* () {
this.workAreaEntryStage = yield EndevorService_1.EndevorService.getEntryStage(this.endevorSession, this.instance, this.currBuildDetails.workArea.environment);
});
}
cleanWorkAreaWhenNOTreusePrev() {
return __awaiter(this, void 0, void 0, function* () {
/**
* Prepare what's needed for delete elements in subsystems
*/
const deleteRequestBody = {
ccid: this.ccid,
comment: this.comment,
oveSign: "yes",
};
/**
* Clean work area subsystem by subsystem
*/
for (const systemMapping of this.currBuildDetails.workArea.systems) {
for (const subsystemMapping of systemMapping.subsystems) {
/**
* First check if lock element is inside this subsystem
*/
if (this.currBuildDetails.workArea.environment === this.currBuildDetails.workArea.lockElement.environment &&
systemMapping.to === this.currBuildDetails.workArea.lockElement.system &&
subsystemMapping.to === this.currBuildDetails.workArea.lockElement.subsystem) {
// Work area contains the same subsystem as lock element, since lock element must be present,
// so there's no need to check if it is there. Just need to first list element then delete everything that is not a lock element
const listEleDef = {
element: "*",
environment: this.currBuildDetails.workArea.environment,
stageNumber: String(this.workAreaEntryStage),
system: systemMapping.to,
subsystem: subsystemMapping.to,
type: "*",
instance: "" // not used in ListElement.listElement
};
const listElementResult = yield EndevorService_1.EndevorService.listElmFromSub(this.endevorSession, this.instance, listEleDef, { data: "BAS" });
for (const elmInSub of listElementResult) {
if ((0, object_1.isNil)(elmInSub.elmName) || (0, object_1.isNil)(elmInSub.typeName) ||
(elmInSub.elmName === this.currBuildDetails.workArea.lockElement.name &&
elmInSub.typeName === this.currBuildDetails.workArea.lockElement.type)) {
continue; // skip lock element
}
const deleteEleDef = {
element: elmInSub.elmName,
environment: this.currBuildDetails.workArea.environment,
stageNumber: String(this.workAreaEntryStage),
system: systemMapping.to,
subsystem: subsystemMapping.to,
type: elmInSub.typeName,
instance: ""
};
yield EndevorService_1.EndevorService.deleteFromSub(this.endevorSession, this.instance, deleteEleDef, deleteRequestBody);
}
}
else {
/**
* Lock element is not in this subsystem, delete with wildcard
*/
const deleteEleDef = {
element: "*",
environment: this.currBuildDetails.workArea.environment,
stageNumber: String(this.workAreaEntryStage),
system: systemMapping.to,
subsystem: subsystemMapping.to,
type: "*",
instance: ""
};
yield EndevorService_1.EndevorService.deleteFromSub(this.endevorSession, this.instance, deleteEleDef, deleteRequestBody);
}
}
}
});
}
prepareWorkAreaWhenNOTreusePrev() {
return __awaiter(this, void 0, void 0, function* () {
/**
* Process this.gitDeletedElement (deleted elements in the current working directory)
*/
const synchronizedBranch = MappingMetadata_1.MappingMetadata.getSynchronizedBranch(this.currBuildDetails.mappingMetadata);
for (const deletedElm of this.gitDeletedElement) {
// list deleted element from gitBridge mapping location, to check if it exist up the map
const isFoundUptheMap = yield this.isFoundUptheMap(deletedElm, synchronizedBranch);
const foundUpMap = isFoundUptheMap.foundUpMap;
const elmUptheMap = isFoundUptheMap.elmUptheMap;
if (foundUpMap) {
const retrieveEleDef = {
element: elmUptheMap.elmName,
environment: elmUptheMap.envName,
stageNumber: (elmUptheMap.stgNum).toString(),
system: elmUptheMap.sysName,
subsystem: elmUptheMap.sbsName,
type: elmUptheMap.typeName,
instance: ""
};
// retrieve the element
const retrieveRequestBody = {
ccid: this.ccid,
comment: this.comment,
noSignout: "yes"
};
const retrieveResultData = yield EndevorService_1.EndevorService.retrieveElm(this.endevorSession, this.instance, retrieveEleDef, retrieveRequestBody);
const pathToSourceFile = path.join(this.endvWrkTempDir, String(hashObj(retrieveEleDef)));
fs.writeFileSync(pathToSourceFile, retrieveResultData);
const retrievedElmDetail = deletedElm;
retrievedElmDetail.pathToSourceFile = pathToSourceFile;
this.toBeUploadToWorkArea.set(hashObj(retrievedElmDetail), retrievedElmDetail);
}
}
});
}
isFoundUptheMap(deletedElm, synchronizedBranch) {
return __awaiter(this, void 0, void 0, function* () {
const listEleDef = {
element: deletedElm.name,
environment: synchronizedBranch.environment,
stageNumber: synchronizedBranch.stageNumber.toString(),
system: deletedElm.fromSys,
subsystem: deletedElm.fromSubsys,
type: deletedElm.type,
instance: "" // not used in ListElement.listElement
};
const listElementResult = yield EndevorService_1.EndevorService.listElmFromSub(this.endevorSession, this.instance, listEleDef, { search: "SEA", return: "ALL", data: "BAS" });
let elmUptheMap = {};
let foundUpMap = false;
if ((0, object_1.isNotNil)(listElementResult) && (listElementResult.length > 0)) {
if (((listElementResult[0].sysName).toUpperCase() === listEleDef.system.toUpperCase()) &&
((listElementResult[0].envName).toUpperCase() === listEleDef.environment.toUpperCase()) &&
((listElementResult[0].stgNum).toString() === listEleDef.stageNumber) &&
((listElementResult[0].sbsName).toUpperCase() === listEleDef.subsystem.toUpperCase())) {
if (listElementResult.length > 1) {
elmUptheMap = listElementResult[1];
foundUpMap = true;
}
}
else {
elmUptheMap = listElementResult[0];
foundUpMap = true;
}
}
return { foundUpMap, elmUptheMap };
});
}
prepareWorkAreaWhenReusePrev() {
return __awaiter(this, void 0, void 0, function* () {
/**
* List elements in work area, put them in this.toBeDeletedFromWorkArea, except for lock element
*/
for (const systemMapping of this.currBuildDetails.workArea.systems) {
for (const subsystemMapping of systemMapping.subsystems) {
const listEleDef = {
element: "*",