Skip to content

Commit

Permalink
Merge pull request #563 from forcedotcom/sh/make-retrieveSubscriberPa…
Browse files Browse the repository at this point in the history
…ckageVersionId-public
  • Loading branch information
WillieRuemmele authored May 17, 2024
2 parents bd8ce73 + 029e19f commit 1c61c65
Show file tree
Hide file tree
Showing 7 changed files with 631 additions and 1,437 deletions.
1,870 changes: 513 additions & 1,357 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
],
"dependencies": {
"@jsforce/jsforce-node": "^3.2.0",
"@salesforce/core": "^7.3.6",
"@salesforce/core": "^7.3.8",
"@salesforce/kit": "^3.1.1",
"@salesforce/schemas": "^1.7.0",
"@salesforce/source-deploy-retrieve": "^11.4.3",
Expand Down
133 changes: 68 additions & 65 deletions src/package/packageVersionCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,71 +91,15 @@ export class PackageVersionCreate {
}
}

private async validateDependencyValues(dependency: PackageDescriptorJson): Promise<void> {
// If valid 04t package, just return it to be used straight away.
if (dependency.subscriberPackageVersionId) {
pkgUtils.validateId(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, dependency.subscriberPackageVersionId);
return;
}

if (dependency.packageId && dependency.package) {
throw messages.createError('errorPackageAndPackageIdCollision', []);
}

const idOrPackage = dependency.packageId ?? dependency.package;
if (!idOrPackage) {
throw messages.createError('errorPackageOrPackageIdMissing', []);
}

const packageIdFromAlias = this.project.getPackageIdFromAlias(idOrPackage) ?? idOrPackage;

// If valid 04t package, just return it to be used straight away.
if (pkgUtils.validateIdNoThrow(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, packageIdFromAlias)) {
dependency.subscriberPackageVersionId = packageIdFromAlias;
return;
}

if (!packageIdFromAlias || !dependency.versionNumber) {
throw messages.createError('errorDependencyPair', [JSON.stringify(dependency)]);
}

// Just override dependency.packageId value to the resolved alias.
dependency.packageId = packageIdFromAlias;

pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, dependency.packageId);
validateVersionNumber(
dependency.versionNumber,
BuildNumberToken.LATEST_BUILD_NUMBER_TOKEN,
BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN
);
await this.validatePatchVersion(dependency.versionNumber, dependency.packageId);

// Validate that the Package2 id exists on the server
const query = `SELECT Id FROM Package2 WHERE Id = '${dependency.packageId}'`;
const result = await this.connection.tooling.query<{ Id: string }>(query);

if (!result.records || result.records.length !== 1) {
throw messages.createError('errorNoIdInHub', [dependency.packageId]);
}
}

