@salesforce/packaging
Version:
Packaging library for the Salesforce packaging platform
202 lines • 9.73 kB
JavaScript
;
/*
* 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
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPackageInstallRequest = createPackageInstallRequest;
exports.getStatus = getStatus;
exports.isErrorFromSPVQueryRestriction = isErrorFromSPVQueryRestriction;
exports.isErrorPackageNotAvailable = isErrorPackageNotAvailable;
exports.getInstallationStatus = getInstallationStatus;
exports.waitForPublish = waitForPublish;
exports.pollStatus = pollStatus;
const core_1 = require("@salesforce/core");
const ts_types_1 = require("@salesforce/ts-types");
const packageUtils_1 = require("../utils/packageUtils");
const interfaces_1 = require("../interfaces");
core_1.Messages.importMessagesDirectory(__dirname);
const installMsgs = core_1.Messages.loadMessages('@salesforce/packaging', 'package_install');
let logger;
const getLogger = () => {
if (!logger) {
logger = core_1.Logger.childFromRoot('installPackage');
}
return logger;
};
async function createPackageInstallRequest(connection, pkgInstallCreateRequest, packageType) {
const defaults = {
ApexCompileType: 'all',
EnableRss: false,
NameConflictResolution: 'Block',
PackageInstallSource: 'U',
SecurityType: 'None',
UpgradeType: 'mixed-mode',
};
const request = Object.assign({}, defaults, pkgInstallCreateRequest);
if (request.Password) {
request.Password = (0, packageUtils_1.escapeInstallationKey)(request.Password);
}
// Only unlocked packages can change the UpgradeType and ApexCompile options from the defaults.
if (packageType !== 'Unlocked') {
if (request.UpgradeType !== defaults.UpgradeType) {
const msg = installMsgs.getMessage('upgradeTypeOnlyForUnlockedWarning');
await core_1.Lifecycle.getInstance().emit(interfaces_1.PackageEvents.install.warning, msg);
delete request.UpgradeType;
}
if (request.ApexCompileType !== defaults.ApexCompileType) {
const msg = installMsgs.getMessage('apexCompileOnlyForUnlockedWarning');
await core_1.Lifecycle.getInstance().emit(interfaces_1.PackageEvents.install.warning, msg);
delete request.ApexCompileType;
}
}
await core_1.Lifecycle.getInstance().emit(interfaces_1.PackageEvents.install.presend, request);
const result = await connection.tooling.create('PackageInstallRequest', request);
await core_1.Lifecycle.getInstance().emit(interfaces_1.PackageEvents.install.postsend, result);
const packageInstallRequestId = result.id;
if (!packageInstallRequestId) {
throw installMsgs.createError('packageInstallRequestError', [
request.SubscriberPackageVersionKey,
result.errors.toString(),
]);
}
return getStatus(connection, packageInstallRequestId);
}
async function getStatus(connection, packageInstallRequestId) {
const results = (await connection.tooling.retrieve('PackageInstallRequest', packageInstallRequestId));
return results;
}
// determines if error is from malformed SubscriberPackageVersion query
// this is in place to allow cli to run against app version 214, where SPV queries
// do not require installation key
function isErrorFromSPVQueryRestriction(err) {
return (err.name === 'MALFORMED_QUERY' &&
err.message.includes('Implementation restriction: You can only perform queries of the form Id'));
}
function isErrorPackageNotAvailable(err) {
return ['UNKNOWN_EXCEPTION', 'PACKAGE_UNAVAILABLE', 'PACKAGE_UNAVAILABLE_CRC', 'PACKAGE_UNAVAILABLE_ZIP'].includes(err.name);
}
async function getInstallationStatus(subscriberPackageVersionId, installationKey, connection) {
let query = `SELECT Id, SubscriberPackageId, InstallValidationStatus FROM SubscriberPackageVersion WHERE Id ='${subscriberPackageVersionId}'`;
if (installationKey) {
query += ` AND InstallationKey ='${(0, packageUtils_1.escapeInstallationKey)(installationKey)}'`;
}
try {
return await connection.tooling.query(query);
}
catch (e) {
if (e instanceof Error && isErrorPackageNotAvailable(e)) {
getLogger().debug('getInstallationStatus:', e.name);
}
else {
throw e;
}
}
}
async function waitForPublish(connection, subscriberPackageVersionId, frequency, timeout, installationKey) {
const pollingTimeout = (0, packageUtils_1.numberToDuration)(timeout);
if (pollingTimeout.milliseconds <= 0) {
return;
}
let queryResult;
let installValidationStatus = 'PACKAGE_UNAVAILABLE';
const pollingOptions = {
frequency: (0, packageUtils_1.numberToDuration)(frequency),
timeout: pollingTimeout,
poll: async () => {
queryResult = await getInstallationStatus(subscriberPackageVersionId, installationKey, connection);
// Continue retrying if there is no record
// or for an InstallValidationStatus of PACKAGE_UNAVAILABLE (replication to the subscriber's instance has not completed)
// or for an InstallValidationStatus of UNINSTALL_IN_PROGRESS
// or PACKAGE_UNAVAILABLE_ZIP or PACKAGE_UNAVAILABLE_CRC
if (queryResult?.records?.length) {
installValidationStatus = queryResult.records[0].InstallValidationStatus;
}
getLogger().debug(installMsgs.getMessage('publishWaitProgress', [` Status = ${installValidationStatus}`]));
await core_1.Lifecycle.getInstance().emit(interfaces_1.PackageEvents.install['subscriber-status'], installValidationStatus);
if (![
'PACKAGE_UNAVAILABLE',
'PACKAGE_UNAVAILABLE_CRC',
'PACKAGE_UNAVAILABLE_ZIP',
'UNINSTALL_IN_PROGRESS',
].includes(installValidationStatus)) {
return { completed: true, payload: installValidationStatus };
}
return { completed: false, payload: installValidationStatus };
},
};
const pollingClient = await core_1.PollingClient.create(pollingOptions);
try {
getLogger().debug(`Polling for package availability in org. Package ID = ${subscriberPackageVersionId}`);
getLogger().debug(`Polling frequency (ms): ${pollingOptions.frequency.milliseconds}`);
getLogger().debug(`Polling timeout (min): ${pollingOptions.timeout.minutes}`);
await pollingClient.subscribe();
}
catch (e) {
// For installation key problems throw that error.
if (e instanceof Error && e.name.includes('INSTALL_KEY')) {
throw core_1.SfError.create({
name: e.name,
message: e.message,
cause: e,
});
}
// if polling timed out
const error = installMsgs.createError('subscriberPackageVersionNotPublished');
if (queryResult?.records[0]) {
error.setData(queryResult?.records[0]);
}
if (error.stack && e instanceof Error && e.stack) {
getLogger().debug(`Error during waitForPublish polling:\n${e.stack}`);
// append the original stack to this new error
error.stack += `\nDUE TO:\n${e.stack}`;
if (e.message) {
error.actions = (error.actions ?? []).concat([e.message]);
}
}
throw error;
}
}
async function pollStatus(connection, installRequestId, options = { pollingFrequency: 5000, pollingTimeout: 300_000 }) {
let packageInstallRequest = await getStatus(connection, installRequestId);
const { pollingFrequency, pollingTimeout } = options;
const frequency = (0, packageUtils_1.numberToDuration)(pollingFrequency ?? 5000);
const timeout = (0, packageUtils_1.numberToDuration)(pollingTimeout ?? 300_000);
const pollingOptions = {
frequency,
timeout,
poll: async () => {
packageInstallRequest = await getStatus(connection, installRequestId);
getLogger().debug(installMsgs.getMessage('packageInstallPolling', [packageInstallRequest?.Status]));
await core_1.Lifecycle.getInstance().emit(interfaces_1.PackageEvents.install.status, packageInstallRequest);
if (['SUCCESS', 'ERROR'].includes(packageInstallRequest?.Status)) {
return { completed: true, payload: packageInstallRequest };
}
return { completed: false };
},
};
const pollingClient = await core_1.PollingClient.create(pollingOptions);
try {
getLogger().debug(`Polling for PackageInstallRequest status. Package ID = ${installRequestId}`);
getLogger().debug(`Polling frequency (ms): ${pollingOptions.frequency.milliseconds}`);
getLogger().debug(`Polling timeout (min): ${pollingOptions.timeout.minutes}`);
await pollingClient.subscribe();
return packageInstallRequest;
}
catch (e) {
const errMsg = e instanceof Error ? e.message : (0, ts_types_1.isString)(e) ? e : 'polling timed out';
const error = new core_1.SfError(errMsg, 'PackageInstallTimeout');
error.setData(packageInstallRequest);
if (error.stack && e instanceof Error && e.stack) {
// add the original stack to this new error
error.stack += `\nDUE TO:\n${e.stack}`;
if (e.message) {
error.actions = (error.actions ?? []).concat([e.message]);
}
}
throw error;
}
}
//# sourceMappingURL=packageInstall.js.map