UNPKG

@flxbl-io/sfp

Version:

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

315 lines 32.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 }); const DeployImpl_1 = __importStar(require("../deploy/DeployImpl")); const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger")); const Stage_1 = require("../Stage"); const ReleaseError_1 = __importDefault(require("../../errors/ReleaseError")); const ChangelogImpl_1 = __importDefault(require("../changelog/ChangelogImpl")); const SFPStatsSender_1 = __importDefault(require("../../core/stats/SFPStatsSender")); const SFPOrg_1 = __importDefault(require("../../core/org/SFPOrg")); const path = require("path"); const os_1 = require("os"); const InstallUnlockedPackageCollection_1 = __importDefault(require("../../core/package/packageInstallers/InstallUnlockedPackageCollection")); const FetchImpl_1 = __importDefault(require("../artifacts/FetchImpl")); const GroupConsoleLogs_1 = __importDefault(require("../../ui/GroupConsoleLogs")); const ArtifactFetcher_1 = __importDefault(require("../../core/artifacts/ArtifactFetcher")); const SfpPackageBuilder_1 = __importDefault(require("../../core/package/SfpPackageBuilder")); const SfpPackageInquirer_1 = __importDefault(require("../../core/package/SfpPackageInquirer")); const ReleaseDefinitionSorter_1 = __importDefault(require("./ReleaseDefinitionSorter")); const FileOutputHandler_1 = __importDefault(require("../../outputs/FileOutputHandler")); class ReleaseImpl { constructor(props, logger) { this.props = props; this.logger = logger; } async exec() { let groupSection = new GroupConsoleLogs_1.default('Fetching artifacts').begin(); let fetchImpl = new FetchImpl_1.default('artifacts', this.props.fetchArtifactScript, this.props.scope, this.props.npmrcPath, this.logger); await fetchImpl.fetchArtifacts(this.props.releaseDefinitions); sfp_logger_1.default.log((0, sfp_logger_1.COLOR_INFO)(`Sorting order of release definitions...`), sfp_logger_1.LoggerLevel.INFO, this.logger); const sortedReleaseDefns = await this.getSortedReleaseDefns('artifacts', this.props.releaseDefinitions, this.logger); const sortedReleaseOrder = sortedReleaseDefns.map((def) => def.release); sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Order of Release Definitions: ${JSON.stringify(sortedReleaseOrder)}`), sfp_logger_1.LoggerLevel.INFO, this.logger); groupSection.end(); let installDependenciesResult; installDependenciesResult = await this.installPackageDependencies(this.props.releaseDefinitions, this.props.targetOrg, this.props.keys, this.props.waitTime); //Clear up the deployment output sfp_logger_1.default.log(`Clearing installation output`, sfp_logger_1.LoggerLevel.TRACE, this.logger); FileOutputHandler_1.default.getInstance().deleteOutputFile(`deployment-breakdown.md`); FileOutputHandler_1.default.getInstance().deleteOutputFile(`release-changelog.md`); let deploymentResults = await this.deployArtifacts(sortedReleaseDefns); //Get all suceeded deploys let succeededDeploymentResults = []; let failedDeploymentResults = []; for (const deploymentResult of deploymentResults) { if (deploymentResult.result.failed.length === 0) succeededDeploymentResults.push(deploymentResult); else failedDeploymentResults.push(deploymentResult); } //Compute Changelog //There is atleast one succeeded result, so changelog is required if (succeededDeploymentResults.length > 0) { //ReleaseName combines all the release together .. even if failed //Combine all release defns to create release attributes let releaseName = ''; let workitemFilters = []; let limit = 30; let workItemUrl; let showAllArtifacts = false; //Lets go through all the succeeded deployments and get the changelog for (const succededDeployment of succeededDeploymentResults) { releaseName = succededDeployment.releaseDefinition.release; let releaseDefinition = succededDeployment.releaseDefinition; if (releaseDefinition.changelog) { if (releaseDefinition.changelog?.workItemFilters) { workitemFilters.push(...releaseDefinition.changelog?.workItemFilters); } if (releaseDefinition.changelog.limit > limit) limit = releaseDefinition.changelog.limit; workItemUrl = releaseDefinition.changelog.workItemUrl; showAllArtifacts = releaseDefinition.changelog.showAllArtifacts; } if (this.props.isGenerateChangelog) { let groupSection = new GroupConsoleLogs_1.default('Release changelog').begin(); try { let changelogImpl = new ChangelogImpl_1.default(this.logger, this.getArtifactDirectory(releaseDefinition), releaseName, workitemFilters, limit, workItemUrl, showAllArtifacts, releaseDefinition.releaseConfigName ? path.join(this.props.directory ? this.props.directory : "", releaseDefinition.releaseConfigName) : this.props.directory ? this.props.directory : "", false, this.props.branch, false, this.props.isDryRun, releaseDefinition.releaseConfigName, this.props.targetOrg); let releaseChangelog = await changelogImpl.exec(); const aggregatedNumberOfWorkItemsInRelease = this.getAggregatedNumberOfWorkItemsInRelease(releaseName, releaseChangelog.releases); SFPStatsSender_1.default.logGauge('release.workitems', aggregatedNumberOfWorkItemsInRelease, { releaseName: releaseName, domain: releaseDefinition.releaseConfigName, }); const aggregatedNumberOfCommitsInRelease = this.getAggregatedNumberOfCommitsInRelease(releaseName, releaseChangelog.releases); SFPStatsSender_1.default.logGauge('release.commits', aggregatedNumberOfCommitsInRelease, { releaseName: releaseName, domain: releaseDefinition.releaseConfigName, }); } catch (error) { sfp_logger_1.default.log(`Unable to push changelog`, sfp_logger_1.LoggerLevel.WARN, this.logger); sfp_logger_1.default.log(error, sfp_logger_1.LoggerLevel.TRACE, this.logger); } groupSection.end(); } } } if (failedDeploymentResults.length > 0) { throw new ReleaseError_1.default('Release failed', { succeededDeployments: succeededDeploymentResults, failedDeployments: failedDeploymentResults, installDependenciesResult: installDependenciesResult, }); } return { succeededDeployments: succeededDeploymentResults, failedDeployments: failedDeploymentResults, installDependenciesResult: installDependenciesResult, }; } /** * * @param releases * @returns aggregated number of work items in a release */ getAggregatedNumberOfWorkItemsInRelease(releaseName, releases) { let aggregatedNumberOfWorkItemsInRelease = 0; releases.forEach((release) => { if (release.names?.includes(releaseName)) { aggregatedNumberOfWorkItemsInRelease += this.getNumberOfWorkItems(release); } }); return aggregatedNumberOfWorkItemsInRelease; } /** * * @param releases * @returns aggregated number of commits in a release */ getAggregatedNumberOfCommitsInRelease(releaseName, releases) { let aggregatedNumberOfCommitsInRelease = 0; releases.forEach((release) => { if (release.names?.includes(releaseName)) { aggregatedNumberOfCommitsInRelease += this.getNumberOfCommits(release); } }); return aggregatedNumberOfCommitsInRelease; } getNumberOfWorkItems(release) { return Object.keys(release.workItems).length; } getNumberOfCommits(release) { let numberOfCommits = 0; release.artifacts.forEach((artifact) => { numberOfCommits += artifact.commits.length; }); return numberOfCommits; } async deployArtifacts(releaseDefinitions) { let deploymentResults = []; for (const releaseDefinition of releaseDefinitions) { let groupSection = new GroupConsoleLogs_1.default(`Release ${releaseDefinition.release} for Release Configuration: ${releaseDefinition.releaseConfigName}`).begin(); sfp_logger_1.default.log(os_1.EOL); this.displayReleaseInfo(releaseDefinition, this.props); let deployProps = { targetUsername: this.props.targetOrg, artifactDir: this.getArtifactDirectory(releaseDefinition), waitTime: this.props.waitTime, tags: this.props.tags, isTestsToBeTriggered: false, deploymentMode: DeployImpl_1.DeploymentMode.NORMAL, skipIfPackageInstalled: releaseDefinition.skipIfAlreadyInstalled, logsGroupSymbol: this.props.logsGroupSymbol, currentStage: Stage_1.Stage.DEPLOY, baselineOrg: releaseDefinition.baselineOrg, isDryRun: this.props.isDryRun, disableArtifactCommit: releaseDefinition.skipArtifactUpdate ? releaseDefinition.skipArtifactUpdate : false, promotePackagesBeforeDeploymentToOrg: releaseDefinition.promotePackagesBeforeDeploymentToOrg, devhubUserName: this.props.devhubUserName, }; FileOutputHandler_1.default.getInstance().appendOutput(`deployment-breakdown.md`, `## ReleaseConfig: ${releaseDefinition.releaseConfigName ? releaseDefinition.releaseConfigName : ""}\n`); let deployImpl = new DeployImpl_1.default(deployProps); let deploymentResult = await deployImpl.exec(); deploymentResults.push({ releaseDefinition: releaseDefinition, result: deploymentResult }); groupSection.end(); //Don't continue deployments if a release breaks in between if (deploymentResult.failed.length > 0) break; } return deploymentResults; } async getSortedReleaseDefns(artifactDirectory, releaseDefns, logger) { let artifacts = ArtifactFetcher_1.default.fetchArtifacts(artifactDirectory, null, logger); if (artifacts.length === 0) throw new Error(`No artifacts to deploy found in ${artifactDirectory}`); //Convert artifacts to SfpPackages let sfpPackages = await this.generateSfpPackageFromArtifacts(artifacts, logger); let sfpPackageInquirer = new SfpPackageInquirer_1.default(sfpPackages, logger); let sfdxProjectConfig = sfpPackageInquirer.getLatestProjectConfig(); let releaseDefinitionSorter = new ReleaseDefinitionSorter_1.default(); return releaseDefinitionSorter.sortReleaseDefinitions(releaseDefns, sfdxProjectConfig, logger); } async generateSfpPackageFromArtifacts(artifacts, logger) { let sfpPackages = []; for (const artifact of artifacts) { let sfpPackage = await SfpPackageBuilder_1.default.buildPackageFromArtifact(artifact, logger); sfpPackages.push(sfpPackage); } return sfpPackages; } async installPackageDependencies(releaseDefinitions, targetOrg, keys, waitTime) { let result = { success: [], skipped: [], failed: [], }; let packageDependencies = {}; releaseDefinitions.forEach((releaseDefinition) => { if (releaseDefinition.packageDependencies) { packageDependencies = Object.assign(packageDependencies, releaseDefinition.packageDependencies); } }); let groupSection = new GroupConsoleLogs_1.default('Installing package dependencies').begin(); try { let packagesToKeys; if (keys) { packagesToKeys = this.parseKeys(keys); } let externalPackage2s = []; // print packages dependencies to install for (let pkg in packageDependencies) { let dependendentPackage = { name: pkg }; if (packageDependencies[pkg].startsWith('04t')) dependendentPackage.subscriberPackageVersionId = packageDependencies[pkg]; if (packagesToKeys?.[pkg]) { dependendentPackage.key = packagesToKeys[pkg]; } externalPackage2s.push(dependendentPackage); } let sfpOrg = await SFPOrg_1.default.create({ aliasOrUsername: targetOrg }); let packageCollectionInstaller = new InstallUnlockedPackageCollection_1.default(sfpOrg, new sfp_logger_1.ConsoleLogger(), this.props.isDryRun); await packageCollectionInstaller.install(externalPackage2s, true, true); groupSection.end(); return result; } catch (err) { console.log(err.message); throw new ReleaseError_1.default('Failed to install package dependencies', { installDependenciesResult: result, succeededDeployments: [], failedDeployments: [] }, err); } } /** * Parse keys in string format "packageA:key packageB:key packageC:key" * Returns map of packages to keys * @param keys */ parseKeys(keys) { let output = {}; keys = keys.trim(); let listOfKeys = keys.split(' '); for (let key of listOfKeys) { let packageKeyPair = key.split(':'); if (packageKeyPair.length === 2) { output[packageKeyPair[0]] = packageKeyPair[1]; } else { // Format is incorrect, throw an error throw new Error(`Error parsing keys, format should be: "packageA:key packageB:key packageC:key"`); } } return output; } displayReleaseInfo(releaseDefinition, props) { sfp_logger_1.default.printHeaderLine('', sfp_logger_1.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO); sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Release: ${releaseDefinition.release}`)); if (releaseDefinition.releaseConfigName) { sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Release Config Name: ${releaseDefinition.releaseConfigName}`)); } sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Skip Packages If Already Installed: ${releaseDefinition.skipIfAlreadyInstalled ? true : false}`)); sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Dry-run: ${props.isDryRun}`)); if (releaseDefinition.baselineOrg) sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Baselined Against Org: ${releaseDefinition.baselineOrg}`)); if (releaseDefinition.promotePackagesBeforeDeploymentToOrg && releaseDefinition.promotePackagesBeforeDeploymentToOrg == props.targetOrg) sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Promte Packages Before Deployment Activated?: true`)); sfp_logger_1.default.printHeaderLine('', sfp_logger_1.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO); } getArtifactDirectory(releaseDefinition) { let revisedArtifactDirectory = path.join('artifacts', releaseDefinition.release.replace(/[/\\?%*:|"<>]/g, '-')); if (releaseDefinition.releaseConfigName) { revisedArtifactDirectory = path.join('artifacts', releaseDefinition.releaseConfigName.replace(/[/\\?%*:|"<>]/g, '-'), releaseDefinition.release.replace(/[/\\?%*:|"<>]/g, '-')); } return revisedArtifactDirectory; } } exports.default = ReleaseImpl; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVsZWFzZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW1wbC9yZWxlYXNlL1JlbGVhc2VJbXBsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQSxtRUFBaUc7QUFDakcsbUVBQWtJO0FBQ2xJLG9DQUFpQztBQUNqQyw2RUFBcUQ7QUFDckQsK0VBQXVEO0FBQ3ZELHFGQUE2RDtBQUU3RCxtRUFBMkM7QUFDM0MsNkJBQThCO0FBQzlCLDJCQUF5QjtBQUV6Qiw2SUFBcUg7QUFDckgsdUVBQStDO0FBQy9DLGlGQUF5RDtBQUN6RCwyRkFBaUY7QUFFakYsNkZBQXFFO0FBQ3JFLCtGQUF1RTtBQUN2RSx3RkFBZ0U7QUFDaEUsd0ZBQWdFO0FBMEJoRSxNQUFxQixXQUFXO0lBSTVCLFlBQW9CLEtBQW1CLEVBQVUsTUFBZTtRQUE1QyxVQUFLLEdBQUwsS0FBSyxDQUFjO1FBQVUsV0FBTSxHQUFOLE1BQU0sQ0FBUztJQUFHLENBQUM7SUFFN0QsS0FBSyxDQUFDLElBQUk7UUFDYixJQUFJLFlBQVksR0FBRyxJQUFJLDBCQUFnQixDQUFDLG9CQUFvQixDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdEUsSUFBSSxTQUFTLEdBQWMsSUFBSSxtQkFBUyxDQUNwQyxXQUFXLEVBQ1gsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsRUFDOUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQ2hCLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUNwQixJQUFJLENBQUMsTUFBTSxDQUNkLENBQUM7UUFDRixNQUFNLFNBQVMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBRTlELG9CQUFTLENBQUMsR0FBRyxDQUFDLElBQUEsdUJBQVUsRUFBQyx5Q0FBeUMsQ0FBQyxFQUFFLHdCQUFXLENBQUMsSUFBSSxFQUFFLElBQUksQ0FB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