@salesforce/packaging 0.0.18 → 0.0.21

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.
@@ -15,18 +15,16 @@ const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
15
15
  const testSetup_1 = require("@salesforce/core/lib/testSetup");
16
16
  const scratchOrgSettingsGenerator_1 = require("@salesforce/core/lib/org/scratchOrgSettingsGenerator");
17
17
  const xml2js = require("xml2js");
18
- const kit_1 = require("@salesforce/kit");
18
+ const scratchOrgInfoGenerator_1 = require("@salesforce/core/lib/org/scratchOrgInfoGenerator");
19
19
  const pkgUtils = require("../utils/packageUtils");
20
- const constants_1 = require("../constants");
21
- const utils_1 = require("../utils");
22
20
  const versionNumber_1 = require("../utils/versionNumber");
21
+ const utils_1 = require("../utils");
23
22
  const packageProfileApi_1 = require("./packageProfileApi");
24
23
  const packageVersionCreateRequest_1 = require("./packageVersionCreateRequest");
25
24
  core_1.Messages.importMessagesDirectory(__dirname);
26
- const messages = core_1.Messages.loadMessages('@salesforce/packaging', 'messages');
25
+ const messages = core_1.Messages.loadMessages('@salesforce/packaging', 'packageVersionCreate');
27
26
  const logger = core_1.Logger.childFromRoot('packageVersionCreate');
28
27
  const DESCRIPTOR_FILE = 'package2-descriptor.json';
