UNPKG

@flxbl-io/sfp

Version:

sfp is a CLI tool to help you manage your Salesforce projects in an artifact centric model

284 lines 28.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const DeploymentExecutor_1 = require("../../deployers/DeploymentExecutor"); const ReconcileProfileAgainstOrgImpl_1 = __importDefault(require("../components/ReconcileProfileAgainstOrgImpl")); const DeployDestructiveManifestToOrgImpl_1 = __importDefault(require("../components/DeployDestructiveManifestToOrgImpl")); const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger")); const fs = __importStar(require("fs-extra")); const path = require('path'); const tmp = require('tmp'); const InstallPackage_1 = require("./InstallPackage"); const DeploySourceToOrgImpl_1 = __importDefault(require("../../deployers/DeploySourceToOrgImpl")); const PackageEmptyChecker_1 = __importDefault(require("../validators/PackageEmptyChecker")); const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve"); const ProjectConfig_1 = __importDefault(require("../../project/ProjectConfig")); const DeploymentFilterRegistry_1 = require("../deploymentFilters/DeploymentFilterRegistry"); const DeploymentOptionDisplayer_1 = __importDefault(require("../../display/DeploymentOptionDisplayer")); const PackageComponentPrinter_1 = __importDefault(require("../../display/PackageComponentPrinter")); const DeployErrorDisplayer_1 = __importDefault(require("../../display/DeployErrorDisplayer")); const sfp_logger_2 = require("@flxbl-io/sfp-logger"); const glob_1 = require("glob"); class InstallSourcePackageImpl extends InstallPackage_1.InstallPackage { constructor(sfpPackage, targetOrg, options, logger) { super(sfpPackage, targetOrg, logger, options); this.options = options; this.pathToReplacementForceIgnore = options.pathToReplacementForceIgnore; this.deploymentType = options.deploymentType; } async install() { let tmpDirObj = tmp.dirSync({ unsafeCleanup: true }); let tempDir = tmpDirObj.name; try { //Handle the right force ignore file this.handleForceIgnores(); // Apply Destructive Manifest await this.applyDestructiveChanges(); //Apply Reconcile if Profiles are found //To Reconcile we have to go for multiple deploys, first we have to reconcile profiles and deploy the metadata let isReconcileActivated = false; let isReconcileErrored = false; let profileFolders; ({ profileFolders, isReconcileActivated, isReconcileErrored, } = await this.reconcileProfilesBeforeDeployment(this.sfpPackage.sourceDir, this.sfpOrg.getUsername(), tempDir)); let deploymentOptions; let result; //Construct Deploy Command for actual payload deploymentOptions = await this.generateDeploymentOptions(this.options.waitTime, this.options.optimizeDeployment, this.options.skipTesting, this.sfpOrg.getUsername(), this.options.apiVersion); //enable source tracking if (this.deploymentType === DeploymentExecutor_1.DeploymentType.SOURCE_PUSH) { deploymentOptions.sourceTracking = true; } //Make a copy.. dont mutate sourceDirectory let resolvedSourceDirectory = this.sfpPackage.sourceDir; let emptyCheck = this.handleEmptyPackage(resolvedSourceDirectory, this.packageDirectory); if (emptyCheck.isToSkip == true) { sfp_logger_1.default.log(`${(0, sfp_logger_1.COLOR_SUCCESS)(`Skipping the package as there is nothing to be deployed`)}`, sfp_logger_1.LoggerLevel.INFO, this.logger); return { deploy_id: `000000`, result: true, message: `Package is empty, nothing to install,skipped`, }; } else if (emptyCheck.isToSkip == false) { //Create componentSet To Be Deployed let componentSet = source_deploy_retrieve_1.ComponentSet.fromSource(path.resolve(emptyCheck.resolvedSourceDirectory, this.packageDirectory)); //Apply Filters let deploymentFilters = DeploymentFilterRegistry_1.DeploymentFilterRegistry.getImplementations(); for (const deploymentFilter of deploymentFilters) { if (deploymentFilter.isToApply(ProjectConfig_1.default.getSFDXProjectConfig(emptyCheck.resolvedSourceDirectory), this.sfpPackage.packageType)) componentSet = await deploymentFilter.apply(this.sfpOrg, componentSet, this.logger); } //Check if there are components to be deployed after filtering //Assume its successfully deployed if (componentSet.size == 0) { return { deploy_id: `000000`, result: true, message: `Package contents were filtered out, nothing to install`, }; } //Print components inside Component Set let components = componentSet.getSourceComponents(); PackageComponentPrinter_1.default.printComponentTable(components, this.logger); if (!this.options.isInstallingForValidation) { DeploymentOptionDisplayer_1.default.printDeploymentOptions(deploymentOptions, this.logger); } let deploySourceToOrgImpl = new DeploySourceToOrgImpl_1.default(this.sfpOrg, this.sfpPackage.sourceDir, componentSet, deploymentOptions, this.logger); result = await deploySourceToOrgImpl.exec(); if (result.result) { //Apply PostDeployment Activities try { if (isReconcileActivated) { //Bring back the original profiles, reconcile and redeploy again await this.reconcileAndRedeployProfiles(profileFolders, this.sfpPackage.sourceDir, this.sfpOrg.getUsername(), this.packageDirectory, tempDir, deploymentOptions); } } catch (error) { sfp_logger_1.default.log('Failed to apply reconcile the second time, Partial Metadata applied', sfp_logger_1.LoggerLevel.INFO, this.logger); } } else if (result.result === false) { DeployErrorDisplayer_1.default.displayErrors(result.response, this.logger); throw new Error(result.message); } } //} } catch (error) { tmpDirObj.removeCallback(); throw error; } } handleEmptyPackage(sourceDirectory, packageDirectory) { //Check empty conditions let status = PackageEmptyChecker_1.default.isToBreakBuildForEmptyDirectory(sourceDirectory, packageDirectory, false); if (status.result == 'break') { throw new Error('No components in the package, Please check your build again'); } else if (status.result == 'skip') { return { isToSkip: true, resolvedSourceDirectory: sourceDirectory, }; } else { return { isToSkip: false, resolvedSourceDirectory: sourceDirectory, }; } } handleForceIgnores() { if (this.pathToReplacementForceIgnore) { this.replaceForceIgnoreInSourceDirectory(this.sfpPackage.sourceDir, this.pathToReplacementForceIgnore); //Handle Diff condition // if (this.isDiffFolderAvailable) // this.replaceForceIgnoreInSourceDirectory( // path.join(this.sfpPackage.sourceDir, 'diff'), // this.pathToReplacementForceIgnore // ); } } async applyDestructiveChanges() { if (this.sfpPackage.destructiveChanges) { try { sfp_logger_1.default.log('Attempt to delete components mentioned in destructive manifest', sfp_logger_1.LoggerLevel.INFO, this.logger); let deployDestructiveManifestToOrg = new DeployDestructiveManifestToOrgImpl_1.default(this.sfpOrg, path.join(this.sfpPackage.sourceDir, 'destructive', 'destructiveChanges.xml')); await deployDestructiveManifestToOrg.exec(); } catch (error) { sfp_logger_1.default.log(`We attempted a deletion of components, However we are not successful. \ Either the components are already deleted or there are components which \ have dependency to components in the manifest. \ Please check whether this manifest works! \ Actual Error Observed: \ -------------------------------------- \ ${(0, sfp_logger_2.COLOR_ERROR)(error.message)}`, sfp_logger_1.LoggerLevel.INFO, this.logger); } } } async reconcileProfilesBeforeDeployment(sourceDirectoryPath, target_org, tempDir) { let profileFolders; let isReconcileActivated = false; let isReconcileErrored = false; try { //Hard exit.. no reconcile set in orchestrator if (this.sfpPackage.reconcileProfiles == false) return { isReconcileActivated: false }; //Handle diff for fastfeedback if (this.sfpPackage.isProfilesFound) { } else { return { isReconcileActivated: false }; } sfp_logger_1.default.log('Attempting reconcile to profiles as payload contain profiles', sfp_logger_1.LoggerLevel.INFO, this.logger); //copy the original profiles to temporary location profileFolders = (0, glob_1.globSync)('**/profiles', { cwd: path.join(sourceDirectoryPath), }); if (profileFolders.length > 0) { profileFolders.forEach((folder) => { fs.copySync(path.join(sourceDirectoryPath, folder), path.join(tempDir, folder)); }); } //Now Reconcile let reconcileProfileAgainstOrg = new ReconcileProfileAgainstOrgImpl_1.default(this.sfpOrg, path.join(sourceDirectoryPath), this.logger); await reconcileProfileAgainstOrg.exec(); isReconcileActivated = true; } catch (err) { sfp_logger_1.default.log('Failed to reconcile profiles:' + err, sfp_logger_1.LoggerLevel.INFO, this.logger); isReconcileErrored = true; if (profileFolders.length > 0) { sfp_logger_1.default.log('Restoring original profiles as preprocessing failed', sfp_logger_1.LoggerLevel.INFO, this.logger); profileFolders.forEach((folder) => { fs.copySync(path.join(tempDir, folder), path.join(this.sfpPackage.sourceDir, folder)); }); } } return { profileFolders, isReconcileActivated, isReconcileErrored }; } async reconcileAndRedeployProfiles(profileFolders, sourceDirectoryPath, target_org, sourceDirectory, tmpdir, deploymentOptions) { //if no profile supported metadata, no point in //doing a reconcile if (this.sfpPackage.isProfilesFound == false) return; if (this.sfpPackage.isPayLoadContainTypesSupportedByProfiles == false) return; if (profileFolders.length > 0) { sfp_logger_1.default.log(`Restoring original profiles for reconcile and deploy`, sfp_logger_1.LoggerLevel.INFO, this.logger); profileFolders.forEach((folder) => { fs.copySync(path.join(tmpdir, folder), path.join(sourceDirectoryPath, folder)); }); //Now Reconcile let reconcileProfileAgainstOrg = new ReconcileProfileAgainstOrgImpl_1.default(this.sfpOrg, sourceDirectoryPath, this.logger); await reconcileProfileAgainstOrg.exec(); //Now deploy the profiles alone const profilesDirs = (0, glob_1.globSync)('**/profiles/', { cwd: path.join(sourceDirectoryPath, sourceDirectory), absolute: true, }); const profileDeploymentStagingDirectory = path.join(sourceDirectoryPath, 'ProfileDeploymentStagingDirectory'); fs.mkdirpSync(path.join(profileDeploymentStagingDirectory, sourceDirectory, 'profiles')); for (const dir of profilesDirs) { // Duplicate profiles are overwritten fs.copySync(dir, path.join(profileDeploymentStagingDirectory, sourceDirectory, 'profiles')); } fs.copySync(path.join(sourceDirectoryPath, 'sfdx-project.json'), path.join(profileDeploymentStagingDirectory, 'sfdx-project.json')); fs.copySync(path.join(sourceDirectoryPath, '.forceignore'), path.join(profileDeploymentStagingDirectory, '.forceignore')); //Create componentSet To Be Deployed let componentSet = source_deploy_retrieve_1.ComponentSet.fromSource(path.resolve(profileDeploymentStagingDirectory, sourceDirectory)); DeploymentOptionDisplayer_1.default.printDeploymentOptions(deploymentOptions, this.logger); let deploySourceToOrgImpl = new DeploySourceToOrgImpl_1.default(this.sfpOrg, this.sfpPackage.sourceDir, componentSet, deploymentOptions, this.logger); let profileReconcile = await deploySourceToOrgImpl.exec(); if (!profileReconcile.result) { DeployErrorDisplayer_1.default.displayErrors(profileReconcile.response, this.logger); sfp_logger_1.default.log('Unable to deploy reconciled profiles', sfp_logger_1.LoggerLevel.INFO, this.logger); } } } /** * Replaces forceignore in source directory with provided forceignore * @param sourceDirectory * @param pathToReplacementForceIgnore */ replaceForceIgnoreInSourceDirectory(sourceDirectory, pathToReplacementForceIgnore) { if (fs.existsSync(pathToReplacementForceIgnore)) fs.copySync(pathToReplacementForceIgnore, path.join(sourceDirectory, '.forceignore')); else { sfp_logger_1.default.log(`${pathToReplacementForceIgnore} does not exist`, sfp_logger_1.LoggerLevel.INFO, this.logger); sfp_logger_1.default.log('Package installation will continue using the unchanged forceignore in the source directory', null, this.logger); } } } exports.default = InstallSourcePackageImpl; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5zdGFsbFNvdXJjZVBhY2thZ2VJbXBsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvcmUvcGFja2FnZS9wYWNrYWdlSW5zdGFsbGVycy9JbnN0YWxsU291cmNlUGFja2FnZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDJFQUE0RztBQUM1RyxrSEFBMEY7QUFDMUYsMEhBQWtHO0FBQ2xHLG1FQUFvRztBQUNwRyw2Q0FBK0I7QUFDL0IsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQzdCLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUMzQixxREFBaUY7QUFDakYsa0dBQWlHO0FBQ2pHLDRGQUFvRTtBQUlwRSwrRUFBa0U7QUFDbEUsZ0ZBQXdEO0FBQ3hELDRGQUF5RjtBQUN6Rix3R0FBZ0Y7QUFDaEYsb0dBQTRFO0FBQzVFLDhGQUFzRTtBQUN0RSxxREFBbUQ7QUFDbkQsK0JBQWdDO0FBRWhDLE1BQXFCLHdCQUF5QixTQUFRLCtCQUFjO0lBTWhFLFlBQ0ksVUFBc0IsRUFDdEIsU0FBaUIsRUFDakIsT0FBc0MsRUFDdEMsTUFBYztRQUVkLEtBQUssQ0FBQyxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM5QyxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsNEJBQTRCLEdBQUcsT0FBTyxDQUFDLDRCQUE0QixDQUFDO1FBQ3pFLElBQUksQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQztJQUNqRCxDQUFDO0lBRU0sS0FBSyxDQUFDLE9BQU87UUFDaEIsSUFBSSxTQUFTLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ3JELElBQUksT0FB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