@salesforce/core
Version:
Core libraries to interact with SFDX projects, orgs, and APIs.
248 lines • 12.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scratchOrgCreate = exports.scratchOrgResume = exports.DEFAULT_STREAM_TIMEOUT_MINUTES = void 0;
/*
* 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
*/
const kit_1 = require("@salesforce/kit");
const ts_types_1 = require("@salesforce/ts-types");
const messages_1 = require("../messages");
const logger_1 = require("../logger/logger");
const configAggregator_1 = require("../config/configAggregator");
const orgConfigProperties_1 = require("../org/orgConfigProperties");
const sfProject_1 = require("../sfProject");
const stateAggregator_1 = require("../stateAggregator/stateAggregator");
const sfError_1 = require("../sfError");
const org_1 = require("./org");
const scratchOrgInfoApi_1 = require("./scratchOrgInfoApi");
const scratchOrgSettingsGenerator_1 = __importDefault(require("./scratchOrgSettingsGenerator"));
const scratchOrgInfoGenerator_1 = require("./scratchOrgInfoGenerator");
const authInfo_1 = require("./authInfo");
const scratchOrgLifecycleEvents_1 = require("./scratchOrgLifecycleEvents");
const scratchOrgCache_1 = require("./scratchOrgCache");
const scratchOrgErrorCodes_1 = require("./scratchOrgErrorCodes");
;
const messages = new messages_1.Messages('@salesforce/core', 'scratchOrgCreate', new Map([["UnsupportedSnapshotOrgCreateOptionsError", "Org snapshots don\u2019t support one or more options you specified: %s."], ["DurationDaysValidationMinError", "Expected 'durationDays' greater than or equal to %s but received %s."], ["DurationDaysValidationMaxError", "Expected 'durationDays' less than or equal to %s but received %s."], ["DurationDaysNotIntError", "Expected 'durationDays' to be an integer number."], ["RetryNotIntError", "Expected 'retry' to be an integer number."], ["CacheMissError", "The ScratchOrgInfoId %s was not found in the cache."]]));
exports.DEFAULT_STREAM_TIMEOUT_MINUTES = 6;
const validateDuration = (durationDays) => {
const min = 1;
const max = 30;
if (Number.isInteger(durationDays)) {
if (durationDays < min) {
throw messages.createError('DurationDaysValidationMinError', [min, durationDays]);
}
if (durationDays > max) {
throw messages.createError('DurationDaysValidationMaxError', [max, durationDays]);
}
return;
}
throw messages.createError('DurationDaysNotIntError');
};
const validateRetry = (retry) => {
if (!Number.isInteger(retry)) {
throw messages.createError('RetryNotIntError');
}
};
const scratchOrgResume = async (jobId, timeout = kit_1.Duration.minutes(15)) => {
const [logger, cache] = await Promise.all([
logger_1.Logger.child('scratchOrgResume'),
scratchOrgCache_1.ScratchOrgCache.create(),
(0, scratchOrgLifecycleEvents_1.emit)({ stage: 'send request' }),
]);
logger.debug(`resuming scratch org creation for jobId: ${jobId}`);
const cached = cache.get(jobId, true);
if (!cached) {
throw messages.createError('CacheMissError', [jobId]);
}
const { hubUsername, apiVersion, clientSecret, signupTargetLoginUrlConfig, definitionjson, alias, setDefault, tracksSource, } = cached;
const signupTargetLoginUrl = signupTargetLoginUrlConfig ?? (await getSignupTargetLoginUrl());
if (signupTargetLoginUrl) {
logger.debug(`resuming org create with LoginUrl override= ${signupTargetLoginUrl}`);
}
const hubOrg = await org_1.Org.create({ aliasOrUsername: hubUsername });
const soi = await (0, scratchOrgErrorCodes_1.validateScratchOrgInfoForResume)({ jobId, hubOrg, cache, hubUsername, timeout });
// At this point, the scratch org is "good".
// Some hubs have all the usernames set to `null`
const username = soi.Username ?? soi.SignupUsername;
// re-auth only if the org isn't in StateAggregator
const stateAggregator = await stateAggregator_1.StateAggregator.getInstance();
const scratchOrgAuthInfo = (await stateAggregator.orgs.exists(username))
? await authInfo_1.AuthInfo.create({ username })
: await (0, scratchOrgInfoApi_1.authorizeScratchOrg)({
scratchOrgInfoComplete: soi,
hubOrg,
clientSecret,
signupTargetLoginUrl,
retry: 0,
});
await setExitCodeIfError(68)(scratchOrgAuthInfo.handleAliasAndDefaultSettings({
alias,
setDefault: setDefault ?? false,
setDefaultDevHub: false,
setTracksSource: tracksSource ?? true,
}));
const scratchOrg = await org_1.Org.create({ aliasOrUsername: username });
const configAggregator = await configAggregator_1.ConfigAggregator.create();
await (0, scratchOrgLifecycleEvents_1.emit)({ stage: 'deploy settings', scratchOrgInfo: soi });
const capitalizeRecordTypes = await getCapitalizeRecordTypesConfig();
const settingsGenerator = new scratchOrgSettingsGenerator_1.default({
capitalizeRecordTypes,
});
await settingsGenerator.extract({ ...soi, ...definitionjson });
const [authInfo] = await setExitCodeIfError(68)(Promise.all([
(0, scratchOrgInfoApi_1.resolveUrl)(scratchOrgAuthInfo),
(0, scratchOrgInfoApi_1.deploySettings)(scratchOrg, settingsGenerator, apiVersion ??
configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.ORG_API_VERSION) ??
(await scratchOrg.retrieveMaxApiVersion())),
]));
cache.unset(soi.Id ?? jobId);
const authFields = authInfo.getFields();
await Promise.all([(0, scratchOrgLifecycleEvents_1.emit)({ stage: 'done', scratchOrgInfo: soi }), cache.write(), (0, scratchOrgLifecycleEvents_1.emitPostOrgCreate)(authFields)]);
return {
username,
scratchOrgInfo: soi,
authInfo,
authFields,
warnings: [],
};
};
exports.scratchOrgResume = scratchOrgResume;
const scratchOrgCreate = async (options) => {
const logger = await logger_1.Logger.child('scratchOrgCreate');
/** epoch milliseconds */
const startTimestamp = Date.now();
logger.debug('preparing scratch org signup request...');
await (0, scratchOrgLifecycleEvents_1.emit)({ stage: 'prepare request' });
const { hubOrg, connectedAppConsumerKey, durationDays = 1, nonamespace, noancestors, wait = kit_1.Duration.minutes(exports.DEFAULT_STREAM_TIMEOUT_MINUTES), retry = 0, apiversion, definitionjson, definitionfile, orgConfig, clientSecret = undefined, alias, setDefault = false, tracksSource = true, } = options;
validateDuration(durationDays);
validateRetry(retry);
const { scratchOrgInfoPayload, ignoreAncestorIds, warnings } = await (0, scratchOrgInfoGenerator_1.getScratchOrgInfoPayload)({
definitionjson,
definitionfile,
connectedAppConsumerKey,
durationDays,
nonamespace,
noancestors,
orgConfig,
});
const scratchOrgInfo = await (0, scratchOrgInfoGenerator_1.generateScratchOrgInfo)({
hubOrg,
scratchOrgInfoPayload,
nonamespace,
ignoreAncestorIds,
});
const capitalizeRecordTypes = await getCapitalizeRecordTypesConfig();
// gets the scratch org settings (will use in both signup paths AND to deploy the settings)
const settingsGenerator = new scratchOrgSettingsGenerator_1.default({
capitalizeRecordTypes,
});
const settings = await settingsGenerator.extract(scratchOrgInfo);
logger.debug(`the scratch org def file has settings: ${settingsGenerator.hasSettings()}`);
const [scratchOrgInfoRequestResult, signupTargetLoginUrl] = await Promise.all([
// creates the scratch org info in the devhub
(0, scratchOrgInfoApi_1.requestScratchOrgCreation)(hubOrg, scratchOrgInfo, settingsGenerator),
getSignupTargetLoginUrl(),
]);
const scratchOrgInfoId = (0, ts_types_1.ensureString)(scratchOrgInfoRequestResult.id);
const cache = await scratchOrgCache_1.ScratchOrgCache.create();
cache.set(scratchOrgInfoId, {
hubUsername: hubOrg.getUsername(),
hubBaseUrl: hubOrg.getField(org_1.Org.Fields.INSTANCE_URL)?.toString(),
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
definitionjson: { ...(definitionjson ? JSON.parse(definitionjson) : {}), ...orgConfig, ...settings },
clientSecret,
alias,
setDefault,
tracksSource,
});
await cache.write();
logger.debug(`scratch org has recordId ${scratchOrgInfoId}`);
// this is where we stop--no polling
if (wait.minutes === 0) {
const soi = await (0, scratchOrgInfoApi_1.queryScratchOrgInfo)(hubOrg, scratchOrgInfoId);
return {
username: soi.SignupUsername,
warnings: [],
scratchOrgInfo: soi,
};
}
const soi = await (0, scratchOrgInfoApi_1.pollForScratchOrgInfo)(hubOrg, scratchOrgInfoId, wait);
const scratchOrgAuthInfo = await (0, scratchOrgInfoApi_1.authorizeScratchOrg)({
scratchOrgInfoComplete: soi,
hubOrg,
clientSecret,
signupTargetLoginUrl,
retry: retry || 0,
});
// anything after this point (org is created and auth'd) is potentially recoverable with the resume scratch command.
await setExitCodeIfError(68)(scratchOrgAuthInfo.handleAliasAndDefaultSettings({
...{
alias,
setDefault,
setDefaultDevHub: false,
setTracksSource: tracksSource === false ? false : true,
},
}));
// we'll need this scratch org connection later;
const scratchOrg = await org_1.Org.create({ aliasOrUsername: soi.Username ?? soi.SignupUsername });
const username = scratchOrg.getUsername();
logger.debug(`scratch org username ${username}`);
await (0, scratchOrgLifecycleEvents_1.emit)({ stage: 'deploy settings', scratchOrgInfo: soi });
const configAggregator = await configAggregator_1.ConfigAggregator.create();
const [authInfo] = await setExitCodeIfError(68)(Promise.all([
(0, scratchOrgInfoApi_1.resolveUrl)(scratchOrgAuthInfo),
(0, scratchOrgInfoApi_1.deploySettings)(scratchOrg, settingsGenerator, apiversion ??
configAggregator.getPropertyValue(orgConfigProperties_1.OrgConfigProperties.ORG_API_VERSION) ??
(await scratchOrg.retrieveMaxApiVersion()),
// some of our "wait" time has already been used. Calculate how much remains that we can spend on the deployment.
kit_1.Duration.milliseconds(wait.milliseconds - (Date.now() - startTimestamp))),
]));
cache.unset(scratchOrgInfoId);
const authFields = authInfo.getFields();
await Promise.all([(0, scratchOrgLifecycleEvents_1.emit)({ stage: 'done', scratchOrgInfo: soi }), cache.write(), (0, scratchOrgLifecycleEvents_1.emitPostOrgCreate)(authFields)]);
return {
username,
scratchOrgInfo: soi,
authInfo,
authFields: authInfo?.getFields(),
warnings,
};
};
exports.scratchOrgCreate = scratchOrgCreate;
const getSignupTargetLoginUrl = async () => {
try {
const project = await sfProject_1.SfProject.resolve();
const projectJson = await project.resolveProjectConfig();
const signupTargetLoginUrl = projectJson.signupTargetLoginUrl;
if (signupTargetLoginUrl) {
logger_1.Logger.childFromRoot('getSignupTargetLoginUrl').debug(`Found signupTargetLoginUrl in project file: ${signupTargetLoginUrl}`);
return signupTargetLoginUrl;
}
}
catch {
// a project isn't required for org:create
}
};
async function getCapitalizeRecordTypesConfig() {
const configAgg = await configAggregator_1.ConfigAggregator.create();
const value = configAgg.getInfo('org-capitalize-record-types').value;
return value !== undefined ? (0, kit_1.toBoolean)(value) : undefined;
}
/** wrap an async function, intercept error and set the given exit code */
const setExitCodeIfError = (exitCode) => async (p) => {
try {
return await p;
}
catch (e) {
const sfError = sfError_1.SfError.wrap(e);
sfError.exitCode = exitCode;
throw sfError;
}
};
//# sourceMappingURL=scratchOrgCreate.js.map