UNPKG

@salesforce/plugin-org

Version:

Commands to interact with Salesforce orgs

213 lines 9.73 kB
/* * Copyright (c) 2022, 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 */ import { EOL } from 'node:os'; import { Flags } from '@salesforce/sf-plugins-core'; import { StateAggregator, Lifecycle, Messages, Org, SandboxEvents, SfError, } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; import { SandboxCommandBase } from '../../../shared/sandboxCommandBase.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-org', 'resume.sandbox'); export default class ResumeSandbox extends SandboxCommandBase { static summary = messages.getMessage('summary'); static description = messages.getMessage('description'); static examples = messages.getMessages('examples'); static aliases = ['env:resume:sandbox']; static deprecateAliases = true; static flags = { wait: Flags.duration({ char: 'w', summary: messages.getMessage('flags.wait.summary'), description: messages.getMessage('flags.wait.description'), min: 0, unit: 'minutes', helpValue: '<minutes>', defaultValue: 0, }), name: Flags.string({ char: 'n', summary: messages.getMessage('flags.name.summary'), parse: (name) => { if (name.length > 10) { throw messages.createError('error.SandboxNameLength', [name]); } return Promise.resolve(name); }, exclusive: ['job-id'], }), 'job-id': Flags.salesforceId({ startsWith: '0GR', char: 'i', summary: messages.getMessage('flags.id.summary'), description: messages.getMessage('flags.id.description'), exclusive: ['name'], }), 'use-most-recent': Flags.boolean({ char: 'l', summary: messages.getMessage('flags.use-most-recent.summary'), }), 'target-org': Flags.optionalOrg({ char: 'o', summary: messages.getMessage('flags.targetOrg.summary'), description: messages.getMessage('flags.targetOrg.description'), }), }; flags; async run() { this.sandboxRequestConfig = await this.getSandboxRequestConfig(); this.flags = (await this.parse(ResumeSandbox)).flags; this.debug('Resume started with args %s ', this.flags); return this.resumeSandbox(); } getCheckSandboxStatusParams() { return [ this.config.bin, ...(this.latestSandboxProgressObj ? [this.latestSandboxProgressObj.Id] : []), ...(this.flags['target-org']?.getUsername() ? [this.flags['target-org'].getUsername()] : []), ]; } createResumeSandboxRequest() { if (this.flags['use-most-recent'] && this.sandboxRequestConfig) { const latestEntry = this.sandboxRequestConfig.getLatestEntry(); if (latestEntry) { const [, sandboxRequestData] = latestEntry; if (sandboxRequestData) { return { SandboxProcessObjId: sandboxRequestData.sandboxProcessObject?.Id }; } } } // build resume sandbox request from data provided return { ...Object.assign({}, this.flags.name ? { SandboxName: this.flags.name } : {}), ...Object.assign({}, this.flags['job-id'] ? { SandboxProcessObjId: this.flags['job-id'] } : {}), }; } async resumeSandbox() { this.sandboxRequestData = this.buildSandboxRequestCacheEntry(); const prodOrgUsername = this.sandboxRequestData.prodOrgUsername; if (!this.sandboxRequestData.sandboxProcessObject.SandboxName) { if (!this.flags['name'] && !this.flags['job-id']) { throw messages.createError('error.NoSandboxNameOrJobId'); } } this.prodOrg = await Org.create({ aliasOrUsername: prodOrgUsername }); this.flags['target-org'] = this.prodOrg; const lifecycle = Lifecycle.getInstance(); this.registerLifecycleListenersAndMSO(lifecycle, { mso: { title: 'Resume Sandbox', refresh: this.sandboxRequestData.action === 'Refresh', }, isAsync: false, alias: this.sandboxRequestData.alias, setDefault: this.sandboxRequestData.setDefault, prodOrg: this.prodOrg, tracksSource: this.sandboxRequestData.tracksSource, }); if (this.latestSandboxProgressObj && (await this.verifyIfAuthExists({ prodOrg: this.prodOrg, sandboxName: this.sandboxRequestData.sandboxProcessObject.SandboxName, jobId: this.flags['job-id'] ?? this.sandboxRequestData.sandboxProcessObject.Id, lifecycle, }))) { return this.getSandboxCommandResponse(); } const sandboxReq = this.createResumeSandboxRequest(); this.debug('Calling resume with ResumeSandboxRequest: %s ', sandboxReq); try { this.latestSandboxProgressObj = await this.prodOrg.resumeSandbox(sandboxReq, { wait: this.flags.wait ?? Duration.seconds(0), interval: Duration.seconds(30), }); return this.getSandboxCommandResponse(); } catch (err) { if (this.latestSandboxProgressObj && this.pollingTimeOut) { void lifecycle.emit(SandboxEvents.EVENT_ASYNC_RESULT, undefined); process.exitCode = 68; return this.latestSandboxProgressObj; } else if (this.latestSandboxProgressObj && err instanceof SfError && err.name === 'SandboxCreateNotCompleteError') { process.exitCode = 68; return this.latestSandboxProgressObj; } throw err; } } buildSandboxRequestCacheEntry() { let sandboxRequestCacheEntry; if (this.sandboxRequestConfig && this.flags['use-most-recent']) { const latest = this.sandboxRequestConfig.getLatestEntry(); const [name, entry] = latest ?? [undefined, undefined]; if (!name) { throw messages.createError('error.LatestSandboxRequestNotFound'); } sandboxRequestCacheEntry = entry; } else if (this.sandboxRequestConfig && this.flags.name) { sandboxRequestCacheEntry = this.sandboxRequestConfig.get(this.flags.name) || sandboxRequestCacheEntry; } else if (this.flags['job-id'] && this.sandboxRequestConfig) { const entries = this.sandboxRequestConfig.entries(); const sce = entries.find(([, e]) => e?.sandboxProcessObject?.Id === this.flags['job-id'])?.[1]; sandboxRequestCacheEntry = sce; if (sandboxRequestCacheEntry === undefined) { this.warn(`Could not find a cache entry for ${this.flags['job-id']}.${EOL}If you are resuming a sandbox operation from a different machine note that we cannot set the alias/set-default flag values as those are saved locally.`); } } // If the action is in the cache entry, use it. if (sandboxRequestCacheEntry?.action) { this.action = sandboxRequestCacheEntry?.action; } return { ...(sandboxRequestCacheEntry ?? { sandboxProcessObject: { SandboxName: this.flags.name }, sandboxRequest: {}, setDefault: false, }), prodOrgUsername: sandboxRequestCacheEntry?.prodOrgUsername ?? this.flags['target-org']?.getUsername(), action: sandboxRequestCacheEntry?.action ?? 'Create', // default to Create }; } async verifyIfAuthExists({ prodOrg, sandboxName, jobId, lifecycle, }) { const sandboxProcessObject = await getSandboxProcessObject(prodOrg, sandboxName, jobId); this.sandboxUsername = this.getSandboxUsername(prodOrg.getUsername(), sandboxProcessObject.SandboxName); const exists = await (await StateAggregator.getInstance()).orgs.exists(this.sandboxUsername); if (exists) { this.latestSandboxProgressObj = sandboxProcessObject; const resultEvent = { sandboxProcessObj: this.latestSandboxProgressObj, sandboxRes: { authUserName: this.sandboxUsername }, }; await lifecycle.emit(SandboxEvents.EVENT_RESULT, resultEvent); return true; } return false; } } const getSandboxProcessObject = async (prodOrg, sandboxName, jobId) => { const where = getWhere(sandboxName, jobId); const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE ${where} AND Status != 'D'`; try { return await prodOrg.getConnection().singleRecordQuery(queryStr, { tooling: true, }); } catch (err) { throw messages.createError('error.NoSandboxRequestFound'); } }; const getWhere = (sandboxName, jobId) => { if (jobId) return `Id='${jobId}'`; if (sandboxName) return `SandboxName='${sandboxName}'`; throw new SfError('There must be a sandbox name or job id to query for the sandbox process object'); }; //# sourceMappingURL=sandbox.js.map