UNPKG

@salesforce/core

Version:

Core libraries to interact with SFDX projects, orgs, and APIs.

226 lines 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getScratchOrgInfoPayload = exports.generateScratchOrgInfo = exports.getAncestorIds = void 0; /* * Copyright (c) 2021, 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 */ // Node const fs_1 = require("fs"); // @salesforce const kit_1 = require("@salesforce/kit"); const ts_types_1 = require("@salesforce/ts-types"); const sfdc_1 = require("./util/sfdc"); const sfdxProject_1 = require("./sfdxProject"); const webOAuthServer_1 = require("./webOAuthServer"); const messages_1 = require("./messages"); const sfdxError_1 = require("./sfdxError"); const scratchOrgFeatureDeprecation_1 = require("./scratchOrgFeatureDeprecation"); const defaultConnectedAppInfo = { clientId: 'PlatformCLI', legacyClientId: 'SalesforceDevelopmentExperience', legacyClientSecret: '1384510088588713504', }; messages_1.Messages.importMessagesDirectory(__dirname); const messages = messages_1.Messages.loadMessages('@salesforce/core', 'scratchOrgInfoGenerator'); const SNAPSHOT_UNSUPPORTED_OPTIONS = [ 'features', 'orgPreferences', 'edition', 'sourceOrg', 'settingsPath', 'releaseVersion', 'language', ]; // A validator function to ensure any options parameters entered by the user adhere // to a allowlist of valid option settings. Because org:create allows options to be // input either key=value pairs or within the definition file, this validator is // executed within the ctor and also after parsing/normalization of the definition file. const optionsValidator = (key, scratchOrgInfoPayload) => { if (key.toLowerCase() === 'durationdays') { throw new sfdxError_1.SfdxError('unrecognizedScratchOrgOption', 'durationDays'); } if (key.toLowerCase() === 'snapshot') { const foundInvalidFields = SNAPSHOT_UNSUPPORTED_OPTIONS.filter((invalidField) => invalidField in scratchOrgInfoPayload); if (foundInvalidFields.length > 0) { throw new sfdxError_1.SfdxError(messages.getMessage('unsupportedSnapshotOrgCreateOptions', [foundInvalidFields.join(', ')]), 'orgSnapshot'); } } }; /** * Generates the package2AncestorIds scratch org property * * @param scratchOrgInfo - the scratchOrgInfo passed in by the user * @param projectJson - sfdxProjectJson * @param hubOrg - the hub org, in case we need to do queries */ const getAncestorIds = async (scratchOrgInfo, projectJson, hubOrg) => { if (Reflect.has(scratchOrgInfo, 'package2AncestorIds')) { throw new sfdxError_1.SfdxError(messages.getMessage('errorpackage2AncestorIdsKeyNotSupported'), 'DeprecationError'); } const packagesWithAncestors = (await projectJson.getPackageDirectories()) // check that the package has any ancestor types (id or version) .filter((packageDir) => packageDir.ancestorId || packageDir.ancestorVersion); if (packagesWithAncestors.length === 0) { return ''; } const ancestorIds = await Promise.all(packagesWithAncestors.map(async (packageDir) => { var _a, _b, _c; // ancestorID can be 05i, or 04t, alias; OR "ancestorVersion": "4.6.0.1" // according to docs, 05i is not ok: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev2gp_config_file.htm if (packageDir.ancestorVersion) { if (!/^[0-9]+.[0-9]+.[0-9]+(.[0-9]+)?$/.test(packageDir.ancestorVersion)) { throw sfdxError_1.SfdxError.create('@salesforce/core', 'scratchOrgInfoGenerator', 'errorInvalidAncestorVersionFormat', [ packageDir.ancestorVersion, ]); } // package can be an ID, but not according to docs const packageAliases = projectJson.get('packageAliases'); const packageId = (_a = packageAliases[ts_types_1.ensureString(packageDir.package)]) !== null && _a !== void 0 ? _a : packageDir.package; const [major, minor, patch] = packageDir.ancestorVersion.split('.'); let releasedAncestor; try { releasedAncestor = await hubOrg .getConnection() .singleRecordQuery(`SELECT Id, IsReleased FROM Package2Version WHERE Package2Id = '${packageId}' AND MajorVersion = ${major} AND MinorVersion = ${minor} AND PatchVersion = ${patch} and IsReleased = true`, { tooling: true }); } catch (err) { throw new sfdxError_1.SfdxError(messages.getMessage('errorNoMatchingAncestor', [packageDir.ancestorVersion, packageDir.package]), 'ErrorNoMatchingAncestor', [messages.getMessage('errorAncestorNotReleased', [packageDir.ancestorVersion])]); } if (packageDir.ancestorId && packageDir.ancestorId !== releasedAncestor.Id) { throw sfdxError_1.SfdxError.create('@salesforce/core', 'scratchOrgInfogenerator', 'ErrorAncestorIdVersionMismatch', [ packageDir.ancestorVersion, packageDir.ancestorId, ]); } return releasedAncestor.Id; } if ((_b = packageDir === null || packageDir === void 0 ? void 0 : packageDir.ancestorId) === null || _b === void 0 ? void 0 : _b.startsWith('05i')) { // if it's already a 05i return it, otherwise query for it return packageDir.ancestorId; } if ((_c = packageDir === null || packageDir === void 0 ? void 0 : packageDir.ancestorId) === null || _c === void 0 ? void 0 : _c.startsWith('04t')) { // query for the Id return (await hubOrg .getConnection() .singleRecordQuery(`SELECT Id FROM Package2Version WHERE SubscriberPackageVersionId = '${packageDir.ancestorId}'`, { tooling: true })).Id; } // ancestorID can be an alias get it from projectJson const packageAliases = projectJson.get('packageAliases'); if (packageDir.ancestorId && (packageAliases === null || packageAliases === void 0 ? void 0 : packageAliases[packageDir.ancestorId])) { return packageAliases[packageDir.ancestorId]; } throw new sfdxError_1.SfdxError(`Invalid ancestorId ${packageDir.ancestorId}`, 'InvalidAncestorId'); })); return Array.from(new Set(ancestorIds)).join(';'); }; exports.getAncestorIds = getAncestorIds; /** * Takes in a scratchOrgInfo and fills in the missing fields * * @param hubOrg the environment hub org * @param scratchOrgInfoPayload - the scratchOrgInfo passed in by the user * @param nonamespace create the scratch org with no namespace * @param ignoreAncestorIds true if the sfdx-project.json ancestorId keys should be ignored */ const generateScratchOrgInfo = async ({ hubOrg, scratchOrgInfoPayload, nonamespace, ignoreAncestorIds, }) => { var _a, _b; let sfdxProject; try { sfdxProject = await sfdxProject_1.SfdxProjectJson.create({}); } catch (e) { // project is not required } scratchOrgInfoPayload.orgName = (_a = scratchOrgInfoPayload.orgName) !== null && _a !== void 0 ? _a : 'Company'; scratchOrgInfoPayload.package2AncestorIds = !ignoreAncestorIds && (sfdxProject === null || sfdxProject === void 0 ? void 0 : sfdxProject.hasPackages()) ? await exports.getAncestorIds(scratchOrgInfoPayload, sfdxProject, hubOrg) : ''; // Use the Hub org's client ID value, if one wasn't provided to us, or the default if (!scratchOrgInfoPayload.connectedAppConsumerKey) { scratchOrgInfoPayload.connectedAppConsumerKey = (_b = hubOrg.getConnection().getAuthInfoFields().clientId) !== null && _b !== void 0 ? _b : defaultConnectedAppInfo.clientId; } if (!nonamespace && (sfdxProject === null || sfdxProject === void 0 ? void 0 : sfdxProject.get('namespace'))) { scratchOrgInfoPayload.namespace = sfdxProject.get('namespace'); } // we already have the info, and want to get rid of configApi, so this doesn't use that scratchOrgInfoPayload.connectedAppCallbackUrl = `http://localhost:${await webOAuthServer_1.WebOAuthServer.determineOauthPort()}/OauthRedirect`; return scratchOrgInfoPayload; }; exports.generateScratchOrgInfo = generateScratchOrgInfo; /** * Returns a valid signup json * * @param definitionjson org definition in JSON format * @param definitionfile path to an org definition file * @param connectedAppConsumerKey The connected app consumer key. May be null for JWT OAuth flow. * @param durationdays duration of the scratch org (in days) (default:1, min:1, max:30) * @param nonamespace create the scratch org with no namespace * @param noancestors do not include second-generation package ancestors in the scratch org * @param orgConfig overrides definitionjson * @returns scratchOrgInfoPayload: ScratchOrgInfoPayload; ignoreAncestorIds: boolean; warnings: string[]; */ const getScratchOrgInfoPayload = async (options) => { var _a; let warnings = []; // orgConfig input overrides definitionjson (-j option; hidden/deprecated) const definitionJson = options.definitionjson ? JSON.parse(options.definitionjson) : {}; const orgConfigInput = { ...definitionJson, ...((_a = options.orgConfig) !== null && _a !== void 0 ? _a : {}) }; let scratchOrgInfoPayload = orgConfigInput; // the -f option if (options.definitionfile) { try { const fileData = await fs_1.promises.readFile(options.definitionfile, 'utf8'); const defFileContents = kit_1.parseJson(fileData); // definitionjson and orgConfig override file input scratchOrgInfoPayload = { ...defFileContents, ...orgConfigInput }; } catch (err) { const error = err; if (error.name === 'JsonParseError') { throw new sfdxError_1.SfdxError(`An error occurred parsing ${options.definitionfile}`); } throw sfdxError_1.SfdxError.wrap(error); } } // scratchOrgInfoPayload must be heads down camelcase. const upperCaseKey = sfdc_1.sfdc.findUpperCaseKeys(scratchOrgInfoPayload); if (upperCaseKey) { throw new sfdxError_1.SfdxError('InvalidJsonCasing', upperCaseKey); } // Now run the fully resolved user input against the validator Object.keys(scratchOrgInfoPayload).forEach((key) => { optionsValidator(key, scratchOrgInfoPayload); }); if (options.connectedAppConsumerKey) { scratchOrgInfoPayload.connectedAppConsumerKey = options.connectedAppConsumerKey; } scratchOrgInfoPayload.durationDays = options.durationDays; // Throw warnings for deprecated scratch org features. const scratchOrgFeatureDeprecation = new scratchOrgFeatureDeprecation_1.ScratchOrgFeatureDeprecation(); // convert various supported array and string formats to a semi-colon-delimited string if (scratchOrgInfoPayload.features) { if (typeof scratchOrgInfoPayload.features === 'string') { scratchOrgInfoPayload.features = scratchOrgInfoPayload.features.split(/[;,]/); } warnings = scratchOrgFeatureDeprecation.getFeatureWarnings(scratchOrgInfoPayload.features); scratchOrgInfoPayload.features = scratchOrgInfoPayload.features.map((feature) => feature.trim()); scratchOrgInfoPayload.features = scratchOrgFeatureDeprecation .filterDeprecatedFeatures(scratchOrgInfoPayload.features) .join(';'); } return { scratchOrgInfoPayload, // Ignore ancestor ids only when 'nonamespace' or 'noancestors' options are specified ignoreAncestorIds: options.nonamespace || options.noancestors || false, warnings, }; }; exports.getScratchOrgInfoPayload = getScratchOrgInfoPayload; //# sourceMappingURL=scratchOrgInfoGenerator.js.map