@salesforce/packaging 4.17.1 → 4.18.0

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.
@@ -17,4 +17,4 @@ export declare function createPackageVersionCreateRequest(context: {
17
17
  seedmetadata?: string;
18
18
  patchversion?: string;
19
19
  codecoverage?: boolean;
20
- }, packageId: string, apiVersion: string): Promise<PackagingSObjects.Package2VersionCreateRequest>;
20
+ }, packageId: string, apiVersion: string, project?: SfProject): Promise<PackagingSObjects.Package2VersionCreateRequest>;
@@ -59,6 +59,7 @@ const node_os_1 = __importDefault(require("node:os"));
59
59
  const node_fs_1 = __importDefault(require("node:fs"));
60
60
  const core_1 = require("@salesforce/core");
61
61
  const kit_1 = require("@salesforce/kit");
62
+ const project_1 = require("@salesforce/core/project");
62
63
  const pkgUtils = __importStar(require("../utils/packageUtils"));
63
64
  const packageUtils_1 = require("../utils/packageUtils");
64
65
  const interfaces_1 = require("../interfaces");
@@ -125,7 +126,7 @@ async function convertPackage(pkg, connection, options, project) {
125
126
  }, packageId,
126
127
  // TODO: createPackageVersionCreateRequest requires apiVersion exist.
127
128
  // UT fail if we validate that it exists (there might not even be a project)
128
- apiVersion);
129
+ apiVersion, project);
129
130
  // TODO: a lot of this is duplicated from PC, PVC, and PVCR.
130
131
  const createResult = await connection.tooling.create('Package2VersionCreateRequest', request);
