@salesforce/packaging 0.0.36 → 0.0.37

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 CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.0.37](https://github.com/forcedotcom/packaging/compare/v0.0.36...v0.0.37) (2022-09-16)
6
+
7
+ ### Bug Fixes
8
+
9
+ - move util functions with single ref ([e7117d3](https://github.com/forcedotcom/packaging/commit/e7117d3530ac56717796da3535394ca184d53643))
10
+
5
11
  ### [0.0.36](https://github.com/forcedotcom/packaging/compare/v0.0.35...v0.0.36) (2022-09-14)
6
12
 
7
13
  ### Bug Fixes
@@ -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 pkgUtils.findOrCreatePackage2(pkg, connection);
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, utils_1.convertCamelCaseStringToSentence)(results[0]?.Status)}'`);
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 _createPackageRequestFromContext(project: SfProject, options: PackageCreateOptions): Package2Request;
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 _generatePackageDirEntry(project: SfProject, options: PackageCreateOptions): PackageDir[] | NamedPackageDir[];
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 _generatePackageAliasEntry(project: SfProject, options: PackageCreateOptions, packageId: string): {
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._generatePackageAliasEntry = exports._generatePackageDirEntry = exports._createPackageRequestFromContext = void 0;
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 _createPackageRequestFromContext(project, options) {
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._createPackageRequestFromContext = _createPackageRequestFromContext;
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 _generatePackageDirEntry(project, options) {
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._generatePackageDirEntry = _generatePackageDirEntry;
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 _generatePackageAliasEntry(project, options, packageId) {
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._generatePackageAliasEntry = _generatePackageAliasEntry;
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 = _createPackageRequestFromContext(project, options);
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 = _generatePackageDirEntry(project, options);
105
- const packageAliases = _generatePackageAliasEntry(project, options, record.Id);
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 (0, utils_1.getPackageTypeBy04t)(request.SubscriberPackageVersionKey, connection, request.Password);
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 && (0, utils_1.isErrorFromSPVQueryRestriction)(e)) {
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 && (0, utils_1.isErrorFromSPVQueryRestriction)(e)) {
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 && !(0, utils_1.isErrorPackageNotAvailable)(e)) {
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 (0, utils_1.getSubscriberPackageVersionId)(id, this.connection);
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 (0, utils_1.getSubscriberPackageVersionId)(packageVersionId, this.connection);
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(pkgUtils.massageErrorMessage(err));
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
- pkgUtils.validateVersionNumber(dependency.versionNumber, utils_1.BuildNumberToken.LATEST_BUILD_NUMBER_TOKEN, utils_1.BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN);
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 (0, utils_2.getAncestorId)(packageDescriptorJson, this.options.project, this.options.connection, this.options.versionnumber ?? packageDescriptorJson.versionNumber, this.options.skipancestorcheck);
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: packageUtils.formatDate(new Date(record.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
  }));