UNPKG

@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
"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: "*",