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