@salesforce/packaging 0.0.4 → 0.0.7

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