Skip to content

Commit

Permalink
fix: add a method that returns a 04t from a partial package descripto…
Browse files Browse the repository at this point in the history
…r entry
  • Loading branch information
shetzel committed May 9, 2024
1 parent 8bf0021 commit bea8753
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 78 deletions.
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

0 comments on commit bea8753

Please sign in to comment.