29
- const POLL_INTERVAL_WITHOUT_VALIDATION_SECONDS = 5;
30
28
  class PackageVersionCreate {
31
29
  constructor(options) {
32
30
  this.options = options;
@@ -34,17 +32,12 @@ class PackageVersionCreate {
34
32
  this.project = this.options.project;
35
33
  }
36
34
  createPackageVersion() {
37
- return this.packageVersionCreate(this.options).catch((err) => {
38
- // TODO: until package2 is GA, wrap perm-based errors w/ 'contact sfdc' action (REMOVE once package2 is GA'd)
39
- err = pkgUtils.massageErrorMessage(err);
40
- throw pkgUtils.applyErrorAction(err);
41
- });
42
- }
43
- async listRequest(createdlastdays, status) {
44
- return (0, packageVersionCreateRequest_1.list)({ createdlastdays, status, connection: this.connection });
45
- }
46
- async listRequestById(id, connection) {
47
- return (0, packageVersionCreateRequest_1.byId)(id, connection);
35
+ try {
36
+ return this.packageVersionCreate();
37
+ }
38
+ catch (err) {
39
+ throw pkgUtils.applyErrorAction(pkgUtils.massageErrorMessage(err));
40
+ }
48
41
  }
49
42
  // convert source to mdapi format and copy to tmp dir packaging up
50
43
  async generateMDFolderForArtifact(options) {
@@ -78,47 +71,42 @@ class PackageVersionCreate {
78
71
  return convertResult;
79
72
  }
80
73
  }
81
- validateDependencyValues(dependency) {
74
+ async validateDependencyValues(dependency) {
82
75
  // If valid 04t package, just return it to be used straight away.
83
76
  if (dependency.subscriberPackageVersionId) {
84
77
  pkgUtils.validateId(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, dependency.subscriberPackageVersionId);
85
- return Promise.resolve();
86
78
  }
87
79
  if (dependency.packageId && dependency.package) {
88
80
  throw messages.createError('errorPackageAndPackageIdCollision', []);
89
81
  }
90
- const packageIdFromAlias = pkgUtils.getPackageIdFromAlias(dependency.packageId || dependency.package, this.project);
91
82
  // If valid 04t package, just return it to be used straight away.
92
- if (pkgUtils.validateIdNoThrow(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, packageIdFromAlias)) {
93
- dependency.subscriberPackageVersionId = packageIdFromAlias;
94
- return Promise.resolve();
83
+ if (pkgUtils.validateIdNoThrow(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, this.packageId)) {
84
+ dependency.subscriberPackageVersionId = this.packageId;
95
85
  }
96
- if (!packageIdFromAlias || !dependency.versionNumber) {
86
+ if (!this.packageId || !dependency.versionNumber) {
97
87
  throw messages.createError('errorDependencyPair', [JSON.stringify(dependency)]);
98
88
  }
99
89
  // Just override dependency.packageId value to the resolved alias.
100
- dependency.packageId = packageIdFromAlias;
90
+ dependency.packageId = this.packageId;
101
91
  pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, dependency.packageId);
102
92
  pkgUtils.validateVersionNumber(dependency.versionNumber, versionNumber_1.BuildNumberToken.LATEST_BUILD_NUMBER_TOKEN, versionNumber_1.BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN);
103
93
  // Validate that the Package2 id exists on the server
104
94
  const query = `SELECT Id FROM Package2 WHERE Id = '${dependency.packageId}'`;
105
- return this.connection.tooling.query(query).then((pkgQueryResult) => {
106
- const subRecords = pkgQueryResult.records;
107
- if (!subRecords || subRecords.length !== 1) {
108
- throw messages.createError('errorNoIdInHub', [dependency.packageId]);
109
- }
110
- });
95
+ const result = await this.connection.tooling.query(query);
96
+ if (!result.records || result.records.length !== 1) {
97
+ throw messages.createError('errorNoIdInHub', [dependency.packageId]);
98
+ }
99
+ return result;
111
100
  }
112
101
  /**
113
- * A dependency in the workspace config file may be specified using either a subscriber package version id (04t)
114
- * or a package Id (0Ho) + a version number. Additionally, a build number may be the actual build number, or a
115
- * keyword: LATEST or RELEASED (meaning the latest or released build number for a given major.minor.patch).
102
+ * A dependency in the workspace config file may be specified using either a subscriber package version id (04t)
103
+ * or a package Id (0Ho) + a version number. Additionally, a build number may be the actual build number, or a
104
+ * keyword: LATEST or RELEASED (meaning the latest or released build number for a given major.minor.patch).
116
105
  *
117
- * This method resolves a package Id + version number to a subscriber package version id (04t)
118
- * and adds it as a SubscriberPackageVersionId parameter in the dependency object.
106
+ * This method resolves a package Id + version number to a subscriber package version id (04t)
107
+ * and adds it as a SubscriberPackageVersionId parameter in the dependency object.
119
108
  */
120
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
- async retrieveSubscriberPackageVersionId(dependency, branchFromFlagOrDef) {
109
+ async retrieveSubscriberPackageVersionId(dependency) {
122
110
  await this.validateDependencyValues(dependency);
123
111
  if (dependency.subscriberPackageVersionId) {
124
112
  delete dependency.package;
@@ -128,7 +116,7 @@ class PackageVersionCreate {
128
116
  const versionNumber = versionNumber_1.VersionNumber.from(dependency.versionNumber);
129
117
  const buildNumber = versionNumber.build;
130
118
  // use the dependency.branch if present otherwise use the branch of the version being created
131
- const branch = dependency.branch || dependency.branch === '' ? dependency.branch : branchFromFlagOrDef;
119
+ const branch = dependency.branch || dependency.branch === '' ? dependency.branch : this.options.branch;
132
120
  const branchString = !branch || branch === '' ? 'null' : `'${branch}'`;
133
121
  // resolve a build number keyword to an actual number, if needed
134
122
  const resolvedBuildNumber = await this.resolveBuildNumber(versionNumber, dependency.packageId, branch);
@@ -138,7 +126,7 @@ class PackageVersionCreate {
138
126
  const branchOrReleasedCondition = buildNumber === versionNumber_1.BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN
139
127
  ? 'AND IsReleased = true'
140
128
  : `AND Branch = ${branchString}`;
141
- const query = `SELECT SubscriberPackageVersionId FROM Package2Version WHERE Package2Id = '${dependency.packageId}' AND MajorVersion = ${versionNumber[0]} AND MinorVersion = ${versionNumber[1]} AND PatchVersion = ${versionNumber[2]} AND BuildNumber = ${resolvedBuildNumber} ${branchOrReleasedCondition}`;
129
+ const query = `SELECT SubscriberPackageVersionId FROM Package2Version WHERE Package2Id = '${dependency.packageId}' AND MajorVersion = ${versionNumber.major} AND MinorVersion = ${versionNumber.minor} AND PatchVersion = ${versionNumber.patch} AND BuildNumber = ${resolvedBuildNumber} ${branchOrReleasedCondition}`;
142
130
  const pkgVerQueryResult = await this.connection.tooling.query(query);
143
131
  const subRecords = pkgVerQueryResult.records;
144
132
  if (!subRecords || subRecords.length !== 1) {
@@ -193,8 +181,7 @@ class PackageVersionCreate {
193
181
  }
194
182
  const query = `SELECT MAX(BuildNumber) FROM Package2Version WHERE Package2Id = '${packageId}' AND IsDeprecated != true AND MajorVersion = ${versionNumber.major} AND MinorVersion = ${versionNumber.minor} AND PatchVersion = ${versionNumber.patch} ${branchCondition} ${releasedCondition}`;
195
183
  const results = await this.connection.tooling.query(query);
196
- const records = results.records;
197
- if (!records || records.length === 0 || records[0].expr0 == null) {
184
+ if (results.records?.length === 0 || results.records[0].expr0 == null) {
198
185
  if (versionNumber.build === versionNumber_1.BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN) {
199
186
  throw messages.createError('noReleaseVersionFound', [packageId, versionNumber.toString()]);
200
187
  }
@@ -202,20 +189,21 @@ class PackageVersionCreate {
202
189
  throw messages.createError('noReleaseVersionFoundForBranch', [packageId, branch, versionNumber.toString()]);
203
190
  }
204
191
  }
192
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
205
193
  return `${results.records[0].expr0}`;
206
194
  }
207
- async createRequestObject(packageId, options, preserveFiles, packageVersTmpRoot, packageVersBlobZipFile) {
195
+ async createRequestObject(preserveFiles, packageVersTmpRoot, packageVersBlobZipFile) {
208
196
  const zipFileBase64 = fs.readFileSync(packageVersBlobZipFile).toString('base64');
209
197
  const requestObject = {
210
- Package2Id: packageId,
198
+ Package2Id: this.packageId,
211
199
  VersionInfo: zipFileBase64,
212
- Tag: options.tag,
213
- Branch: options.branch,
214
- InstallKey: options.installationkey,
215
- Instance: options.buildinstance,
216
- SourceOrg: options.sourceorg,
217
- CalculateCodeCoverage: options.codecoverage || false,
218
- SkipValidation: options.skipvalidation || false,
200
+ Tag: this.options.tag,
201
+ Branch: this.options.branch,
202
+ InstallKey: this.options.installationkey,
203
+ Instance: this.options.buildinstance,
204
+ SourceOrg: this.options.sourceorg,
205
+ CalculateCodeCoverage: this.options.codecoverage || false,
206
+ SkipValidation: this.options.skipvalidation || false,
219
207
  };
220
208
  if (preserveFiles) {
221
209
  logger.info(messages.getMessage('tempFileLocation', [packageVersTmpRoot]));
@@ -225,30 +213,15 @@ class PackageVersionCreate {
225
213
  return fs.promises.rm(packageVersTmpRoot, { recursive: true, force: true }).then(() => requestObject);
226
214
  }
227
215
  }
228
- getPackageDescriptorJsonFromPackageId(packageId, options) {
229
- const artDir = options.path;
230
- const packageDescriptorJson = this.project.getPackageDirectories().find((packageDir) => {
231
- const packageDirPackageId = pkgUtils.getPackageIdFromAlias(packageDir.package, this.project);
232
- return !!packageDirPackageId && packageDirPackageId === packageId ? packageDir : null;
233
- });
234
- if (!packageDescriptorJson) {
235
- throw messages.createError('packagingDirNotFoundInConfigFile', [constants_1.consts.WORKSPACE_CONFIG_FILENAME, artDir]);
236
- }
237
- return packageDescriptorJson;
238
- }
239
216
  /**
240
217
  * Convert the list of command line options to a JSON object that can be used to create an Package2VersionCreateRequest entity.
241
218
  *
242
- * @param options
243
- * @param packageId
244
- * @param versionNumberString
245
219
  * @returns {{Package2Id: (*|p|boolean), Package2VersionMetadata: *, Tag: *, Branch: number}}
246
220
  * @private
247
221
  */
248
- async createPackageVersionCreateRequestFromOptions(options, packageId, versionNumberString) {
249
- const artDir = options.path;
250
- const preserveFiles = !!(options.preserve || process.env.SFDX_PACKAGE2_VERSION_CREATE_PRESERVE);
251
- const uniqueHash = (0, testSetup_1.uniqid)({ template: `${packageId}-%s` });
222
+ async createPackageVersionCreateRequestFromOptions() {
223
+ const preserveFiles = !!(this.options.preserve || process.env.SFDX_PACKAGE2_VERSION_CREATE_PRESERVE);
224
+ const uniqueHash = (0, testSetup_1.uniqid)({ template: `${this.packageId}-%s` });
252
225
  const packageVersTmpRoot = path.join(os.tmpdir(), `${uniqueHash}`);
253
226
  const packageVersMetadataFolder = path.join(packageVersTmpRoot, 'md-files');
254
227
  const unpackagedMetadataFolder = path.join(packageVersTmpRoot, 'unpackaged-md-files');
@@ -258,7 +231,7 @@ class PackageVersionCreate {
258
231
  const unpackagedMetadataZipFile = path.join(packageVersBlobDirectory, 'unpackaged-metadata-package.zip');
259
232
  const settingsZipFile = path.join(packageVersBlobDirectory, 'settings.zip');
260
233
  const packageVersBlobZipFile = path.join(packageVersTmpRoot, 'package-version-info.zip');
261
- const sourceBaseDir = path.join(this.project.getPath(), artDir);
234
+ const sourceBaseDir = path.join(this.project.getPath(), this.packageObject.path ?? '');
262
235
  const mdOptions = {
263
236
  deploydir: packageVersMetadataFolder,
264
237
  sourceDir: sourceBaseDir,
@@ -267,14 +240,16 @@ class PackageVersionCreate {
267
240
  const clientSideInfo = new Map();
268
241
  await fs.promises.mkdir(packageVersBlobDirectory, { recursive: true });
269
242
  const settingsGenerator = new scratchOrgSettingsGenerator_1.default({ asDirectory: true });
270
- // Copy all of the metadata from the workspace to a tmp folder
243
+ // Copy all the metadata from the workspace to a tmp folder
271
244
  await this.generateMDFolderForArtifact(mdOptions);
272
- const packageDescriptorJson = this.getPackageDescriptorJsonFromPackageId(packageId, options);
245
+ const packageDescriptorJson = this.packageObject;
273
246
  if (packageDescriptorJson.package) {
274
247
  delete packageDescriptorJson.package;
275
- packageDescriptorJson.id = packageId;
248
+ packageDescriptorJson.id = this.packageId;
276
249
  }
277
- const definitionFile = options.definitionfile ? options.definitionfile : packageDescriptorJson.definitionFile;
250
+ const definitionFile = this.options.definitionfile
251
+ ? this.options.definitionfile
252
+ : packageDescriptorJson.definitionFile;
278
253
  if (definitionFile) {
279
254
  // package2-descriptor.json sent to the server should contain only the features, snapshot & orgPreferences
280
255
  // defined in the definition file.
@@ -284,56 +259,47 @@ class PackageVersionCreate {
284
259
  delete packageDescriptorJson.snapshot;
285
260
  const definitionFilePayload = await fs.promises.readFile(definitionFile, 'utf8');
286
261
  const definitionFileJson = JSON.parse(definitionFilePayload);
287
- const pkgProperties = [
288
- 'country',
289
- 'edition',
290
- 'language',
291
- 'features',
292
- 'orgPreferences',
293
- 'snapshot',
294
- 'release',
295
- 'sourceOrg',
296
- ];
297
262
  // Load any settings from the definition
298
263
  await settingsGenerator.extract(definitionFileJson);
299
264
  if (settingsGenerator.hasSettings() && definitionFileJson.orgPreferences) {
300
265
  // this is not allowed, exit with an error
301
- return Promise.reject(messages.createError('signupDuplicateSettingsSpecified'));
266
+ throw messages.createError('signupDuplicateSettingsSpecified');
302
267
  }
303
- pkgProperties.forEach((prop) => {
268
+ ['country', 'edition', 'language', 'features', 'orgPreferences', 'snapshot', 'release', 'sourceOrg'].forEach((prop) => {
304
269
  const propValue = definitionFileJson[prop];
305
270
  if (propValue) {
306
271
  packageDescriptorJson[prop] = propValue;
307
272
  }
308
273
  });
309
274
  }
310
- const hasUnpackagedMetadata = await this.resolveUnpackagedMetadata(packageDescriptorJson, unpackagedMetadataFolder, clientSideInfo, options.codecoverage);
311
- this.resolveApexTestPermissions(packageDescriptorJson, options);
275
+ this.resolveApexTestPermissions(packageDescriptorJson);
312
276
  // All dependencies for the packaging dir should be resolved to an 04t id to be passed to the server.
313
277
  // (see _retrieveSubscriberPackageVersionId for details)
314
278
  const dependencies = packageDescriptorJson.dependencies;
315
- // branch can be set via flag or descriptor; flag takes precedence
316
- options.branch = options.branch ? options.branch : packageDescriptorJson.branch;
317
- const resultValues = await Promise.all(!dependencies
318
- ? []
319
- : dependencies.map((dependency) => this.retrieveSubscriberPackageVersionId(dependency, options.branch)));
320
- const ancestorId = await pkgUtils.getAncestorId(packageDescriptorJson, this.connection, this.project, versionNumberString, options.skipancestorcheck);
279
+ // branch can be set via options or descriptor; option takes precedence
280
+ this.options.branch = this.options.branch ?? packageDescriptorJson.branch;
281
+ const resultValues = await Promise.all(!dependencies ? [] : dependencies.map((dependency) => this.retrieveSubscriberPackageVersionId(dependency)));
282
+ const ancestorId = await (0, scratchOrgInfoGenerator_1.getAncestorIds)(
283
+ // TODO: investigate if it's ok to convert to ScratchOggInfoPayload
284
+ this.packageObject, this.options.project.getSfProjectJson(), await core_1.Org.create({ aliasOrUsername: this.options.connection.getUsername() }));
321
285
  // If dependencies exist, the resultValues array will contain the dependencies populated with a resolved
322
286
  // subscriber pkg version id.
323
287
  if (resultValues.length > 0) {
324
288
  packageDescriptorJson.dependencies = resultValues;
325
289
  }
326
290
  this.cleanPackageDescriptorJson(packageDescriptorJson);
327
- this.setPackageDescriptorJsonValues(packageDescriptorJson, options);
291
+ this.setPackageDescriptorJsonValues(packageDescriptorJson);
328
292
  await fs.promises.mkdir(packageVersTmpRoot, { recursive: true });
329
293
  await fs.promises.mkdir(packageVersBlobDirectory, { recursive: true });
330
294
  if (Reflect.has(packageDescriptorJson, 'ancestorVersion')) {
331
295
  delete packageDescriptorJson.ancestorVersion;
332
296
  }
333
297
  packageDescriptorJson.ancestorId = ancestorId;
334
- await fs.promises.writeFile(path.join(packageVersBlobDirectory, DESCRIPTOR_FILE),
335
- // TODO: need to make sure packageDescriptorJson contains the right values for the descriptor
336
- JSON.stringify(packageDescriptorJson), 'utf-8');
298
+ await fs.promises.writeFile(path.join(packageVersBlobDirectory, DESCRIPTOR_FILE), JSON.stringify(packageDescriptorJson), 'utf-8');
299
+ await this.cleanGeneratedPackage(packageVersMetadataFolder, packageVersProfileFolder, unpackagedMetadataFolder, metadataZipFile, settingsZipFile, packageVersBlobDirectory, packageVersBlobZipFile, unpackagedMetadataZipFile, clientSideInfo, settingsGenerator);
300
+ return this.createRequestObject(preserveFiles, packageVersTmpRoot, packageVersBlobZipFile);
301
+ }
302
+ async cleanGeneratedPackage(packageVersMetadataFolder, packageVersProfileFolder, unpackagedMetadataFolder, metadataZipFile, settingsZipFile, packageVersBlobDirectory, packageVersBlobZipFile, unpackagedMetadataZipFile, clientSideInfo, settingsGenerator) {
337
303
  // As part of the source convert process, the package.xml has been written into the tmp metadata directory.
338
304
  // The package.xml may need to be manipulated due to processing profiles in the workspace or additional
339
305
  // metadata exclusions. If necessary, read the existing package.xml and then re-write it.
@@ -345,18 +311,19 @@ class PackageVersionCreate {
345
311
  // Apply any necessary exclusions to typesArr.
346
312
  let typesArr = packageJson.Package.types;
347
313
  this.apiVersionFromPackageXml = packageJson.Package.version;
314
+ const hasUnpackagedMetadata = await this.resolveUnpackagedMetadata(this.packageObject, unpackagedMetadataFolder, clientSideInfo, this.options.codecoverage);
348
315
  // if we're using unpackaged metadata, don't package the profiles located there
349
316
  if (hasUnpackagedMetadata) {
350
- typesArr = options.profileApi.filterAndGenerateProfilesForManifest(typesArr, [
317
+ typesArr = this.options.profileApi.filterAndGenerateProfilesForManifest(typesArr, [
351
318
  clientSideInfo.get('UnpackagedMetadataPath'),
352
319
  ]);
353
320
  }
354
321
  else {
355
- typesArr = options.profileApi.filterAndGenerateProfilesForManifest(typesArr);
322
+ typesArr = this.options.profileApi.filterAndGenerateProfilesForManifest(typesArr);
356
323
  }
357
324
  // Next generate profiles and retrieve any profiles that were excluded because they had no matching nodes.
358
- const excludedProfiles = options.profileApi.generateProfiles(packageVersProfileFolder, {
359
- Package: { types: typesArr },
325
+ const excludedProfiles = this.options.profileApi.generateProfiles(packageVersProfileFolder, {
326
+ Package: typesArr,
360
327
  }, [clientSideInfo.get('UnpackagedMetadataPath')]);
361
328
  if (excludedProfiles.length > 0) {
362
329
  const profileIdx = typesArr.findIndex((e) => e.name[0] === 'Profile');
@@ -369,7 +336,7 @@ class PackageVersionCreate {
369
336
  });
370
337
  const xml = xmlBuilder.buildObject(packageJson);
371
338
  // Log information about the profiles being packaged up
372
- const profiles = options.profileApi.getProfileInformation();
339
+ const profiles = this.options.profileApi.getProfileInformation();
373
340
  profiles.forEach((profile) => {
374
341
  if (logger.shouldLog(core_1.LoggerLevel.DEBUG)) {
375
342
  logger.debug(profile.logDebug());
@@ -378,8 +345,6 @@ class PackageVersionCreate {
378
345
  logger.info(profile.logInfo());
379
346
  }
380
347
  });
381
- // TODO: confirm that param xml is writeable
382
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
383
348
  await fs.promises.writeFile(path.join(packageVersMetadataFolder, 'package.xml'), xml, 'utf-8');
384
349
  // Zip the packageVersMetadataFolder folder and put the zip in {packageVersBlobDirectory}/package.zip
385
350
  await (0, utils_1.zipDir)(packageVersMetadataFolder, metadataZipFile);
@@ -395,21 +360,20 @@ class PackageVersionCreate {
395
360
  }
396
361
  // Zip the Version Info and package.zip files into another zip
397
362
  await (0, utils_1.zipDir)(packageVersBlobDirectory, packageVersBlobZipFile);
398
- return this.createRequestObject(packageId, options, preserveFiles, packageVersTmpRoot, packageVersBlobZipFile);
399
363
  }
400
- resolveApexTestPermissions(packageDescriptorJson, options) {
364
+ resolveApexTestPermissions(packageDescriptorJson) {
401
365
  // Process permissionSet and permissionSetLicenses that should be enabled when running Apex tests
402
366
  // This only applies if code coverage is enabled
403
- if (options.codecoverage) {
367
+ if (this.options.codecoverage) {
404
368
  // Assuming no permission sets are named 0, 0n, null, undefined, false, NaN, and the empty string
405
- if (packageDescriptorJson.apexTestAccess && packageDescriptorJson.apexTestAccess.permissionSets) {
369
+ if (packageDescriptorJson.apexTestAccess?.permissionSets) {
406
370
  let permSets = packageDescriptorJson.apexTestAccess.permissionSets;
407
371
  if (!Array.isArray(permSets)) {
408
372
  permSets = permSets.split(',');
409
373
  }
410
374
  packageDescriptorJson.permissionSetNames = permSets.map((s) => s.trim());
411
375
  }
412
- if (packageDescriptorJson.apexTestAccess && packageDescriptorJson.apexTestAccess.permissionSetLicenses) {
376
+ if (packageDescriptorJson.apexTestAccess?.permissionSetLicenses) {
413
377
  let permissionSetLicenses = packageDescriptorJson.apexTestAccess.permissionSetLicenses;
414
378
  if (!Array.isArray(permissionSetLicenses)) {
415
379
  permissionSetLicenses = permissionSetLicenses.split(',');
@@ -420,15 +384,10 @@ class PackageVersionCreate {
420
384
  delete packageDescriptorJson.apexTestAccess;
421
385
  }
422
386
  async resolveUnpackagedMetadata(packageDescriptorJson, unpackagedMetadataFolder, clientSideInfo, codeCoverage) {
423
- let hasUnpackagedMetadata = false;
424
387
  // Add the Unpackaged Metadata, if any, to the output directory, only when code coverage is specified
425
388
  if (codeCoverage && packageDescriptorJson.unpackagedMetadata && packageDescriptorJson.unpackagedMetadata.path) {
426
- hasUnpackagedMetadata = true;
427
389
  const unpackagedPath = path.join(process.cwd(), packageDescriptorJson.unpackagedMetadata.path);
428
- try {
429
- fs.statSync(unpackagedPath);
430
- }
431
- catch (err) {
390
+ if (!fs.existsSync(unpackagedPath)) {
432
391
  throw messages.createError('unpackagedMDDirectoryDoesNotExist', [
433
392
  packageDescriptorJson.unpackagedMetadata.path,
434
393
  ]);
@@ -440,251 +399,59 @@ class PackageVersionCreate {
440
399
  });
441
400
  // Set which package is the "unpackaged" package
442
401
  clientSideInfo.set('UnpackagedMetadataPath', packageDescriptorJson.unpackagedMetadata.path);
402
+ return true;
443
403
  }
444
- return hasUnpackagedMetadata;
445
- }
446
- getPackagePropertyFromPackage(packageDirs, options) {
447
- let foundByPackage = packageDirs.some((x) => x['package'] === options.package);
448
- let foundById = packageDirs.some((x) => x['id'] === options.package);
449
- if (foundByPackage && foundById) {
450
- throw messages.createError('errorPackageAndIdCollision', []);
451
- }
452
- // didn't find anything? let's see if we can reverse look up
453
- if (!foundByPackage && !foundById) {
454
- // is it an alias?
455
- const pkgId = pkgUtils.getPackageIdFromAlias(options.package, this.project);
456
- if (pkgId === options.package) {
457
- // not an alias, or not a valid one, try to reverse lookup an alias in case this is an id
458
- const aliases = pkgUtils.getPackageAliasesFromId(options.package, this.project);
459
- // if we found an alias, try to look that up in the config.
460
- foundByPackage = aliases.some((alias) => packageDirs.find((x) => x['package'] === alias));
461
- }
462
- else {
463
- // it is an alias; try to lookup it's id in the config
464
- foundByPackage = packageDirs.some((x) => x['package'] === pkgId);
465
- foundById = packageDirs.some((x) => x['id'] === pkgId);
466
- if (!foundByPackage && !foundById) {
467
- // check if any configs use a different alias to that same id
468
- const aliases = pkgUtils.getPackageAliasesFromId(pkgId, this.project);
469
- foundByPackage = aliases.some((alias) => {
470
- const pd = packageDirs.find((x) => x['package'] === alias);
471
- if (pd) {
472
- // if so, set this.options.package.flags.package to be this alias instead of the alternate
473
- options.package = alias;
474
- }
475
- return pd;
476
- });
477
- }
478
- }
479
- // if we still didn't find anything, throw the error
480
- if (!foundByPackage && !foundById) {
481
- throw messages.createError('errorMissingPackage', [pkgId]);
482
- }
483
- }
484
- return foundByPackage ? 'package' : 'id';
485
- }
486
- getPackageValuePropertyFromDirectory(directoryFlag, options) {
487
- const packageValue = this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), 'package', 'path', options.path, directoryFlag, options);
488
- const packageIdValue = this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), 'id', 'path', options.path, directoryFlag, options);
489
- let packagePropVal;
490
- if (!packageValue && !packageIdValue) {
491
- throw messages.createError('errorMissingPackage', []);
492
- }
493
- else if (packageValue && packageIdValue) {
494
- throw messages.createError('errorPackageAndIdCollision', []);
495
- }
496
- else if (packageValue) {
497
- packagePropVal = {
498
- packageProperty: 'package',
499
- packageValue,
500
- };
501
- }
502
- else {
503
- packagePropVal = {
504
- packageProperty: 'id',
505
- packageValue: packageIdValue,
506
- };
507
- }
508
- return packagePropVal;
404
+ return false;
509
405
  }
510
- /**
511
- * Returns the property value that corresponds to the propertyToLookup. This value found for a particular
512
- * package directory element that matches the knownProperty and knownValue. In other words, we locate a package
513
- * directory element whose knownProperty matches the knownValue, then we grab the value for the propertyToLookup
514
- * and return it.
515
- *
516
- * @param packageDirs The list of all the package directories from the sfdx-project.json
517
- * @param propertyToLookup The property ID whose value we want to find
518
- * @param knownProperty The JSON property in the packageDirectories that is already known
519
- * @param knownValue The value that corresponds to the knownProperty in the packageDirectories JSON
520
- * @param knownFlag The flag details e.g. short/long name, etc. Only used for the error message
521
- * @param options
522
- */
523
- getConfigPackageDirectoriesValue(packageDirs, propertyToLookup, knownProperty, knownValue, knownFlag, options
524
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
525
- ) {
526
- let value;
527
- let packageDir = packageDirs.find((x) => x[knownProperty] === knownValue);
528
- if (!packageDir && knownFlag === 'path' && knownValue.endsWith(path.sep)) {
529
- // if this is the directory flag, try removing the trailing slash added by CLI auto-complete
530
- const dirWithoutTrailingSlash = knownValue.slice(0, -1);
531
- packageDir = packageDirs.find((x) => x[knownProperty] === dirWithoutTrailingSlash);
532
- if (packageDir) {
533
- // TODO: how to deal with this side effect?
534
- options.path = dirWithoutTrailingSlash;
535
- }
536
- }
537
- // didn't find it with the package property, try a reverse lookup with alias and id
538
- if (!packageDir && knownProperty === 'package') {
539
- const pkgId = pkgUtils.getPackageIdFromAlias(knownValue, this.project);
540
- if (pkgId !== knownValue) {
541
- packageDir = packageDirs.find((x) => x[knownProperty] === pkgId);
542
- }
543
- else {
544
- const aliases = pkgUtils.getPackageAliasesFromId(knownValue, this.project);
545
- aliases.some((alias) => {
546
- packageDir = packageDirs.find((x) => x[knownProperty] === alias);
547
- return packageDir;
548
- });
549
- }
550
- }
551
- if (packageDir) {
552
- value = packageDir[propertyToLookup];
553
- }
554
- else {
555
- throw messages.createError('errorNoMatchingPackageDirectory', [`--${knownFlag}`, knownValue, knownProperty]);
556
- }
557
- return value;
558
- }
559
- async packageVersionCreate(options) {
406
+ async packageVersionCreate() {
560
407
  // For the first rollout of validating sfdx-project.json data against schema, make it optional and defaulted
561
- // to false. Validation only occurs if the hidden -j (--validateschema) flag has been specified.
562
- if (options.validateschema) {
408
+ // to false. Validation only occurs if the optional validateschema option has been specified.
409
+ if (this.options.validateschema) {
563
410
  await this.project.getSfProjectJson().schemaValidate();
564
411
  }
565
412
  // Check for empty packageDirectories
566
413
  if (this.project.getPackageDirectories()?.length === 0) {
567
414
  throw messages.createError('errorEmptyPackageDirs');
568
415
  }
569
- const canonicalPackageProperty = this.resolveCanonicalPackageProperty(options);
570
- const resolvedPackageId = pkgUtils.getPackageIdFromAlias(options.package, this.project);
416
+ // from the packageDirectories in sfdx-project.json, find the correct package entry either by finding a matching package (name) or path
417
+ this.packageAlias = (0, utils_1.getPackageAliasesFromId)(this.options.packageId, this.options.project).join();
418
+ // set on the class so we can access them in other methods without redoing this logic
419
+ this.packageObject = this.project.getPackageDirectories().find((pkg) => pkg.package === this.packageAlias);
420
+ this.options.profileApi = await this.resolveUserLicenses(this.packageObject.includeProfileUserLicenses);
421
+ this.packageId = (0, utils_1.getPackageIdFromAlias)(this.packageObject.package, this.project);
571
422
  // At this point, the packageIdFromAlias should have been resolved to an Id. Now, we
572
423
  // need to validate that the Id is correct.
573
- pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, resolvedPackageId);
574
- await this.validateFlagsForPackageType(resolvedPackageId, options);
575
- const versionNumberString = await this.validateVersionNumber(canonicalPackageProperty, resolvedPackageId, options);
576
- try {
577
- fs.statSync(path.join(process.cwd(), options.path));
578
- }
579
- catch (err) {
580
- throw messages.createError('directoryDoesNotExist', [options.path]);
581
- }
582
- options.profileApi = await this.resolveUserLicenses(canonicalPackageProperty, options);
583
- const request = await this.createPackageVersionCreateRequestFromOptions(options, resolvedPackageId, versionNumberString);
424
+ pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, this.packageId);
425
+ await this.validateOptionsForPackageType();
426
+ const request = await this.createPackageVersionCreateRequestFromOptions();
584
427
  const createResult = await this.connection.tooling.create('Package2VersionCreateRequest', request);
585
428
  if (!createResult.success) {
586
- const errStr = createResult.errors && createResult.errors.length ? createResult.errors.join(', ') : createResult.errors;
429
+ const errStr = createResult.errors?.join(', ') ?? createResult.errors;
587
430
  throw messages.createError('failedToCreatePVCRequest', [
588
431
  createResult.id ? ` [${createResult.id}]` : '',
589
432
  errStr.toString(),
590
433
  ]);
591
434
  }
592
- let pollInterval = kit_1.Duration.seconds(pkgUtils.POLL_INTERVAL_SECONDS);
593
- let maxRetries = 0;
594
- if (options.wait?.milliseconds > 0) {
595
- if (options.skipvalidation === true) {
596
- pollInterval = kit_1.Duration.seconds(POLL_INTERVAL_WITHOUT_VALIDATION_SECONDS);
597
- }
598
- maxRetries = (60 / pollInterval.seconds) * options.wait.seconds;
599
- }
600
- [pollInterval, maxRetries] = await this.resolveOrgDependentPollingTime(resolvedPackageId, options, pollInterval, maxRetries);
601
- return (await this.listRequestById(createResult.id, this.connection))[0];
602
- }
603
- resolveCanonicalPackageProperty(options) {
604
- let canonicalPackageProperty;
605
- if (!options.package) {
606
- const packageValProp = this.getPackageValuePropertyFromDirectory(options.path, options);
607
- options.package = packageValProp.packageValue;
608
- canonicalPackageProperty = packageValProp.packageProperty;
609
- }
610
- else if (!options.path) {
611
- canonicalPackageProperty = this.getPackagePropertyFromPackage(this.project.getPackageDirectories(), options);
612
- options.path = this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), 'path', canonicalPackageProperty, options.package, 'package', options);
613
- }
614
- else {
615
- canonicalPackageProperty = this.getPackagePropertyFromPackage(this.project.getPackageDirectories(), options);
616
- this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), canonicalPackageProperty, 'path', options.path, 'path', options);
617
- const expectedPackageId = this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), canonicalPackageProperty, 'path', options.path, 'path', options);
618
- // This will throw an error if the package id flag value doesn't match
619
- // any of the :id values in the package dirs.
620
- this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), 'path', canonicalPackageProperty, options.package, 'package', options);
621
- // This will throw an error if the package id flag value doesn't match
622
- // the correct corresponding directory with that packageId.
623
- if (options.package !== expectedPackageId) {
624
- throw messages.createError('errorDirectoryIdMismatch', ['--path', options.path, '--package', options.package]);
625
- }
626
- }
627
- return canonicalPackageProperty;
628
- }
629
- // TODO: should be in pkg utils
630
- async validateVersionNumber(canonicalPackageProperty, resolvedPackageId, options) {
631
- // validate the versionNumber flag value if specified, otherwise the descriptor value
632
- const versionNumberString = options.versionnumber
633
- ? options.versionnumber
634
- : this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), 'versionNumber', canonicalPackageProperty, options.package, 'package', options);
635
- pkgUtils.validateVersionNumber(versionNumberString, versionNumber_1.BuildNumberToken.NEXT_BUILD_NUMBER_TOKEN, null);
636
- await pkgUtils.validatePatchVersion(this.connection, versionNumberString, resolvedPackageId);
637
- return versionNumberString;
435
+ return (await (0, packageVersionCreateRequest_1.byId)(createResult.id, this.connection))[0];
638
436
  }
639
- async resolveUserLicenses(canonicalPackageProperty, options) {
640
- // Check for an includeProfileUserLiceneses flag in the packageDirectory
641
- const includeProfileUserLicenses = this.getConfigPackageDirectoriesValue(this.project.getPackageDirectories(), 'includeProfileUserLicenses', canonicalPackageProperty, options.package, 'package', options);
642
- if (includeProfileUserLicenses !== undefined &&
643
- includeProfileUserLicenses !== true &&
644
- includeProfileUserLicenses !== false) {
645
- throw messages.createError('errorProfileUserLicensesInvalidValue', [includeProfileUserLicenses]);
646
- }
437
+ async resolveUserLicenses(includeUserLicenses) {
647
438
  const shouldGenerateProfileInformation = logger.shouldLog(core_1.LoggerLevel.INFO) || logger.shouldLog(core_1.LoggerLevel.DEBUG);
648
- return packageProfileApi_1.PackageProfileApi.create({
439
+ return await packageProfileApi_1.PackageProfileApi.create({
649
440
  project: this.project,
650
- includeUserLicenses: includeProfileUserLicenses,
441
+ includeUserLicenses,
651
442
  generateProfileInformation: shouldGenerateProfileInformation,
652
443
  });
653
444
  }
654
- async resolveOrgDependentPollingTime(resolvedPackageId, options, pollInterval, maxRetries) {
655
- let pi = pollInterval;
656
- let mr = maxRetries;
657
- // If we are polling check to see if the package is Org-Dependent, if so, update the poll time
658
- if (options.wait) {
659
- const query = `SELECT IsOrgDependent FROM Package2 WHERE Id = '${resolvedPackageId}'`;
660
- try {
661
- const pkgQueryResult = await this.connection.singleRecordQuery(query, {
662
- tooling: true,
663
- });
664
- if (pkgQueryResult.IsOrgDependent) {
665
- pi = kit_1.Duration.seconds(POLL_INTERVAL_WITHOUT_VALIDATION_SECONDS);
666
- mr = (60 / pollInterval.seconds) * options.wait.seconds;
667
- }
668
- }
669
- catch {
670
- // do nothing
671
- }
672
- }
673
- return [pi, mr];
674
- }
675
- async validateFlagsForPackageType(packageId, options) {
676
- const packageType = await pkgUtils.getPackageType(packageId, this.connection);
677
- if (packageType === 'Unlocked') {
678
- if (options.postinstallscript || options.uninstallscript) {
679
- // migrate coreMessages to messages
680
- throw messages.createError('version_create.errorScriptsNotApplicableToUnlockedPackage');
445
+ async validateOptionsForPackageType() {
446
+ this.packageType = await pkgUtils.getPackageType(this.packageId, this.connection);
447
+ if (this.packageType === 'Unlocked') {
448
+ // Don't allow scripts in unlocked packages
449
+ if (this.options.postinstallscript || this.options.uninstallscript) {
450
+ throw messages.createError('errorScriptsNotApplicableToUnlockedPackage');
681
451
  }
682
452
  // Don't allow ancestor in unlocked packages
683
- const packageDescriptorJson = this.getPackageDescriptorJsonFromPackageId(packageId, options);
684
- const ancestorId = packageDescriptorJson.ancestorId;
685
- const ancestorVersion = packageDescriptorJson.ancestorVersion;
686
- if (ancestorId || ancestorVersion) {
687
- throw messages.createError('version_create.errorAncestorNotApplicableToUnlockedPackage');
453
+ if (this.packageObject.ancestorId || this.packageObject.ancestorVersion) {
454
+ throw messages.createError('errorAncestorNotApplicableToUnlockedPackage');
688
455
  }
689
456
  }
690
457
  }
@@ -703,7 +470,8 @@ class PackageVersionCreate {
703
470
  /**
704
471
  * Sets default or override values for packageDescriptorJSON attribs
705
472
  */
706
- setPackageDescriptorJsonValues(packageDescriptorJson, options) {
473
+ setPackageDescriptorJsonValues(packageDescriptorJson) {
474
+ const options = this.options;
707
475
  if (options.versionname) {
708
476
  packageDescriptorJson.versionName = options.versionname;
709
477
  }
@@ -725,13 +493,13 @@ class PackageVersionCreate {
725
493
  if (options.releasenotesurl) {
726
494
  packageDescriptorJson.releaseNotesUrl = options.releasenotesurl;
727
495
  }
728
- if (packageDescriptorJson.releaseNotesUrl && !pkgUtils.validUrl(packageDescriptorJson.releaseNotesUrl)) {
496
+ if (packageDescriptorJson.releaseNotesUrl && !core_1.SfdcUrl.isValidUrl(packageDescriptorJson.releaseNotesUrl)) {
729
497
  throw messages.createError('malformedUrl', ['releaseNotesUrl', packageDescriptorJson.releaseNotesUrl]);
730
498
  }
731
499
  if (options.postinstallurl) {
732
500
  packageDescriptorJson.postInstallUrl = options.postinstallurl;
733
501
  }
734
- if (packageDescriptorJson.postInstallUrl && !pkgUtils.validUrl(packageDescriptorJson.postInstallUrl)) {
502
+ if (packageDescriptorJson.postInstallUrl && !core_1.SfdcUrl.isValidUrl(packageDescriptorJson.postInstallUrl)) {
735
503
  throw messages.createError('malformedUrl', ['postInstallUrl', packageDescriptorJson.postInstallUrl]);
736
504
  }
737
505
  if (options.postinstallscript) {