@salesforce/plugin-org
Version:
Commands to interact with Salesforce orgs
118 lines • 5.36 kB
JavaScript
/*
* Copyright 2026, Salesforce, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import fs from 'node:fs';
import { Logger, Messages, SfError, Lifecycle } from '@salesforce/core';
import { lowerToUpper } from './utils.js';
import { SandboxLicenseType } from './orgTypes.js';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const cloneMessages = Messages.loadMessages('@salesforce/plugin-org', 'clone');
export const generateSboxName = async () => {
// sandbox names are 10 chars or less, a radix of 36 = [a-z][0-9]
// technically without querying the production org, the generated name could already exist, but the chances of that are lower than the perf penalty of querying and verifying
const generated = `sbx${Date.now().toString(36).slice(-7)}`;
await Lifecycle.getInstance().emitWarning(`No SandboxName defined, generating new SandboxName: ${generated}`);
return generated;
};
// Reads the sandbox definition file and converts properties to CapCase.
export function readSandboxDefFile(defFile) {
const fileContent = fs.readFileSync(defFile, 'utf-8');
const parsedContent = lowerToUpper(JSON.parse(fileContent));
// validate input
if (parsedContent.ApexClassName && parsedContent.ApexClassId) {
throw cloneMessages.createError('error.bothApexClassIdAndNameProvided');
}
if (parsedContent.ActivationUserGroupId && parsedContent.ActivationUserGroupName) {
throw cloneMessages.createError('error.bothUserGroupIdAndNameProvided');
}
if (parsedContent.SourceId && parsedContent.SourceSandboxName) {
throw cloneMessages.createError('error.bothSourceIdAndNameProvided');
}
if (parsedContent.SourceId && parsedContent.LicenseType) {
throw cloneMessages.createError('error.bothSourceIdAndLicenseTypeProvided');
}
if (parsedContent.LicenseType && parsedContent.SourceSandboxName) {
throw cloneMessages.createError('error.bothSourceSandboxNameAndLicenseTypeProvided');
}
return parsedContent;
}
export async function createSandboxRequest(definitionFile, logger, properties) {
if (!logger) {
logger = await Logger.child('createSandboxRequest');
}
logger.debug('Varargs: %s ', properties);
const sandboxDefFileContents = definitionFile ? readSandboxDefFile(definitionFile) : {};
const capitalizedVarArgs = properties ? lowerToUpper(properties) : {};
// varargs override file input
const sandboxReqWithName = {
...sandboxDefFileContents,
...capitalizedVarArgs,
SandboxName: capitalizedVarArgs.SandboxName ??
sandboxDefFileContents.SandboxName ??
(await generateSboxName()),
};
const isClone = sandboxReqWithName.SourceSandboxName ?? sandboxReqWithName.SourceId;
const { SourceSandboxName, SourceId, ...sandboxReq } = sandboxReqWithName;
logger.debug('SandboxRequest after merging DefFile and Varargs: %s ', sandboxReq);
if (isClone) {
if (!sandboxReqWithName.SourceSandboxName && !sandboxReqWithName.SourceId) {
// error - we need SourceSandboxName or SourceID to know which sandbox to clone from
throw new SfError(cloneMessages.getMessage('missingSourceSandboxNameORSourceId'), cloneMessages.getMessage('missingSourceSandboxNameORSourceIdAction'));
}
return { sandboxReq, srcSandboxName: SourceSandboxName, srcId: SourceId };
}
else {
if (!sandboxReq.LicenseType) {
return { sandboxReq: { ...sandboxReq, LicenseType: SandboxLicenseType.developer } };
}
return { sandboxReq };
}
}
export async function getApexClassIdByName(conn, className) {
try {
const result = (await conn.singleRecordQuery(`SELECT Id FROM ApexClass WHERE Name = '${className}'`)).Id;
return result;
}
catch (err) {
throw cloneMessages.createError('error.apexClassQueryFailed', [className], [], err);
}
}
export async function getUserGroupIdByName(conn, groupName) {
try {
const result = (await conn.singleRecordQuery(`SELECT id FROM Group WHERE NAME = '${groupName}'`)).Id;
return result;
}
catch (err) {
throw cloneMessages.createError('error.userGroupQueryFailed', [groupName], [], err);
}
}
export async function getSrcIdByName(conn, sandboxName) {
try {
const result = (await conn.singleRecordQuery(`SELECT id FROM SandboxInfo WHERE SandboxName = '${sandboxName}'`, { tooling: true })).Id;
return result;
}
catch (err) {
throw cloneMessages.createError('error.sandboxNameQueryFailed', [sandboxName], [], err);
}
}
export default {
createSandboxRequest,
generateSboxName,
readSandboxDefFile,
getApexClassIdByName,
getUserGroupIdByName,
getSrcIdByName,
};
//# sourceMappingURL=sandboxRequest.js.map