UNPKG

@dxatscale/sfprofiles

Version:
292 lines (267 loc) 11.3 kB
import * as fs from 'fs-extra'; import * as xml2js from 'xml2js'; const _ = require('lodash'); import * as util from 'util'; import DiffUtil from './diffUtil'; const parser = new xml2js.Parser({ explicitArray: false, valueProcessors: [ function (name) { let result: boolean; if (name === 'true') result = true; if (name === 'false') result = false; return result; }, ], }); export default class SharingRuleDiff { public static async generateSharingRulesXml( sharingRuleXml1: string, sharingRuleXml2: string, outputFilePath: string, objectName: string, destructivePackageObj: any[], resultOutput: any[], isDestructive: boolean ) { const parseString = util.promisify(parser.parseString) as _.Function1<xml2js.convertableToString, Promise<{ SharingRules: any }>>; let sharingRulesObj1: any = {}; let sharingRulesObj2: any = {}; if (sharingRuleXml1 !== '') { let parseResult = await parseString(sharingRuleXml1); sharingRulesObj1 = parseResult.SharingRules || {}; } if (sharingRuleXml2 !== '') { let parseResult = await parseString(sharingRuleXml2); sharingRulesObj2 = parseResult.SharingRules || {}; } let addedEditedOrDeleted = SharingRuleDiff.buildSharingRulesObj(sharingRulesObj1, sharingRulesObj2); SharingRuleDiff.writeSharingRule(addedEditedOrDeleted.addedEdited, outputFilePath); destructivePackageObj = SharingRuleDiff.buildDestructiveChangesObj( addedEditedOrDeleted.deleted, destructivePackageObj, objectName ); SharingRuleDiff.updateOutput( addedEditedOrDeleted.addedEdited, resultOutput, objectName, 'Deploy', outputFilePath ); if (isDestructive) { SharingRuleDiff.updateOutput( addedEditedOrDeleted.deleted, resultOutput, objectName, 'Delete', 'destructiveChanges.xml' ); } return destructivePackageObj; } private static updateOutput(sharingRulesObj, resultOutput: any[], objectName, action, filePath) { sharingRulesObj.sharingCriteriaRules.forEach((elem) => { resultOutput.push({ action: action, metadataType: 'SharingCriteriaRule', componentName: `${objectName}.${elem.fullName}`, path: filePath, }); }); sharingRulesObj.sharingOwnerRules.forEach((elem) => { resultOutput.push({ action: action, metadataType: 'SharingOwnerRule', componentName: `${objectName}.${elem.fullName}`, path: filePath, }); }); sharingRulesObj.sharingTerritoryRules.forEach((elem) => { resultOutput.push({ action: action, metadataType: 'SharingTerritoryRule', componentName: `${objectName}.${elem.fullName}`, path: filePath, }); }); } private static ensureArray(sharingObj) { let keys = Object.keys(sharingObj); keys.forEach((key) => { if (typeof sharingObj[key] === 'object' && !Array.isArray(sharingObj[key]) && key !== '$') { sharingObj[key] = [sharingObj[key]]; } }); return sharingObj; } public static async getMembers(filePath: string) { let fileContent = fs.readFileSync(filePath, 'utf8').toString(); const parseString = util.promisify(parser.parseString) as _.Function1<xml2js.convertableToString, Promise<{ SharingRules: any }>>; let members = {}; if (fileContent !== '') { let parseResult = await parseString(fileContent); let sharingRulesObj = parseResult.SharingRules || {}; if (!_.isNil(sharingRulesObj.sharingCriteriaRules)) { if (!Array.isArray(sharingRulesObj.sharingCriteriaRules)) { members['SharingCriteriaRule'] = [sharingRulesObj.sharingCriteriaRules.fullName]; } else { members['SharingCriteriaRule'] = sharingRulesObj.sharingCriteriaRules.map((sharingRule) => { return sharingRule.fullName; }); } } if (!_.isNil(sharingRulesObj.sharingOwnerRules)) { if (!Array.isArray(sharingRulesObj.sharingOwnerRules)) { members['SharingOwnerRule'] = [sharingRulesObj.sharingOwnerRules.fullName]; } else { members['SharingOwnerRule'] = sharingRulesObj.sharingOwnerRules.map((sharingRule) => { return sharingRule.fullName; }); } } if (!_.isNil(sharingRulesObj.sharingTerritoryRules)) { if (!Array.isArray(sharingRulesObj.sharingTerritoryRules)) { members['SharingTerritoryRule'] = [sharingRulesObj.sharingTerritoryRules.fullName]; } else { members['SharingTerritoryRule'] = sharingRulesObj.sharingTerritoryRules.map((sharingRule) => { return sharingRule.fullName; }); } } if (!_.isNil(sharingRulesObj.sharingGuestRules)) { if (!Array.isArray(sharingRulesObj.sharingGuestRules)) { members['SharingGuestRule'] = [sharingRulesObj.sharingGuestRules.fullName]; } else { members['SharingGuestRule'] = sharingRulesObj.sharingGuestRules.map((sharingRule) => { return sharingRule.fullName; }); } } } return members; } private static buildSharingRulesObj( sharingRuleObj1: any, sharingRulesObj2: any ): { addedEdited: any; deleted: any } { let newSharingRuleObj = { $: { xmlns: 'http://soap.sforce.com/2006/04/metadata' }, sharingCriteriaRules: [], sharingOwnerRules: [], sharingTerritoryRules: [], sharingGuestRules: [], }; sharingRuleObj1 = SharingRuleDiff.ensureArray(sharingRuleObj1); sharingRulesObj2 = SharingRuleDiff.ensureArray(sharingRulesObj2); let deletedSharingObj = { $: { xmlns: 'http://soap.sforce.com/2006/04/metadata' }, sharingCriteriaRules: [], sharingOwnerRules: [], sharingTerritoryRules: [], sharingGuestRules: [], }; let addedDeleted = DiffUtil.getChangedOrAdded( sharingRuleObj1.sharingCriteriaRules, sharingRulesObj2.sharingCriteriaRules, 'fullName' ); newSharingRuleObj.sharingCriteriaRules = addedDeleted.addedEdited; deletedSharingObj.sharingCriteriaRules = addedDeleted.deleted; addedDeleted = DiffUtil.getChangedOrAdded( sharingRuleObj1.sharingOwnerRules, sharingRulesObj2.sharingOwnerRules, 'fullName' ); newSharingRuleObj.sharingOwnerRules = addedDeleted.addedEdited; deletedSharingObj.sharingOwnerRules = addedDeleted.deleted; addedDeleted = DiffUtil.getChangedOrAdded( sharingRuleObj1.sharingTerritoryRules, sharingRulesObj2.sharingTerritoryRules, 'fullName' ); newSharingRuleObj.sharingTerritoryRules = addedDeleted.addedEdited; deletedSharingObj.sharingTerritoryRules = addedDeleted.deleted; addedDeleted = DiffUtil.getChangedOrAdded( sharingRuleObj1.sharingGuestRules, sharingRulesObj2.sharingGuestRules, 'fullName' ); newSharingRuleObj.sharingGuestRules = addedDeleted.addedEdited; deletedSharingObj.sharingGuestRules = addedDeleted.deleted; return { addedEdited: newSharingRuleObj, deleted: deletedSharingObj, }; } private static buildDestructiveChangesObj(deletedSharing: any, destructivePackageObj: any[], objectName: string) { let sharingCriteriaRules: any = _.find(destructivePackageObj, function (metaType: any) { return metaType.name === 'SharingCriteriaRule'; }); if ( sharingCriteriaRules === undefined && deletedSharing.sharingCriteriaRules !== undefined && deletedSharing.sharingCriteriaRules.length > 0 ) { sharingCriteriaRules = { name: 'SharingCriteriaRule', members: [], }; destructivePackageObj.push(sharingCriteriaRules); } if (deletedSharing.sharingCriteriaRules !== undefined) { deletedSharing.sharingCriteriaRules.forEach((elem) => { sharingCriteriaRules.members.push(objectName + '.' + elem.fullName); }); } let sharingOwnerRules: any = _.find(destructivePackageObj, function (metaType: any) { return metaType.name === 'SharingOwnerRule'; }); if ( sharingOwnerRules === undefined && deletedSharing.sharingOwnerRules !== undefined && deletedSharing.sharingOwnerRules.length > 0 ) { sharingOwnerRules = { name: 'SharingOwnerRule', members: [], }; destructivePackageObj.push(sharingOwnerRules); } if (deletedSharing.sharingOwnerRules !== undefined) { deletedSharing.sharingOwnerRules.forEach((elem) => { sharingOwnerRules.members.push(objectName + '.' + elem.fullName); }); } let sharingTerritoryRules: any = _.find(destructivePackageObj, function (metaType: any) { return metaType.name === 'SharingTerritoryRule'; }); if ( sharingTerritoryRules === undefined && deletedSharing.sharingTerritoryRules !== undefined && deletedSharing.sharingTerritoryRules.length > 0 ) { sharingTerritoryRules = { name: 'SharingTerritoryRule', members: [], }; destructivePackageObj.push(sharingTerritoryRules); } if (deletedSharing.sharingTerritoryRules !== undefined) { deletedSharing.sharingTerritoryRules.forEach((elem) => { sharingTerritoryRules.members.push(objectName + '.' + elem.fullName); }); } return destructivePackageObj; } private static writeSharingRule(newSharingRulesObj: any, outputFilePath: string) { const builder = new xml2js.Builder({ xmldec: { version: '1.0', encoding: 'UTF-8', standalone: null }, }); let sharingRulesObj = { SharingRules: newSharingRulesObj, }; let xml = builder.buildObject(sharingRulesObj); fs.writeFileSync(outputFilePath, xml); } }