131
132
  if (!createResult.success) {
@@ -163,7 +164,7 @@ async function convertPackage(pkg, connection, options, project) {
163
164
  * @returns {{Package2Id: string, Package2VersionMetadata: *, Tag: *, Branch: number}}
164
165
  * @private
165
166
  */
166
- async function createPackageVersionCreateRequest(context, packageId, apiVersion) {
167
+ async function createPackageVersionCreateRequest(context, packageId, apiVersion, project) {
167
168
  const uniqueId = (0, packageUtils_1.uniqid)({ template: `${packageId}-%s` });
168
169
  const packageVersTmpRoot = node_path_1.default.join(node_os_1.default.tmpdir(), uniqueId);
169
170
  const packageVersMetadataFolder = node_path_1.default.join(packageVersTmpRoot, 'md-files');
@@ -173,10 +174,12 @@ async function createPackageVersionCreateRequest(context, packageId, apiVersion)
173
174
  const settingsZipFile = node_path_1.default.join(packageVersBlobDirectory, 'settings.zip');
174
175
  const metadataZipFile = node_path_1.default.join(packageVersBlobDirectory, 'package.zip');
175
176
  const packageVersBlobZipFile = node_path_1.default.join(packageVersTmpRoot, 'package-version-info.zip');
176
- let packageDescriptorJson = {
177
- id: packageId,
178
- versionNumber: context.patchversion,
179
- };
177
+ const packageObject = project ? (0, packageUtils_1.findPackageDirectory)(project, packageId) : undefined;
178
+ let packageDescriptorJson = buildPackageDescriptorJson({
179
+ packageId,
180
+ base: { versionNumber: context.patchversion },
181
+ packageObject,
182
+ });
180
183
  const settingsGenerator = new core_1.ScratchOrgSettingsGenerator({ asDirectory: true });
181
184
  const definitionFile = context.definitionfile;
182
185
  let definitionFileJson;
@@ -197,10 +200,11 @@ async function createPackageVersionCreateRequest(context, packageId, apiVersion)
197
200
  await node_fs_1.default.promises.mkdir(packageVersTmpRoot, { recursive: true });
198
201
  await node_fs_1.default.promises.mkdir(packageVersBlobDirectory, { recursive: true });
199
202
  await node_fs_1.default.promises.mkdir(packageVersMetadataFolder, { recursive: true });
200
- const hasSeedMetadata = await new packageVersionCreate_1.MetadataResolver().resolveMetadata(context.seedmetadata, seedMetadataFolder, 'seedMDDirectoryDoesNotExist', apiVersion);
203
+ const seedMetadataPath = context.seedmetadata ?? packageDescriptorJson.seedMetadata?.path;
204
+ const hasSeedMetadata = await new packageVersionCreate_1.MetadataResolver().resolveMetadata(seedMetadataPath, seedMetadataFolder, 'seedMDDirectoryDoesNotExist', apiVersion);
201
205
  if (hasSeedMetadata) {
202
206
  // Zip the seedMetadataFolder folder and put the zip in {packageVersBlobDirectory}/{seedMetadataZipFile}
203
- core_1.Logger.childFromRoot('packageConvert:pollForStatusWithInterval').debug(`Including metadata found in '${context.seedmetadata ?? '<undefined seedmetadata>'}'.`);
207
+ core_1.Logger.childFromRoot('packageConvert:pollForStatusWithInterval').debug(`Including metadata found in '${seedMetadataPath ?? '<undefined seedmetadata>'}'.`);
204
208
  await pkgUtils.zipDir(seedMetadataFolder, seedMetadataZipFile);
205
209
  }
206
210
  await settingsGenerator.createDeploy();
@@ -211,11 +215,32 @@ async function createPackageVersionCreateRequest(context, packageId, apiVersion)
211
215
  await node_fs_1.default.promises.writeFile(node_path_1.default.join(packageVersMetadataFolder, 'package.xml'), currentPackageXml, 'utf-8');
212
216
  // Zip the packageVersMetadataFolder folder and put the zip in {packageVersBlobDirectory}/package.zip
213
217
  await pkgUtils.zipDir(packageVersMetadataFolder, metadataZipFile);
218
+ packageDescriptorJson = (0, packageUtils_1.resolveBuildUserPermissions)(packageDescriptorJson, context.codecoverage ?? false);
219
+ packageDescriptorJson = (0, packageUtils_1.cleanPackageDescriptorJson)(packageDescriptorJson);
214
220
  await node_fs_1.default.promises.writeFile(node_path_1.default.join(packageVersBlobDirectory, 'package2-descriptor.json'), JSON.stringify(packageDescriptorJson, undefined, 2));
215
221
  // Zip the Version Info and package.zip files into another zip
216
222
  await pkgUtils.zipDir(packageVersBlobDirectory, packageVersBlobZipFile);
217
223
  return createRequestObject(packageId, context, packageVersTmpRoot, packageVersBlobZipFile);
218
224
  }
225
+ function buildPackageDescriptorJson(args) {
226
+ const { packageId, base, packageObject } = args;
227
+ const descriptor = {
228
+ id: packageId,
229
+ ...(base ?? {}),
230
+ };
231
+ if (packageObject && (0, project_1.isPackagingDirectory)(packageObject)) {
232
+ const allowedKeys = ['apexTestAccess', 'seedMetadata'];
233
+ for (const key of allowedKeys) {
234
+ if (Object.prototype.hasOwnProperty.call(packageObject, key)) {
235
+ const value = packageObject[key];
236
+ if (value !== undefined) {
237
+ descriptor[key] = value;
238
+ }
239
+ }
240
+ }
241
+ }
242
+ return descriptor;
243
+ }
219
244
  async function createRequestObject(packageId, options, packageVersTmpRoot, packageVersBlobZipFile) {
220
245
  const zipFileBase64 = (await node_fs_1.default.promises.readFile(packageVersBlobZipFile)).toString('base64');
221
246
  const requestObject = {
@@ -36,8 +36,6 @@ export declare class PackageVersionCreate {
36
36
  private createPackageVersionCreateRequestFromOptions;
37
37
  private verifyHasSource;
38
38
  private cleanGeneratedPackage;
39
- /** side effect: modifies the passed in parameter! */
40
- private resolveBuildUserPermissions;
41
39
  private packageVersionCreate;
42
40
  private getPackageDirFromId;
43
41
  private getPackageType;
@@ -350,7 +350,7 @@ class PackageVersionCreate {
350
350
  }
351
351
  packageDescriptorJson = (0, packageUtils_1.copyDescriptorProperties)(packageDescriptorJson, definitionFileJson);
352
352
  }
353
- this.resolveBuildUserPermissions(packageDescriptorJson);
353
+ packageDescriptorJson = pkgUtils.resolveBuildUserPermissions(packageDescriptorJson, this.options.codecoverage ?? false);
354
354
  // All dependencies for the packaging dir should be resolved to an 04t id to be passed to the server.
355
355
  // (see resolveSubscriberPackageVersionId() for details)
356
356
  const dependencies = packageDescriptorJson.dependencies;
@@ -368,7 +368,7 @@ class PackageVersionCreate {
368
368
  if (resultValues.length > 0) {
369
369
  packageDescriptorJson.dependencies = resultValues;
370
370
  }
371
- packageDescriptorJson = cleanPackageDescriptorJson(packageDescriptorJson);
371
+ packageDescriptorJson = pkgUtils.cleanPackageDescriptorJson(packageDescriptorJson);
372
372
  packageDescriptorJson = setPackageDescriptorJsonValues(packageDescriptorJson, this.options, this.logger);
373
373
  await node_fs_1.default.promises.mkdir(packageVersTmpRoot, { recursive: true });
374
374
  await node_fs_1.default.promises.mkdir(packageVersBlobDirectory, { recursive: true });
@@ -476,45 +476,6 @@ class PackageVersionCreate {
476
476
  // Zip the Version Info and package.zip files into another zip
477
477
  await (0, packageUtils_1.zipDir)(packageVersBlobDirectory, packageVersBlobZipFile);
478
478
  }
479
- /** side effect: modifies the passed in parameter! */
480
- resolveBuildUserPermissions(packageDescriptorJson) {
481
- // Process permissionSet and permissionSetLicenses that should be enabled when running Apex tests
482
- // This only applies if code coverage is enabled
483
- if (this.options.codecoverage) {
484
- // Assuming no permission sets are named 0, 0n, null, undefined, false, NaN, and the empty string
485
- if (packageDescriptorJson.apexTestAccess?.permissionSets) {
486
- let permSets = packageDescriptorJson.apexTestAccess.permissionSets;
487
- if (!Array.isArray(permSets)) {
488
- permSets = permSets.split(',');
489
- }
490
- packageDescriptorJson.permissionSetNames = permSets.map((s) => s.trim());
491
- }
492
- if (packageDescriptorJson.apexTestAccess?.permissionSetLicenses) {
493
- let permissionSetLicenses = packageDescriptorJson.apexTestAccess.permissionSetLicenses;
494
- if (!Array.isArray(permissionSetLicenses)) {
495
- permissionSetLicenses = permissionSetLicenses.split(',');
496
- }
497
- packageDescriptorJson.permissionSetLicenseDeveloperNames = permissionSetLicenses.map((s) => s.trim());
498
- }
499
- }
500
- // Process permissionSet and permissionsetLicenses that should be enabled for the package metadata deploy
501
- if (packageDescriptorJson.packageMetadataAccess?.permissionSets) {
502
- let permSets = packageDescriptorJson.packageMetadataAccess.permissionSets;
503
- if (!Array.isArray(permSets)) {
504
- permSets = permSets.split(',');
505
- }
506
- packageDescriptorJson.packageMetadataPermissionSetNames = permSets.map((s) => s.trim());
507
- }
508
- if (packageDescriptorJson.packageMetadataAccess?.permissionSetLicenses) {
509
- let permissionSetLicenses = packageDescriptorJson.packageMetadataAccess.permissionSetLicenses;
510
- if (!Array.isArray(permissionSetLicenses)) {
511
- permissionSetLicenses = permissionSetLicenses.split(',');
512
- }
513
- packageDescriptorJson.packageMetadataPermissionSetLicenseNames = permissionSetLicenses.map((s) => s.trim());
514
- }
515
- delete packageDescriptorJson.apexTestAccess;
516
- delete packageDescriptorJson.packageMetadataAccess;
517
- }
518
479
  // eslint-disable-next-line complexity
519
480
  async packageVersionCreate() {
520
481
  // For the first rollout of validating sfdx-project.json data against schema, make it optional and defaulted
@@ -967,21 +928,4 @@ const setPackageDescriptorJsonValues = (packageDescriptorJson, options, logger)
967
928
  }
968
929
  return merged;
969
930
  };
970
- /**
971
- * Cleans client-side-only attribute(s) from the packageDescriptorJSON so it can go to API
972
- */
973
- const cleanPackageDescriptorJson = (packageDescriptorJson) => {
974
- // properties only used by the client side
975
- const clientOnlyProps = [
976
- 'default',
977
- 'includeProfileUserLicenses',
978
- 'unpackagedMetadata',
979
- 'seedMetadata',
980
- 'branch',
981
- 'fullPath',
982
- 'name',
983
- 'scopeProfiles',
984
- ];
985
- return Object.fromEntries(Object.entries(packageDescriptorJson).filter(([key]) => !clientOnlyProps.includes(key)));
986
- };
987
931
  //# sourceMappingURL=packageVersionCreate.js.map
@@ -1,5 +1,6 @@
1
1
  import { Connection, ScratchOrgInfo, SfdcUrl, SfError, SfProject } from '@salesforce/core';
2
- import { Many } from '@salesforce/ts-types';
2
+ import { NamedPackageDir } from '@salesforce/core/project';
3
+ import { Many, Optional } from '@salesforce/ts-types';
3
4
  import type { SaveError } from '@jsforce/jsforce-node';
4
5
  import { Duration } from '@salesforce/kit';
5
6
  import { PackageDescriptorJson, PackageType, PackagingSObjects } from '../interfaces';
@@ -106,6 +107,28 @@ export declare function copyDir(src: string, dest: string): void;
106
107
  * overridden from definition file based on case-insensitive matches.
107
108
  */
108
109
  export declare function copyDescriptorProperties(packageDescriptorJson: PackageDescriptorJson, definitionFileJson: ScratchOrgInfo): PackageDescriptorJson;
110
+ /**
111
+ * Resolve descriptor permissions for build/test execution.
112
+ *
113
+ * When {@link codecoverage} is true, converts {@link apexTestAccess} settings into
114
+ * permissionSetNames and permissionSetLicenseDeveloperNames.
115
+ * Always converts {@link packageMetadataAccess} settings into
116
+ * packageMetadataPermissionSetNames and packageMetadataPermissionSetLicenseNames.
117
+ * Removes apexTestAccess and packageMetadataAccess from the returned descriptor.
118
+ *
119
+ * @param descriptor Package descriptor to normalize
120
+ * @param codecoverage Whether to enable apexTestAccess-based permission processing
121
+ * @returns A normalized copy of the descriptor with flattened permission fields
122
+ */
123
+ export declare function resolveBuildUserPermissions(descriptor: PackageDescriptorJson, codecoverage: boolean): PackageDescriptorJson;
124
+ /**
125
+ * This function finds the package directory in the project that matches the given packageId
126
+ *
127
+ * @param project The SfProject instance to search
128
+ * @param packageId The package ID to match against
129
+ * @returns A NamedPackageDir or empty object if not found
130
+ */
131
+ export declare function findPackageDirectory(project: SfProject | undefined, packageId: string): Optional<NamedPackageDir>;
109
132
  /**
110
133
  * Brand new SFDX projects contain a force-app directory tree containing empty folders
111
134
  * and a few .eslintrc.json files. We still want to consider such a directory tree
@@ -116,3 +139,7 @@ export declare function copyDescriptorProperties(packageDescriptorJson: PackageD
116
139
  * directories containing only an .eslintrc.json file.
117
140
  */
118
141
  export declare function isPackageDirectoryEffectivelyEmpty(directory: string): boolean;
142
+ /**
143
+ * Cleans client-side-only attribute(s) from the packageDescriptorJSON so it can go to API
144
+ */
145
+ export declare function cleanPackageDescriptorJson(packageDescriptorJson: PackageDescriptorJson): PackageDescriptorJson;
@@ -54,7 +54,10 @@ exports.numberToDuration = numberToDuration;
54
54
  exports.zipDir = zipDir;
55
55
  exports.copyDir = copyDir;
56
56
  exports.copyDescriptorProperties = copyDescriptorProperties;
57
+ exports.resolveBuildUserPermissions = resolveBuildUserPermissions;
58
+ exports.findPackageDirectory = findPackageDirectory;
57
59
  exports.isPackageDirectoryEffectivelyEmpty = isPackageDirectoryEffectivelyEmpty;
60
+ exports.cleanPackageDescriptorJson = cleanPackageDescriptorJson;
58
61
  /*
59
62
  * Copyright 2025, Salesforce, Inc.
60
63
  *
@@ -77,6 +80,7 @@ const node_stream_1 = require("node:stream");
77
80
  const node_util_1 = __importStar(require("node:util"));
78
81
  const node_crypto_1 = require("node:crypto");
79
82
  const core_1 = require("@salesforce/core");
83
+ const project_1 = require("@salesforce/core/project");
80
84
  const ts_types_1 = require("@salesforce/ts-types");
81
85
  const kit_1 = require("@salesforce/kit");
82
86
  const globby_1 = __importDefault(require("globby"));
@@ -450,6 +454,69 @@ function copyDescriptorProperties(packageDescriptorJson, definitionFileJson) {
450
454
  return [[prop], matchCase ? definitionFileJsonCopy[matchCase] : undefined];
451
455
  })));
452
456
  }
457
+ /**
458
+ * Resolve descriptor permissions for build/test execution.
459
+ *
460
+ * When {@link codecoverage} is true, converts {@link apexTestAccess} settings into
461
+ * permissionSetNames and permissionSetLicenseDeveloperNames.
462
+ * Always converts {@link packageMetadataAccess} settings into
463
+ * packageMetadataPermissionSetNames and packageMetadataPermissionSetLicenseNames.
464
+ * Removes apexTestAccess and packageMetadataAccess from the returned descriptor.
465
+ *
466
+ * @param descriptor Package descriptor to normalize
467
+ * @param codecoverage Whether to enable apexTestAccess-based permission processing
468
+ * @returns A normalized copy of the descriptor with flattened permission fields
469
+ */
470
+ function resolveBuildUserPermissions(descriptor, codecoverage) {
471
+ const copy = structuredClone(descriptor);
472
+ if (codecoverage) {
473
+ if (copy.apexTestAccess?.permissionSets) {
474
+ let permSets = copy.apexTestAccess.permissionSets;
475
+ if (!Array.isArray(permSets))
476
+ permSets = permSets.split(',');
477
+ copy.permissionSetNames = permSets.map((s) => s.trim());
478
+ }
479
+ if (copy.apexTestAccess?.permissionSetLicenses) {
480
+ let psl = copy.apexTestAccess.permissionSetLicenses;
481
+ if (!Array.isArray(psl))
482
+ psl = psl.split(',');
483
+ copy.permissionSetLicenseDeveloperNames = psl.map((s) => s.trim());
484
+ }
485
+ }
486
+ if (copy.packageMetadataAccess?.permissionSets) {
487
+ let permSets = copy.packageMetadataAccess.permissionSets;
488
+ if (!Array.isArray(permSets))
489
+ permSets = permSets.split(',');
490
+ copy.packageMetadataPermissionSetNames = permSets.map((s) => s.trim());
491
+ }
492
+ if (copy.packageMetadataAccess?.permissionSetLicenses) {
493
+ let psl = copy.packageMetadataAccess.permissionSetLicenses;
494
+ if (!Array.isArray(psl))
495
+ psl = psl.split(',');
496
+ copy.packageMetadataPermissionSetLicenseNames = psl.map((s) => s.trim());
497
+ }
498
+ delete copy.apexTestAccess;
499
+ delete copy.packageMetadataAccess;
500
+ return copy;
501
+ }
502
+ /**
503
+ * This function finds the package directory in the project that matches the given packageId
504
+ *
505
+ * @param project The SfProject instance to search
506
+ * @param packageId The package ID to match against
507
+ * @returns A NamedPackageDir or empty object if not found
508
+ */
509
+ function findPackageDirectory(project, packageId) {
510
+ if (!project) {
511
+ return undefined;
512
+ }
513
+ return project.findPackage((namedPackageDir) => {
514
+ if (!(0, project_1.isPackagingDirectory)(namedPackageDir))
515
+ return false;
516
+ const dirPackageId = project.getPackageIdFromAlias(namedPackageDir.package) ?? namedPackageDir.package;
517
+ return dirPackageId === packageId;
518
+ });
519
+ }
453
520
  /**
454
521
  * Brand new SFDX projects contain a force-app directory tree containing empty folders
455
522
  * and a few .eslintrc.json files. We still want to consider such a directory tree
@@ -468,4 +535,21 @@ function isPackageDirectoryEffectivelyEmpty(directory) {
468
535
  ? isPackageDirectoryEffectivelyEmpty((0, node_path_1.join)(directory, entry.name))
469
536
  : entry.name === '.eslintrc.json');
470
537
  }
538
+ /**
539
+ * Cleans client-side-only attribute(s) from the packageDescriptorJSON so it can go to API
540
+ */
541
+ function cleanPackageDescriptorJson(packageDescriptorJson) {
542
+ // properties only used by the client side
543
+ const clientOnlyProps = [
544
+ 'default',
545
+ 'includeProfileUserLicenses',
546
+ 'unpackagedMetadata',
547
+ 'seedMetadata',
548
+ 'branch',
549
+ 'fullPath',
550
+ 'name',
551
+ 'scopeProfiles',
552
+ ];
553
+ return Object.fromEntries(Object.entries(packageDescriptorJson).filter(([key]) => !clientOnlyProps.includes(key)));
554
+ }
471
555
  //# sourceMappingURL=packageUtils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/packaging",
3
- "version": "4.17.1",
3
+ "version": "4.18.0",
4
4
  "description": "Packaging library for the Salesforce packaging platform",
5
5
  "main": "lib/exported",
6
6
  "types": "lib/exported.d.ts",
@@ -43,8 +43,8 @@
43
43
  ],
44
44
  "dependencies": {
45
45
  "@jsforce/jsforce-node": "^3.10.8",
46
- "@salesforce/core": "^8.23.2",
47
- "@salesforce/kit": "^3.2.3",
46
+ "@salesforce/core": "^8.23.3",
47
+ "@salesforce/kit": "^3.2.4",
48
48
  "@salesforce/schemas": "^1.10.3",
49
49
  "@salesforce/source-deploy-retrieve": "^12.24.0",
50
50
  "@salesforce/ts-types": "^2.0.11",