UNPKG

sfdx-hardis

Version:

Swiss-army-knife Toolbox for Salesforce. Allows you to define a complete CD/CD Pipeline. Orchestrate base commands and assist users with interactive wizards

192 lines • 9.7 kB
/* jscpd:ignore-start */ import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core'; import c from 'chalk'; import { assert } from 'console'; import fs from 'fs-extra'; import moment from 'moment'; import * as os from 'os'; import * as path from 'path'; import { clearCache } from '../../../common/cache/index.js'; import { elapseEnd, elapseStart, execSfdxJson, getCurrentGitBranch, uxLog } from '../../../common/utils/index.js'; import { initApexScripts, initOrgData, initPermissionSetAssignments, promptUserEmail, } from '../../../common/utils/orgUtils.js'; import { WebSocketClient } from '../../../common/websocketClient.js'; import { getConfig } from '../../../config/index.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('sfdx-hardis', 'org'); export default class SandboxCreate extends SfCommand { static title = 'Create sandbox org'; static description = 'Create and initialize sandbox org'; static examples = ['$ sf hardis:org:create']; // public static args = [{name: 'file'}]; static flags = { debug: Flags.boolean({ char: 'd', default: false, description: messages.getMessage('debugMode'), }), websocket: Flags.string({ description: messages.getMessage('websocket'), }), skipauth: Flags.boolean({ description: 'Skip authentication check when a default username is required', }), }; static supportsDevhubUsername = true; // Set this to true if your command requires a project workspace; 'requiresProject' is false by default static requiresProject = true; // List required plugins, their presence will be tested before running the command static requiresSfdxPlugins = ['sfdmu']; /* jscpd:ignore-end */ debugMode = false; configInfo; devHubAlias; sandboxOrgAlias; userEmail; gitBranch; projectSandboxDef; sandboxOrgInfo; sandboxOrgUsername; sandboxOrgSfdxAuthUrl; authFileJson; projectName; sandboxOrgFromPool; async run() { const { flags } = await this.parse(SandboxCreate); this.debugMode = flags.debug || false; elapseStart(`Create and initialize sandbox org`); await this.initConfig(); await this.createSandboxOrg(); try { await this.updateSandboxOrgUser(); await initPermissionSetAssignments(this.configInfo.initPermissionSets || [], this.sandboxOrgUsername); await initApexScripts(this.configInfo.sandboxOrgInitApexScripts || [], this.sandboxOrgUsername); await initOrgData(path.join('.', 'scripts', 'data', 'SandboxInit'), this.sandboxOrgUsername); } catch (e) { elapseEnd(`Create and initialize sandbox org`); uxLog(this, c.grey('Error: ' + e.message + '\n' + e.stack)); throw e; } elapseEnd(`Create and initialize sandbox org`); // Return an object to be displayed with --json return { status: 0, sandboxOrgAlias: this.sandboxOrgAlias, sandboxOrgInfo: this.sandboxOrgInfo, sandboxOrgUsername: this.sandboxOrgUsername, sandboxOrgSfdxAuthUrl: this.sandboxOrgSfdxAuthUrl, authFileJson: this.authFileJson, outputString: 'Created and initialized sandbox org', }; } // Initialize configuration from .sfdx-hardis.yml + .gitbranch.sfdx-hardis.yml + .username.sfdx-hardis.yml async initConfig() { this.configInfo = await getConfig('user'); this.gitBranch = (await getCurrentGitBranch({ formatted: true })) || ''; const newSandboxName = os.userInfo().username + '-' + (this.gitBranch.split('/').pop() || '').slice(0, 15) + '_' + moment().format('YYYYMMDD_hhmm'); this.sandboxOrgAlias = process.env.SANDBOX_ORG_ALIAS || newSandboxName; this.projectName = process.env.PROJECT_NAME || this.configInfo.projectName; this.devHubAlias = process.env.DEVHUB_ALIAS || this.configInfo.devHubAlias; this.userEmail = process.env.USER_EMAIL || process.env.GITLAB_USER_EMAIL || this.configInfo.userEmail; // If not found, prompt user email and store it in user config file if (this.userEmail == null) { this.userEmail = await promptUserEmail(); } } // Create a new sandbox org or reuse existing one async createSandboxOrg() { // Build project-sandbox-def-branch-user.json uxLog(this, c.cyan('Building custom project-sandbox-def.json...')); if (fs.existsSync('./config/project-sandbox-def.json')) { this.projectSandboxDef = JSON.parse(fs.readFileSync('./config/project-sandbox-def.json', 'utf-8')); } else { uxLog(this, c.yellow(`Default values used: you may define a file ${c.bold('config/project-sandbox-def.json')}`)); this.projectSandboxDef = { sandboxName: '', description: 'SFDX Hardis developer sandbox', licenseType: 'Developer', sourceSandbox: '', }; } this.projectSandboxDef.sandboxName = os.userInfo().username.substring(0, 10); const projectSandboxDefLocal = `./config/user/project-sandbox-def-${this.sandboxOrgAlias}.json`; await fs.ensureDir(path.dirname(projectSandboxDefLocal)); await fs.writeFile(projectSandboxDefLocal, JSON.stringify(this.projectSandboxDef, null, 2)); // Fix @salesforce/cli bug: remove shape.zip if found const tmpShapeFolder = path.join(os.tmpdir(), 'shape'); if (fs.existsSync(tmpShapeFolder)) { await fs.remove(tmpShapeFolder); uxLog(this, c.grey('Deleted ' + tmpShapeFolder)); } // Create new sandbox org uxLog(this, c.cyan('Creating new sandbox org...')); const waitTime = process.env.SANDBOX_ORG_WAIT || '60'; const createCommand = 'sf org create sandbox --set-default ' + `--definition-file ${projectSandboxDefLocal} ` + `--alias ${this.sandboxOrgAlias} ` + `--wait ${waitTime} ` + `--target-org ${this.devHubAlias} `; const createResult = await execSfdxJson(createCommand, this, { fail: false, output: false, debug: this.debugMode, }); await clearCache('sf org list'); assert(createResult.status === 0 && createResult.result, this.buildSandboxCreateErrorMessage(createResult)); this.sandboxOrgInfo = createResult.result; this.sandboxOrgUsername = this.sandboxOrgInfo.username; // Trigger a status refresh on VsCode WebSocket Client WebSocketClient.sendMessage({ event: 'refreshStatus' }); // Open sandbox org for user if not in CI await execSfdxJson('sf org open', this, { fail: true, output: false, debug: this.debugMode, }); uxLog(this, c.cyan(`Created sandbox org ${c.green(this.sandboxOrgAlias)} with user ${c.green(this.sandboxOrgUsername)}`)); } buildSandboxCreateErrorMessage(createResult) { if (createResult.status === 0 && createResult.result) { return c.green('Sandbox create OK'); } else if (createResult.status === 1 && createResult.errorMessage.includes('Socket timeout occurred while listening for results')) { return c.red(`[sfdx-hardis] Error creating sandbox org. ${c.bold('This is probably a Salesforce error, try again manually or launch again CI job')}\n${JSON.stringify(createResult, null, 2)}`); } return c.red(`[sfdx-hardis] Error creating sandbox org. Maybe try ${c.yellow(c.bold('sf hardis:sandbox:create --forcenew'))} ?\n${JSON.stringify(createResult, null, 2)}`); } // Update sandbox org user async updateSandboxOrgUser() { const config = await getConfig('user'); // Update sandbox org main user uxLog(this, c.cyan('Update / fix sandbox org user ' + this.sandboxOrgUsername)); const userQueryCommand = `sf data get record --sobject User --where "Username=${this.sandboxOrgUsername}" --target-org ${this.sandboxOrgAlias}`; const userQueryRes = await execSfdxJson(userQueryCommand, this, { fail: true, output: false, debug: this.debugMode, }); let updatedUserValues = `LastName='SFDX-HARDIS' FirstName='Sandbox Org'`; // Fix country value is State & Country picklist activated /* jscpd:ignore-start */ if ((this.projectSandboxDef.features || []).includes('StateAndCountryPicklist') && userQueryRes.result.CountryCode == null) { updatedUserValues += ` CountryCode='${config.defaultCountryCode || 'FR'}' Country='${config.defaultCountry || 'France'}'`; } if ((this.projectSandboxDef.features || []).includes('MarketingUser') && userQueryRes.result.UserPermissionsMarketingUser === false) { // Make sure MarketingUser is checked on sandbox org user if it is supposed to be updatedUserValues += ' UserPermissionsMarketingUser=true'; } const userUpdateCommand = `sf data update record --sobject User --record-id ${userQueryRes.result.Id} --values "${updatedUserValues}" --target-org ${this.sandboxOrgAlias}`; await execSfdxJson(userUpdateCommand, this, { fail: false, output: true, debug: this.debugMode }); /* jscpd:ignore-end */ } } //# sourceMappingURL=create.js.map