UNPKG

salesforce-alm

Version:

This package contains tools, and APIs, for an improved salesforce.com developer experience.

295 lines (293 loc) 13.6 kB
"use strict"; /* * Copyright (c) 2020, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ Object.defineProperty(exports, "__esModule", { value: true }); exports.SourceApiCommand = void 0; const os = require("os"); const util = require("util"); const core_1 = require("@salesforce/core"); const srcDevUtil = require("../core/srcDevUtil"); const consts = require("../core/constants"); const logger = require("../core/logApi"); const almError = require("../core/almError"); const sourceDeployApi_1 = require("./sourceDeployApi"); const sourceUtil_1 = require("./sourceUtil"); const sourcePushApi_1 = require("./sourcePushApi"); const syncCommandHelper = require("./syncCommandHelper"); core_1.Messages.importMessagesDirectory(__dirname); // One of these flags must be specified for a valid deploy. const requiredFlags = ['manifest', 'metadata', 'sourcepath', 'validateddeployrequestid']; class SourceApiCommand { constructor(isSourceDelete) { this.isSourceDelete = isSourceDelete; this.metadataTypeDeployed = []; this.logger = logger.child(`source:${this.deploytype}`); this.pushMsgs = core_1.Messages.loadMessages('salesforce-alm', 'source_push'); this.deployMsgs = core_1.Messages.loadMessages('salesforce-alm', 'source_deploy'); this.commonMsgs = core_1.Messages.loadMessages('salesforce-alm', 'source'); } getPreExecuteMessage({ orgId, username }) { return this.commonMsgs.getMessage(`${this.deploytype}CommandCliPreExecute`, [orgId, username]); } /** * Executes the source deploy or push command * * @param context - the cli context * @returns {Promise} */ async execute(context) { const rows = []; const projectPath = this.orgApi.config.getProjectPath(); let results; const options = { org: this.orgApi }; const deployApi = this.isDeploy() ? await sourceDeployApi_1.SourceDeployApi.create(options) : await sourcePushApi_1.MdapiPushApi.create(options); return Promise.resolve() .then(() => { context.unsupportedMimeTypes = []; // for logging unsupported static resource mime types context.delete = this.isSourceDelete; // SourceDeployApi is for source:deploy and MdapiPushApi is for source:push return deployApi.doDeploy(context); }) .catch((e) => { if (e.name === 'SourceConflict') { const error = almError('sourceConflictDetected'); e.sourceConflictElements.forEach((sourceElement) => syncCommandHelper.createConflictRows(rows, sourceElement, projectPath)); error['columns'] = syncCommandHelper.getColumnMetaInfo(this.commonMsgs); error['result'] = rows; this.logger.error(this.pushMsgs.getMessage('pushCommandConflictMsg')); throw error; } else if (e.name === 'DeployFailed') { e.failures.forEach((failure) => syncCommandHelper.createDeployFailureRow(rows, failure, projectPath)); const messageBundle = this.deploytype === 'deploy' ? this.deployMsgs : this.pushMsgs; const actions = core_1.SfdxProject.getInstance().hasMultiplePackages() ? ['Check the order of your dependencies and ensure all metadata is included.'] : []; const error = new core_1.SfdxError(messageBundle.getMessage(`source${this.deploytype}Failed`), 'DeployFailed', actions); if (!util.isNullOrUndefined(e.outboundFiles)) { const successes = []; e.outboundFiles.forEach((sourceElement) => syncCommandHelper.createDisplayRows(successes, sourceElement, projectPath)); error['partialSuccess'] = successes.length > 0 ? successes : undefined; } error['columns'] = this._getErrorColumnData(); error.setData(rows); if (e.message) { error['message'] = e.message; this.logger.error(error.message); } throw error; } else if (e.name === 'PollingTimeout') { const errConfig = new core_1.SfdxErrorConfig('salesforce-alm', 'source', 'DeployTimeout'); errConfig.setErrorTokens([this.deploytype, context.wait]); throw core_1.SfdxError.create(errConfig); } else { throw e; } }) .then((deployResult) => { // checkonly and validateddeployrequestid flags display mdapi:deploy output if (this.checkonly || this.isQuickDeploy || this.isAsync) { results = deployResult; return; } if (deployResult.userCanceled) { // user canceled the delete by selecting 'n' when prompted. this.userCanceled = deployResult.userCanceled; } else { deployResult.outboundFiles.forEach((sourceElement) => { if (!this.metadataTypeDeployed.includes(sourceElement.type)) { this.metadataTypeDeployed.push(sourceElement.type); } syncCommandHelper.createDisplayRows(rows, sourceElement, projectPath); }); } }) .then(() => { this.createEvent(); if (this.isAsync) { SourceApiCommand.prototype['getHumanSuccessMessage'] = this.getHumanSuccessMessageDelegate; } // checkonly and validateddeployrequestid flags display mdapi:deploy output if (!(this.userCanceled || this.checkonly || this.isQuickDeploy || this.isAsync)) { // User elected to continue the deleted so we can display the proper tabular output. const tableHeaderKey = this.isSourceDelete ? 'deleteCommandHumanSuccess' : `${this.deploytype}CommandHumanSuccess`; const tableHeader = this.commonMsgs.getMessage(tableHeaderKey); this.logger.styledHeader(this.logger.color.blue(tableHeader)); SourceApiCommand.prototype['getColumnData'] = this._getColumnData; } }) .then(() => srcDevUtil.logUnsupportedMimeTypeError(context.unsupportedMimeTypes, this.logger, this.orgApi.force)) .then(() => { // checkonly and validateddeployrequestid flags display mdapi:deploy output if (this.checkonly || this.isQuickDeploy || this.isAsync) { return results; } if (this.userCanceled) { return {}; } if (context.json) { if (this.isDeploy()) { return this.isSourceDelete ? { deletedSource: rows } : { deployedSource: rows }; } return { pushedSource: rows }; } return rows; }); } getHumanSuccessMessageDelegate(obj) { if (obj.status && obj.id) { this.logger.styledHeader(this.logger.color.yellow('Status')); // Change the color based on state? this.logger.log(`Status: ${obj.status}`); this.logger.log(`Id: ${obj.id}${os.EOL}`); this.logger.log(`Run sfdx force:source:deploy:cancel -i ${obj.id} to cancel the deploy.`); this.logger.log(`Run sfdx force:source:deploy:report -i ${obj.id} to get the latest status.`); } else { // do something } } /** * Validates the source push or deploy command parameters * * @param context - the cli context * @returns {Promise} */ async validate(context) { this.orgApi = context.org; this.verbose = context.flags.verbose; this.json = context.flags.json; this.deploytype = context.deploytype; this.checkonly = context.flags.checkonly; this.isQuickDeploy = context.flags.validateddeployrequestid; this.isAsync = this.isDeploy() && context.flags.wait === `${consts.MIN_SRC_DEPLOY_WAIT_MINUTES}`; const fixedContext = srcDevUtil.fixCliContext(context); // Validate the wait param if set and convert to an integer. if (this.isAsync) { sourceUtil_1.parseWaitParam(fixedContext, consts.MIN_SRC_DEPLOY_WAIT_MINUTES); } else { sourceUtil_1.parseWaitParam(fixedContext); } if (this.isDeploy()) { // verify that the user defined one of: manifest, metadata, sourcepath, validateddeployrequestid if (!Object.keys(context.flags).some((flag) => requiredFlags.includes(flag))) { throw core_1.SfdxError.create('salesforce-alm', 'source', 'MissingRequiredParam', requiredFlags); } // verify that the manifest file exists and is readable. if (fixedContext.manifest) { await sourceUtil_1.validateManifestPath(fixedContext.manifest); } } return Promise.resolve(fixedContext); } isDeploy() { return this.deploytype === SourceApiCommand.SOURCE_DEPLOY; } /** * This indicates to index.js that this command should produce tabular output. * * @returns {*[]} */ _getColumnData() { return syncCommandHelper.getColumnMetaInfo(this.commonMsgs, this.isDeploy()); } getHumanErrorMessage(error) { if (!error.partialSuccess) { return; // Don't get in the way of single table normal errors } let needNewLine = false; if (error.partialSuccess && error.partialSuccess.length > 0) { const headerSuccess = this.commonMsgs.getMessage(`${this.deploytype}CommandHumanSuccess`); const columnsSuccess = syncCommandHelper.getColumnMetaInfo(this.commonMsgs); this.logger.styledHeader(this.logger.color.blue(headerSuccess)); this.logger.table(error.partialSuccess, { columns: columnsSuccess }); needNewLine = true; } if (error.data && error.data.length > 0) { if (needNewLine) { this.logger.log(os.EOL); } const headerErrors = this.commonMsgs.getMessage(`${this.deploytype}CommandHumanError`); this.logger.styledHeader(this.logger.color.red(headerErrors)); } return; } _getErrorColumnData() { if (this.verbose || this.json) { return [ { key: 'fullName', label: this.commonMsgs.getMessage('fullNameTableColumn'), }, { key: 'type', label: this.commonMsgs.getMessage('typeTableColumn') }, { key: 'filePath', label: this.commonMsgs.getMessage('workspacePathTableColumn'), }, { key: 'error', label: this.commonMsgs.getMessage('errorColumn') }, { key: 'lineNumber', label: this.commonMsgs.getMessage('lineNumberColumn'), }, { key: 'columnNumber', label: this.commonMsgs.getMessage('columnNumberColumn'), }, ]; } else { return [ { key: 'problemType', label: this.commonMsgs.getMessage('typeTableColumn'), }, { key: 'filePath', label: this.commonMsgs.getMessage('workspacePathTableColumn'), }, { key: 'error', label: this.commonMsgs.getMessage('errorColumn'), }, ]; } } createEvent() { let listOfMetadataTypesDeployed = this.metadataTypeDeployed.toString(); const operation = this.isDeploy() ? 'source:deploy' : 'source:push'; const totalNumberOfPackagesInProject = core_1.SfdxProject.getInstance().getUniquePackageDirectories().length; const packagesDeployed = this.isDeploy() ? sourceDeployApi_1.SourceDeployApi.packagesDeployed : sourcePushApi_1.MdapiPushApi.packagesDeployed; const istruncated = listOfMetadataTypesDeployed.length < 8000 ? false : true; if (istruncated) { listOfMetadataTypesDeployed = listOfMetadataTypesDeployed .slice(0, 7975) .toString() .concat('..metadataTypes truncated'); } if (global.cliTelemetry && global.cliTelemetry.record) { global.cliTelemetry.record({ eventName: 'SOURCE_OPERATION', operation, type: 'EVENT', totalNumberOfPackages: totalNumberOfPackagesInProject, numberOfPackagesDeployed: packagesDeployed, componentsDeployed: listOfMetadataTypesDeployed, componentsDeployedTruncated: istruncated, }); } } } exports.SourceApiCommand = SourceApiCommand; SourceApiCommand.SOURCE_DEPLOY = 'deploy'; SourceApiCommand.SOURCE_PUSH = 'push'; //# sourceMappingURL=sourceApiCommand.js.map