@salesforce/packaging 0.0.36 → 0.0.38
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/lib/package/packageConvert.d.ts +1 -0
- package/lib/package/packageConvert.js +40 -3
- package/lib/package/packageCreate.d.ts +3 -3
- package/lib/package/packageCreate.js +11 -10
- package/lib/package/packageInstall.d.ts +2 -0
- package/lib/package/packageInstall.js +37 -5
- package/lib/package/packageVersion.d.ts +7 -0
- package/lib/package/packageVersion.js +25 -2
- package/lib/package/packageVersionCreate.d.ts +6 -0
- package/lib/package/packageVersionCreate.js +208 -3
- package/lib/package/packageVersionCreateRequest.js +7 -2
- package/lib/package/packageVersionReport.js +28 -2
- package/lib/utils/packageUtils.d.ts +1 -35
- package/lib/utils/packageUtils.js +5 -315
- package/messages/package_install.md +4 -0
- package/messages/package_version.md +3 -0
- package/messages/package_version_create.md +29 -0
- package/messages/pkg_utils.md +0 -29
- package/package.json +2 -2
- package/CHANGELOG.md +0 -228
- package/messages/messages.md +0 -281
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Connection, SfProject } from '@salesforce/core';
|
|
2
2
|
import { PackagingSObjects, PackageVersionCreateRequestResult, ConvertPackageOptions } from '../interfaces';
|
|
3
|
+
export declare function findOrCreatePackage2(seedPackage: string, connection: Connection): Promise<string>;
|
|
3
4
|
export declare function convertPackage(pkg: string, connection: Connection, options: ConvertPackageOptions, project?: SfProject): Promise<PackageVersionCreateRequestResult>;
|
|
4
5
|
/**
|
|
5
6
|
* Convert the list of command line options to a JSON object that can be used to create an Package2VersionCreateRequest entity.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.createPackageVersionCreateRequest = exports.convertPackage = void 0;
|
|
9
|
+
exports.createPackageVersionCreateRequest = exports.convertPackage = exports.findOrCreatePackage2 = void 0;
|
|
10
10
|
const path = require("path");
|
|
11
11
|
const os = require("os");
|
|
12
12
|
const fs = require("fs");
|
|
@@ -23,13 +23,49 @@ const pvcr = require("./packageVersionCreateRequest");
|
|
|
23
23
|
var Package2VersionStatus = interfaces_1.PackagingSObjects.Package2VersionStatus;
|
|
24
24
|
core_1.Messages.importMessagesDirectory(__dirname);
|
|
25
25
|
const messages = core_1.Messages.loadMessages('@salesforce/packaging', 'package_version_create');
|
|
26
|
+
async function findOrCreatePackage2(seedPackage, connection) {
|
|
27
|
+
const query = `SELECT Id FROM Package2 WHERE ConvertedFromPackageId = '${seedPackage}'`;
|
|
28
|
+
const queryResult = (await connection.tooling.query(query)).records;
|
|
29
|
+
if (queryResult?.length > 1) {
|
|
30
|
+
const ids = queryResult.map((r) => r.Id);
|
|
31
|
+
throw messages.createError('errorMoreThanOnePackage2WithSeed', [ids.join(', ')]);
|
|
32
|
+
}
|
|
33
|
+
if (queryResult?.length === 1) {
|
|
34
|
+
// return the package2 object
|
|
35
|
+
return queryResult[0].Id;
|
|
36
|
+
}
|
|
37
|
+
// Need to create a new Package2
|
|
38
|
+
const subQuery = `SELECT Name, Description, NamespacePrefix FROM SubscriberPackage WHERE Id = '${seedPackage}'`;
|
|
39
|
+
let subscriberResult;
|
|
40
|
+
try {
|
|
41
|
+
subscriberResult = await connection.singleRecordQuery(subQuery, {
|
|
42
|
+
tooling: true,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
throw messages.createError('errorNoSubscriberPackageRecord', [seedPackage]);
|
|
47
|
+
}
|
|
48
|
+
const request = {
|
|
49
|
+
Name: subscriberResult.Name,
|
|
50
|
+
Description: subscriberResult.Description,
|
|
51
|
+
NamespacePrefix: subscriberResult.NamespacePrefix,
|
|
52
|
+
ContainerOptions: 'Managed',
|
|
53
|
+
ConvertedFromPackageId: seedPackage,
|
|
54
|
+
};
|
|
55
|
+
const createResult = await connection.tooling.create('Package2', request);
|
|
56
|
+
if (!createResult.success) {
|
|
57
|
+
throw pkgUtils.combineSaveErrors('Package2', 'create', createResult.errors);
|
|
58
|
+
}
|
|
59
|
+
return createResult.id;
|
|
60
|
+
}
|
|
61
|
+
exports.findOrCreatePackage2 = findOrCreatePackage2;
|
|
26
62
|
async function convertPackage(pkg, connection, options, project) {
|
|
27
63
|
let maxRetries = 0;
|
|
28
64
|
const branch = 'main';
|
|
29
65
|
if (options.wait) {
|
|
30
66
|
maxRetries = (60 / pkgUtils.POLL_INTERVAL_SECONDS) * options.wait.minutes;
|
|
31
67
|
}
|
|
32
|
-
const packageId = await
|
|
68
|
+
const packageId = await findOrCreatePackage2(pkg, connection);
|
|
33
69
|
const request = await createPackageVersionCreateRequest({ installationkey: options.installationKey, buildinstance: options.buildInstance }, packageId);
|
|
34
70
|
// TODO: a lot of this is duplicated from PC, PVC, and PVCR.
|
|
35
71
|
const createResult = await connection.tooling.create('Package2VersionCreateRequest', request);
|
|
@@ -105,6 +141,7 @@ async function pollForStatusWithInterval(id, retries, packageId, branch, withPro
|
|
|
105
141
|
const record = pkgQueryResult.records[0];
|
|
106
142
|
return `${record.MajorVersion}.${record.MinorVersion}.${record.PatchVersion}-${record.BuildNumber}`;
|
|
107
143
|
});
|
|
144
|
+
// TODO SfProjectJson.addPackageAlias
|
|
108
145
|
const newConfig = await (0, utils_1.generatePackageAliasEntry)(connection, withProject, results[0].SubscriberPackageVersionId, packageVersionVersionString, branch, packageId);
|
|
109
146
|
withProject.getSfProjectJson().set('packageAliases', newConfig);
|
|
110
147
|
await withProject.getSfProjectJson().write();
|
|
@@ -143,7 +180,7 @@ async function pollForStatusWithInterval(id, retries, packageId, branch, withPro
|
|
|
143
180
|
timeRemaining: remainingTime,
|
|
144
181
|
});
|
|
145
182
|
const logger = core_1.Logger.childFromRoot('packageConvert');
|
|
146
|
-
logger.info(`Request in progress. Sleeping ${interval.seconds} seconds. Will wait a total of ${remainingTime.seconds} more seconds before timing out. Current Status='${(0,
|
|
183
|
+
logger.info(`Request in progress. Sleeping ${interval.seconds} seconds. Will wait a total of ${remainingTime.seconds} more seconds before timing out. Current Status='${(0, kit_1.camelCaseToTitleCase)(results[0]?.Status)}'`);
|
|
147
184
|
remainingRetries--;
|
|
148
185
|
return { completed: false, payload: results[0] };
|
|
149
186
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Connection, NamedPackageDir, PackageDir, SfProject } from '@salesforce/core';
|
|
2
2
|
import { PackageCreateOptions, PackagingSObjects } from '../interfaces';
|
|
3
3
|
declare type Package2Request = Pick<PackagingSObjects.Package2, 'Name' | 'Description' | 'NamespacePrefix' | 'ContainerOptions' | 'IsOrgDependent' | 'PackageErrorUsername'>;
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function createPackageRequestFromContext(project: SfProject, options: PackageCreateOptions): Package2Request;
|
|
5
5
|
/**
|
|
6
6
|
* Generate packageDirectory json entry for this package that can be written to sfdx-project.json
|
|
7
7
|
*
|
|
@@ -9,7 +9,7 @@ export declare function _createPackageRequestFromContext(project: SfProject, opt
|
|
|
9
9
|
* @param packageId the 0Ho id of the package to create the entry for
|
|
10
10
|
* @private
|
|
11
11
|
*/
|
|
12
|
-
export declare function
|
|
12
|
+
export declare function generatePackageDirEntry(project: SfProject, options: PackageCreateOptions): PackageDir[] | NamedPackageDir[];
|
|
13
13
|
/**
|
|
14
14
|
* Generate package alias json entry for this package that can be written to sfdx-project.json
|
|
15
15
|
*
|
|
@@ -17,7 +17,7 @@ export declare function _generatePackageDirEntry(project: SfProject, options: Pa
|
|
|
17
17
|
* @param packageId the 0Ho id of the package to create the alias entry for
|
|
18
18
|
* @private
|
|
19
19
|
*/
|
|
20
|
-
export declare function
|
|
20
|
+
export declare function generatePackageAliasEntry(project: SfProject, options: PackageCreateOptions, packageId: string): {
|
|
21
21
|
[key: string]: string;
|
|
22
22
|
};
|
|
23
23
|
export declare function createPackage(connection: Connection, project: SfProject, options: PackageCreateOptions): Promise<{
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.createPackage = exports.
|
|
9
|
+
exports.createPackage = exports.generatePackageAliasEntry = exports.generatePackageDirEntry = exports.createPackageRequestFromContext = void 0;
|
|
10
10
|
const core_1 = require("@salesforce/core");
|
|
11
11
|
const ts_types_1 = require("@salesforce/ts-types");
|
|
12
12
|
const pkgUtils = require("../utils/packageUtils");
|
|
13
13
|
core_1.Messages.importMessagesDirectory(__dirname);
|
|
14
14
|
const messages = core_1.Messages.loadMessages('@salesforce/packaging', 'package_create');
|
|
15
|
-
function
|
|
15
|
+
function createPackageRequestFromContext(project, options) {
|
|
16
16
|
const namespace = options.noNamespace ? '' : project.getSfProjectJson().getContents().namespace || '';
|
|
17
17
|
return {
|
|
18
18
|
Name: options.name,
|
|
@@ -23,7 +23,7 @@ function _createPackageRequestFromContext(project, options) {
|
|
|
23
23
|
PackageErrorUsername: options.errorNotificationUsername,
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
-
exports.
|
|
26
|
+
exports.createPackageRequestFromContext = createPackageRequestFromContext;
|
|
27
27
|
/**
|
|
28
28
|
* Generate packageDirectory json entry for this package that can be written to sfdx-project.json
|
|
29
29
|
*
|
|
@@ -31,7 +31,8 @@ exports._createPackageRequestFromContext = _createPackageRequestFromContext;
|
|
|
31
31
|
* @param packageId the 0Ho id of the package to create the entry for
|
|
32
32
|
* @private
|
|
33
33
|
*/
|
|
34
|
-
function
|
|
34
|
+
function generatePackageDirEntry(project, options) {
|
|
35
|
+
// TODO: use SfProjectJson#addPackageDirectory for this maintenance
|
|
35
36
|
let packageDirs = project.getPackageDirectories();
|
|
36
37
|
if (!packageDirs) {
|
|
37
38
|
packageDirs = [];
|
|
@@ -64,7 +65,7 @@ function _generatePackageDirEntry(project, options) {
|
|
|
64
65
|
}
|
|
65
66
|
return packageDirs;
|
|
66
67
|
}
|
|
67
|
-
exports.
|
|
68
|
+
exports.generatePackageDirEntry = generatePackageDirEntry;
|
|
68
69
|
/**
|
|
69
70
|
* Generate package alias json entry for this package that can be written to sfdx-project.json
|
|
70
71
|
*
|
|
@@ -72,17 +73,17 @@ exports._generatePackageDirEntry = _generatePackageDirEntry;
|
|
|
72
73
|
* @param packageId the 0Ho id of the package to create the alias entry for
|
|
73
74
|
* @private
|
|
74
75
|
*/
|
|
75
|
-
function
|
|
76
|
+
function generatePackageAliasEntry(project, options, packageId) {
|
|
76
77
|
const packageAliases = project.getSfProjectJson().getContents().packageAliases || {};
|
|
77
78
|
const packageName = options.name;
|
|
78
79
|
packageAliases[packageName] = packageId;
|
|
79
80
|
return packageAliases;
|
|
80
81
|
}
|
|
81
|
-
exports.
|
|
82
|
+
exports.generatePackageAliasEntry = generatePackageAliasEntry;
|
|
82
83
|
async function createPackage(connection, project, options) {
|
|
83
84
|
// strip trailing slash from path param
|
|
84
85
|
options.path = options.path.replace(/\/$/, '');
|
|
85
|
-
const request =
|
|
86
|
+
const request = createPackageRequestFromContext(project, options);
|
|
86
87
|
let packageId = null;
|
|
87
88
|
const createResult = await connection.tooling
|
|
88
89
|
.sobject('Package2')
|
|
@@ -101,8 +102,8 @@ async function createPackage(connection, project, options) {
|
|
|
101
102
|
}
|
|
102
103
|
const record = queryResult.records[0];
|
|
103
104
|
if (!process.env.SFDX_PROJECT_AUTOUPDATE_DISABLE_FOR_PACKAGE_CREATE) {
|
|
104
|
-
const packageDirectory =
|
|
105
|
-
const packageAliases =
|
|
105
|
+
const packageDirectory = generatePackageDirEntry(project, options);
|
|
106
|
+
const packageAliases = generatePackageAliasEntry(project, options, record.Id);
|
|
106
107
|
const projectJson = project.getSfProjectJson();
|
|
107
108
|
projectJson.set('packageDirectories', packageDirectory);
|
|
108
109
|
projectJson.set('packageAliases', packageAliases);
|
|
@@ -14,4 +14,6 @@ export declare function installPackage(connection: Connection, pkgInstallCreateR
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function getExternalSites(connection: Connection, subscriberPackageVersionId: string, installationKey?: string): Promise<Optional<string[]>>;
|
|
16
16
|
export declare function getStatus(connection: Connection, installRequestId: string): Promise<PackageInstallRequest>;
|
|
17
|
+
export declare function isErrorFromSPVQueryRestriction(err: Error): boolean;
|
|
18
|
+
export declare function isErrorPackageNotAvailable(err: Error): boolean;
|
|
17
19
|
export declare function waitForPublish(connection: Connection, subscriberPackageVersionId: string, timeout: number | Duration, installationKey?: string): Promise<void>;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.waitForPublish = exports.getStatus = exports.getExternalSites = exports.installPackage = void 0;
|
|
9
|
+
exports.waitForPublish = exports.isErrorPackageNotAvailable = exports.isErrorFromSPVQueryRestriction = exports.getStatus = exports.getExternalSites = exports.installPackage = void 0;
|
|
10
10
|
const core_1 = require("@salesforce/core");
|
|
11
11
|
const ts_types_1 = require("@salesforce/ts-types");
|
|
12
12
|
const kit_1 = require("@salesforce/kit");
|
|
@@ -22,6 +22,26 @@ const getLogger = () => {
|
|
|
22
22
|
}
|
|
23
23
|
return logger;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Given 04t the package type type (Managed, Unlocked, Locked(deprecated?))
|
|
27
|
+
*
|
|
28
|
+
* @param packageVersionId the 04t
|
|
29
|
+
* @param connection For tooling query
|
|
30
|
+
* @param installKey For tooling query, if an installation key is applicable to the package version it must be passed in the queries
|
|
31
|
+
* @throws Error with message when package2 cannot be found
|
|
32
|
+
*/
|
|
33
|
+
async function getPackageTypeBy04t(packageVersionId, connection, installKey) {
|
|
34
|
+
let query = `SELECT Package2ContainerOptions FROM SubscriberPackageVersion WHERE id ='${packageVersionId}'`;
|
|
35
|
+
if (installKey) {
|
|
36
|
+
const escapedInstallationKey = installKey.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
37
|
+
query += ` AND InstallationKey ='${escapedInstallationKey}'`;
|
|
38
|
+
}
|
|
39
|
+
const queryResult = await connection.tooling.query(query);
|
|
40
|
+
if (!queryResult || queryResult.records === null || queryResult.records.length === 0) {
|
|
41
|
+
throw installMsgs.createError('errorInvalidPackageId', [packageVersionId]);
|
|
42
|
+
}
|
|
43
|
+
return queryResult.records[0].Package2ContainerOptions;
|
|
44
|
+
}
|
|
25
45
|
async function installPackage(connection, pkgInstallCreateRequest, options) {
|
|
26
46
|
const defaults = {
|
|
27
47
|
ApexCompileType: 'all',
|
|
@@ -35,7 +55,7 @@ async function installPackage(connection, pkgInstallCreateRequest, options) {
|
|
|
35
55
|
if (request.Password) {
|
|
36
56
|
request.Password = (0, utils_1.escapeInstallationKey)(request.Password);
|
|
37
57
|
}
|
|
38
|
-
const pkgType = await
|
|
58
|
+
const pkgType = await getPackageTypeBy04t(request.SubscriberPackageVersionKey, connection, request.Password);
|
|
39
59
|
// Only unlocked packages can change the UpgradeType and ApexCompile options from the defaults.
|
|
40
60
|
if (pkgType !== 'Unlocked') {
|
|
41
61
|
if (request.UpgradeType !== defaults.UpgradeType) {
|
|
@@ -87,7 +107,7 @@ async function getExternalSites(connection, subscriberPackageVersionId, installa
|
|
|
87
107
|
catch (e) {
|
|
88
108
|
// First check for Implementation Restriction error that is enforced in 214, before it was possible to query
|
|
89
109
|
// against InstallationKey, otherwise surface the error.
|
|
90
|
-
if (e instanceof Error &&
|
|
110
|
+
if (e instanceof Error && isErrorFromSPVQueryRestriction(e)) {
|
|
91
111
|
queryResult = await connection.tooling.query(queryNoKey);
|
|
92
112
|
}
|
|
93
113
|
else {
|
|
@@ -159,6 +179,18 @@ async function pollStatus(connection, installRequestId, options) {
|
|
|
159
179
|
throw error;
|
|
160
180
|
}
|
|
161
181
|
}
|
|
182
|
+
// determines if error is from malformed SubscriberPackageVersion query
|
|
183
|
+
// this is in place to allow cli to run against app version 214, where SPV queries
|
|
184
|
+
// do not require installation key
|
|
185
|
+
function isErrorFromSPVQueryRestriction(err) {
|
|
186
|
+
return (err.name === 'MALFORMED_QUERY' &&
|
|
187
|
+
err.message.includes('Implementation restriction: You can only perform queries of the form Id'));
|
|
188
|
+
}
|
|
189
|
+
exports.isErrorFromSPVQueryRestriction = isErrorFromSPVQueryRestriction;
|
|
190
|
+
function isErrorPackageNotAvailable(err) {
|
|
191
|
+
return err.name === 'UNKNOWN_EXCEPTION' || err.name === 'PACKAGE_UNAVAILABLE';
|
|
192
|
+
}
|
|
193
|
+
exports.isErrorPackageNotAvailable = isErrorPackageNotAvailable;
|
|
162
194
|
async function waitForPublish(connection, subscriberPackageVersionId, timeout, installationKey) {
|
|
163
195
|
let queryResult;
|
|
164
196
|
const pollingOptions = {
|
|
@@ -174,11 +206,11 @@ async function waitForPublish(connection, subscriberPackageVersionId, timeout, i
|
|
|
174
206
|
catch (e) {
|
|
175
207
|
// Check first for Implementation Restriction error that is enforced in 214, before it was possible to query
|
|
176
208
|
// against InstallationKey, otherwise surface the error.
|
|
177
|
-
if (e instanceof Error &&
|
|
209
|
+
if (e instanceof Error && isErrorFromSPVQueryRestriction(e)) {
|
|
178
210
|
queryResult = await connection.tooling.query(QUERY_NO_KEY);
|
|
179
211
|
}
|
|
180
212
|
else {
|
|
181
|
-
if (e instanceof Error && !
|
|
213
|
+
if (e instanceof Error && !isErrorPackageNotAvailable(e)) {
|
|
182
214
|
throw e;
|
|
183
215
|
}
|
|
184
216
|
}
|
|
@@ -63,4 +63,11 @@ export declare class PackageVersion {
|
|
|
63
63
|
update(id: string, options: PackageVersionUpdateOptions): Promise<PackageSaveResult>;
|
|
64
64
|
private updateDeprecation;
|
|
65
65
|
private updateProjectWithPackageVersion;
|
|
66
|
+
/**
|
|
67
|
+
* Given a package version ID (05i) or subscriber package version ID (04t), return the subscriber package version ID (04t)
|
|
68
|
+
*
|
|
69
|
+
* @param versionId The suscriber package version ID
|
|
70
|
+
* @param connection For tooling query
|
|
71
|
+
*/
|
|
72
|
+
private getSubscriberPackageVersionId;
|
|
66
73
|
}
|
|
@@ -17,6 +17,7 @@ const packageVersionCreateRequestReport_1 = require("./packageVersionCreateReque
|
|
|
17
17
|
const packageVersionList_1 = require("./packageVersionList");
|
|
18
18
|
const packageVersionCreateRequest_1 = require("./packageVersionCreateRequest");
|
|
19
19
|
core_1.Messages.importMessagesDirectory(__dirname);
|
|
20
|
+
const messages = core_1.Messages.loadMessages('@salesforce/packaging', 'package_version');
|
|
20
21
|
class PackageVersion {
|
|
21
22
|
constructor(options) {
|
|
22
23
|
this.options = options;
|
|
@@ -195,7 +196,7 @@ class PackageVersion {
|
|
|
195
196
|
throw new Error(result.errors.join(', '));
|
|
196
197
|
}
|
|
197
198
|
// Use the 04t ID for the success message
|
|
198
|
-
result.id = await
|
|
199
|
+
result.id = await this.getSubscriberPackageVersionId(id);
|
|
199
200
|
return result;
|
|
200
201
|
}
|
|
201
202
|
async updateDeprecation(idOrAlias, IsDeprecated) {
|
|
@@ -213,7 +214,7 @@ class PackageVersion {
|
|
|
213
214
|
if (!updateResult.success) {
|
|
214
215
|
throw (0, utils_1.combineSaveErrors)('Package2', 'update', updateResult.errors);
|
|
215
216
|
}
|
|
216
|
-
updateResult.id = await
|
|
217
|
+
updateResult.id = await this.getSubscriberPackageVersionId(packageVersionId);
|
|
217
218
|
return updateResult;
|
|
218
219
|
}
|
|
219
220
|
async updateProjectWithPackageVersion(withProject, results) {
|
|
@@ -229,6 +230,28 @@ class PackageVersion {
|
|
|
229
230
|
await this.project.getSfProjectJson().write();
|
|
230
231
|
}
|
|
231
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Given a package version ID (05i) or subscriber package version ID (04t), return the subscriber package version ID (04t)
|
|
235
|
+
*
|
|
236
|
+
* @param versionId The suscriber package version ID
|
|
237
|
+
* @param connection For tooling query
|
|
238
|
+
*/
|
|
239
|
+
async getSubscriberPackageVersionId(versionId) {
|
|
240
|
+
// if it's already a 04t return it, otherwise query for it
|
|
241
|
+
if (!versionId || versionId.startsWith(utils_1.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID.prefix)) {
|
|
242
|
+
return versionId;
|
|
243
|
+
}
|
|
244
|
+
const query = `SELECT SubscriberPackageVersionId FROM Package2Version WHERE Id = '${versionId}'`;
|
|
245
|
+
const queryResult = await this.connection.tooling.query(query);
|
|
246
|
+
if (!queryResult || !queryResult.totalSize) {
|
|
247
|
+
throw messages.createError('errorInvalidIdNoMatchingVersionId', [
|
|
248
|
+
utils_1.BY_LABEL.PACKAGE_VERSION_ID.label,
|
|
249
|
+
versionId,
|
|
250
|
+
utils_1.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID.label,
|
|
251
|
+
]);
|
|
252
|
+
}
|
|
253
|
+
return queryResult.records[0].SubscriberPackageVersionId;
|
|
254
|
+
}
|
|
232
255
|
}
|
|
233
256
|
exports.PackageVersion = PackageVersion;
|
|
234
257
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -44,4 +44,10 @@ export declare class PackageVersionCreate {
|
|
|
44
44
|
* Sets default or override values for packageDescriptorJSON attribs
|
|
45
45
|
*/
|
|
46
46
|
private setPackageDescriptorJsonValues;
|
|
47
|
+
private validateVersionNumber;
|
|
48
|
+
private validatePatchVersion;
|
|
49
|
+
private massageErrorMessage;
|
|
50
|
+
private getAncestorId;
|
|
51
|
+
private validateAncestorId;
|
|
52
|
+
private getAncestorIdHighestRelease;
|
|
47
53
|
}
|
|
@@ -36,7 +36,7 @@ class PackageVersionCreate {
|
|
|
36
36
|
return this.packageVersionCreate();
|
|
37
37
|
}
|
|
38
38
|
catch (err) {
|
|
39
|
-
throw pkgUtils.applyErrorAction(
|
|
39
|
+
throw pkgUtils.applyErrorAction(this.massageErrorMessage(err));
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
// convert source to mdapi format and copy to tmp dir packaging up
|
|
@@ -92,7 +92,8 @@ class PackageVersionCreate {
|
|
|
92
92
|
// Just override dependency.packageId value to the resolved alias.
|
|
93
93
|
dependency.packageId = packageIdFromAlias;
|
|
94
94
|
pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, dependency.packageId);
|
|
95
|
-
|
|
95
|
+
this.validateVersionNumber(dependency.versionNumber, utils_1.BuildNumberToken.LATEST_BUILD_NUMBER_TOKEN, utils_1.BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN);
|
|
96
|
+
await this.validatePatchVersion(dependency.versionNumber, dependency.packageId);
|
|
96
97
|
// Validate that the Package2 id exists on the server
|
|
97
98
|
const query = `SELECT Id FROM Package2 WHERE Id = '${dependency.packageId}'`;
|
|
98
99
|
const result = await this.connection.tooling.query(query);
|
|
@@ -286,7 +287,7 @@ class PackageVersionCreate {
|
|
|
286
287
|
// branch can be set via options or descriptor; option takes precedence
|
|
287
288
|
this.options.branch = this.options.branch ?? packageDescriptorJson.branch;
|
|
288
289
|
const resultValues = await Promise.all(!dependencies ? [] : dependencies.map((dependency) => this.retrieveSubscriberPackageVersionId(dependency)));
|
|
289
|
-
const ancestorId = await
|
|
290
|
+
const ancestorId = await this.getAncestorId(packageDescriptorJson, this.options.project, this.options.versionnumber ?? packageDescriptorJson.versionNumber, this.options.skipancestorcheck);
|
|
290
291
|
// If dependencies exist, the resultValues array will contain the dependencies populated with a resolved
|
|
291
292
|
// subscriber pkg version id.
|
|
292
293
|
if (resultValues.length > 0) {
|
|
@@ -516,6 +517,210 @@ class PackageVersionCreate {
|
|
|
516
517
|
packageDescriptorJson.uninstallScript = options.uninstallscript;
|
|
517
518
|
}
|
|
518
519
|
}
|
|
520
|
+
validateVersionNumber(versionNumberString, supportedBuildNumberToken, supportedBuildNumberToken2) {
|
|
521
|
+
const versionNumber = utils_1.VersionNumber.from(versionNumberString);
|
|
522
|
+
// build number can be a number or valid token
|
|
523
|
+
if (Number.isNaN(parseInt(`${versionNumber.build}`, 10)) &&
|
|
524
|
+
versionNumber.build !== supportedBuildNumberToken &&
|
|
525
|
+
versionNumber.build !== supportedBuildNumberToken2) {
|
|
526
|
+
if (supportedBuildNumberToken2) {
|
|
527
|
+
throw messages.createError('errorInvalidBuildNumberForKeywords', [
|
|
528
|
+
versionNumberString,
|
|
529
|
+
supportedBuildNumberToken,
|
|
530
|
+
supportedBuildNumberToken2,
|
|
531
|
+
]);
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
throw messages.createError('errorInvalidBuildNumber', [versionNumberString, supportedBuildNumberToken]);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return versionNumberString;
|
|
538
|
+
}
|
|
539
|
+
async validatePatchVersion(versionNumberString, packageId) {
|
|
540
|
+
const query = `SELECT ContainerOptions FROM Package2 WHERE id ='${packageId}'`;
|
|
541
|
+
const queryResult = await this.connection.tooling.query(query);
|
|
542
|
+
if (queryResult.records === null || queryResult.records.length === 0) {
|
|
543
|
+
throw messages.createError('errorInvalidPackageId', [packageId]);
|
|
544
|
+
}
|
|
545
|
+
// Enforce a patch version of zero (0) for Locked packages only
|
|
546
|
+
if (queryResult.records[0].ContainerOptions === 'Locked') {
|
|
547
|
+
const versionNumber = utils_1.VersionNumber.from(versionNumberString);
|
|
548
|
+
if (versionNumber.patch !== '0') {
|
|
549
|
+
throw messages.createError('errorInvalidPatchNumber', [versionNumberString]);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
massageErrorMessage(err) {
|
|
554
|
+
if (err.name === 'INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST') {
|
|
555
|
+
err['message'] = messages.getMessage('invalidPackageTypeMessage');
|
|
556
|
+
}
|
|
557
|
+
if (err.name === 'MALFORMED_ID' &&
|
|
558
|
+
(err.message.includes('Version ID') || err.message.includes('Version Definition ID'))) {
|
|
559
|
+
err['message'] = messages.getMessage('malformedPackageVersionIdMessage');
|
|
560
|
+
}
|
|
561
|
+
if (err.name === 'MALFORMED_ID' && err.message.includes('Package2 ID')) {
|
|
562
|
+
err['message'] = messages.getMessage('malformedPackageIdMessage');
|
|
563
|
+
}
|
|
564
|
+
// remove references to Second Generation
|
|
565
|
+
if (err.message.includes('Second Generation ')) {
|
|
566
|
+
err['message'] = err.message.replace('Second Generation ', '');
|
|
567
|
+
}
|
|
568
|
+
return err;
|
|
569
|
+
}
|
|
570
|
+
// eslint-disable-next-line complexity
|
|
571
|
+
async getAncestorId(packageDescriptorJson, project, versionNumberString, skipAncestorCheck) {
|
|
572
|
+
// If an id property is present, use it. Otherwise, look up the package id from the package property.
|
|
573
|
+
const packageId = packageDescriptorJson.id ?? (0, utils_2.getPackageIdFromAlias)(packageDescriptorJson.package, project);
|
|
574
|
+
// No need to proceed if Unlocked
|
|
575
|
+
const packageType = await (0, utils_2.getPackageType)(packageId, this.connection);
|
|
576
|
+
if (packageType === 'Unlocked') {
|
|
577
|
+
return '';
|
|
578
|
+
}
|
|
579
|
+
let ancestorId = '';
|
|
580
|
+
// ancestorID can be alias, 05i, or 04t;
|
|
581
|
+
// validate and convert to 05i, as needed
|
|
582
|
+
const versionNumber = utils_1.VersionNumber.from(versionNumberString);
|
|
583
|
+
let origSpecifiedAncestor = packageDescriptorJson.ancestorId;
|
|
584
|
+
let highestReleasedVersion = null;
|
|
585
|
+
const explicitUseHighestRelease = packageDescriptorJson.ancestorId === utils_1.BuildNumberToken.HIGHEST_VERSION_NUMBER_TOKEN ||
|
|
586
|
+
packageDescriptorJson.ancestorVersion === utils_1.BuildNumberToken.HIGHEST_VERSION_NUMBER_TOKEN;
|
|
587
|
+
const explicitUseNoAncestor = packageDescriptorJson.ancestorId === utils_1.BuildNumberToken.NONE_VERSION_NUMBER_TOKEN ||
|
|
588
|
+
packageDescriptorJson.ancestorVersion === utils_1.BuildNumberToken.NONE_VERSION_NUMBER_TOKEN;
|
|
589
|
+
if ((explicitUseHighestRelease || explicitUseNoAncestor) &&
|
|
590
|
+
packageDescriptorJson.ancestorId &&
|
|
591
|
+
packageDescriptorJson.ancestorVersion) {
|
|
592
|
+
if (packageDescriptorJson.ancestorId !== packageDescriptorJson.ancestorVersion) {
|
|
593
|
+
// both ancestorId and ancestorVersion specified, HIGHEST and/or NONE are used, the values disagree
|
|
594
|
+
throw messages.createError('errorAncestorIdVersionHighestOrNoneMismatch', [
|
|
595
|
+
packageDescriptorJson.ancestorId,
|
|
596
|
+
packageDescriptorJson.ancestorVersion,
|
|
597
|
+
]);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (explicitUseNoAncestor && skipAncestorCheck) {
|
|
601
|
+
return '';
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
const result = await this.getAncestorIdHighestRelease(packageId, versionNumberString, explicitUseHighestRelease, skipAncestorCheck);
|
|
605
|
+
if (result.finalAncestorId) {
|
|
606
|
+
return result.finalAncestorId;
|
|
607
|
+
}
|
|
608
|
+
highestReleasedVersion = result.highestReleasedVersion;
|
|
609
|
+
}
|
|
610
|
+
// at this point if explicitUseHighestRelease=true, we have returned the ancestorId or thrown an error
|
|
611
|
+
// highestReleasedVersion should be null only if skipAncestorCheck or if there is no existing released package version
|
|
612
|
+
if (!explicitUseNoAncestor && packageDescriptorJson.ancestorId) {
|
|
613
|
+
ancestorId = (0, utils_2.getPackageIdFromAlias)(packageDescriptorJson.ancestorId, project);
|
|
614
|
+
(0, utils_2.validateId)([utils_2.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, utils_2.BY_LABEL.PACKAGE_VERSION_ID], ancestorId);
|
|
615
|
+
ancestorId = await (0, utils_2.getPackageVersionId)(ancestorId, this.connection);
|
|
616
|
+
}
|
|
617
|
+
if (!explicitUseNoAncestor && packageDescriptorJson.ancestorVersion) {
|
|
618
|
+
const regNumbers = new RegExp('^[0-9]+$');
|
|
619
|
+
const versionNumber = packageDescriptorJson.ancestorVersion.split(utils_2.VERSION_NUMBER_SEP);
|
|
620
|
+
if (versionNumber.length < 3 ||
|
|
621
|
+
versionNumber.length > 4 ||
|
|
622
|
+
!versionNumber[0].match(regNumbers) ||
|
|
623
|
+
!versionNumber[1].match(regNumbers) ||
|
|
624
|
+
!versionNumber[2].match(regNumbers)) {
|
|
625
|
+
throw new Error(messages.getMessage('errorInvalidAncestorVersionFormat', [packageDescriptorJson.ancestorVersion]));
|
|
626
|
+
}
|
|
627
|
+
const query = 'SELECT Id, IsReleased FROM Package2Version ' +
|
|
628
|
+
`WHERE Package2Id = '${packageId}' AND MajorVersion = ${versionNumber[0]} AND MinorVersion = ${versionNumber[1]} AND PatchVersion = ${versionNumber[2]}`;
|
|
629
|
+
let queriedAncestorId;
|
|
630
|
+
const ancestorVersionResult = await this.connection.tooling.query(query);
|
|
631
|
+
if (!ancestorVersionResult || !ancestorVersionResult.totalSize) {
|
|
632
|
+
throw messages.createError('errorNoMatchingAncestor', [packageDescriptorJson.ancestorVersion, packageId]);
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
const releasedAncestor = ancestorVersionResult.records.find((rec) => rec.IsReleased === true);
|
|
636
|
+
if (!releasedAncestor) {
|
|
637
|
+
throw messages.createError('errorAncestorNotReleased', [packageDescriptorJson.ancestorVersion]);
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
queriedAncestorId = releasedAncestor.Id;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
// check for discrepancy between queried ancestorId and descriptor's ancestorId
|
|
644
|
+
if (packageDescriptorJson?.ancestorId && ancestorId !== queriedAncestorId) {
|
|
645
|
+
throw messages.createError('errorAncestorIdVersionMismatch', [
|
|
646
|
+
packageDescriptorJson.ancestorVersion,
|
|
647
|
+
packageDescriptorJson.ancestorId,
|
|
648
|
+
]);
|
|
649
|
+
}
|
|
650
|
+
ancestorId = queriedAncestorId;
|
|
651
|
+
origSpecifiedAncestor = packageDescriptorJson.ancestorVersion;
|
|
652
|
+
}
|
|
653
|
+
return this.validateAncestorId(ancestorId, highestReleasedVersion, explicitUseNoAncestor, versionNumber.patch !== '0', skipAncestorCheck, origSpecifiedAncestor);
|
|
654
|
+
}
|
|
655
|
+
validateAncestorId(ancestorId, highestReleasedVersion, explicitUseNoAncestor, isPatch, skipAncestorCheck, origSpecifiedAncestor) {
|
|
656
|
+
if (explicitUseNoAncestor) {
|
|
657
|
+
if (!highestReleasedVersion) {
|
|
658
|
+
return '';
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
// the explicitUseNoAncestor && skipAncestorCheck case is handled above
|
|
662
|
+
throw messages.createError('errorAncestorNoneNotAllowed', [(0, utils_2.getPackageVersionNumber)(highestReleasedVersion)]);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
if (!isPatch && !skipAncestorCheck) {
|
|
666
|
+
if (highestReleasedVersion) {
|
|
667
|
+
if (highestReleasedVersion.Id !== ancestorId) {
|
|
668
|
+
throw messages.createError('errorAncestorNotHighest', [
|
|
669
|
+
origSpecifiedAncestor,
|
|
670
|
+
(0, utils_2.getPackageVersionNumber)(highestReleasedVersion),
|
|
671
|
+
]);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
// looks like the initial version:create - allow
|
|
676
|
+
ancestorId = '';
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
return ancestorId;
|
|
680
|
+
}
|
|
681
|
+
async getAncestorIdHighestRelease(packageId, versionNumberString, explicitUseHighestRelease, skipAncestorCheck) {
|
|
682
|
+
const versionNumber = versionNumberString.split(utils_2.VERSION_NUMBER_SEP);
|
|
683
|
+
const isPatch = versionNumber[2] !== '0';
|
|
684
|
+
const result = { finalAncestorId: null, highestReleasedVersion: null };
|
|
685
|
+
if (isPatch && explicitUseHighestRelease) {
|
|
686
|
+
// based on server-side validation, whatever ancestor is specified for a patch is
|
|
687
|
+
// tightly controlled; therefore we only need concern ourselves if explicitUseHighestRelease == true;
|
|
688
|
+
// equally applies when skipAncestorCheck == true
|
|
689
|
+
// gather appropriate matching major.minor.0
|
|
690
|
+
const query = `SELECT Id FROM Package2Version WHERE Package2Id = '${packageId}' ` +
|
|
691
|
+
'AND IsReleased = True AND IsDeprecated = False AND PatchVersion = 0 ' +
|
|
692
|
+
`AND MajorVersion = ${versionNumber[0]} AND MinorVersion = ${versionNumber[1]} ` +
|
|
693
|
+
'ORDER BY MajorVersion Desc, MinorVersion Desc, PatchVersion Desc, BuildNumber Desc LIMIT 1';
|
|
694
|
+
const majorMinorVersionResult = await this.connection.tooling.query(query);
|
|
695
|
+
const majorMinorVersionRecords = majorMinorVersionResult.records;
|
|
696
|
+
if (majorMinorVersionRecords && majorMinorVersionRecords?.length === 1 && majorMinorVersionRecords[0]) {
|
|
697
|
+
result.finalAncestorId = majorMinorVersionRecords[0].Id;
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
const majorMinorNotFound = `${versionNumber[0]}.${versionNumber[1]}.0`;
|
|
701
|
+
throw messages.createError('errorNoMatchingMajorMinorForPatch', [majorMinorNotFound]);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
else if (!isPatch && (explicitUseHighestRelease || !skipAncestorCheck)) {
|
|
705
|
+
// ancestor must be set to latest released major.minor version
|
|
706
|
+
const query = 'SELECT Id, SubscriberPackageVersionId, MajorVersion, MinorVersion, PatchVersion FROM Package2Version ' +
|
|
707
|
+
`WHERE Package2Id = '${packageId}' AND IsReleased = True AND IsDeprecated = False AND PatchVersion = 0 ` +
|
|
708
|
+
'ORDER BY MajorVersion Desc, MinorVersion Desc, PatchVersion Desc, BuildNumber Desc LIMIT 1';
|
|
709
|
+
const highestVersionResult = await this.connection.tooling.query(query);
|
|
710
|
+
const highestVersionRecords = highestVersionResult.records;
|
|
711
|
+
if (highestVersionRecords && highestVersionRecords[0]) {
|
|
712
|
+
result.highestReleasedVersion = highestVersionRecords[0];
|
|
713
|
+
if (explicitUseHighestRelease) {
|
|
714
|
+
result.finalAncestorId = result.highestReleasedVersion.Id;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
else if (explicitUseHighestRelease) {
|
|
718
|
+
// there is no eligible ancestor version
|
|
719
|
+
throw messages.createError('errorNoMatchingAncestor', [versionNumberString, packageId]);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return result;
|
|
723
|
+
}
|
|
519
724
|
}
|
|
520
725
|
exports.PackageVersionCreate = PackageVersionCreate;
|
|
521
726
|
//# sourceMappingURL=packageVersionCreate.js.map
|
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.byId = exports.list = void 0;
|
|
10
10
|
const util = require("util");
|
|
11
11
|
const core_1 = require("@salesforce/core");
|
|
12
|
-
const packageUtils = require("../utils/packageUtils");
|
|
13
12
|
core_1.Messages.importMessagesDirectory(__dirname);
|
|
14
13
|
const messages = core_1.Messages.loadMessages('@salesforce/packaging', 'package_version_create');
|
|
15
14
|
const STATUS_ERROR = 'Error';
|
|
@@ -19,6 +18,12 @@ const QUERY = 'SELECT Id, Status, Package2Id, Package2VersionId, Package2Version
|
|
|
19
18
|
'%s' + // WHERE, if applicable
|
|
20
19
|
'ORDER BY CreatedDate';
|
|
21
20
|
const ERROR_QUERY = "SELECT Message FROM Package2VersionCreateRequestError WHERE ParentRequest.Id = '%s'";
|
|
21
|
+
function formatDate(date) {
|
|
22
|
+
const pad = (num) => {
|
|
23
|
+
return num < 10 ? `0${num}` : `${num}`;
|
|
24
|
+
};
|
|
25
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
26
|
+
}
|
|
22
27
|
async function list(options) {
|
|
23
28
|
const whereClause = _constructWhere(options);
|
|
24
29
|
return _query(util.format(QUERY, whereClause), options.connection);
|
|
@@ -43,7 +48,7 @@ async function _query(query, connection) {
|
|
|
43
48
|
Tag: record.Tag,
|
|
44
49
|
Branch: record.Branch,
|
|
45
50
|
Error: [],
|
|
46
|
-
CreatedDate:
|
|
51
|
+
CreatedDate: formatDate(new Date(record.CreatedDate)),
|
|
47
52
|
HasMetadataRemoved: record.Package2Version != null ? record.Package2Version.HasMetadataRemoved : null,
|
|
48
53
|
CreatedBy: record.CreatedById,
|
|
49
54
|
}));
|