/**
* A dependency in the workspace config file may be specified using either a subscriber package version id (04t)
* A dependency in the project config file may be specified using either a subscriber package version id (04t)
* or a package Id (0Ho) + a version number. Additionally, a build number may be the actual build number, or a
* keyword: LATEST or RELEASED (meaning the latest or released build number for a given major.minor.patch).
*
* This method resolves a package Id + version number to a subscriber package version id (04t)
* and adds it as a SubscriberPackageVersionId parameter in the dependency object.
*/
private async retrieveSubscriberPackageVersionId(dependency: PackageDescriptorJson): Promise<PackageDescriptorJson> {
await this.validateDependencyValues(dependency);
if (dependency.subscriberPackageVersionId) {
delete dependency.package;

// if a 04t id is specified just use it.
return dependency;
}

public async retrieveSubscriberPackageVersionId(dependency: PackageDescriptorJson): Promise<string> {
if (!dependency.versionNumber) {
throw messages.createError('errorDependencyPair', [JSON.stringify(dependency)]);
}
Expand All @@ -168,7 +112,7 @@ export class PackageVersionCreate {

// use the dependency.branch if present otherwise use the branch of the version being created
const branch = dependency.branch ?? this.options.branch;
const branchString = !branch || branch === '' ? 'null' : `'${branch}'`;
const branchString = !branch ? 'null' : `'${branch}'`;

// resolve a build number keyword to an actual number, if needed
const resolvedBuildNumber = await this.resolveBuildNumber(versionNumber, dependency.packageId, branch);
Expand All @@ -192,10 +136,8 @@ export class PackageVersionCreate {
]);
}

dependency.subscriberPackageVersionId = pkgVerQueryResult.records[0].SubscriberPackageVersionId;

// warn user of the resolved build number when LATEST and RELEASED keywords are used
if (versionNumber.isbuildKeyword()) {
if (versionNumber.isBuildKeyword()) {
versionNumber.build = resolvedBuildNumber;

if (buildNumber === BuildNumberToken.LATEST_BUILD_NUMBER_TOKEN) {
Expand All @@ -218,6 +160,19 @@ export class PackageVersionCreate {
}
}

return pkgVerQueryResult.records[0].SubscriberPackageVersionId;
}

private async resolveSubscriberPackageVersionId(dependency: PackageDescriptorJson): Promise<PackageDescriptorJson> {
await this.validateDependencyValues(dependency);
if (dependency.subscriberPackageVersionId) {
delete dependency.package;

// if a 04t id is specified just use it.
return dependency;
}

dependency.subscriberPackageVersionId = await this.retrieveSubscriberPackageVersionId(dependency);
delete dependency.packageId;
delete dependency.package;
delete dependency.versionNumber;
Expand All @@ -226,12 +181,60 @@ export class PackageVersionCreate {
return dependency;
}

private async validateDependencyValues(dependency: PackageDescriptorJson): Promise<void> {
// If valid 04t package, just return it to be used straight away.
if (dependency.subscriberPackageVersionId) {
pkgUtils.validateId(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, dependency.subscriberPackageVersionId);
return;
}

if (dependency.packageId && dependency.package) {
throw messages.createError('errorPackageAndPackageIdCollision', []);
}

const idOrPackage = dependency.packageId ?? dependency.package;
if (!idOrPackage) {
throw messages.createError('errorPackageOrPackageIdMissing', []);
}

const packageIdFromAlias = this.project.getPackageIdFromAlias(idOrPackage) ?? idOrPackage;

// If valid 04t package, just return it to be used straight away.
if (pkgUtils.validateIdNoThrow(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, packageIdFromAlias)) {
dependency.subscriberPackageVersionId = packageIdFromAlias;
return;
}

if (!packageIdFromAlias || !dependency.versionNumber) {
throw messages.createError('errorDependencyPair', [JSON.stringify(dependency)]);
}

// Just override dependency.packageId value to the resolved alias.
dependency.packageId = packageIdFromAlias;

pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, dependency.packageId);
validateVersionNumber(
dependency.versionNumber,
BuildNumberToken.LATEST_BUILD_NUMBER_TOKEN,
BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN
);
await this.validatePatchVersion(dependency.versionNumber, dependency.packageId);

// Validate that the Package2 id exists on the server
const query = `SELECT Id FROM Package2 WHERE Id = '${dependency.packageId}'`;
const result = await this.connection.tooling.query<{ Id: string }>(query);

if (!result.records || result.records.length !== 1) {
throw messages.createError('errorNoIdInHub', [dependency.packageId]);
}
}

private async resolveBuildNumber(
versionNumber: VersionNumber,
packageId: string,
branch: string | undefined
): Promise<string> {
if (!versionNumber.isbuildKeyword()) {
if (!versionNumber.isBuildKeyword()) {
// The build number is already specified so just return it using the tooling query result obj structure
return `${versionNumber.build}`;
}
Expand Down Expand Up @@ -377,15 +380,15 @@ export class PackageVersionCreate {
this.resolveBuildUserPermissions(packageDescriptorJson);

// All dependencies for the packaging dir should be resolved to an 04t id to be passed to the server.
// (see _retrieveSubscriberPackageVersionId for details)
// (see resolveSubscriberPackageVersionId() for details)
const dependencies = packageDescriptorJson.dependencies;

// branch and APV language can be set via options or packageDirectory; option takes precedence
this.options.branch = this.options.branch ?? packageDescriptorJson.branch;
this.options.language = this.options.language ?? apvLanguage;

const resultValues = await Promise.all(
!dependencies ? [] : dependencies.map((dependency) => this.retrieveSubscriberPackageVersionId(dependency))
!dependencies ? [] : dependencies.map((dependency) => this.resolveSubscriberPackageVersionId(dependency))
);

const versionNumber = this.options.versionnumber ?? packageDescriptorJson.versionNumber;
Expand Down
25 changes: 23 additions & 2 deletions src/package/subscriberPackageVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Duration } from '@salesforce/kit';
import { Nullable, Optional } from '@salesforce/ts-types';
import {
InstalledPackages,
PackageDescriptorJson,
PackageInstallCreateRequest,
PackageInstallOptions,
PackageType,
Expand All @@ -19,6 +20,7 @@ import {
import { applyErrorAction, escapeInstallationKey, massageErrorMessage, numberToDuration } from '../utils/packageUtils';
import { createPackageInstallRequest, getStatus, pollStatus, waitForPublish } from './packageInstall';
import { getUninstallErrors, uninstallPackage } from './packageUninstall';
import { PackageVersionCreate } from './packageVersionCreate';
import { VersionNumber } from './versionNumber';

Messages.importMessagesDirectory(__dirname);
Expand Down Expand Up @@ -232,6 +234,25 @@ export class SubscriberPackageVersion {
return installRequest;
}

/**
* Resolve fields from a packageDirectories entry to a SubscriberPackageVersionId (04t).
* Specifically uses the `versionNumber` and `packageId` fields, as well as an optional
* `branch` field.
*
* @param connection A connection object to the org
* @param pkgDescriptor Fields from a packageDirectories entry in sfdx-project.json.
* The `versionNumber` and `packageId` fields are required. Optionally, the `branch` and
* `package` fields can be passed.
* @returns the SubscriberPackageVersionId (04t)
*/
public static async resolveId(
connection: Connection,
pkgDescriptor: Partial<PackageDescriptorJson>
): Promise<string> {
const pvc = new PackageVersionCreate({ connection, project: SfProject.getInstance() });
return pvc.retrieveSubscriberPackageVersionId(pkgDescriptor);
}

/**
* Get the package version ID for this SubscriberPackageVersion.
*
Expand All @@ -244,7 +265,7 @@ export class SubscriberPackageVersion {
/**
* Get the package type for this SubscriberPackageVersion.
*
* @returns {PackageType} The package type.
* @returns {PackageType} The package type ("Managed" or "Unlocked") for this SubscriberPackageVersion.
*/
public async getPackageType(): Promise<PackageType> {
return this.getField<SPV['Package2ContainerOptions']>('Package2ContainerOptions');
Expand All @@ -262,7 +283,7 @@ export class SubscriberPackageVersion {
/**
* Get the subscriber package Id (033) for this SubscriberPackageVersion.
*
* @returns {string} The subscriber package Id.
* @returns {string} The subscriber package Id (033).
*/
public async getSubscriberPackageId(): Promise<string> {
return this.getField<SPV['SubscriberPackageId']>('SubscriberPackageId');
Expand Down
7 changes: 0 additions & 7 deletions src/package/versionNumber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,6 @@ export class VersionNumber {
}
}

/**
* @deprecated use isBuildKeyword instead
*/
public isbuildKeyword(): boolean {
return this.isBuildKeyword();
}

public isBuildKeyword(): boolean {
return VersionNumber.isABuildKeyword(this.build);
}
Expand Down
6 changes: 2 additions & 4 deletions src/utils/packageUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,8 @@ const pipeline = promisify(cbPipeline);
/**
* Zips directory to given zipfile.
*
* https://github.com/archiverjs/node-archiver
*
* @param dir to zip
* @param zipfile
* @param dir directory to zip
* @param zipfile path to the zip file to create
*/
export async function zipDir(dir: string, zipfile: string): Promise<void> {
const logger = Logger.childFromRoot('srcDevUtils#zipDir');
Expand Down
25 changes: 24 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@
strip-ansi "6.0.1"
ts-retry-promise "^0.8.0"

"@salesforce/core@^7.3.1", "@salesforce/core@^7.3.5", "@salesforce/core@^7.3.6":
"@salesforce/core@^7.3.1", "@salesforce/core@^7.3.5":
version "7.3.6"
resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.3.6.tgz#b2769abf3d8cee6fef26741dd9bdbe977a497023"
integrity sha512-LngaY4GxixZ7X5oPGa00NdRzpqTXC8jPOQ/H+oFNiZb8nhMfYTBsQob258z33sIBf+G/5RZOJgX10Z+teJzt6A==
Expand All @@ -585,6 +585,29 @@
semver "^7.6.2"
ts-retry-promise "^0.7.1"

"@salesforce/core@^7.3.8":
version "7.3.8"
resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.3.8.tgz#8a646b5321f08c0fb4d22e2fa8b1d60b3a20df9b"
integrity sha512-VWhXHfjwjtC3pJWYp8wt5/fnNQ5tK61ovMG5eteXzVD2oFd7og1f6YjwuAzoYIZK7kYWWv7KJfGtCsPs7Zw+Ww==
dependencies:
"@jsforce/jsforce-node" "^3.2.0"
"@salesforce/kit" "^3.1.1"
"@salesforce/schemas" "^1.7.0"
"@salesforce/ts-types" "^2.0.9"
ajv "^8.13.0"
change-case "^4.1.2"
faye "^1.4.0"
form-data "^4.0.0"
js2xmlparser "^4.0.1"
jsonwebtoken "9.0.2"
jszip "3.10.1"
pino "^8.21.0"
pino-abstract-transport "^1.1.0"
pino-pretty "^10.3.1"
proper-lockfile "^4.1.2"
semver "^7.6.2"
ts-retry-promise "^0.7.1"

"@salesforce/dev-config@^4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@salesforce/dev-config/-/dev-config-4.1.0.tgz#e529576466d074e7a5f1441236510fef123da01e"
Expand Down

0 comments on commit 1c61c65

Please sign in to comment.