UNPKG

@flxbl-io/sfp

Version:

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

672 lines 72.5 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 }); exports.DeploymentMode = void 0; const ArtifactFetcher_1 = __importDefault(require("../../core/artifacts/ArtifactFetcher")); const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger")); const Stage_1 = require("../Stage"); const ProjectConfig_1 = __importDefault(require("../../core/project/ProjectConfig")); const semver = require("semver"); const PromoteUnlockedPackageImpl_1 = __importDefault(require("../../core/package/promote/PromoteUnlockedPackageImpl")); const DeploymentExecutor_1 = require("../../core/deployers/DeploymentExecutor"); const sfp_logger_2 = require("@flxbl-io/sfp-logger"); const PackageInstallationResult_1 = require("../../core/package/packageInstallers/PackageInstallationResult"); const SFPOrg_1 = __importDefault(require("../../core/org/SFPOrg")); const SfpPackage_1 = require("../../core/package/SfpPackage"); const SfpPackageInquirer_1 = __importDefault(require("../../core/package/SfpPackageInquirer")); const SfpPackageBuilder_1 = __importDefault(require("../../core/package/SfpPackageBuilder")); const SfpPackageInstaller_1 = __importDefault(require("../../core/package/SfpPackageInstaller")); const InstallPackage_1 = require("../../core/package/packageInstallers/InstallPackage"); const _ = __importStar(require("lodash")); const GroupConsoleLogs_1 = __importDefault(require("../../ui/GroupConsoleLogs")); const TableConstants_1 = require("../../ui/TableConstants"); const VersionNumberConverter_1 = __importDefault(require("../../core/utils/VersionNumberConverter")); const ReleaseConfigLoader_1 = __importDefault(require("../release/ReleaseConfigLoader")); const markdown_table_ts_1 = require("markdown-table-ts"); const FileOutputHandler_1 = __importDefault(require("../../outputs/FileOutputHandler")); const Table = require('cli-table'); const retry = require('async-retry'); var DeploymentMode; (function (DeploymentMode) { DeploymentMode[DeploymentMode["NORMAL"] = 0] = "NORMAL"; DeploymentMode[DeploymentMode["SOURCEPACKAGES"] = 1] = "SOURCEPACKAGES"; DeploymentMode[DeploymentMode["SOURCEPACKAGES_PUSH"] = 2] = "SOURCEPACKAGES_PUSH"; })(DeploymentMode || (exports.DeploymentMode = DeploymentMode = {})); class DeployImpl { constructor(props) { this.props = props; //Set defaults if (!this.props.maxRetryCount) this.props.maxRetryCount = 1; } set postDeployHook(hook) { this._postDeployHook = hook; } set preDeployHook(hook) { this._preDeployHook = hook; } async exec() { let deployed = []; let failed = []; let queue = []; let packagesToPackageInfo; try { //Create Org this.targetOrg = await SFPOrg_1.default.create({ aliasOrUsername: this.props.targetUsername }); let artifacts = ArtifactFetcher_1.default.fetchArtifacts(this.props.artifactDir, null, this.props.logger); if (artifacts.length === 0) throw new Error(`No artifacts to install found in ${this.props.artifactDir}`); //Convert artifacts to SfpPackages let sfpPackages = await this.generateSfpPackageFromArtifacts(artifacts); //Filter artifacts based on release config if (this.props.releaseConfigPath) sfpPackages = this.filterSfPPackagesBasedOnReleaseConfig(sfpPackages, this.props.releaseConfigPath, this.props.logger); else if (this.props.filterByProvidedArtifacts) sfpPackages = this.filterSfPPackagesBasedOnArtifacts(sfpPackages, this.props.filterByProvidedArtifacts, this.props.logger); if (sfpPackages.length <= 0 && (this.props.releaseConfigPath || this.props.filterByProvidedArtifacts)) { sfp_logger_1.default.log(`Skipping deployment, no artifacts found based on filters defined in ${this.props.releaseConfigPath ? ' release config' : '--artifacts parameter'}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); return { scheduled: 0, deployed: deployed, failed: failed, queue: queue, packagesToPackageInfo: null, error: null, }; } //Grab the latest projectConfig from Packages let sfpPackageInquirer = new SfpPackageInquirer_1.default(sfpPackages, this.props.logger); let sfdxProjectConfig = sfpPackageInquirer.getLatestProjectConfig(); if (sfdxProjectConfig == null) { // If unable to find latest package manifest in artifacts, use package manifest in project directory sfdxProjectConfig = ProjectConfig_1.default.getSFDXProjectConfig(null); } sfp_logger_1.default.log('Artifacts' + sfpPackages.length, sfp_logger_1.LoggerLevel.TRACE, this.props.logger); packagesToPackageInfo = await this.getPackagesToPackageInfo(sfpPackages); sfp_logger_1.default.log('Artifacts' + JSON.stringify(packagesToPackageInfo), sfp_logger_1.LoggerLevel.TRACE, this.props.logger); queue = this.getPackagesToDeploy(sfdxProjectConfig, packagesToPackageInfo); sfp_logger_1.default.log('queue:' + JSON.stringify(queue), sfp_logger_1.LoggerLevel.TRACE, this.props.logger); if (this.props.skipIfPackageInstalled) { //Filter the queue based on what is deployed in the target org let isBaselinOrgModeActivated; if (this.props.baselineOrg) { isBaselinOrgModeActivated = true; } else { isBaselinOrgModeActivated = false; this.props.baselineOrg = this.props.targetUsername; //Change baseline to the target one itself } let filteredDeploymentQueue = await this.filterByPackagesInstalledInTheOrg(sfdxProjectConfig, queue, packagesToPackageInfo, this.props.baselineOrg); sfp_logger_1.default.log('filtered queue:' + JSON.stringify(filteredDeploymentQueue), sfp_logger_1.LoggerLevel.TRACE, this.props.logger); this.printArtifactVersionsWhenSkipped(queue, packagesToPackageInfo, isBaselinOrgModeActivated, this.props); queue = filteredDeploymentQueue; } else { this.printArtifactVersions(queue, packagesToPackageInfo); } for (let i = 0; i < queue.length; i++) { let packageInfo = packagesToPackageInfo[queue[i].packageName]; let sfpPackage = packageInfo.sfpPackage; let packageType = sfpPackage.packageType; let pkgDescriptor = ProjectConfig_1.default.getPackageDescriptorFromConfig(queue[i].packageName, sfdxProjectConfig); let groupSection; if (this.props.currentStage == Stage_1.Stage.VALIDATE) { groupSection = new GroupConsoleLogs_1.default(`Validating/Synchronizing: ${i + 1}/${queue.length} ${queue[i].packageName}`, this.props.logger).begin(); } else groupSection = new GroupConsoleLogs_1.default(`Installing: ${i + 1}/${queue.length} ${queue[i].packageName}`, this.props.logger).begin(); //Display Header this.displayHeader(sfpPackage, pkgDescriptor, queue[i].packageName); let preHookStatus = await this._preDeployHook?.preDeployPackage(sfpPackage, this.props.targetUsername, sfpPackages, this.props.devhubUserName, this.props.logger); if (preHookStatus?.isToFailDeployment) { failed = queue.slice(i).map((pkg) => packagesToPackageInfo[pkg.packageName]); throw new Error(preHookStatus.message ? preHookStatus.message : 'Hook Failed to execute, but didnt provide proper message'); } let isToBeRetried = this.props.isRetryOnFailure; let packageInstallationResult = await retry(async (bail, attemptCount) => { try { try { await this.promotePackagesBeforeInstallation(packageInfo.sourceDirectory, sfpPackage); } catch (error) { //skip packages already promoted sfp_logger_1.default.log(`Artifact already promoted .. skipping`, sfp_logger_1.LoggerLevel.WARN); } this.displayRetryHeader(isToBeRetried, attemptCount); let installPackageResult = await this.installPackage(packageType, queue[i], this.targetOrg, queue[i].packageDescriptor.skipTesting, this.props.waitTime.toString(), pkgDescriptor, false, //Queue already filtered by deploy, there is no further need for individual //commands to decide the skip logic. TODO: fix this incorrect pattern sfpPackage.apiVersion || sfpPackage.payload?.Package?.version // Use package.xml version for backwards compat with old artifacts ); //Handle specific error condition which need a retry, overriding the set value isToBeRetried = handleRetryOnSpecificConditions(isToBeRetried, installPackageResult, attemptCount, this.props.maxRetryCount); if (isToBeRetried) { throw new Error(installPackageResult.message); } else return installPackageResult; } catch (error) { if (isToBeRetried) { throw error; } else { // Any other exception, in regular cases dont retry, just bail out let failedPackageInstallationResult = { result: PackageInstallationResult_1.PackageInstallationStatus.Failed, message: error, }; FileOutputHandler_1.default.getInstance().writeOutput(`deployment-error.md`, `### 💣 Deployment Failed 💣`); FileOutputHandler_1.default.getInstance().appendOutput(`deployment-error.md`, `Artifact Installation failed for **${queue[i].packageName}**`); FileOutputHandler_1.default.getInstance().appendOutput(`deployment-error.md`, `Reasons:`); FileOutputHandler_1.default.getInstance().appendOutput(`deployment-error.md`, `${error}`); return failedPackageInstallationResult; } } function handleRetryOnSpecificConditions(isToBeRetried, installPackageResult, retryCount, maxRetryCount) { //override current value when encountering such issue if (installPackageResult.result === PackageInstallationResult_1.PackageInstallationStatus.Failed) { if (installPackageResult.message?.includes('ongoing background job')) return true; else if (isToBeRetried && retryCount <= maxRetryCount) return true; else return false; } else return false; } }, { retries: 10, minTimeout: 30000 }); if (packageInstallationResult.result === PackageInstallationResult_1.PackageInstallationStatus.Succeeded) { deployed.push(packageInfo); } else if (packageInstallationResult.result === PackageInstallationResult_1.PackageInstallationStatus.Skipped) { continue; } else if (packageInstallationResult.result === PackageInstallationResult_1.PackageInstallationStatus.Failed) { failed = queue.slice(i).map((pkg) => packagesToPackageInfo[pkg.packageName]); } // Only deploy post hook when package installation is successful if (packageInstallationResult.result === PackageInstallationResult_1.PackageInstallationStatus.Succeeded) { let postHookStatus = await this._postDeployHook?.postDeployPackage(sfpPackage, packageInstallationResult, this.props.targetUsername, sfpPackages, this.props.devhubUserName, this.props.logger); if (postHookStatus?.isToFailDeployment) { failed = queue.slice(i).map((pkg) => packagesToPackageInfo[pkg.packageName]); throw new Error(postHookStatus.message ? postHookStatus.message : 'Hook Failed to execute, but didnt provide proper message'); } } if (packageInstallationResult.result === PackageInstallationResult_1.PackageInstallationStatus.Failed) { failed = queue.slice(i).map((pkg) => packagesToPackageInfo[pkg.packageName]); throw new Error(packageInstallationResult.message); } groupSection.end(); } return { scheduled: queue.length, deployed: deployed, failed: failed, queue: queue, packagesToPackageInfo: packagesToPackageInfo, error: null, }; } catch (err) { sfp_logger_1.default.log(err, sfp_logger_1.LoggerLevel.ERROR, this.props.logger); return { scheduled: queue?.length ? queue.length : 0, deployed: deployed, failed: failed, queue: queue, packagesToPackageInfo: packagesToPackageInfo, error: err.message, }; } } filterSfPPackagesBasedOnReleaseConfig(sfpPackages, releaseConfigPath, logger) { if (!releaseConfigPath) return sfpPackages; else { sfp_logger_1.default.log((0, sfp_logger_2.COLOR_KEY_MESSAGE)(`Filtering packages to be deployed based on release config ${(0, sfp_logger_2.COLOR_KEY_VALUE)(releaseConfigPath)}`), sfp_logger_1.LoggerLevel.INFO, logger); let releaseConfigLoader = new ReleaseConfigLoader_1.default(logger, releaseConfigPath); let packages = releaseConfigLoader.getPackagesAsPerReleaseConfig(); //Filter artifacts based on packages let filteredSfPPackages = []; for (const sfpPackage of sfpPackages) { if (packages.includes(sfpPackage.packageName)) { filteredSfPPackages.push(sfpPackage); } } return filteredSfPPackages; } } filterSfPPackagesBasedOnArtifacts(sfpPackages, artifacts, logger) { if (!artifacts || artifacts.length == 0) return sfpPackages; else { sfp_logger_1.default.log((0, sfp_logger_2.COLOR_KEY_MESSAGE)(`Filtering packages to be deployed based on provided artifacts ${(0, sfp_logger_2.COLOR_KEY_VALUE)(artifacts)}`), sfp_logger_1.LoggerLevel.INFO, logger); //Filter artifacts based on packages let filteredSfPPackages = []; for (const sfpPackage of sfpPackages) { if (artifacts.includes(sfpPackage.packageName)) { filteredSfPPackages.push(sfpPackage); } } return filteredSfPPackages; } } async generateSfpPackageFromArtifacts(artifacts) { let sfpPackages = []; for (const artifact of artifacts) { let sfpPackage = await SfpPackageBuilder_1.default.buildPackageFromArtifact(artifact, this.props.logger); sfpPackages.push(sfpPackage); } return sfpPackages; } async promotePackagesBeforeInstallation(sourceDirectory, sfpPackage) { if (this.props.promotePackagesBeforeDeploymentToOrg === this.props.targetUsername) { if (sfpPackage.packageType === SfpPackage_1.PackageType.Unlocked) { console.log((0, sfp_logger_2.COLOR_KEY_MESSAGE)(`Attempting to promote artifact ${sfpPackage.packageName} before installation`)); if (!this.props.isDryRun) { let promoteUnlockedPackageImpl = new PromoteUnlockedPackageImpl_1.default(sourceDirectory, sfpPackage.package_version_id, this.props.devhubUserName); await promoteUnlockedPackageImpl.promote(); } } } } displayRetryHeader(isRetryOnFailure, count) { if (isRetryOnFailure && count > 1) { sfp_logger_1.default.printHeaderLine('', sfp_logger_2.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO, this.props.logger); sfp_logger_1.default.log(`Retrying On Failure Attempt: ${count}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); sfp_logger_1.default.printHeaderLine('', sfp_logger_2.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO, this.props.logger); } } displayHeader(sfpPackage, pkgDescriptor, pkg) { let alwaysDeployMessage; if (this.props.skipIfPackageInstalled) { if (pkgDescriptor.alwaysDeploy) alwaysDeployMessage = `Always Deploy: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(`True`)}`; else alwaysDeployMessage = `Always Deploy: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(`False`)}`; } else alwaysDeployMessage = undefined; //Display header let message = 'Installing'; if (this.props.currentStage == Stage_1.Stage.VALIDATE) { if (this.props.impactedPackagesAsPerBranch) { let isPackageImpacted = this.props.impactedPackagesAsPerBranch?.get(pkg); message = isPackageImpacted ? 'Validating' : 'Synchronizing'; } else { message = 'Validating'; } } sfp_logger_1.default.printHeaderLine(`${message} artifact:${pkg}`, sfp_logger_2.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO, this.props.logger); sfp_logger_1.default.log((0, sfp_logger_2.COLOR_HEADER)(`Name: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(pkg)}`), sfp_logger_1.LoggerLevel.INFO, this.props.logger); sfp_logger_1.default.log(`Type: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(sfpPackage.packageType)}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); sfp_logger_1.default.log(`Version Number: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(sfpPackage.versionNumber)}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); this.displayTestInfoHeader(sfpPackage); if (pkgDescriptor.aliasfy) sfp_logger_1.default.log(`Aliasified Package: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(`True`)}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); if (sfpPackage.isApexFound) sfp_logger_1.default.log(`Contains Apex Classes/Triggers: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(sfpPackage.isApexFound)}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); if (sfpPackage.packageType == SfpPackage_1.PackageType.Source || sfpPackage.packageType == SfpPackage_1.PackageType.Unlocked) { if (!pkgDescriptor.aliasfy) { sfp_logger_1.default.log(`Metadata to be deployed: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(sfpPackage.metadataCount)}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); } } if (pkgDescriptor.skipTesting) { sfp_logger_1.default.log(`Skip Testing: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)('true')}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); } else { sfp_logger_1.default.log(`Skip Testing: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)('false')}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); } if (alwaysDeployMessage) sfp_logger_1.default.log(alwaysDeployMessage, sfp_logger_1.LoggerLevel.INFO, this.props.logger); sfp_logger_1.default.printHeaderLine('', sfp_logger_2.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO, this.props.logger); } displayTestInfoHeader(sfpPackage) { if (sfpPackage.packageType == SfpPackage_1.PackageType.Source) { if (!sfpPackage.isTriggerAllTests) sfp_logger_1.default.log(`Optimized Deployment: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(this.isOptimizedDeploymentForSourcePackage(sfpPackage.packageDescriptor))}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); else sfp_logger_1.default.log(`Trigger All Tests: ${(0, sfp_logger_2.COLOR_KEY_MESSAGE)(`true`)}`, sfp_logger_1.LoggerLevel.INFO, this.props.logger); } } printArtifactVersionsWhenSkipped(queue, packagesToPackageInfo, isBaselinOrgModeActivated, props) { let groupSection = new GroupConsoleLogs_1.default(`Full Installation Breakdown`, this.props.logger).begin(); let maxTable = new Table({ head: [ 'Artifact', 'Incoming Version', isBaselinOrgModeActivated ? 'Version in baseline org' : 'Version in org', 'To be installed?', ], chars: TableConstants_1.ZERO_BORDER_TABLE, }); queue.forEach((pkg) => { maxTable.push(processColoursForAllPackages(pkg)); }); sfp_logger_1.default.log(maxTable.toString(), sfp_logger_1.LoggerLevel.INFO, this.props.logger); //Insane Hack //TODO: Export the value to the caller printDeploymentBreakDownInMarkdown(); groupSection.end(); groupSection = new GroupConsoleLogs_1.default(`Artifacts to be installed`, this.props.logger).begin(); let minTable = new Table({ head: [ 'Artifact', 'Incoming Version', isBaselinOrgModeActivated ? 'Version in baseline org' : 'Version in org', ], chars: TableConstants_1.ZERO_BORDER_TABLE, }); queue.forEach((pkg) => { if (!packagesToPackageInfo[pkg.packageName].isPackageInstalled) minTable.push([ (0, sfp_logger_2.COLOR_KEY_MESSAGE)(pkg.packageName), (0, sfp_logger_2.COLOR_KEY_MESSAGE)(pkg.versionNumber), packagesToPackageInfo[pkg.packageName].versionInstalledInOrg ? (0, sfp_logger_2.COLOR_KEY_MESSAGE)(packagesToPackageInfo[pkg.packageName].versionInstalledInOrg) : (0, sfp_logger_2.COLOR_KEY_MESSAGE)('N/A'), ]); }); sfp_logger_1.default.log(minTable.toString(), sfp_logger_1.LoggerLevel.INFO, this.props.logger); groupSection.end(); function printDeploymentBreakDownInMarkdown() { let tableData = { table: { head: [ 'Artifact', 'Incoming Version', isBaselinOrgModeActivated ? 'Version in baseline org' : 'Version in org', 'To be installed?', 'Promotion Status', ], body: [], }, alignment: [markdown_table_ts_1.Align.Left, markdown_table_ts_1.Align.Left, markdown_table_ts_1.Align.Left, markdown_table_ts_1.Align.Right], }; for (const pkg of queue) { tableData.table.body.push(getRowForMarkdownTable(pkg, props)); } const table = (0, markdown_table_ts_1.getMarkdownTable)(tableData); const outputHandler = FileOutputHandler_1.default.getInstance(); outputHandler.appendOutput('deployment-breakdown.md', table); } function processColoursForAllPackages(pkg) { const pkgInfo = packagesToPackageInfo[pkg.packageName]; let packageName = pkg.packageName; let versionNumber = pkg.versionNumber; let versionInstalledInOrg = pkgInfo.versionInstalledInOrg ? pkgInfo.versionInstalledInOrg : 'N/A'; let isPackageInstalled = pkgInfo.isPackageInstalled ? 'No' : 'Yes'; if (pkgInfo.isPackageInstalled) { packageName = (0, sfp_logger_1.COLOR_SUCCESS)(packageName); versionNumber = (0, sfp_logger_1.COLOR_SUCCESS)(versionNumber); versionInstalledInOrg = (0, sfp_logger_1.COLOR_SUCCESS)(versionInstalledInOrg); isPackageInstalled = (0, sfp_logger_1.COLOR_SUCCESS)(isPackageInstalled); } else { packageName = (0, sfp_logger_1.COLOR_ERROR)(packageName); versionNumber = (0, sfp_logger_1.COLOR_ERROR)(versionNumber); versionInstalledInOrg = (0, sfp_logger_1.COLOR_ERROR)(versionInstalledInOrg); isPackageInstalled = (0, sfp_logger_1.COLOR_ERROR)(isPackageInstalled); } return [packageName, versionNumber, versionInstalledInOrg, isPackageInstalled]; } function getRowForMarkdownTable(pkg, props) { const pkgInfo = packagesToPackageInfo[pkg.packageName]; let packageName = pkg.packageName; let versionNumber = pkg.versionNumber; let versionInstalledInOrg = pkgInfo.versionInstalledInOrg ? pkgInfo.versionInstalledInOrg : 'N/A'; let isPackageToBeInstalled = pkgInfo.isPackageInstalled ? 'No' : 'Yes'; let promotionStatus = 'N/A'; if (isPackageToBeInstalled == 'Yes') { isPackageToBeInstalled = `![Yes](https://img.shields.io/badge/Yes-green.svg)`; packageName = `**${packageName}**`; if (pkg.packageType == SfpPackage_1.PackageType.Unlocked) { if (props.promotePackagesBeforeDeploymentToOrg == props.targetUsername && versionInstalledInOrg == 'N/A') { promotionStatus = '![Pending](https://img.shields.io/badge/Pending-yellow.svg)'; } else if (props.promotePackagesBeforeDeploymentToOrg == props.targetUsername) { let versionInstalledInOrgConvertedToSemver = (0, VersionNumberConverter_1.default)(versionInstalledInOrg); let versionNumberConvertedToSemver = (0, VersionNumberConverter_1.default)(versionNumber); if (semver.diff(versionInstalledInOrgConvertedToSemver, versionNumberConvertedToSemver) == 'prerelease') { promotionStatus = '![Already Promoted](https://img.shields.io/badge/Already%20Promoted-red.svg)'; } else { promotionStatus = '![Pending](https://img.shields.io/badge/Pending-yellow.svg)'; } } else { promotionStatus = 'N/A'; } } versionNumber = `**${versionNumber}**`; versionInstalledInOrg = `**${versionInstalledInOrg}**`; } else { versionNumber = `**${versionNumber}**`; versionInstalledInOrg = `**${versionInstalledInOrg}**`; } return [packageName, versionNumber, versionInstalledInOrg, isPackageToBeInstalled, promotionStatus]; } } printArtifactVersions(queue, packagesToPackageInfo) { let groupSection = new GroupConsoleLogs_1.default(`Packages to be deployed`, this.props.logger).begin(); let table = new Table({ head: ['Package', 'Version to be installed'], chars: TableConstants_1.ZERO_BORDER_TABLE, }); queue.forEach((pkg) => { table.push([pkg.packageName, pkg.versionNumber]); }); sfp_logger_1.default.log(table.toString(), sfp_logger_1.LoggerLevel.INFO, this.props.logger); groupSection.end(); printDeploymentBreakDownInMarkdown(this.props); function printDeploymentBreakDownInMarkdown(props) { let tableData = { table: { head: ['Package', props.currentStage == Stage_1.Stage.VALIDATE ? `Version` : `Commit Id`, 'Reason?'], body: [], }, alignment: [markdown_table_ts_1.Align.Left, markdown_table_ts_1.Align.Left, markdown_table_ts_1.Align.Left, markdown_table_ts_1.Align.Left], }; for (const pkg of queue) { tableData.table.body.push(getRowForMarkdownTable(pkg, props)); } const outputHandler = FileOutputHandler_1.default.getInstance(); outputHandler.writeOutput('deployment-breakdown.md', `Please find the artifacts that will be installed below`); outputHandler.appendOutput('deployment-breakdown.md', `\n\n${(0, markdown_table_ts_1.getMarkdownTable)(tableData)}`); } function getRowForMarkdownTable(pkg, props) { let packageName = pkg.packageName; if (props.currentStage == Stage_1.Stage.VALIDATE) { if (props.impactedPackagesAsPerBranch && props.impactedPackagesAsPerBranch.get(pkg.packageName)) return [packageName, pkg.sourceVersion, '![validation](https://img.shields.io/badge/validation-yellow.svg)']; else return [packageName, pkg.sourceVersion, `![sync](https://img.shields.io/badge/sync-green.svg)`]; } else { return [packageName, pkg.versionNumber, 'Deploy']; } } } async filterByPackagesInstalledInTheOrg(packageManifest, queue, packagesToPackageInfo, targetUsername) { let targetOrg = await SFPOrg_1.default.create({ aliasOrUsername: targetUsername }); const clonedQueue = _.clone(queue); for (let i = queue.length - 1; i >= 0; i--) { let packageInfo = packagesToPackageInfo[clonedQueue[i].packageName]; let sfpPackage = packageInfo.sfpPackage; let pkgDescriptor = ProjectConfig_1.default.getPackageDescriptorFromConfig(clonedQueue[i].packageName, packageManifest); let packageInstalledInTheOrg = await targetOrg.isArtifactInstalledInOrg(this.props.logger, sfpPackage); if (packageInstalledInTheOrg.versionNumber) packageInfo.versionInstalledInOrg = packageInstalledInTheOrg.versionNumber; if (packageInstalledInTheOrg.isInstalled) { if (!pkgDescriptor.alwaysDeploy) { packageInfo.isPackageInstalled = true; clonedQueue.splice(i, 1); } } } return clonedQueue; } /** * Returns map of package name to package info * @param artifacts */ async getPackagesToPackageInfo(sfpPackages) { let packagesToPackageInfo = {}; for (let sfpPackage of sfpPackages) { if (packagesToPackageInfo[sfpPackage.packageName]) { let previousVersionNumber = (0, VersionNumberConverter_1.default)(packagesToPackageInfo[sfpPackage.packageName].sfpPackage.versionNumber); let currentVersionNumber = (0, VersionNumberConverter_1.default)(sfpPackage.versionNumber); // replace existing packageInfo if package version number is newer if (semver.gt(currentVersionNumber, previousVersionNumber)) { packagesToPackageInfo[sfpPackage.packageName] = { sourceDirectory: sfpPackage.sourceDir, sfpPackage: sfpPackage, }; } } else { packagesToPackageInfo[sfpPackage.packageName] = { sourceDirectory: sfpPackage.sourceDir, sfpPackage: sfpPackage, }; } } return packagesToPackageInfo; } /** * Decider for which package installation type to run */ async installPackage(packageType, sfpPackage, targetOrg, skipTesting, waitTime, pkgDescriptor, skipIfPackageInstalled, apiVersion) { //Compute Deployment Type let deploymentType = this.props.deploymentMode === DeploymentMode.SOURCEPACKAGES_PUSH ? DeploymentExecutor_1.DeploymentType.SOURCE_PUSH : DeploymentExecutor_1.DeploymentType.MDAPI_DEPLOY; //Add Installation Options let installationOptions = new InstallPackage_1.SfpPackageInstallationOptions(); (installationOptions.installationkey = null), (installationOptions.apexcompile = 'package'); installationOptions.waitTime = waitTime; installationOptions.apiVersion = apiVersion; installationOptions.publishWaitTime = 60; installationOptions.isInstallingForValidation = this.props.deploymentMode != DeploymentMode.NORMAL && (this.props.currentStage === Stage_1.Stage.PREPARE || this.props.currentStage === Stage_1.Stage.VALIDATE); installationOptions.optimizeDeployment = this.isOptimizedDeploymentForSourcePackage(pkgDescriptor); installationOptions.skipTesting = skipTesting; installationOptions.deploymentType = deploymentType; installationOptions.disableArtifactCommit = this.props.disableArtifactCommit; //During validate, if optimizeDeploymentMode is false, use full local tests to validate //but respect skipTesting #issue 1075 //During Prepare (push), dont trigger tests if (this.props.currentStage == Stage_1.Stage.VALIDATE) { //Always enable skipTest as the default installation option during validate //as test are run subsequently installationOptions.skipTesting = true; if (!this.isOptimizedDeploymentForSourcePackage(pkgDescriptor)) { if (sfpPackage.packageDescriptor.skipTesting) installationOptions.skipTesting = sfpPackage.packageDescriptor.skipTesting; else installationOptions.skipTesting = false; } } else if (this.props.currentStage === Stage_1.Stage.PREPARE) { installationOptions.optimizeDeployment = false; installationOptions.skipTesting = true; } installationOptions.skipIfPackageInstalled = skipIfPackageInstalled; installationOptions.isDryRun = this.props.isDryRun; return SfpPackageInstaller_1.default.installPackage(this.props.logger, sfpPackage, targetOrg, installationOptions, { currentStage: this.props.currentStage, }, sfpPackage.packageType == SfpPackage_1.PackageType.Unlocked && installationOptions.isInstallingForValidation ? SfpPackage_1.PackageType.Source : undefined //Override to source ); } /** * Checks if package should be installed to target username * @param packageDescriptor */ isSkipDeployment(packageDescriptor, targetUsername) { let skipDeployOnOrgs = packageDescriptor.skipDeployOnOrgs; if (packageDescriptor.skipInstallOnOrgs) { skipDeployOnOrgs = packageDescriptor.skipInstallOnOrgs; } if (skipDeployOnOrgs) { if (!(skipDeployOnOrgs instanceof Array)) throw new Error(`Property 'skipDeployOnOrgs' or 'skipInstallOnOrgs' must be of type Array`); else return skipDeployOnOrgs.includes(targetUsername); } else return false; } // Allow individual packages to use non optimized path isOptimizedDeploymentForSourcePackage(pkgDescriptor) { if (pkgDescriptor.isOptimizedDeployment == null) return true; else return pkgDescriptor.isOptimizedDeployment; } /** * Returns the packages in the project config that have an artifact */ getPackagesToDeploy(sfdxProjectConfig, packagesToPackageInfo) { let packagesToDeploy = []; let packages = sfdxProjectConfig['packageDirectories']; // Filter package manifest by whats available in artifacts for (const pkg of packages) { if (packagesToPackageInfo[pkg.package]) packagesToDeploy.push(packagesToPackageInfo[pkg.package].sfpPackage); } // Filter out packages that are to be skipped on the target org packagesToDeploy = packagesToDeploy.filter((sfpPackage) => !this.isSkipDeployment(sfpPackage.packageDescriptor, this.props.targetUsername)); //Ignore packages based on stage packagesToDeploy = packagesToDeploy.filter((pkg) => { if (pkg.packageDescriptor.ignoreOnStage?.find((stage) => { stage = stage.toLowerCase(); return stage === this.props.currentStage; })) return false; else return true; }); return packagesToDeploy; } } exports.default = DeployImpl; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVwbG95SW1wbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9pbXBsL2RlcGxveS9EZXBsb3lJbXBsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsMkZBQWlGO0FBQ2pGLG1FQUFrRztBQUNsRyxvQ0FBaUM7QUFDakMscUZBQTZEO0FBQzdELGlDQUFrQztBQUNsQyx1SEFBK0Y7QUFDL0YsZ0ZBQXlFO0FBQ3pFLHFEQUF3RjtBQUN4Riw4R0FHd0U7QUFDeEUsbUVBQTJDO0FBQzNDLDhEQUF3RTtBQUN4RSwrRkFBdUU7QUFHdkUsNkZBQXFFO0FBQ3JFLGlHQUF5RTtBQUN6RSx3RkFBb0c7QUFDcEcsMENBQTRCO0FBQzVCLGlGQUF5RDtBQUN6RCw0REFBNEQ7QUFDNUQscUdBQXNGO0FBQ3RGLHlGQUFpRTtBQUNqRSx5REFBNEQ7QUFDNUQsd0ZBQWdFO0FBRWhFLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUNuQyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7QUFFckMsSUFBWSxjQUlYO0FBSkQsV0FBWSxjQUFjO0lBQ3RCLHVEQUFNLENBQUE7SUFDTix1RUFBYyxDQUFBO0lBQ2QsaUZBQW1CLENBQUE7QUFDdkIsQ0FBQyxFQUpXLGNBQWMsOEJBQWQsY0FBYyxRQUl6QjtBQTBCRCxNQUFxQixVQUFVO0lBSzNCLFlBQW9CLEtBQWtCO1FBQWxCLFVBQUssR0FBTCxLQUFLLENBQWE7UUFDbEMsY0FBYztRQUNkLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWE7WUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsR0FBRyxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVELElBQVcsY0FBYyxDQUFDLElBQW9CO1FBQzFDLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDO0lBQ2hDLENBQUM7SUFFRCxJ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