@salesforce/packaging 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/lib/exported.d.ts +1 -0
- package/lib/exported.js +1 -0
- package/lib/interfaces/index.d.ts +1 -0
- package/lib/interfaces/index.js +1 -0
- package/lib/interfaces/packagingInterfacesAndType.d.ts +29 -3
- package/lib/interfaces/packagingInterfacesAndType.js +6 -0
- package/lib/interfaces/packagingSObjects.d.ts +225 -0
- package/lib/interfaces/packagingSObjects.js +20 -0
- package/lib/package/index.d.ts +2 -1
- package/lib/package/index.js +2 -1
- package/lib/package/packageList.d.ts +4 -0
- package/lib/package/packageList.js +19 -0
- package/lib/package/{package2Version.d.ts → packageVersion2GP.d.ts} +2 -2
- package/lib/package/{package2Version.js → packageVersion2GP.js} +4 -4
- package/lib/package/packageVersionCreateRequestApi.d.ts +17 -0
- package/lib/package/packageVersionCreateRequestApi.js +92 -0
- package/lib/package1/index.d.ts +1 -1
- package/lib/package1/index.js +1 -1
- package/lib/package1/{package1Version.d.ts → packageVersion1GP.d.ts} +3 -3
- package/lib/package1/{package1Version.js → packageVersion1GP.js} +4 -4
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +24 -0
- package/lib/utils/packageUtils.d.ts +152 -0
- package/lib/utils/packageUtils.js +786 -0
- package/lib/utils/versionNumber.d.ts +16 -0
- package/lib/utils/versionNumber.js +56 -0
- package/messages/messages.md +191 -0
- package/package.json +2 -2
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2022, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.formatDate = exports.getSoqlWhereClauseMaxLength = exports.pollForStatusWithInterval = exports._getPackageVersionCreateRequestApi = exports.findOrCreatePackage2 = exports.getPackageAliasesFromId = exports.convertCamelCaseStringToSentence = exports.getPackageIdFromAlias = exports.getConfigPackageDirectory = exports.getConfigPackageDirectories = exports.getPackage2VersionNumber = exports.concatVersion = exports.getAncestorIdHighestRelease = exports.validateAncestorId = exports.getAncestorId = exports.getInClauseItemsCount = exports.queryWithInConditionChunking = exports.getPackageVersionStrings = exports.getHasMetadataRemoved = exports.getContainerOptions = exports.getSubscriberPackageVersionId = exports.getPackage2TypeBy04t = exports.getPackage2Type = exports.getPackageVersionId = exports.applyErrorAction = exports.massageErrorMessage = exports.isErrorPackageNotAvailable = exports.isErrorFromSPVQueryRestriction = exports.validUrl = exports.validatePatchVersion = exports.validateVersionNumber = exports.validateIdNoThrow = exports.validateId = exports.BY_LABEL = exports.BY_PREFIX = exports.DEFAULT_PACKAGE_DIR = exports.POLL_INTERVAL_SECONDS = exports.SOQL_WHERE_CLAUSE_MAX_LENGTH = exports.INSTALL_URL_BASE = exports.VERSION_NUMBER_SEP = void 0;
|
|
10
|
+
const core_1 = require("@salesforce/core");
|
|
11
|
+
const kit_1 = require("@salesforce/kit");
|
|
12
|
+
const interfaces_1 = require("../interfaces");
|
|
13
|
+
const packageVersionCreateRequestApi_1 = require("../package/packageVersionCreateRequestApi");
|
|
14
|
+
const versionNumber_1 = require("./versionNumber");
|
|
15
|
+
var Package2VersionStatus = interfaces_1.PackagingSObjects.Package2VersionStatus;
|
|
16
|
+
core_1.Messages.importMessagesDirectory(__dirname);
|
|
17
|
+
const messages = core_1.Messages.loadMessages('@salesforce/packaging', 'messages');
|
|
18
|
+
exports.VERSION_NUMBER_SEP = '.';
|
|
19
|
+
const INVALID_TYPE_REGEX = /[\w]*(sObject type '[A-Za-z]*Package[2]?[A-Za-z]*' is not supported)[\w]*/im;
|
|
20
|
+
const ID_REGISTRY = [
|
|
21
|
+
{
|
|
22
|
+
prefix: '0Ho',
|
|
23
|
+
label: 'Package Id',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
prefix: '05i',
|
|
27
|
+
label: 'Package Version Id',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
prefix: '08c',
|
|
31
|
+
label: 'Package Version Create Request Id',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
prefix: '04t',
|
|
35
|
+
label: 'Subscriber Package Version Id',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
exports.INSTALL_URL_BASE = 'https://login.salesforce.com/packaging/installPackage.apexp?p0=';
|
|
39
|
+
// https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_soslsoql.htm
|
|
40
|
+
exports.SOQL_WHERE_CLAUSE_MAX_LENGTH = 4000;
|
|
41
|
+
exports.POLL_INTERVAL_SECONDS = 30;
|
|
42
|
+
exports.DEFAULT_PACKAGE_DIR = {
|
|
43
|
+
path: '',
|
|
44
|
+
package: '',
|
|
45
|
+
versionName: 'ver 0.1',
|
|
46
|
+
versionNumber: '0.1.0.NEXT',
|
|
47
|
+
default: true,
|
|
48
|
+
};
|
|
49
|
+
const logger = core_1.Logger.childFromRoot('packageUtils');
|
|
50
|
+
exports.BY_PREFIX = (() => {
|
|
51
|
+
return Object.fromEntries(ID_REGISTRY.map((id) => [id.prefix, { prefix: id.prefix, label: id.label }]));
|
|
52
|
+
})();
|
|
53
|
+
exports.BY_LABEL = (() => {
|
|
54
|
+
return Object.fromEntries(ID_REGISTRY.map((id) => [id.label.replace(/ /g, '_').toUpperCase(), { prefix: id.prefix, label: id.label }]));
|
|
55
|
+
})();
|
|
56
|
+
function validateId(idObj, value) {
|
|
57
|
+
if (!validateIdNoThrow(idObj, value)) {
|
|
58
|
+
throw messages.createError('invalidIdOrAlias', [
|
|
59
|
+
Array.isArray(idObj) ? idObj.map((e) => e.label).join(' or ') : idObj.label,
|
|
60
|
+
value,
|
|
61
|
+
Array.isArray(idObj) ? idObj.map((e) => e.prefix).join(' or ') : idObj.prefix,
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.validateId = validateId;
|
|
66
|
+
function validateIdNoThrow(idObj, value) {
|
|
67
|
+
if (!value || (value.length !== 15 && value.length !== 18)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return Array.isArray(idObj) ? idObj.some((e) => value.startsWith(e.prefix)) : value.startsWith(idObj.prefix);
|
|
71
|
+
}
|
|
72
|
+
exports.validateIdNoThrow = validateIdNoThrow;
|
|
73
|
+
function validateVersionNumber(versionNumberString, supportedBuildNumberToken, supportedBuildNumberToken2) {
|
|
74
|
+
const versionNumber = versionNumber_1.VersionNumber.from('1.1.0.NEXT');
|
|
75
|
+
// build number can be a number or valid token
|
|
76
|
+
if (Number.isNaN(parseInt(versionNumber.build, 10)) &&
|
|
77
|
+
versionNumber.build !== supportedBuildNumberToken &&
|
|
78
|
+
versionNumber.build !== supportedBuildNumberToken2) {
|
|
79
|
+
if (supportedBuildNumberToken2) {
|
|
80
|
+
throw messages.createError('errorInvalidBuildNumberForKeywords', [
|
|
81
|
+
versionNumberString,
|
|
82
|
+
supportedBuildNumberToken,
|
|
83
|
+
supportedBuildNumberToken2,
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
throw messages.createError('errorInvalidBuildNumber', [versionNumberString, supportedBuildNumberToken]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return versionNumberString;
|
|
91
|
+
}
|
|
92
|
+
exports.validateVersionNumber = validateVersionNumber;
|
|
93
|
+
async function validatePatchVersion(connection, versionNumberString, packageId) {
|
|
94
|
+
const query = `SELECT ContainerOptions FROM Package2 WHERE id ='${packageId}'`;
|
|
95
|
+
const queryResult = await connection.tooling.query(query);
|
|
96
|
+
if (queryResult.records === null || queryResult.records.length === 0) {
|
|
97
|
+
throw messages.createError('errorInvalidPackageId', [packageId]);
|
|
98
|
+
}
|
|
99
|
+
// Enforce a patch version of zero (0) for Locked packages only
|
|
100
|
+
if (queryResult.records[0].ContainerOptions === 'Locked') {
|
|
101
|
+
const versionNumber = versionNumber_1.VersionNumber.from(versionNumberString);
|
|
102
|
+
if (versionNumber.patch !== '0') {
|
|
103
|
+
throw messages.createError('errorInvalidPatchNumber', [versionNumberString]);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.validatePatchVersion = validatePatchVersion;
|
|
108
|
+
// TODO: let's get rid of this in favor of SfdcUrl.isValidUrl()
|
|
109
|
+
// check that the provided url has a valid format
|
|
110
|
+
function validUrl(url) {
|
|
111
|
+
return core_1.SfdcUrl.isValidUrl(url);
|
|
112
|
+
}
|
|
113
|
+
exports.validUrl = validUrl;
|
|
114
|
+
// determines if error is from malformed SubscriberPackageVersion query
|
|
115
|
+
// this is in place to allow cli to run against app version 214, where SPV queries
|
|
116
|
+
// do not require installation key
|
|
117
|
+
function isErrorFromSPVQueryRestriction(err) {
|
|
118
|
+
return (err.name === 'MALFORMED_QUERY' &&
|
|
119
|
+
err.message.includes('Implementation restriction: You can only perform queries of the form Id'));
|
|
120
|
+
}
|
|
121
|
+
exports.isErrorFromSPVQueryRestriction = isErrorFromSPVQueryRestriction;
|
|
122
|
+
function isErrorPackageNotAvailable(err) {
|
|
123
|
+
return err.name === 'UNKNOWN_EXCEPTION' || err.name === 'PACKAGE_UNAVAILABLE';
|
|
124
|
+
}
|
|
125
|
+
exports.isErrorPackageNotAvailable = isErrorPackageNotAvailable;
|
|
126
|
+
// overwrites error message under certain conditions
|
|
127
|
+
function massageErrorMessage(err) {
|
|
128
|
+
if (err.name === 'INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST') {
|
|
129
|
+
err['message'] = messages.getMessage('invalidPackageTypeMessage');
|
|
130
|
+
}
|
|
131
|
+
if (err.name === 'MALFORMED_ID' &&
|
|
132
|
+
(err.message.includes('Version ID') || err.message.includes('Version Definition ID'))) {
|
|
133
|
+
err['message'] = messages.getMessage('malformedPackageVersionIdMessage');
|
|
134
|
+
}
|
|
135
|
+
if (err.name === 'MALFORMED_ID' && err.message.includes('Package2 ID')) {
|
|
136
|
+
err['message'] = messages.getMessage('malformedPackageIdMessage');
|
|
137
|
+
}
|
|
138
|
+
// remove references to Second Generation
|
|
139
|
+
if (err.message.includes('Second Generation ')) {
|
|
140
|
+
err['message'] = err.message.replace('Second Generation ', '');
|
|
141
|
+
}
|
|
142
|
+
return err;
|
|
143
|
+
}
|
|
144
|
+
exports.massageErrorMessage = massageErrorMessage;
|
|
145
|
+
// applies actions to common package errors
|
|
146
|
+
// eslint-disable-next-line complexity
|
|
147
|
+
function applyErrorAction(err) {
|
|
148
|
+
// append when actions already exist
|
|
149
|
+
const actions = [];
|
|
150
|
+
// include existing actions
|
|
151
|
+
if (err['action']) {
|
|
152
|
+
actions.push(err['action']);
|
|
153
|
+
}
|
|
154
|
+
// TODO: (need to get with packaging team on this)
|
|
155
|
+
// until next generation packaging is GA, wrap perm-based errors w/
|
|
156
|
+
// 'contact sfdc' action (REMOVE once GA'd)
|
|
157
|
+
if ((err.name === 'INVALID_TYPE' && INVALID_TYPE_REGEX.test(err.message)) ||
|
|
158
|
+
(err.name === 'NOT_FOUND' && err.message === messages.getMessage('notFoundMessage'))) {
|
|
159
|
+
// contact sfdc customer service
|
|
160
|
+
actions.push(messages.getMessage('packageNotEnabledAction'));
|
|
161
|
+
}
|
|
162
|
+
if (err.name === 'INVALID_FIELD' && err.message.includes('Instance')) {
|
|
163
|
+
actions.push(messages.getMessage('packageInstanceNotEnabled'));
|
|
164
|
+
}
|
|
165
|
+
if (err.name === 'INVALID_FIELD' && err.message.includes('SourceOrg')) {
|
|
166
|
+
actions.push(messages.getMessage('packageSourceOrgNotEnabled'));
|
|
167
|
+
}
|
|
168
|
+
if (err.name === 'INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST') {
|
|
169
|
+
actions.push(messages.getMessage('invalidPackageTypeAction'));
|
|
170
|
+
}
|
|
171
|
+
if (err.name === 'MALFORMED_ID' && err.message === messages.getMessage('malformedPackageIdMessage')) {
|
|
172
|
+
actions.push(messages.getMessage('malformedPackageIdAction'));
|
|
173
|
+
}
|
|
174
|
+
if (err.name === 'MALFORMED_ID' && err.message === messages.getMessage('malformedPackageVersionIdMessage')) {
|
|
175
|
+
actions.push(messages.getMessage('malformedPackageVersionIdAction'));
|
|
176
|
+
}
|
|
177
|
+
if ((err.message.includes(exports.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID.label) && err.message.includes('is invalid')) ||
|
|
178
|
+
err.name === 'INVALID_ID_FIELD' ||
|
|
179
|
+
(err.name === 'INVALID_INPUT' && err.message.includes('Verify you entered the correct ID')) ||
|
|
180
|
+
err.name === 'MALFORMED_ID') {
|
|
181
|
+
actions.push(messages.getMessage('idNotFoundAction'));
|
|
182
|
+
}
|
|
183
|
+
if (actions.length > 0) {
|
|
184
|
+
err['action'] = actions.join('\n');
|
|
185
|
+
}
|
|
186
|
+
return err;
|
|
187
|
+
}
|
|
188
|
+
exports.applyErrorAction = applyErrorAction;
|
|
189
|
+
/**
|
|
190
|
+
* Given a subscriber package version ID (04t) or package version ID (05i), return the package version ID (05i)
|
|
191
|
+
*
|
|
192
|
+
* @param versionId The subscriber package version ID
|
|
193
|
+
* @param connection For tooling query
|
|
194
|
+
*/
|
|
195
|
+
async function getPackageVersionId(versionId, connection) {
|
|
196
|
+
// if it's already a 05i return it, otherwise query for it
|
|
197
|
+
if (versionId === null || versionId === void 0 ? void 0 : versionId.startsWith(exports.BY_LABEL.PACKAGE_VERSION_ID.prefix)) {
|
|
198
|
+
return versionId;
|
|
199
|
+
}
|
|
200
|
+
const query = `SELECT Id FROM Package2Version WHERE SubscriberPackageVersionId = '${versionId}'`;
|
|
201
|
+
return connection.tooling.query(query).then((queryResult) => {
|
|
202
|
+
if (!queryResult || !queryResult.totalSize) {
|
|
203
|
+
throw messages.createError('errorInvalidIdNoMatchingVersionId', [
|
|
204
|
+
exports.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID.label,
|
|
205
|
+
versionId,
|
|
206
|
+
exports.BY_LABEL.PACKAGE_VERSION_ID.label,
|
|
207
|
+
]);
|
|
208
|
+
}
|
|
209
|
+
return queryResult.records[0].Id;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
exports.getPackageVersionId = getPackageVersionId;
|
|
213
|
+
/**
|
|
214
|
+
* Given 0Ho the package type type (Managed, Unlocked, Locked(deprecated?))
|
|
215
|
+
*
|
|
216
|
+
* @param package2Id the 0Ho
|
|
217
|
+
* @param connection For tooling query
|
|
218
|
+
* @throws Error with message when package2 cannot be found
|
|
219
|
+
*/
|
|
220
|
+
async function getPackage2Type(package2Id, connection) {
|
|
221
|
+
const query = `SELECT ContainerOptions FROM Package2 WHERE id ='${package2Id}'`;
|
|
222
|
+
const queryResult = await connection.tooling.query(query);
|
|
223
|
+
if (!queryResult || queryResult.records === null || queryResult.records.length === 0) {
|
|
224
|
+
throw messages.createError('errorInvalidPackageId', [package2Id]);
|
|
225
|
+
}
|
|
226
|
+
return queryResult.records[0].ContainerOptions;
|
|
227
|
+
}
|
|
228
|
+
exports.getPackage2Type = getPackage2Type;
|
|
229
|
+
/**
|
|
230
|
+
* Given 04t the package type type (Managed, Unlocked, Locked(deprecated?))
|
|
231
|
+
*
|
|
232
|
+
* @param package2VersionId the 04t
|
|
233
|
+
* @param connection For tooling query
|
|
234
|
+
* @param installKey For tooling query, if an installation key is applicable to the package version it must be passed in the queries
|
|
235
|
+
* @throws Error with message when package2 cannot be found
|
|
236
|
+
*/
|
|
237
|
+
async function getPackage2TypeBy04t(package2VersionId, connection, installKey) {
|
|
238
|
+
let query = `SELECT Package2ContainerOptions FROM SubscriberPackageVersion WHERE id ='${package2VersionId}'`;
|
|
239
|
+
if (installKey) {
|
|
240
|
+
const escapedInstallationKey = installKey.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
241
|
+
query += ` AND InstallationKey ='${escapedInstallationKey}'`;
|
|
242
|
+
}
|
|
243
|
+
const queryResult = await connection.tooling.query(query);
|
|
244
|
+
if (!queryResult || queryResult.records === null || queryResult.records.length === 0) {
|
|
245
|
+
throw messages.createError('errorInvalidPackageId', [package2VersionId]);
|
|
246
|
+
}
|
|
247
|
+
return queryResult.records[0].Package2ContainerOptions;
|
|
248
|
+
}
|
|
249
|
+
exports.getPackage2TypeBy04t = getPackage2TypeBy04t;
|
|
250
|
+
/**
|
|
251
|
+
* Given a package version ID (05i) or subscriber package version ID (04t), return the subscriber package version ID (04t)
|
|
252
|
+
*
|
|
253
|
+
* @param versionId The suscriber package version ID
|
|
254
|
+
* @param connection For tooling query
|
|
255
|
+
*/
|
|
256
|
+
async function getSubscriberPackageVersionId(versionId, connection) {
|
|
257
|
+
// if it's already a 04t return it, otherwise query for it
|
|
258
|
+
if (!versionId || versionId.startsWith(exports.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID.prefix)) {
|
|
259
|
+
return versionId;
|
|
260
|
+
}
|
|
261
|
+
const query = `SELECT SubscriberPackageVersionId FROM Package2Version WHERE Id = '${versionId}'`;
|
|
262
|
+
const queryResult = await connection.tooling.query(query);
|
|
263
|
+
if (!queryResult || !queryResult.totalSize) {
|
|
264
|
+
throw messages.createError('errorInvalidIdNoMatchingVersionId', [
|
|
265
|
+
exports.BY_LABEL.PACKAGE_VERSION_ID.label,
|
|
266
|
+
versionId,
|
|
267
|
+
exports.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID.label,
|
|
268
|
+
]);
|
|
269
|
+
}
|
|
270
|
+
return queryResult.records[0].SubscriberPackageVersionId;
|
|
271
|
+
}
|
|
272
|
+
exports.getSubscriberPackageVersionId = getSubscriberPackageVersionId;
|
|
273
|
+
/**
|
|
274
|
+
* Get the ContainerOptions for the specified Package2 (0Ho) IDs.
|
|
275
|
+
*
|
|
276
|
+
* @return Map of 0Ho id to container option api value
|
|
277
|
+
* @param package2Ids The list of package IDs
|
|
278
|
+
* @param connection For tooling query
|
|
279
|
+
*/
|
|
280
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
281
|
+
async function getContainerOptions(package2Ids, connection) {
|
|
282
|
+
if (!package2Ids || package2Ids.length === 0) {
|
|
283
|
+
return new Map();
|
|
284
|
+
}
|
|
285
|
+
const query = 'SELECT Id, ContainerOptions FROM Package2 WHERE Id IN (%IDS%)';
|
|
286
|
+
const records = await queryWithInConditionChunking(query, package2Ids, '%IDS%', connection);
|
|
287
|
+
if (records && records.length > 0) {
|
|
288
|
+
return new Map(records.map((record) => [record.Id, record.ContainerOptions]));
|
|
289
|
+
}
|
|
290
|
+
return new Map();
|
|
291
|
+
}
|
|
292
|
+
exports.getContainerOptions = getContainerOptions;
|
|
293
|
+
/**
|
|
294
|
+
* Return the Package2Version.HasMetadataRemoved field value for the given Id (05i)
|
|
295
|
+
*
|
|
296
|
+
* @param packageVersionId package version ID (05i)
|
|
297
|
+
* @param connection For tooling query
|
|
298
|
+
*/
|
|
299
|
+
async function getHasMetadataRemoved(packageVersionId, connection) {
|
|
300
|
+
const query = `SELECT HasMetadataRemoved FROM Package2Version WHERE Id = '${packageVersionId}'`;
|
|
301
|
+
const queryResult = await connection.tooling.query(query);
|
|
302
|
+
if (!queryResult || queryResult.records === null || queryResult.records.length === 0) {
|
|
303
|
+
throw messages.createError('errorInvalidIdNoMatchingVersionId', [
|
|
304
|
+
exports.BY_LABEL.PACKAGE_VERSION_ID.label,
|
|
305
|
+
packageVersionId,
|
|
306
|
+
exports.BY_LABEL.PACKAGE_VERSION_ID.label,
|
|
307
|
+
]);
|
|
308
|
+
}
|
|
309
|
+
return queryResult.records[0].HasMetadataRemoved;
|
|
310
|
+
}
|
|
311
|
+
exports.getHasMetadataRemoved = getHasMetadataRemoved;
|
|
312
|
+
/**
|
|
313
|
+
* Given a list of subscriber package version IDs (04t), return the associated version strings (e.g., Major.Minor.Patch.Build)
|
|
314
|
+
*
|
|
315
|
+
* @return Map of subscriberPackageVersionId to versionString
|
|
316
|
+
* @param subscriberPackageVersionIds
|
|
317
|
+
* @param connection For tooling query
|
|
318
|
+
*/
|
|
319
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
320
|
+
async function getPackageVersionStrings(subscriberPackageVersionIds, connection) {
|
|
321
|
+
let results = new Map();
|
|
322
|
+
if (!subscriberPackageVersionIds || subscriberPackageVersionIds.length === 0) {
|
|
323
|
+
return results;
|
|
324
|
+
}
|
|
325
|
+
// remove any duplicate Ids
|
|
326
|
+
const ids = [...new Set(subscriberPackageVersionIds)];
|
|
327
|
+
const query = 'SELECT SubscriberPackageVersionId, MajorVersion, MinorVersion, PatchVersion, BuildNumber FROM Package2Version WHERE SubscriberPackageVersionId IN (%IDS%)';
|
|
328
|
+
const records = await queryWithInConditionChunking(query, ids, '%IDS%', connection);
|
|
329
|
+
if (records && records.length > 0) {
|
|
330
|
+
results = new Map(records.map((record) => {
|
|
331
|
+
const version = concatVersion(record.MajorVersion, record.MinorVersion, record.PatchVersion, record.BuildNumber);
|
|
332
|
+
return [record.SubscriberPackageVersionId, version];
|
|
333
|
+
}));
|
|
334
|
+
}
|
|
335
|
+
return results;
|
|
336
|
+
}
|
|
337
|
+
exports.getPackageVersionStrings = getPackageVersionStrings;
|
|
338
|
+
/**
|
|
339
|
+
* For queries with an IN condition, determine if the WHERE clause will exceed
|
|
340
|
+
* SOQL's 4000 character limit. Perform multiple queries as needed to stay below the limit.
|
|
341
|
+
*
|
|
342
|
+
* @return concatenated array of records returned from the resulting query(ies)
|
|
343
|
+
* @param query The full query to execute containing the replaceToken param in its IN clause
|
|
344
|
+
* @param items The IN clause items. A length-appropriate single-quoted comma-separated string chunk will be made from the items.
|
|
345
|
+
* @param replaceToken A placeholder in the query's IN condition that will be replaced with the chunked items
|
|
346
|
+
* @param connection For tooling query
|
|
347
|
+
*/
|
|
348
|
+
async function queryWithInConditionChunking(query, items, replaceToken, connection) {
|
|
349
|
+
let records = [];
|
|
350
|
+
if (!query || !items || !replaceToken) {
|
|
351
|
+
return records;
|
|
352
|
+
}
|
|
353
|
+
const whereClause = query.substring(query.toLowerCase().indexOf('where'), query.length);
|
|
354
|
+
const inClauseItemsMaxLength = exports.SOQL_WHERE_CLAUSE_MAX_LENGTH - whereClause.length - replaceToken.length;
|
|
355
|
+
let itemsQueried = 0;
|
|
356
|
+
while (itemsQueried < items.length) {
|
|
357
|
+
const chunkCount = getInClauseItemsCount(items, itemsQueried, inClauseItemsMaxLength);
|
|
358
|
+
if (chunkCount === 0) {
|
|
359
|
+
throw messages.createError('itemDoesNotFitWithinMaxLength', [
|
|
360
|
+
query,
|
|
361
|
+
items[itemsQueried].slice(0, 20),
|
|
362
|
+
items[itemsQueried].length,
|
|
363
|
+
inClauseItemsMaxLength,
|
|
364
|
+
]);
|
|
365
|
+
}
|
|
366
|
+
const itemsStr = `${items.slice(itemsQueried, itemsQueried + chunkCount).join("','")}`;
|
|
367
|
+
const queryChunk = query.replace(replaceToken, itemsStr);
|
|
368
|
+
const result = await connection.tooling.query(queryChunk);
|
|
369
|
+
if (result && result.records.length > 0) {
|
|
370
|
+
records = records.concat(result.records);
|
|
371
|
+
}
|
|
372
|
+
itemsQueried += chunkCount;
|
|
373
|
+
}
|
|
374
|
+
return records;
|
|
375
|
+
}
|
|
376
|
+
exports.queryWithInConditionChunking = queryWithInConditionChunking;
|
|
377
|
+
/**
|
|
378
|
+
* Returns the number of items that can be included in a quoted comma-separated string (e.g., "'item1','item2'") not exceeding maxLength
|
|
379
|
+
*/
|
|
380
|
+
// TODO: this function cannot handle a single item that is longer than maxLength - what to do, since this could be the root cause of an infinite loop?
|
|
381
|
+
function getInClauseItemsCount(items, startIndex, maxLength) {
|
|
382
|
+
let resultLength = 0;
|
|
383
|
+
let includedCount = 0;
|
|
384
|
+
while (startIndex + includedCount < items.length) {
|
|
385
|
+
let itemLength = 0;
|
|
386
|
+
if (items[startIndex + includedCount]) {
|
|
387
|
+
itemLength = items[startIndex + includedCount].length + 3; // 3 = length of "'',"
|
|
388
|
+
if (resultLength + itemLength > maxLength) {
|
|
389
|
+
// the limit has been exceeded, return the current count
|
|
390
|
+
return includedCount;
|
|
391
|
+
}
|
|
392
|
+
includedCount++;
|
|
393
|
+
resultLength += itemLength;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return includedCount;
|
|
397
|
+
}
|
|
398
|
+
exports.getInClauseItemsCount = getInClauseItemsCount;
|
|
399
|
+
/**
|
|
400
|
+
* Given a package descriptor, return the ancestor ID. This code was duplicated to scratchOrgInfoGenerator.getAncestorIds,
|
|
401
|
+
* changes here may need to be duplicated there until that code, and/or this code is moved to a separate plugin.
|
|
402
|
+
*
|
|
403
|
+
* @param packageDescriptorJson JSON for packageDirectories element in sfdx-project.json
|
|
404
|
+
* @param connection For tooling query
|
|
405
|
+
* @param project The project to use for looking up the ancestor ID
|
|
406
|
+
* @param versionNumberString The version number string to use for looking up the ancestor ID
|
|
407
|
+
* @param skipAncestorCheck If true, skip the check for the ancestor ID
|
|
408
|
+
*/
|
|
409
|
+
async function getAncestorId(packageDescriptorJson, connection, project, versionNumberString, skipAncestorCheck) {
|
|
410
|
+
// eslint-disable-next-line complexity
|
|
411
|
+
return Promise.resolve().then(async () => {
|
|
412
|
+
var _a;
|
|
413
|
+
// If an id property is present, use it. Otherwise, look up the package id from the package property.
|
|
414
|
+
const packageId = (_a = packageDescriptorJson['id']) !== null && _a !== void 0 ? _a : getPackageIdFromAlias(packageDescriptorJson.package, project);
|
|
415
|
+
// No need to proceed if Unlocked
|
|
416
|
+
const packageType = await getPackage2Type(packageId, connection);
|
|
417
|
+
if (packageType === 'Unlocked') {
|
|
418
|
+
return '';
|
|
419
|
+
}
|
|
420
|
+
let ancestorId = '';
|
|
421
|
+
// ancestorID can be alias, 05i, or 04t;
|
|
422
|
+
// validate and convert to 05i, as needed
|
|
423
|
+
const versionNumber = versionNumberString.split(exports.VERSION_NUMBER_SEP);
|
|
424
|
+
const isPatch = versionNumber[2] !== '0';
|
|
425
|
+
let origSpecifiedAncestor = packageDescriptorJson.ancestorId;
|
|
426
|
+
let highestReleasedVersion = null;
|
|
427
|
+
const explicitUseHighestRelease = packageDescriptorJson.ancestorId === versionNumber_1.BuildNumberToken.HIGHEST_VERSION_NUMBER_TOKEN ||
|
|
428
|
+
packageDescriptorJson.ancestorVersion === versionNumber_1.BuildNumberToken.HIGHEST_VERSION_NUMBER_TOKEN;
|
|
429
|
+
const explicitUseNoAncestor = packageDescriptorJson.ancestorId === versionNumber_1.BuildNumberToken.NONE_VERSION_NUMBER_TOKEN ||
|
|
430
|
+
packageDescriptorJson.ancestorVersion === versionNumber_1.BuildNumberToken.NONE_VERSION_NUMBER_TOKEN;
|
|
431
|
+
if ((explicitUseHighestRelease || explicitUseNoAncestor) &&
|
|
432
|
+
packageDescriptorJson.ancestorId &&
|
|
433
|
+
packageDescriptorJson.ancestorVersion) {
|
|
434
|
+
if (packageDescriptorJson.ancestorId !== packageDescriptorJson.ancestorVersion) {
|
|
435
|
+
// both ancestorId and ancestorVersion specified, HIGHEST and/or NONE are used, the values disagree
|
|
436
|
+
throw messages.createError('errorAncestorIdVersionHighestOrNoneMismatch', [
|
|
437
|
+
packageDescriptorJson.ancestorId,
|
|
438
|
+
packageDescriptorJson.ancestorVersion,
|
|
439
|
+
]);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (explicitUseNoAncestor && skipAncestorCheck) {
|
|
443
|
+
return '';
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
const result = await getAncestorIdHighestRelease(connection, packageId, versionNumberString, explicitUseHighestRelease, skipAncestorCheck);
|
|
447
|
+
if (result.finalAncestorId) {
|
|
448
|
+
return result.finalAncestorId;
|
|
449
|
+
}
|
|
450
|
+
highestReleasedVersion = result.highestReleasedVersion;
|
|
451
|
+
}
|
|
452
|
+
// at this point if explicitUseHighestRelease=true, we have returned the ancestorId or thrown an error
|
|
453
|
+
// highestReleasedVersion should be null only if skipAncestorCheck or if there is no existing released package version
|
|
454
|
+
if (!explicitUseNoAncestor && packageDescriptorJson.ancestorId) {
|
|
455
|
+
ancestorId = getPackageIdFromAlias(packageDescriptorJson.ancestorId, project);
|
|
456
|
+
validateId([exports.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, exports.BY_LABEL.PACKAGE_VERSION_ID], ancestorId);
|
|
457
|
+
ancestorId = await getPackageVersionId(ancestorId, connection);
|
|
458
|
+
}
|
|
459
|
+
if (!explicitUseNoAncestor && packageDescriptorJson.ancestorVersion) {
|
|
460
|
+
const regNumbers = new RegExp('^[0-9]+$');
|
|
461
|
+
const versionNumber = packageDescriptorJson.ancestorVersion.split(exports.VERSION_NUMBER_SEP);
|
|
462
|
+
if (versionNumber.length < 3 ||
|
|
463
|
+
versionNumber.length > 4 ||
|
|
464
|
+
!versionNumber[0].match(regNumbers) ||
|
|
465
|
+
!versionNumber[1].match(regNumbers) ||
|
|
466
|
+
!versionNumber[2].match(regNumbers)) {
|
|
467
|
+
throw messages.createError('errorInvalidAncestorVersionFormat', [packageDescriptorJson.ancestorVersion]);
|
|
468
|
+
}
|
|
469
|
+
const query = 'SELECT Id, IsReleased FROM Package2Version ' +
|
|
470
|
+
`WHERE Package2Id = '${packageId}' AND MajorVersion = ${versionNumber[0]} AND MinorVersion = ${versionNumber[1]} AND PatchVersion = ${versionNumber[2]}`;
|
|
471
|
+
let queriedAncestorId;
|
|
472
|
+
const ancestorVersionResult = await connection.tooling.query(query);
|
|
473
|
+
if (!ancestorVersionResult || !ancestorVersionResult.totalSize) {
|
|
474
|
+
throw messages.createError('errorNoMatchingAncestor', [packageDescriptorJson.ancestorVersion, packageId]);
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
const releasedAncestor = ancestorVersionResult.records.find((rec) => rec.IsReleased === true);
|
|
478
|
+
if (!releasedAncestor) {
|
|
479
|
+
throw messages.createError('errorAncestorNotReleased', [packageDescriptorJson.ancestorVersion]);
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
queriedAncestorId = releasedAncestor.Id;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// check for discrepancy between queried ancestorId and descriptor's ancestorId
|
|
486
|
+
if (Object.prototype.hasOwnProperty.call(packageDescriptorJson, 'ancestorId') &&
|
|
487
|
+
ancestorId !== queriedAncestorId) {
|
|
488
|
+
throw messages.createError('errorAncestorIdVersionMismatch', [
|
|
489
|
+
packageDescriptorJson.ancestorVersion,
|
|
490
|
+
packageDescriptorJson.ancestorId,
|
|
491
|
+
]);
|
|
492
|
+
}
|
|
493
|
+
ancestorId = queriedAncestorId;
|
|
494
|
+
origSpecifiedAncestor = packageDescriptorJson.ancestorVersion;
|
|
495
|
+
}
|
|
496
|
+
return validateAncestorId(ancestorId, highestReleasedVersion, explicitUseNoAncestor, isPatch, skipAncestorCheck, origSpecifiedAncestor);
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
exports.getAncestorId = getAncestorId;
|
|
500
|
+
function validateAncestorId(ancestorId, highestReleasedVersion, explicitUseNoAncestor, isPatch, skipAncestorCheck, origSpecifiedAncestor) {
|
|
501
|
+
if (explicitUseNoAncestor) {
|
|
502
|
+
if (!highestReleasedVersion) {
|
|
503
|
+
return '';
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
// the explicitUseNoAncestor && skipAncestorCheck case is handled above
|
|
507
|
+
throw messages.createError('errorAncestorNoneNotAllowed', [getPackage2VersionNumber(highestReleasedVersion)]);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (!isPatch && !skipAncestorCheck) {
|
|
511
|
+
if (highestReleasedVersion) {
|
|
512
|
+
if (highestReleasedVersion.Id !== ancestorId) {
|
|
513
|
+
throw messages.createError('errorAncestorNotHighest', [
|
|
514
|
+
origSpecifiedAncestor,
|
|
515
|
+
getPackage2VersionNumber(highestReleasedVersion),
|
|
516
|
+
]);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
// looks like the initial version:create - allow
|
|
521
|
+
ancestorId = '';
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return ancestorId;
|
|
525
|
+
}
|
|
526
|
+
exports.validateAncestorId = validateAncestorId;
|
|
527
|
+
async function getAncestorIdHighestRelease(connection, packageId, versionNumberString, explicitUseHighestRelease, skipAncestorCheck) {
|
|
528
|
+
const versionNumber = versionNumberString.split(exports.VERSION_NUMBER_SEP);
|
|
529
|
+
const isPatch = versionNumber[2] !== '0';
|
|
530
|
+
const result = { finalAncestorId: null, highestReleasedVersion: null };
|
|
531
|
+
if (isPatch && explicitUseHighestRelease) {
|
|
532
|
+
// based on server-side validation, whatever ancestor is specified for a patch is
|
|
533
|
+
// tightly controlled; therefore we only need concern ourselves if explicitUseHighestRelease == true;
|
|
534
|
+
// equally applies when skipAncestorCheck == true
|
|
535
|
+
// gather appropriate matching major.minor.0
|
|
536
|
+
const query = `SELECT Id FROM Package2Version WHERE Package2Id = '${packageId}' ` +
|
|
537
|
+
'AND IsReleased = True AND IsDeprecated = False AND PatchVersion = 0 ' +
|
|
538
|
+
`AND MajorVersion = ${versionNumber[0]} AND MinorVersion = ${versionNumber[1]} ` +
|
|
539
|
+
'ORDER BY MajorVersion Desc, MinorVersion Desc, PatchVersion Desc, BuildNumber Desc LIMIT 1';
|
|
540
|
+
const majorMinorVersionResult = await connection.tooling.query(query);
|
|
541
|
+
const majorMinorVersionRecords = majorMinorVersionResult.records;
|
|
542
|
+
if (majorMinorVersionRecords && (majorMinorVersionRecords === null || majorMinorVersionRecords === void 0 ? void 0 : majorMinorVersionRecords.length) === 1 && majorMinorVersionRecords[0]) {
|
|
543
|
+
result.finalAncestorId = majorMinorVersionRecords[0].Id;
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
const majorMinorNotFound = `${versionNumber[0]}.${versionNumber[1]}.0`;
|
|
547
|
+
throw messages.createError('errorNoMatchingMajorMinorForPatch', [majorMinorNotFound]);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
else if (!isPatch && (explicitUseHighestRelease || !skipAncestorCheck)) {
|
|
551
|
+
// ancestor must be set to latest released major.minor version
|
|
552
|
+
const query = 'SELECT Id, SubscriberPackageVersionId, MajorVersion, MinorVersion, PatchVersion FROM Package2Version ' +
|
|
553
|
+
`WHERE Package2Id = '${packageId}' AND IsReleased = True AND IsDeprecated = False AND PatchVersion = 0 ` +
|
|
554
|
+
'ORDER BY MajorVersion Desc, MinorVersion Desc, PatchVersion Desc, BuildNumber Desc LIMIT 1';
|
|
555
|
+
const highestVersionResult = await connection.tooling.query(query);
|
|
556
|
+
const highestVersionRecords = highestVersionResult.records;
|
|
557
|
+
if (highestVersionRecords && highestVersionRecords[0]) {
|
|
558
|
+
result.highestReleasedVersion = highestVersionRecords[0];
|
|
559
|
+
if (explicitUseHighestRelease) {
|
|
560
|
+
result.finalAncestorId = result.highestReleasedVersion.Id;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
else if (explicitUseHighestRelease) {
|
|
564
|
+
// there is no eligible ancestor version
|
|
565
|
+
throw new Error(messages.getMessage('errorNoMatchingAncestor', [versionNumberString, packageId]));
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return result;
|
|
569
|
+
}
|
|
570
|
+
exports.getAncestorIdHighestRelease = getAncestorIdHighestRelease;
|
|
571
|
+
/**
|
|
572
|
+
* Return a version string in Major.Minor.Patch.Build format, using 0 for any empty part
|
|
573
|
+
*/
|
|
574
|
+
function concatVersion(major, minor, patch, build) {
|
|
575
|
+
return [major, minor, patch, build].map((part) => (part ? `${part}` : '0')).join('.');
|
|
576
|
+
}
|
|
577
|
+
exports.concatVersion = concatVersion;
|
|
578
|
+
function getPackage2VersionNumber(package2VersionObj) {
|
|
579
|
+
const version = concatVersion(package2VersionObj.MajorVersion, package2VersionObj.MinorVersion, package2VersionObj.PatchVersion, undefined);
|
|
580
|
+
return version.slice(0, version.lastIndexOf('.'));
|
|
581
|
+
}
|
|
582
|
+
exports.getPackage2VersionNumber = getPackage2VersionNumber;
|
|
583
|
+
// TODO: get rid of this function if possible.
|
|
584
|
+
function getConfigPackageDirectories(project) {
|
|
585
|
+
return project.getPackageDirectories();
|
|
586
|
+
}
|
|
587
|
+
exports.getConfigPackageDirectories = getConfigPackageDirectories;
|
|
588
|
+
function getConfigPackageDirectory(packageDirs, lookupProperty, lookupValue) {
|
|
589
|
+
return packageDirs === null || packageDirs === void 0 ? void 0 : packageDirs.find((pkgDir) => pkgDir[lookupProperty] === lookupValue);
|
|
590
|
+
}
|
|
591
|
+
exports.getConfigPackageDirectory = getConfigPackageDirectory;
|
|
592
|
+
/**
|
|
593
|
+
* Given a packageAlias, attempt to return the associated id from the config
|
|
594
|
+
*
|
|
595
|
+
* @param packageAlias string representing a package alias
|
|
596
|
+
* @param project for obtaining the project config
|
|
597
|
+
* @returns the associated id or the arg given.
|
|
598
|
+
*/
|
|
599
|
+
function getPackageIdFromAlias(packageAlias, project) {
|
|
600
|
+
const packageAliases = project.getSfProjectJson().getContents().packageAliases || {};
|
|
601
|
+
// return alias if it exists, otherwise return what was passed in
|
|
602
|
+
return packageAliases[packageAlias] || packageAlias;
|
|
603
|
+
}
|
|
604
|
+
exports.getPackageIdFromAlias = getPackageIdFromAlias;
|
|
605
|
+
/**
|
|
606
|
+
* @param stringIn pascal or camel case string
|
|
607
|
+
* @returns space delimited and lower-cased (except for 1st char) string (e.g. in "AbcdEfghIj" => "Abcd efgh ij")
|
|
608
|
+
*/
|
|
609
|
+
function convertCamelCaseStringToSentence(stringIn) {
|
|
610
|
+
return (0, kit_1.camelCaseToTitleCase)(stringIn);
|
|
611
|
+
}
|
|
612
|
+
exports.convertCamelCaseStringToSentence = convertCamelCaseStringToSentence;
|
|
613
|
+
/**
|
|
614
|
+
* Given a package id, attempt to return the associated aliases from the config
|
|
615
|
+
*
|
|
616
|
+
* @param packageId string representing a package id
|
|
617
|
+
* @param project for obtaining the project config
|
|
618
|
+
* @returns an array of alias for the given id.
|
|
619
|
+
*/
|
|
620
|
+
function getPackageAliasesFromId(packageId, project) {
|
|
621
|
+
const packageAliases = project.getSfProjectJson().getContents().packageAliases || {};
|
|
622
|
+
// check for a matching alias
|
|
623
|
+
return Object.entries(packageAliases)
|
|
624
|
+
.filter((alias) => alias[1] === packageId)
|
|
625
|
+
.map((alias) => alias[0]);
|
|
626
|
+
}
|
|
627
|
+
exports.getPackageAliasesFromId = getPackageAliasesFromId;
|
|
628
|
+
async function findOrCreatePackage2(seedPackage, connection) {
|
|
629
|
+
const query = `SELECT Id FROM Package2 WHERE ConvertedFromPackageId = '${seedPackage}'`;
|
|
630
|
+
const queryResult = await connection.tooling.query(query);
|
|
631
|
+
const records = queryResult.records;
|
|
632
|
+
if (records && records.length > 1) {
|
|
633
|
+
const ids = records.map((r) => r.Id);
|
|
634
|
+
throw new Error(messages.getMessage('errorMoreThanOnePackage2WithSeed', [ids.join(', ')]));
|
|
635
|
+
}
|
|
636
|
+
if (records && records.length === 1) {
|
|
637
|
+
// return the package2 object
|
|
638
|
+
return records[0].Id;
|
|
639
|
+
}
|
|
640
|
+
// Need to create a new Package2
|
|
641
|
+
const subQuery = `SELECT Name, Description, NamespacePrefix FROM SubscriberPackage WHERE Id = '${seedPackage}'`;
|
|
642
|
+
const subscriberResult = await connection.tooling.query(subQuery);
|
|
643
|
+
const subscriberRecords = subscriberResult.records;
|
|
644
|
+
if (!subscriberRecords || subscriberRecords.length <= 0) {
|
|
645
|
+
throw new Error(messages.getMessage('errorNoSubscriberPackageRecord', [seedPackage]));
|
|
646
|
+
}
|
|
647
|
+
const request = {
|
|
648
|
+
Name: subscriberRecords[0].Name,
|
|
649
|
+
Description: subscriberRecords[0].Description,
|
|
650
|
+
NamespacePrefix: subscriberRecords[0].NamespacePrefix,
|
|
651
|
+
ContainerOptions: 'Managed',
|
|
652
|
+
ConvertedFromPackageId: seedPackage,
|
|
653
|
+
};
|
|
654
|
+
const createResult = await connection.tooling.create('Package2', request);
|
|
655
|
+
if (!createResult.success) {
|
|
656
|
+
throw new Error(createResult.errors.map((e) => e.message).join('\n'));
|
|
657
|
+
}
|
|
658
|
+
return createResult.id;
|
|
659
|
+
}
|
|
660
|
+
exports.findOrCreatePackage2 = findOrCreatePackage2;
|
|
661
|
+
function _getPackageVersionCreateRequestApi(connection) {
|
|
662
|
+
return new packageVersionCreateRequestApi_1.PackageVersionCreateRequestApi({ connection });
|
|
663
|
+
}
|
|
664
|
+
exports._getPackageVersionCreateRequestApi = _getPackageVersionCreateRequestApi;
|
|
665
|
+
async function pollForStatusWithInterval(context, id, retries, packageId, branch, withProject, connection, interval) {
|
|
666
|
+
let remainingRetries = retries;
|
|
667
|
+
const pollingClient = await core_1.PollingClient.create({
|
|
668
|
+
poll: async () => {
|
|
669
|
+
var _a;
|
|
670
|
+
const pvcrApi = new packageVersionCreateRequestApi_1.PackageVersionCreateRequestApi({ connection });
|
|
671
|
+
const results = await pvcrApi.byId(id);
|
|
672
|
+
if (_isStatusEqualTo(results, [Package2VersionStatus.success, Package2VersionStatus.error])) {
|
|
673
|
+
// complete
|
|
674
|
+
if (_isStatusEqualTo(results, [Package2VersionStatus.success])) {
|
|
675
|
+
// update sfdx-project.json
|
|
676
|
+
let projectUpdated = false;
|
|
677
|
+
if (withProject && !process.env.SFDX_PROJECT_AUTOUPDATE_DISABLE_FOR_PACKAGE_VERSION_CREATE) {
|
|
678
|
+
projectUpdated = true;
|
|
679
|
+
const query = `SELECT MajorVersion, MinorVersion, PatchVersion, BuildNumber FROM Package2Version WHERE Id = '${results[0].Package2VersionId}'`;
|
|
680
|
+
const package2VersionVersionString = await connection.tooling
|
|
681
|
+
.query(query)
|
|
682
|
+
.then((pkgQueryResult) => {
|
|
683
|
+
const record = pkgQueryResult.records[0];
|
|
684
|
+
return `${record.MajorVersion}.${record.MinorVersion}.${record.PatchVersion}-${record.BuildNumber}`;
|
|
685
|
+
});
|
|
686
|
+
const newConfig = await _generatePackageAliasEntry(connection, withProject, results[0].SubscriberPackageVersionId, package2VersionVersionString, branch, packageId);
|
|
687
|
+
withProject.getSfProjectJson().set('packageAliases', newConfig);
|
|
688
|
+
await withProject.getSfProjectJson().write();
|
|
689
|
+
}
|
|
690
|
+
core_1.Lifecycle.getInstance().emit(Package2VersionStatus.success, {
|
|
691
|
+
id,
|
|
692
|
+
package2VersionCreateRequestResult: results[0],
|
|
693
|
+
projectUpdated,
|
|
694
|
+
});
|
|
695
|
+
return { completed: true, payload: results[0] };
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
let status = 'Unknown Error';
|
|
699
|
+
if ((results === null || results === void 0 ? void 0 : results.length) > 0 && results[0].Error.length > 0) {
|
|
700
|
+
const errors = [];
|
|
701
|
+
// for multiple errors, display one per line prefixed with (x)
|
|
702
|
+
if (results[0].Error.length > 1) {
|
|
703
|
+
results[0].Error.forEach((error) => {
|
|
704
|
+
errors.push(`(${errors.length + 1}) ${error}`);
|
|
705
|
+
});
|
|
706
|
+
errors.unshift(messages.getMessage('versionCreateFailedWithMultipleErrors'));
|
|
707
|
+
}
|
|
708
|
+
status = errors.length !== 0 ? errors.join('\n') : results[0].Error.join('\n');
|
|
709
|
+
}
|
|
710
|
+
core_1.Lifecycle.getInstance().emit(Package2VersionStatus.error, { id, status });
|
|
711
|
+
throw new core_1.SfError(status);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
const remainingTime = kit_1.Duration.milliseconds(interval.milliseconds * remainingRetries);
|
|
716
|
+
core_1.Lifecycle.getInstance().emit(Package2VersionStatus.inProgress, {
|
|
717
|
+
id,
|
|
718
|
+
package2VersionCreateRequestResult: results[0],
|
|
719
|
+
message: '',
|
|
720
|
+
remainingTime,
|
|
721
|
+
});
|
|
722
|
+
logger.info(`Request in progress. Sleeping ${interval} seconds. Will wait a total of ${remainingTime.seconds} more seconds before timing out. Current Status='${convertCamelCaseStringToSentence((_a = results[0]) === null || _a === void 0 ? void 0 : _a.Status)}'`);
|
|
723
|
+
remainingRetries--;
|
|
724
|
+
return { completed: false, payload: results[0] };
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
frequency: kit_1.Duration.milliseconds(interval.milliseconds * 1000),
|
|
728
|
+
timeout: kit_1.Duration.milliseconds(interval.milliseconds * retries * 1000),
|
|
729
|
+
});
|
|
730
|
+
return pollingClient.subscribe();
|
|
731
|
+
}
|
|
732
|
+
exports.pollForStatusWithInterval = pollForStatusWithInterval;
|
|
733
|
+
/**
|
|
734
|
+
* Generate package alias json entry for this package version that can be written to sfdx-project.json
|
|
735
|
+
*
|
|
736
|
+
* @param connection
|
|
737
|
+
* @param project SfProject instance for the project
|
|
738
|
+
* @param packageVersionId 04t id of the package to create the alias entry for
|
|
739
|
+
* @param packageVersionNumber that will be appended to the package name to form the alias
|
|
740
|
+
* @param branch
|
|
741
|
+
* @param packageId the 0Ho id
|
|
742
|
+
* @private
|
|
743
|
+
*/
|
|
744
|
+
async function _generatePackageAliasEntry(connection, project, packageVersionId, packageVersionNumber, branch, packageId) {
|
|
745
|
+
const configContent = project.getSfProjectJson().getContents();
|
|
746
|
+
const packageAliases = configContent.packageAliases || {};
|
|
747
|
+
const aliasForPackageId = getPackageAliasesFromId(packageId, project);
|
|
748
|
+
let packageName;
|
|
749
|
+
if (!aliasForPackageId || aliasForPackageId.length === 0) {
|
|
750
|
+
const query = `SELECT Name FROM Package2 WHERE Id = '${packageId}'`;
|
|
751
|
+
packageName = await connection.tooling
|
|
752
|
+
.query(query)
|
|
753
|
+
.then((pkgQueryResult) => { var _a; return (_a = pkgQueryResult.records[0]) === null || _a === void 0 ? void 0 : _a.Name; });
|
|
754
|
+
}
|
|
755
|
+
else {
|
|
756
|
+
packageName = aliasForPackageId[0];
|
|
757
|
+
}
|
|
758
|
+
const packageAlias = branch
|
|
759
|
+
? `${packageName}@${packageVersionNumber}-${branch}`
|
|
760
|
+
: `${packageName}@${packageVersionNumber}`;
|
|
761
|
+
packageAliases[packageAlias] = packageVersionId;
|
|
762
|
+
return { packageAliases };
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Return true if the queryResult.records[0].Status is equal to one of the values in statuses.
|
|
766
|
+
*
|
|
767
|
+
* @param results to examine
|
|
768
|
+
* @param statuses array of statuses to look for
|
|
769
|
+
* @returns {boolean} if one of the values in status is found.
|
|
770
|
+
*/
|
|
771
|
+
function _isStatusEqualTo(results, statuses) {
|
|
772
|
+
return (results === null || results === void 0 ? void 0 : results.length) <= 0 ? false : statuses === null || statuses === void 0 ? void 0 : statuses.some((status) => results[0].Status === status);
|
|
773
|
+
}
|
|
774
|
+
// added for unit testing
|
|
775
|
+
function getSoqlWhereClauseMaxLength() {
|
|
776
|
+
return exports.SOQL_WHERE_CLAUSE_MAX_LENGTH;
|
|
777
|
+
}
|
|
778
|
+
exports.getSoqlWhereClauseMaxLength = getSoqlWhereClauseMaxLength;
|
|
779
|
+
function formatDate(date) {
|
|
780
|
+
const pad = (num) => {
|
|
781
|
+
return num < 10 ? `0${num}` : num;
|
|
782
|
+
};
|
|
783
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
784
|
+
}
|
|
785
|
+
exports.formatDate = formatDate;
|
|
786
|
+
//# sourceMappingURL=packageUtils.js.map
|