From 075d2da769b0f446df7d2f728f06a9119bfb900b Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Fri, 4 Nov 2022 16:10:45 -0600 Subject: [PATCH 1/5] fix: update imports to focus on main classes --- src/interfaces/packagingInterfacesAndType.ts | 2 +- src/package/index.ts | 4 ---- src/package/package.ts | 16 ++++++++++++++++ src/package/packageInstalledList.ts | 19 ------------------- src/package1/index.ts | 2 +- test/package/packageTest.nut.ts | 18 +++++++++--------- .../subscriberPackageVersionInstall.test.ts | 4 ++-- 7 files changed, 29 insertions(+), 36 deletions(-) delete mode 100644 src/package/packageInstalledList.ts diff --git a/src/interfaces/packagingInterfacesAndType.ts b/src/interfaces/packagingInterfacesAndType.ts index 88c110467..db26dbc1a 100644 --- a/src/interfaces/packagingInterfacesAndType.ts +++ b/src/interfaces/packagingInterfacesAndType.ts @@ -11,7 +11,7 @@ import { SaveResult } from 'jsforce'; import { Attributes } from 'graphology-types'; import { Optional } from '@salesforce/ts-types'; import { PackageProfileApi } from '../package/packageProfileApi'; -import { PackageAncestryNode } from '../package'; +import { PackageAncestryNode } from '../package/packageAncestry'; import { PackagingSObjects } from './packagingSObjects'; import Package2VersionStatus = PackagingSObjects.Package2VersionStatus; import PackageInstallRequest = PackagingSObjects.PackageInstallRequest; diff --git a/src/package/index.ts b/src/package/index.ts index 0fea472d3..dd57c10f3 100644 --- a/src/package/index.ts +++ b/src/package/index.ts @@ -5,10 +5,6 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ export * from './package'; -export * from './packageInstall'; export * from './packageVersion'; -export * from './packageVersionCreateRequest'; -export * from './packageInstalledList'; -export * from './packageVersionCreateRequestReport'; export * from './packageAncestry'; export * from './subscriberPackageVersion'; diff --git a/src/package/package.ts b/src/package/package.ts index 2dc2cc051..686de42b4 100644 --- a/src/package/package.ts +++ b/src/package/package.ts @@ -7,6 +7,7 @@ import { Connection, Messages, SfError, SfProject } from '@salesforce/core'; import { ConvertPackageOptions, + InstalledPackages, PackageCreateOptions, PackageOptions, PackageSaveResult, @@ -113,6 +114,21 @@ export class Package { )?.records; } + /** + * list the packages installed in the org + * + * @param conn: Connection to the org + */ + public static async installedList(conn: Connection): Promise { + try { + const query = + 'SELECT Id, SubscriberPackageId, SubscriberPackage.NamespacePrefix, SubscriberPackage.Name, SubscriberPackageVersion.Id, SubscriberPackageVersion.Name, SubscriberPackageVersion.MajorVersion, SubscriberPackageVersion.MinorVersion, SubscriberPackageVersion.PatchVersion, SubscriberPackageVersion.BuildNumber FROM InstalledSubscriberPackage ORDER BY SubscriberPackageId'; + return (await conn.tooling.query(query)).records; + } catch (err) { + throw applyErrorAction(massageErrorMessage(err as Error)); + } + } + /** * Returns the package versions in the org. * See {@link PackageVersionListOptions} for list options diff --git a/src/package/packageInstalledList.ts b/src/package/packageInstalledList.ts deleted file mode 100644 index ded76a87d..000000000 --- a/src/package/packageInstalledList.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020, salesforce.com, inc. - * All rights reserved. - * Licensed under the BSD 3-Clause license. - * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ -import { Connection } from '@salesforce/core'; -import { InstalledPackages } from '../interfaces'; -import { applyErrorAction, massageErrorMessage } from '../utils'; - -export async function packageInstalledList(conn: Connection): Promise { - try { - const query = - 'SELECT Id, SubscriberPackageId, SubscriberPackage.NamespacePrefix, SubscriberPackage.Name, SubscriberPackageVersion.Id, SubscriberPackageVersion.Name, SubscriberPackageVersion.MajorVersion, SubscriberPackageVersion.MinorVersion, SubscriberPackageVersion.PatchVersion, SubscriberPackageVersion.BuildNumber FROM InstalledSubscriberPackage ORDER BY SubscriberPackageId'; - return (await conn.tooling.query(query)).records; - } catch (err) { - throw applyErrorAction(massageErrorMessage(err as Error)); - } -} diff --git a/src/package1/index.ts b/src/package1/index.ts index 0fb60c31a..545f09352 100644 --- a/src/package1/index.ts +++ b/src/package1/index.ts @@ -4,4 +4,4 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -export * from './package1Version'; +export { Package1Version } from './package1Version'; diff --git a/test/package/packageTest.nut.ts b/test/package/packageTest.nut.ts index 457b2e932..153010d1c 100644 --- a/test/package/packageTest.nut.ts +++ b/test/package/packageTest.nut.ts @@ -8,7 +8,6 @@ import * as os from 'os'; import * as path from 'path'; import { expect } from 'chai'; import { readJSON } from 'fs-extra'; - import { TestSession, execCmd } from '@salesforce/cli-plugins-testkit'; import { Duration, sleep } from '@salesforce/kit'; import { ProjectJson } from '@salesforce/core/lib/sfProject'; @@ -21,17 +20,18 @@ import { AncestryRepresentationProducer, AncestryRepresentationProducerOptions, PackagingSObjects, - packageInstalledList, Package, PackageVersion, - AncestryJsonProducer, - PackageAncestry, - AncestryTreeProducer, - VersionNumber, PackageVersionEvents, } from '../../src/exported'; import { PackageEvents } from '../../src/interfaces'; -import { SubscriberPackageVersion } from '../../src/package/subscriberPackageVersion'; +import { + AncestryJsonProducer, + SubscriberPackageVersion, + AncestryTreeProducer, + PackageAncestry, +} from '../../src/package'; +import { VersionNumber } from '../../src/utils'; let session: TestSession; @@ -423,7 +423,7 @@ describe('Integration tests for @salesforce/packaging library', () => { it('packageInstalledList returns the correct information', async () => { const connection = scratchOrg.getConnection(); - const result = await packageInstalledList(connection); + const result = await Package.installedList(connection); const foundRecord = result.filter((item) => item.SubscriberPackageVersion.Id === subscriberPkgVersionId); expect(result).to.have.length.at.least(1); @@ -496,7 +496,7 @@ describe('Integration tests for @salesforce/packaging library', () => { }); it('gets zero results from packageInstalledList', async () => { - const result = await packageInstalledList(scratchOrg.getConnection()); + const result = await Package.installedList(scratchOrg.getConnection()); expect(result).to.have.length(0); }); }); diff --git a/test/package/subscriberPackageVersionInstall.test.ts b/test/package/subscriberPackageVersionInstall.test.ts index 4f2f8d9d9..1bc048321 100644 --- a/test/package/subscriberPackageVersionInstall.test.ts +++ b/test/package/subscriberPackageVersionInstall.test.ts @@ -9,9 +9,9 @@ import { expect } from 'chai'; import { Connection, Lifecycle, Messages } from '@salesforce/core'; import { QueryResult, SaveResult } from 'jsforce'; import { Duration } from '@salesforce/kit'; -import { isErrorPackageNotAvailable, isErrorFromSPVQueryRestriction } from '../../src/package'; +import { isErrorFromSPVQueryRestriction, isErrorPackageNotAvailable } from '../../src/package/packageInstall'; import { PackagingSObjects, PackageInstallCreateRequest, PackageInstallOptions } from '../../src/interfaces'; -import { SubscriberPackageVersion } from '../../src/package/subscriberPackageVersion'; +import { SubscriberPackageVersion } from '../../src/package'; import PackageInstallRequest = PackagingSObjects.PackageInstallRequest; const myPackageVersion04t = '04t6A0000000X0UQAU'; From ecaaedcc2c4018db6d49a75d85917d62c358e12b Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Mon, 7 Nov 2022 08:37:31 -0700 Subject: [PATCH 2/5] chore: bump to 1.0.0, remove consts, add Ancestry to PV --- package.json | 4 +-- src/constants.ts | 44 --------------------------------- src/package/index.ts | 1 - src/package/packageConvert.ts | 5 ++-- src/package/packageInstall.ts | 5 ++-- src/package/packageVersion.ts | 13 ++++++++++ test/package/packageTest.nut.ts | 8 ++---- 7 files changed, 21 insertions(+), 59 deletions(-) delete mode 100644 src/constants.ts diff --git a/package.json b/package.json index e6e365180..b8f28e988 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@salesforce/packaging", - "version": "0.1.20", + "version": "1.0.0", "description": "packing libraries to Salesforce packaging platform", "main": "lib/exported", "types": "lib/exported.d.ts", @@ -90,4 +90,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 931f88103..000000000 --- a/src/constants.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2022, salesforce.com, inc. - * All rights reserved. - * Licensed under the BSD 3-Clause license. - * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ - -/* -------------------------------------------------------------------------------------------------------------------- - * WARNING: This file has been deprecated and should now be considered locked against further changes. Its contents - * have been partially or wholly superseded by functionality included in the @salesforce/core npm package, and exists - * now to service prior uses in this repository only until they can be ported to use the new @salesforce/core library. - * - * If you need or want help deciding where to add new functionality or how to migrate to the new library, please - * contact the CLI team at alm-cli@salesforce.com. - * ----------------------------------------------------------------------------------------------------------------- */ - -import { Duration } from '@salesforce/kit'; - -export const consts = { - DEFAULT_USER_DIR_MODE: '700', - DEFAULT_USER_FILE_MODE: '600', - DEFAULT_STREAM_TIMEOUT_MINUTES: 6, - MIN_STREAM_TIMEOUT_MINUTES: 2, - DEFAULT_SRC_WAIT_MINUTES: 33, - DEFAULT_MDAPI_WAIT_MINUTES: 0, - DEFAULT_MDAPI_RETRIEVE_WAIT_MINUTES: -1, - DEFAULT_MDAPI_POLL_INTERVAL_MINUTES: 0.1, - DEFAULT_MDAPI_POLL_INTERVAL_MILLISECONDS: 0.1 * 60 * 1000, - MIN_SRC_WAIT_MINUTES: 1, - MIN_SRC_DEPLOY_WAIT_MINUTES: 0, - WORKSPACE_CONFIG_FILENAME: 'sfdx-project.json', - OLD_WORKSPACE_CONFIG_FILENAME: 'sfdx-workspace.json', - DEFAULT_DEV_HUB_USERNAME: 'defaultdevhubusername', - DEFAULT_USERNAME: 'defaultusername', - ACKNOWLEDGED_USAGE_COLLECTION_FILENAME: 'acknowledgedUsageCollection.json', - PACKAGE_VERSION_INFO_FILE_ZIP: 'package-version-info.zip', - // tokens to be replaced on source:push - INSTANCE_URL_TOKEN: '__SFDX_INSTANCE_URL__', - PACKAGE2_DESCRIPTOR_FILE: 'package2-descriptor.json', - PACKAGE_INSTALL_POLL_FREQUENCY: 5000, // 5000ms - PACKAGE_INSTALL_POLL_TIMEOUT: 5, // 5 minutes - PACKAGE_PUBLISH_POLL_FREQUENCY: Duration.milliseconds(0), // 0ms - PACKAGE_PUBLISH_POLL_TIMEOUT: Duration.milliseconds(0), // 0ms -}; diff --git a/src/package/index.ts b/src/package/index.ts index dd57c10f3..72a21c006 100644 --- a/src/package/index.ts +++ b/src/package/index.ts @@ -6,5 +6,4 @@ */ export * from './package'; export * from './packageVersion'; -export * from './packageAncestry'; export * from './subscriberPackageVersion'; diff --git a/src/package/packageConvert.ts b/src/package/packageConvert.ts index 6a5111378..bea03aaf9 100644 --- a/src/package/packageConvert.ts +++ b/src/package/packageConvert.ts @@ -31,7 +31,6 @@ import { PackageVersionCreateEventData, PackageEvents, } from '../interfaces'; -import { consts } from '../constants'; import * as srcDevUtil from '../utils/srcDevUtils'; import { generatePackageAliasEntry } from '../utils'; import { byId } from './packageVersionCreateRequest'; @@ -154,7 +153,7 @@ export async function createPackageVersionCreateRequest( const packageVersBlobDirectory = path.join(packageVersTmpRoot, 'package-version-info'); const settingsZipFile = path.join(packageVersBlobDirectory, 'settings.zip'); const metadataZipFile = path.join(packageVersBlobDirectory, 'package.zip'); - const packageVersBlobZipFile = path.join(packageVersTmpRoot, consts.PACKAGE_VERSION_INFO_FILE_ZIP); + const packageVersBlobZipFile = path.join(packageVersTmpRoot, 'package-version-info.zip'); const packageDescriptorJson = { id: packageId, @@ -205,7 +204,7 @@ export async function createPackageVersionCreateRequest( // Zip the packageVersMetadataFolder folder and put the zip in {packageVersBlobDirectory}/package.zip await srcDevUtil.zipDir(packageVersMetadataFolder, metadataZipFile); await fs.promises.writeFile( - path.join(packageVersBlobDirectory, consts.PACKAGE2_DESCRIPTOR_FILE), + path.join(packageVersBlobDirectory, 'package2-descriptor.json'), JSON.stringify(packageDescriptorJson, undefined, 2) ); // Zip the Version Info and package.zip files into another zip diff --git a/src/package/packageInstall.ts b/src/package/packageInstall.ts index a784d66ef..650815bdc 100644 --- a/src/package/packageInstall.ts +++ b/src/package/packageInstall.ts @@ -17,7 +17,6 @@ import { PackageType, PackageInstallOptions, } from '../interfaces'; -import { consts } from '../constants'; import SubscriberPackageVersion = PackagingSObjects.SubscriberPackageVersion; import PackageInstallRequest = PackagingSObjects.PackageInstallRequest; @@ -179,9 +178,9 @@ export async function pollStatus( let packageInstallRequest: PackageInstallRequest; const { pollingFrequency, pollingTimeout } = options; - const frequency = numberToDuration(pollingFrequency || consts.PACKAGE_INSTALL_POLL_FREQUENCY); + const frequency = numberToDuration(pollingFrequency || 5000); - const timeout = numberToDuration(pollingTimeout || consts.PACKAGE_INSTALL_POLL_TIMEOUT); + const timeout = numberToDuration(pollingTimeout || 300000); const pollingOptions: Partial = { frequency, diff --git a/src/package/packageVersion.ts b/src/package/packageVersion.ts index 7d87f3cbc..e366531de 100644 --- a/src/package/packageVersion.ts +++ b/src/package/packageVersion.ts @@ -33,6 +33,7 @@ import { PackageVersionCreate } from './packageVersionCreate'; import { getPackageVersionReport } from './packageVersionReport'; import { getCreatePackageVersionCreateRequestReport } from './packageVersionCreateRequestReport'; import { list } from './packageVersionCreateRequest'; +import { PackageAncestry } from './packageAncestry'; import Package2 = PackagingSObjects.Package2; import Package2VersionStatus = PackagingSObjects.Package2VersionStatus; @@ -99,6 +100,18 @@ export class PackageVersion { } } + public static async getAncestry( + packageId: string, + project: SfProject, + connection: Connection + ): Promise { + return PackageAncestry.create({ + packageId, + project, + connection, + }); + } + /** * Sends a request to create a new package version and optionally polls for * the status of the request until the package version is created or the diff --git a/test/package/packageTest.nut.ts b/test/package/packageTest.nut.ts index 153010d1c..c7d9c017f 100644 --- a/test/package/packageTest.nut.ts +++ b/test/package/packageTest.nut.ts @@ -25,13 +25,9 @@ import { PackageVersionEvents, } from '../../src/exported'; import { PackageEvents } from '../../src/interfaces'; -import { - AncestryJsonProducer, - SubscriberPackageVersion, - AncestryTreeProducer, - PackageAncestry, -} from '../../src/package'; +import { SubscriberPackageVersion } from '../../src/package'; import { VersionNumber } from '../../src/utils'; +import { AncestryJsonProducer, AncestryTreeProducer, PackageAncestry } from '../../src/package/packageAncestry'; let session: TestSession; From 94a544b47cbe1e0c314b2fcf01a1074cbde5e889 Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Mon, 7 Nov 2022 13:29:47 -0700 Subject: [PATCH 3/5] refactor: limit exports, update imports, consolidate utils, remove refactor'd code --- src/package/index.ts | 1 + src/package/package.ts | 17 +--- src/package/packageAncestry.ts | 5 +- src/package/packageConvert.ts | 24 +++-- src/package/packageDelete.ts | 8 +- src/package/packageInstall.ts | 2 +- src/package/packageUninstall.ts | 2 +- src/package/packageVersion.ts | 14 +-- src/package/packageVersionCreate.ts | 22 +++-- src/package/packageVersionCreateRequest.ts | 2 +- src/package/packageVersionList.ts | 2 +- src/package/subscriberPackageVersion.ts | 11 +-- src/{utils => package}/versionNumber.ts | 0 src/utils/index.ts | 4 +- src/utils/packageUtils.ts | 91 +++++++++++++------ src/utils/srcDevUtils.ts | 65 ------------- src/utils/uniqid.ts | 30 ------ test/package/package.test.ts | 21 +++-- test/package/packageTest.nut.ts | 2 +- test/{utils => package}/versionNumber.test.ts | 2 +- test/utils/packageUtils.test.ts | 91 +++++++++++-------- test/utils/srcDevUtils.test.ts | 56 ------------ 22 files changed, 172 insertions(+), 300 deletions(-) rename src/{utils => package}/versionNumber.ts (100%) delete mode 100644 src/utils/srcDevUtils.ts delete mode 100644 src/utils/uniqid.ts rename test/{utils => package}/versionNumber.test.ts (97%) delete mode 100644 test/utils/srcDevUtils.test.ts diff --git a/src/package/index.ts b/src/package/index.ts index 72a21c006..ab192ae0d 100644 --- a/src/package/index.ts +++ b/src/package/index.ts @@ -7,3 +7,4 @@ export * from './package'; export * from './packageVersion'; export * from './subscriberPackageVersion'; +export { VersionNumber } from './versionNumber'; diff --git a/src/package/package.ts b/src/package/package.ts index 686de42b4..60a0d9232 100644 --- a/src/package/package.ts +++ b/src/package/package.ts @@ -18,16 +18,8 @@ import { PackageVersionListResult, PackagingSObjects, } from '../interfaces'; -import { - applyErrorAction, - BY_LABEL, - getPackageAliasesFromId, - getPackageIdFromAlias, - massageErrorMessage, - validateId, -} from '../utils'; +import { applyErrorAction, BY_LABEL, massageErrorMessage, validateId } from '../utils/packageUtils'; import { createPackage } from './packageCreate'; - import { convertPackage } from './packageConvert'; import { listPackageVersions } from './packageVersionList'; import { deletePackage } from './packageDelete'; @@ -73,7 +65,8 @@ export class Package { public constructor(private options: PackageOptions) { let packageId = this.options.packageAliasOrId; if (!packageId.startsWith(packagePrefixes.PackageId)) { - packageId = getPackageIdFromAlias(this.options.packageAliasOrId, this.options.project); + packageId = + this.options.project.getPackageIdFromAlias(this.options.packageAliasOrId) ?? this.options.packageAliasOrId; if (packageId === this.options.packageAliasOrId) { throw messages.createError('packageAliasNotFound', [this.options.packageAliasOrId]); } @@ -144,7 +137,7 @@ export class Package { ): Promise { // resolve/verify packages const packages = options?.packages?.map((pkg) => { - const id = getPackageIdFromAlias(pkg, project); + const id = project.getPackageIdFromAlias(pkg) ?? pkg; // validate ID if (id.startsWith('0Ho')) { @@ -266,7 +259,7 @@ export class Package { } private verifyAliasForId(): void { - if (getPackageAliasesFromId(this.packageId, this.options.project).length === 0) { + if (this.options.project.getAliasesFromPackageId(this.packageId).length === 0) { throw new SfError(messages.getMessage('couldNotFindAliasForId', [this.packageId])); } } diff --git a/src/package/packageAncestry.ts b/src/package/packageAncestry.ts index 45d64ce39..97eda74b9 100644 --- a/src/package/packageAncestry.ts +++ b/src/package/packageAncestry.ts @@ -20,9 +20,9 @@ import { PackageType, } from '../interfaces'; import * as pkgUtils from '../utils/packageUtils'; -import { VersionNumber } from '../utils'; import { PackageVersion } from './packageVersion'; import { Package } from './package'; +import { VersionNumber } from './versionNumber'; Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/packaging', 'package_ancestry'); @@ -204,7 +204,8 @@ export class PackageAncestry extends AsyncCreatable { private async getRoots(): Promise { let roots: PackageAncestryNode[] = []; - this.#requestedPackageId = pkgUtils.getPackageIdFromAlias(this.options.packageId, this.options.project); + this.#requestedPackageId = + this.options.project.getPackageIdFromAlias(this.options.packageId) ?? this.options.packageId; switch (this.requestedPackageId.slice(0, 3)) { case '0Ho': pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, this.requestedPackageId); diff --git a/src/package/packageConvert.ts b/src/package/packageConvert.ts index bea03aaf9..9bcfa524f 100644 --- a/src/package/packageConvert.ts +++ b/src/package/packageConvert.ts @@ -22,7 +22,7 @@ import { import { camelCaseToTitleCase, Duration } from '@salesforce/kit'; import { Many } from '@salesforce/ts-types'; import SettingsGenerator from '@salesforce/core/lib/org/scratchOrgSettingsGenerator'; -import { uniqid } from '../utils/uniqid'; +import { genUniqueString } from '@salesforce/cli-plugins-testkit'; import * as pkgUtils from '../utils/packageUtils'; import { PackagingSObjects, @@ -31,8 +31,7 @@ import { PackageVersionCreateEventData, PackageEvents, } from '../interfaces'; -import * as srcDevUtil from '../utils/srcDevUtils'; -import { generatePackageAliasEntry } from '../utils'; +import { generatePackageAliasEntry } from '../utils/packageUtils'; import { byId } from './packageVersionCreateRequest'; import * as pvcr from './packageVersionCreateRequest'; import Package2VersionStatus = PackagingSObjects.Package2VersionStatus; @@ -106,7 +105,6 @@ export async function convertPackage( ); // TODO: a lot of this is duplicated from PC, PVC, and PVCR. - const createResult = await connection.tooling.create('Package2VersionCreateRequest', request); if (!createResult.success) { const errStr = createResult?.errors.length ? createResult.errors.join(', ') : createResult.errors; @@ -147,7 +145,7 @@ export async function createPackageVersionCreateRequest( packageId: string, apiVersion: string ): Promise { - const uniqueId = uniqid({ template: `${packageId}-%s` }); + const uniqueId = genUniqueString(`${packageId}-%s`); const packageVersTmpRoot = path.join(os.tmpdir(), uniqueId); const packageVersMetadataFolder = path.join(packageVersTmpRoot, 'md-files'); const packageVersBlobDirectory = path.join(packageVersTmpRoot, 'package-version-info'); @@ -193,7 +191,7 @@ export async function createPackageVersionCreateRequest( await settingsGenerator.createDeploy(); await settingsGenerator.createDeployPackageContents(apiVersion); - await srcDevUtil.zipDir( + await pkgUtils.zipDir( `${settingsGenerator.getDestinationPath()}${path.sep}${settingsGenerator.getShapeDirName()}`, settingsZipFile ); @@ -202,13 +200,13 @@ export async function createPackageVersionCreateRequest( const currentPackageXml = await fs.promises.readFile(path.join(shapeDirectory, 'package.xml'), 'utf8'); await fs.promises.writeFile(path.join(packageVersMetadataFolder, 'package.xml'), currentPackageXml, 'utf-8'); // Zip the packageVersMetadataFolder folder and put the zip in {packageVersBlobDirectory}/package.zip - await srcDevUtil.zipDir(packageVersMetadataFolder, metadataZipFile); + await pkgUtils.zipDir(packageVersMetadataFolder, metadataZipFile); await fs.promises.writeFile( path.join(packageVersBlobDirectory, 'package2-descriptor.json'), JSON.stringify(packageDescriptorJson, undefined, 2) ); // Zip the Version Info and package.zip files into another zip - await srcDevUtil.zipDir(packageVersBlobDirectory, packageVersBlobZipFile); + await pkgUtils.zipDir(packageVersBlobDirectory, packageVersBlobZipFile); return createRequestObject(packageId, context, packageVersTmpRoot, packageVersBlobZipFile); } @@ -235,7 +233,7 @@ async function pollForStatusWithInterval( retries: number, packageId: string, branch: string, - withProject: SfProject, + project: SfProject, connection: Connection, interval: Duration ): Promise { @@ -249,7 +247,7 @@ async function pollForStatusWithInterval( if (isStatusEqualTo(results, [Package2VersionStatus.success])) { // update sfdx-project.json let projectUpdated = false; - if (withProject && !process.env.SFDX_PROJECT_AUTOUPDATE_DISABLE_FOR_PACKAGE_VERSION_CREATE) { + if (project && !process.env.SFDX_PROJECT_AUTOUPDATE_DISABLE_FOR_PACKAGE_VERSION_CREATE) { projectUpdated = true; const query = `SELECT MajorVersion, MinorVersion, PatchVersion, BuildNumber FROM Package2Version WHERE Id = '${results[0].Package2VersionId}'`; const packageVersionVersionString: string = await connection.tooling @@ -260,14 +258,14 @@ async function pollForStatusWithInterval( }); const [alias, writtenId] = await generatePackageAliasEntry( connection, - withProject, + project, results[0].SubscriberPackageVersionId, packageVersionVersionString, branch, packageId ); - withProject.getSfProjectJson().addPackageAlias(alias, writtenId); - await withProject.getSfProjectJson().write(); + project.getSfProjectJson().addPackageAlias(alias, writtenId); + await project.getSfProjectJson().write(); } await Lifecycle.getInstance().emit(PackageEvents.convert.success, { id, diff --git a/src/package/packageDelete.ts b/src/package/packageDelete.ts index d79b602b5..43d0139ac 100644 --- a/src/package/packageDelete.ts +++ b/src/package/packageDelete.ts @@ -6,10 +6,8 @@ */ import { Connection, SfProject } from '@salesforce/core'; -import * as pkgUtils from '../utils/packageUtils'; -import { combineSaveErrors } from '../utils'; +import { combineSaveErrors, applyErrorAction, massageErrorMessage, validateId, BY_LABEL } from '../utils/packageUtils'; import { PackageSaveResult } from '../interfaces'; -import { applyErrorAction, massageErrorMessage } from '../utils/packageUtils'; export async function deletePackage( idOrAlias: string, @@ -17,8 +15,8 @@ export async function deletePackage( connection: Connection, undelete: boolean ): Promise { - const packageId = pkgUtils.getPackageIdFromAlias(idOrAlias, project); - pkgUtils.validateId(pkgUtils.BY_LABEL.PACKAGE_ID, packageId); + const packageId = project.getPackageIdFromAlias(idOrAlias) ?? idOrAlias; + validateId(BY_LABEL.PACKAGE_ID, packageId); const request = {} as { Id: string; IsDeprecated: boolean }; request.Id = packageId; diff --git a/src/package/packageInstall.ts b/src/package/packageInstall.ts index 650815bdc..e1807f9ff 100644 --- a/src/package/packageInstall.ts +++ b/src/package/packageInstall.ts @@ -9,7 +9,7 @@ import { Connection, Lifecycle, Logger, Messages, PollingClient, SfError, Status import { isString } from '@salesforce/ts-types'; import { QueryResult } from 'jsforce'; import { Duration } from '@salesforce/kit'; -import { escapeInstallationKey, numberToDuration } from '../utils'; +import { escapeInstallationKey, numberToDuration } from '../utils/packageUtils'; import { PackagingSObjects, PackageInstallCreateRequest, diff --git a/src/package/packageUninstall.ts b/src/package/packageUninstall.ts index d9dd7a68e..3c84c0786 100644 --- a/src/package/packageUninstall.ts +++ b/src/package/packageUninstall.ts @@ -8,7 +8,7 @@ import * as os from 'os'; import { Connection, Lifecycle, Messages, PollingClient, SfError } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; import { PackageEvents, PackagingSObjects } from '../interfaces'; -import { applyErrorAction, massageErrorMessage } from '../utils'; +import { applyErrorAction, massageErrorMessage } from '../utils/packageUtils'; Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/packaging', 'package_uninstall'); diff --git a/src/package/packageVersion.ts b/src/package/packageVersion.ts index e366531de..8e05f7c4c 100644 --- a/src/package/packageVersion.ts +++ b/src/package/packageVersion.ts @@ -20,15 +20,7 @@ import { PackageVersionUpdateOptions, PackagingSObjects, } from '../interfaces'; -import { - applyErrorAction, - BY_LABEL, - combineSaveErrors, - getPackageAliasesFromId, - getPackageIdFromAlias, - massageErrorMessage, - validateId, -} from '../utils'; +import { applyErrorAction, BY_LABEL, combineSaveErrors, massageErrorMessage, validateId } from '../utils/packageUtils'; import { PackageVersionCreate } from './packageVersionCreate'; import { getPackageVersionReport } from './packageVersionReport'; import { getCreatePackageVersionCreateRequestReport } from './packageVersionCreateRequestReport'; @@ -560,7 +552,7 @@ export class PackageVersion { `SELECT Branch, MajorVersion, MinorVersion, PatchVersion, BuildNumber FROM Package2Version WHERE SubscriberPackageVersionId='${results.SubscriberPackageVersionId}'` ) ).records[0]; - const version = `${getPackageAliasesFromId(results.Package2Id, this.project).join()}@${ + const version = `${this.project.getAliasesFromPackageId(results.Package2Id).join()}@${ versionResult.MajorVersion ?? 0 }.${versionResult.MinorVersion ?? 0}.${versionResult.PatchVersion ?? 0}`; const build = versionResult.BuildNumber ? `-${versionResult.BuildNumber}` : ''; @@ -572,6 +564,6 @@ export class PackageVersion { } } private resolveId(): string { - return getPackageIdFromAlias(this.options.idOrAlias, this.project); + return this.project.getPackageIdFromAlias(this.options.idOrAlias) ?? this.options.idOrAlias; } } diff --git a/src/package/packageVersionCreate.ts b/src/package/packageVersionCreate.ts index 089c46428..abc96b785 100644 --- a/src/package/packageVersionCreate.ts +++ b/src/package/packageVersionCreate.ts @@ -23,9 +23,8 @@ import { ComponentSetBuilder, ConvertResult, MetadataConverter } from '@salesfor import SettingsGenerator from '@salesforce/core/lib/org/scratchOrgSettingsGenerator'; import * as xml2js from 'xml2js'; import { PackageDirDependency } from '@salesforce/core/lib/sfProject'; -import { uniqid } from '../utils/uniqid'; +import { genUniqueString } from '@salesforce/cli-plugins-testkit'; import * as pkgUtils from '../utils/packageUtils'; -import { BuildNumberToken, VersionNumber } from '../utils'; import { MDFolderForArtifactOptions, PackageDescriptorJson, @@ -38,17 +37,17 @@ import { } from '../interfaces'; import { BY_LABEL, - getPackageIdFromAlias, getPackageVersionId, getPackageVersionNumber, validateId, VERSION_NUMBER_SEP, copyDir, zipDir, -} from '../utils'; +} from '../utils/packageUtils'; import { PackageProfileApi } from './packageProfileApi'; import { byId } from './packageVersionCreateRequest'; import { Package } from './package'; +import { BuildNumberToken, VersionNumber } from './versionNumber'; Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/packaging', 'package_version_create'); @@ -123,7 +122,9 @@ export class PackageVersionCreate { throw messages.createError('errorPackageAndPackageIdCollision', []); } - const packageIdFromAlias = pkgUtils.getPackageIdFromAlias(dependency.packageId || dependency.package, this.project); + const packageIdFromAlias = + this.project.getPackageIdFromAlias(dependency.packageId || dependency.package) ?? + (dependency.packageId || dependency.package); // If valid 04t package, just return it to be used straight away. if (pkgUtils.validateIdNoThrow(pkgUtils.BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, packageIdFromAlias)) { @@ -302,7 +303,7 @@ export class PackageVersionCreate { */ private async createPackageVersionCreateRequestFromOptions(): Promise { const preserveFiles = !!(this.options.preserve || process.env.SFDX_PACKAGE2_VERSION_CREATE_PRESERVE); - const uniqueHash = uniqid({ template: `${this.packageId}-%s` }); + const uniqueHash = genUniqueString(`${this.packageId}-%s`); const packageVersTmpRoot = path.join(os.tmpdir(), `${uniqueHash}`); const packageVersMetadataFolder = path.join(packageVersTmpRoot, 'md-files'); const unpackagedMetadataFolder = path.join(packageVersTmpRoot, 'unpackaged-md-files'); @@ -621,7 +622,7 @@ export class PackageVersionCreate { ]); } - this.packageId = this.project.getPackageIdFromAlias(packageName) || packageName; + this.packageId = this.project.getPackageIdFromAlias(packageName) ?? packageName; this.options.profileApi = await this.resolveUserLicenses(this.packageObject.includeProfileUserLicenses); @@ -808,7 +809,10 @@ export class PackageVersionCreate { skipAncestorCheck: boolean ): Promise { // If an id property is present, use it. Otherwise, look up the package id from the package property. - const packageId = packageDescriptorJson.id ?? getPackageIdFromAlias(packageDescriptorJson.package, project); + const packageId = + packageDescriptorJson.id ?? + project.getPackageIdFromAlias(packageDescriptorJson.package) ?? + packageDescriptorJson.package; // No need to proceed if Unlocked if ((await this.getPackageType()) === 'Unlocked') { @@ -862,7 +866,7 @@ export class PackageVersionCreate { // highestReleasedVersion should be null only if skipAncestorCheck or if there is no existing released package version if (!explicitUseNoAncestor && packageDescriptorJson.ancestorId) { - ancestorId = getPackageIdFromAlias(packageDescriptorJson.ancestorId, project); + ancestorId = project.getPackageIdFromAlias(packageDescriptorJson.ancestorId) ?? packageDescriptorJson.ancestorId; validateId([BY_LABEL.SUBSCRIBER_PACKAGE_VERSION_ID, BY_LABEL.PACKAGE_VERSION_ID], ancestorId); ancestorId = await getPackageVersionId(ancestorId, this.connection); } diff --git a/src/package/packageVersionCreateRequest.ts b/src/package/packageVersionCreateRequest.ts index fd8fc3dda..6d7e5717e 100644 --- a/src/package/packageVersionCreateRequest.ts +++ b/src/package/packageVersionCreateRequest.ts @@ -13,7 +13,7 @@ import { PackageVersionCreateRequestQueryOptions, PackagingSObjects, } from '../interfaces'; -import { applyErrorAction, massageErrorMessage } from '../utils'; +import { applyErrorAction, massageErrorMessage } from '../utils/packageUtils'; Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/packaging', 'package_version_create'); diff --git a/src/package/packageVersionList.ts b/src/package/packageVersionList.ts index e0be215e7..ed0ef6902 100644 --- a/src/package/packageVersionList.ts +++ b/src/package/packageVersionList.ts @@ -8,7 +8,7 @@ import { Logger, Messages } from '@salesforce/core'; import { QueryResult, Schema } from 'jsforce'; import { isNumber } from '@salesforce/ts-types'; -import { BY_LABEL, validateId } from '../utils'; +import { BY_LABEL, validateId } from '../utils/packageUtils'; import { PackageVersionListResult, PackageVersionListOptions, ListPackageVersionOptions } from '../interfaces'; Messages.importMessagesDirectory(__dirname); diff --git a/src/package/subscriberPackageVersion.ts b/src/package/subscriberPackageVersion.ts index 61ff073c0..16f1641f4 100644 --- a/src/package/subscriberPackageVersion.ts +++ b/src/package/subscriberPackageVersion.ts @@ -15,15 +15,10 @@ import { PackagingSObjects, SubscriberPackageVersionOptions, } from '../interfaces'; -import { - applyErrorAction, - escapeInstallationKey, - massageErrorMessage, - numberToDuration, - VersionNumber, -} from '../utils'; +import { applyErrorAction, escapeInstallationKey, massageErrorMessage, numberToDuration } from '../utils/packageUtils'; import { createPackageInstallRequest, getStatus, pollStatus, waitForPublish } from './packageInstall'; import { getUninstallErrors, uninstallPackage } from './packageUninstall'; +import { VersionNumber } from './versionNumber'; Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/packaging', 'subscriber_package_version'); @@ -110,7 +105,7 @@ export class SubscriberPackageVersion { try { const project = SfProject.getInstance(); - this.id = project.getPackageIdFromAlias(this.options.aliasOrId) || this.options.aliasOrId; + this.id = project.getPackageIdFromAlias(this.options.aliasOrId) ?? this.options.aliasOrId; } catch (error) { const err = (error as Error).message; getLogger().debug(err); diff --git a/src/utils/versionNumber.ts b/src/package/versionNumber.ts similarity index 100% rename from src/utils/versionNumber.ts rename to src/package/versionNumber.ts diff --git a/src/utils/index.ts b/src/utils/index.ts index 7f892799d..00118bf5a 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,6 +4,4 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -export * from './packageUtils'; -export * from './srcDevUtils'; -export * from './versionNumber'; +export { INSTALL_URL_BASE, getContainerOptions, getPackageVersionStrings } from './packageUtils'; diff --git a/src/utils/packageUtils.ts b/src/utils/packageUtils.ts index 3d972a999..ab5ae3bef 100644 --- a/src/utils/packageUtils.ts +++ b/src/utils/packageUtils.ts @@ -5,10 +5,17 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import * as os from 'os'; +import * as fs from 'fs'; +import { join } from 'path'; +import { pipeline as cbPipeline } from 'stream'; +import { promisify } from 'util'; import { Connection, Messages, NamedPackageDir, PackageDir, SfdcUrl, SfError, SfProject } from '@salesforce/core'; import { isNumber, Many, Nullable, Optional } from '@salesforce/ts-types'; import { SaveError } from 'jsforce'; import { Duration } from '@salesforce/kit'; +import { Logger } from '@salesforce/core'; +import * as globby from 'globby'; +import * as JSZIP from 'jszip'; import { PackageType, PackagingSObjects } from '../interfaces'; Messages.importMessagesDirectory(__dirname); @@ -377,7 +384,7 @@ export function getPackageVersionNumber(package2VersionObj: PackagingSObjects.Pa return version.slice(0, version.lastIndexOf('.')); } -// TODO: replace with sfProject.getPackageDirectoryWithProperty() +// TODO: replace with sfProject.getPackageDirectoryWithProperty(), still needs to be moved export function getConfigPackageDirectory( packageDirs: NamedPackageDir[] | PackageDir[], lookupProperty: string, @@ -385,34 +392,6 @@ export function getConfigPackageDirectory( ): NamedPackageDir | PackageDir | undefined { return packageDirs?.find((pkgDir) => pkgDir[lookupProperty] === lookupValue); } -/** - * Given a packageAlias, attempt to return the associated id from the config - * - * @param packageAlias string representing a package alias - * @param project for obtaining the project config - * @returns the associated id or the arg given. - */ -// TODO: replace with SfProject.getPackageIdFromAlias() -export function getPackageIdFromAlias(packageAlias: string, project: SfProject): string { - const packageAliases = project.getSfProjectJson().getContents().packageAliases || {}; - // return alias if it exists, otherwise return what was passed in - return packageAliases[packageAlias] || packageAlias; -} -/** - * Given a package id, attempt to return the associated aliases from the config - * - * @param packageId string representing a package id - * @param project for obtaining the project config - * @returns an array of alias for the given id. - */ -// TODO: replace with SfProject.getAliasesFromPackageId() -export function getPackageAliasesFromId(packageId: string, project: SfProject): string[] { - const packageAliases = project?.getSfProjectJson().getContents().packageAliases || {}; - // check for a matching alias - return Object.entries(packageAliases) - .filter((alias) => alias[1] === packageId) - .map((alias) => alias[0]); -} /** * Generate package alias json entry for this package version that can be written to sfdx-project.json @@ -434,7 +413,7 @@ export async function generatePackageAliasEntry( branch: string, packageId: string ): Promise<[string, string]> { - const aliasForPackageId = getPackageAliasesFromId(packageId, project); + const aliasForPackageId = project.getAliasesFromPackageId(packageId); let packageName: Optional; if (aliasForPackageId?.length === 0) { const query = `SELECT Name FROM Package2 WHERE Id = '${packageId}'`; @@ -478,3 +457,55 @@ export function numberToDuration( ): Duration { return isNumber(duration) ? new Duration(duration, unit) : duration; } + +const pipeline = promisify(cbPipeline); + +/** + * Zips directory to given zipfile. + * + * https://github.com/archiverjs/node-archiver + * + * @param dir to zip + * @param zipfile + */ +export async function zipDir(dir: string, zipfile: string): Promise { + const logger = Logger.childFromRoot('srcDevUtils#zipDir'); + + const timer = process.hrtime(); + const globbyResult: string[] = await globby('**/*', { expandDirectories: true, cwd: dir }); + const zip = new JSZIP(); + // add files tp zip + for (const file of globbyResult) { + zip.file(file, fs.readFileSync(join(dir, file))); + } + // write zip to file + const zipStream = zip.generateNodeStream({ + type: 'nodebuffer', + streamFiles: true, + compression: 'DEFLATE', + compressionOptions: { + level: 3, + }, + }); + await pipeline(zipStream, fs.createWriteStream(zipfile)); + const stat = fs.statSync(zipfile); + logger.debug(`${stat.size} bytes written to ${zipfile} in ${getElapsedTime(timer)}ms`); + return; +} + +export function getElapsedTime(timer: [number, number]): string { + const elapsed = process.hrtime(timer); + return (elapsed[0] * 1000 + elapsed[1] / 1000000).toFixed(3); +} + +export function copyDir(src: string, dest: string): void { + fs.mkdirSync(dest, { recursive: true }); + const entries = fs.readdirSync(src, { withFileTypes: true }); + + entries.map((entry) => { + const srcPath = join(src, entry.name); + const destPath = join(dest, entry.name); + + return entry.isDirectory() ? copyDir(srcPath, destPath) : fs.copyFileSync(srcPath, destPath); + }); +} diff --git a/src/utils/srcDevUtils.ts b/src/utils/srcDevUtils.ts deleted file mode 100644 index 030fce7f6..000000000 --- a/src/utils/srcDevUtils.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2020, salesforce.com, inc. - * All rights reserved. - * Licensed under the BSD 3-Clause license. - * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ -import * as fs from 'fs'; -import { join } from 'path'; -import { pipeline as cbPipeline } from 'stream'; -import { promisify } from 'util'; -import { Logger } from '@salesforce/core'; -import * as globby from 'globby'; -import * as JSZIP from 'jszip'; - -const pipeline = promisify(cbPipeline); - -/** - * Zips directory to given zipfile. - * - * https://github.com/archiverjs/node-archiver - * - * @param dir to zip - * @param zipfile - */ -export async function zipDir(dir: string, zipfile: string): Promise { - const logger = Logger.childFromRoot('srcDevUtils#zipDir'); - - const timer = process.hrtime(); - const globbyResult: string[] = await globby('**/*', { expandDirectories: true, cwd: dir }); - const zip = new JSZIP(); - // add files tp zip - for (const file of globbyResult) { - zip.file(file, fs.readFileSync(join(dir, file))); - } - // write zip to file - const zipStream = zip.generateNodeStream({ - type: 'nodebuffer', - streamFiles: true, - compression: 'DEFLATE', - compressionOptions: { - level: 3, - }, - }); - await pipeline(zipStream, fs.createWriteStream(zipfile)); - const stat = fs.statSync(zipfile); - logger.debug(`${stat.size} bytes written to ${zipfile} in ${getElapsedTime(timer)}ms`); - return; -} - -export function getElapsedTime(timer: [number, number]): string { - const elapsed = process.hrtime(timer); - return (elapsed[0] * 1000 + elapsed[1] / 1000000).toFixed(3); -} - -export function copyDir(src: string, dest: string): void { - fs.mkdirSync(dest, { recursive: true }); - const entries = fs.readdirSync(src, { withFileTypes: true }); - - entries.map((entry) => { - const srcPath = join(src, entry.name); - const destPath = join(dest, entry.name); - - return entry.isDirectory() ? copyDir(srcPath, destPath) : fs.copyFileSync(srcPath, destPath); - }); -} diff --git a/src/utils/uniqid.ts b/src/utils/uniqid.ts deleted file mode 100644 index 7efd14a65..000000000 --- a/src/utils/uniqid.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2022, salesforce.com, inc. - * All rights reserved. - * Licensed under the BSD 3-Clause license. - * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ -import { randomBytes } from 'crypto'; -import * as util from 'util'; - -/** - * A function to generate a unique id and return it in the context of a template, if supplied. - * - * A template is a string that can contain `${%s}` to be replaced with a unique id. - * If the template contains the "%s" placeholder, it will be replaced with the unique id otherwise the id will be appended to the template. - * - * @param options an object with the following properties: - * - template: a template string. - * - length: the length of the unique id as presented in hexadecimal. - */ -export function uniqid(options?: { template?: string; length?: number }): string { - const uniqueString = randomBytes(Math.ceil((options?.length ?? 32) / 2.0)) - .toString('hex') - .slice(0, options?.length ?? 32); - if (!options?.template) { - return uniqueString; - } - return options.template.includes('%s') - ? util.format(options.template, uniqueString) - : `${options.template}${uniqueString}`; -} diff --git a/test/package/package.test.ts b/test/package/package.test.ts index e8021b4fc..e0585e94d 100644 --- a/test/package/package.test.ts +++ b/test/package/package.test.ts @@ -42,6 +42,7 @@ async function setupProject(setup: (project: SfProject) => void = () => {}) { describe('Package', () => { const $$ = instantiateContext(); let project: SfProject; + const pkgId = '0Hoasdsadfasdfa'; beforeEach(() => { stubContext($$); @@ -78,25 +79,25 @@ describe('Package', () => { it('should create a new package - from alias', async () => { $$.inProject(true); project = await setupProject((p) => { - p.getSfProjectJson().set('packageAliases', { mypkgalias: '0Hoasdsadfasdf' }); + p.getSfProjectJson().set('packageAliases', { mypkgalias: pkgId }); }); const pkg = new Package({ connection: undefined, packageAliasOrId: 'mypkgalias', project }); - expect(pkg.getId()).to.equal('0Hoasdsadfasdf'); + expect(pkg.getId()).to.equal(pkgId); }); it('should create a new package - from 0Ho', async () => { $$.inProject(true); project = await setupProject((p) => { - p.getSfProjectJson().set('packageAliases', { mypkgalias: '0Hoasdsadfasdf' }); + p.getSfProjectJson().set('packageAliases', { mypkgalias: pkgId }); }); - const pkg = new Package({ connection: undefined, packageAliasOrId: '0Hoasdsadfasdf', project }); - expect(pkg.getId()).to.equal('0Hoasdsadfasdf'); + const pkg = new Package({ connection: undefined, packageAliasOrId: pkgId, project }); + expect(pkg.getId()).to.equal(pkgId); }); it('should not create a new package - from 04t', async () => { $$.inProject(true); project = await setupProject((p) => { p.getSfProjectJson().set('packageAliases', { 'mypkgalias@1.0.0': '04tasdsadfasdf', - mypkgalias: '0Hoasdsadfasdf', + mypkgalias: pkgId, }); }); @@ -115,19 +116,19 @@ describe('Package', () => { it('should create a new package - from 0Ho', async () => { $$.inProject(true); project = await setupProject((p) => { - p.getSfProjectJson().set('packageAliases', { mypkgalias: '0Hoasdsadfasdf' }); + p.getSfProjectJson().set('packageAliases', { mypkgalias: pkgId }); }); const conn = { tooling: { sobject: () => ({ - retrieve: () => ({ Id: '0Hoasdsadfasdf', ContainerOptions: 'Unlocked' }), + retrieve: () => ({ Id: pkgId, ContainerOptions: 'Unlocked' }), }), }, } as unknown as Connection; - const pkg = new Package({ connection: conn, packageAliasOrId: '0Hoasdsadfasdf', project }); + const pkg = new Package({ connection: conn, packageAliasOrId: pkgId, project }); expect(pkg['packageData']).to.not.be.ok; - expect(pkg.getId()).to.equal('0Hoasdsadfasdf'); + expect(pkg.getId()).to.equal(pkgId); expect(await pkg.getType()).to.equal('Unlocked'); expect(pkg['packageData']).to.be.ok; }); diff --git a/test/package/packageTest.nut.ts b/test/package/packageTest.nut.ts index c7d9c017f..c87346b81 100644 --- a/test/package/packageTest.nut.ts +++ b/test/package/packageTest.nut.ts @@ -26,8 +26,8 @@ import { } from '../../src/exported'; import { PackageEvents } from '../../src/interfaces'; import { SubscriberPackageVersion } from '../../src/package'; -import { VersionNumber } from '../../src/utils'; import { AncestryJsonProducer, AncestryTreeProducer, PackageAncestry } from '../../src/package/packageAncestry'; +import { VersionNumber } from '../../src/package/versionNumber'; let session: TestSession; diff --git a/test/utils/versionNumber.test.ts b/test/package/versionNumber.test.ts similarity index 97% rename from test/utils/versionNumber.test.ts rename to test/package/versionNumber.test.ts index 512999ec1..1d0e78f45 100644 --- a/test/utils/versionNumber.test.ts +++ b/test/package/versionNumber.test.ts @@ -5,7 +5,7 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import { expect } from 'chai'; -import { VersionNumber } from '../../src/utils/versionNumber'; +import { VersionNumber } from '../../src/package/versionNumber'; describe('VersionNumber', () => { it('should be able to parse a version number', () => { diff --git a/test/utils/packageUtils.test.ts b/test/utils/packageUtils.test.ts index a8fdb53de..59e558c39 100644 --- a/test/utils/packageUtils.test.ts +++ b/test/utils/packageUtils.test.ts @@ -5,24 +5,27 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; import { assert, expect } from 'chai'; import { Connection, SfProject } from '@salesforce/core'; import { instantiateContext, MockTestOrgData, restoreContext, stubContext } from '@salesforce/core/lib/testSetup'; import { SaveError } from 'jsforce'; import { Duration } from '@salesforce/kit'; +import * as JSZIP from 'jszip'; import { applyErrorAction, - getPackageAliasesFromId, - getPackageIdFromAlias, - getConfigPackageDirectory, getPackageVersionNumber, getInClauseItemsCount, massageErrorMessage, queryWithInConditionChunking, combineSaveErrors, -} from '../../src/utils'; + getConfigPackageDirectory, + zipDir, + numberToDuration, +} from '../../src/utils/packageUtils'; import { PackagingSObjects } from '../../src/interfaces'; -import { numberToDuration } from '../../lib/utils'; describe('packageUtils', () => { const $$ = instantiateContext(); @@ -35,41 +38,6 @@ describe('packageUtils', () => { restoreContext($$); }); - describe('getPackageAliasesFromId', () => { - it('should return an empty array if the packageId is not valid', async () => { - $$.inProject(true); - const project = await SfProject.resolve(); - const result = getPackageAliasesFromId('', project); - expect(result).to.have.lengthOf(0); - }); - it('should return an alias from valid id', async () => { - $$.inProject(true); - const project = await SfProject.resolve(); - const pjson = project.getSfProjectJson().getContents(); - pjson.packageAliases = { myPackage: 'myPackageId' }; - project.getSfProjectJson().setContents(pjson); - const result = getPackageAliasesFromId('myPackageId', project); - expect(result).to.have.lengthOf(1); - expect(result).to.deep.equal(['myPackage']); - }); - }); - describe('getPackageIdFromAlias', () => { - it('should return an empty string if the packageAlias is not valid', async () => { - $$.inProject(true); - const project = await SfProject.resolve(); - const result = getPackageIdFromAlias('', project); - expect(result).to.equal(''); - }); - it('should return an id from valid alias', async () => { - $$.inProject(true); - const project = await SfProject.resolve(); - const pjson = project.getSfProjectJson().getContents(); - pjson.packageAliases = { myPackage: 'myPackageId' }; - project.getSfProjectJson().setContents(pjson); - const result = getPackageIdFromAlias('myPackage', project); - expect(result).to.equal('myPackageId'); - }); - }); describe('getConfigPackageDirectory', () => { it('should through if "packageDirectories" is not present or empty', async () => { $$.inProject(true); @@ -229,4 +197,47 @@ describe('packageUtils', () => { expect(result).to.be.not.ok; }); }); + describe('zipDir', () => { + let tmpZipDir: string; + let tmpSrcDir: string; + beforeEach(() => { + tmpZipDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`); + tmpSrcDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`); + fs.mkdirSync(path.join(tmpSrcDir, 'empty-dir'), { recursive: true }); + fs.mkdirSync(path.join(tmpSrcDir, 'not-empty-dir', 'empty-sub-dir'), { recursive: true }); + fs.mkdirSync(path.join(tmpSrcDir, 'not-empty-dir', 'sub-dir'), { recursive: true }); + fs.writeFileSync(path.join(tmpSrcDir, 'file1.txt'), 'file contents'); + fs.writeFileSync(path.join(tmpSrcDir, 'file2.txt'), 'file contents'); + fs.writeFileSync(path.join(tmpSrcDir, 'not-empty-dir', 'sub-dir', 'file4.txt'), 'file contents'); + fs.writeFileSync(path.join(tmpSrcDir, 'not-empty-dir', 'file3.txt'), 'file contents'); + }); + afterEach(() => { + fs.rmSync(tmpZipDir, { recursive: true }); + fs.rmSync(tmpSrcDir, { recursive: true }); + }); + + it('should be defined', async () => { + const entries = [ + 'file1.txt', + 'file2.txt', + 'not-empty-dir/', + 'not-empty-dir/file3.txt', + 'not-empty-dir/sub-dir/', + 'not-empty-dir/sub-dir/file4.txt', + ]; + await zipDir(path.resolve(tmpSrcDir), path.join(tmpZipDir, 'test.zip')); + try { + const stat = fs.statSync(path.join(tmpZipDir, 'test.zip')); + expect(stat.size).to.be.greaterThan(0); + } catch (e) { + assert.fail((e as Error).message); + } + + const zip = await JSZIP.loadAsync(await fs.promises.readFile(path.join(tmpZipDir, 'test.zip'))); + expect(Object.keys(zip.files)).to.have.lengthOf(entries.length); + zip.forEach((file) => { + expect(entries.includes(file)).to.be.true; + }); + }); + }); }); diff --git a/test/utils/srcDevUtils.test.ts b/test/utils/srcDevUtils.test.ts deleted file mode 100644 index 3c1e306e9..000000000 --- a/test/utils/srcDevUtils.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2020, salesforce.com, inc. - * All rights reserved. - * Licensed under the BSD 3-Clause license. - * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import { assert, expect } from 'chai'; -import * as JSZIP from 'jszip'; -import { zipDir } from '../../src/utils'; - -describe('srcDevUtils', () => { - let tmpZipDir: string; - let tmpSrcDir: string; - beforeEach(() => { - tmpZipDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`); - tmpSrcDir = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`); - fs.mkdirSync(path.join(tmpSrcDir, 'empty-dir'), { recursive: true }); - fs.mkdirSync(path.join(tmpSrcDir, 'not-empty-dir', 'empty-sub-dir'), { recursive: true }); - fs.mkdirSync(path.join(tmpSrcDir, 'not-empty-dir', 'sub-dir'), { recursive: true }); - fs.writeFileSync(path.join(tmpSrcDir, 'file1.txt'), 'file contents'); - fs.writeFileSync(path.join(tmpSrcDir, 'file2.txt'), 'file contents'); - fs.writeFileSync(path.join(tmpSrcDir, 'not-empty-dir', 'sub-dir', 'file4.txt'), 'file contents'); - fs.writeFileSync(path.join(tmpSrcDir, 'not-empty-dir', 'file3.txt'), 'file contents'); - }); - afterEach(() => { - fs.rmSync(tmpZipDir, { recursive: true }); - fs.rmSync(tmpSrcDir, { recursive: true }); - }); - - it('should be defined', async () => { - const entries = [ - 'file1.txt', - 'file2.txt', - 'not-empty-dir/', - 'not-empty-dir/file3.txt', - 'not-empty-dir/sub-dir/', - 'not-empty-dir/sub-dir/file4.txt', - ]; - await zipDir(path.resolve(tmpSrcDir), path.join(tmpZipDir, 'test.zip')); - try { - const stat = fs.statSync(path.join(tmpZipDir, 'test.zip')); - expect(stat.size).to.be.greaterThan(0); - } catch (e) { - assert.fail((e as Error).message); - } - - const zip = await JSZIP.loadAsync(await fs.promises.readFile(path.join(tmpZipDir, 'test.zip'))); - expect(Object.keys(zip.files)).to.have.lengthOf(entries.length); - zip.forEach((file) => { - expect(entries.includes(file)).to.be.true; - }); - }); -}); From 3eea81e3454656a9f8205f2d03cc341d4a8875cc Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Mon, 7 Nov 2022 13:46:33 -0700 Subject: [PATCH 4/5] chore: ts-prune --- src/package/packageConvert.ts | 2 +- src/utils/packageUtils.ts | 59 +++------------------- test/package/packageConvert.test.ts | 5 -- test/utils/packageUtils.test.ts | 78 +---------------------------- 4 files changed, 10 insertions(+), 134 deletions(-) diff --git a/src/package/packageConvert.ts b/src/package/packageConvert.ts index 9bcfa524f..144e71df3 100644 --- a/src/package/packageConvert.ts +++ b/src/package/packageConvert.ts @@ -92,7 +92,7 @@ export async function convertPackage( const packageId = await findOrCreatePackage2(pkg, connection); - const apiVersion = pkgUtils.getSourceApiVersion(project); + const apiVersion = project?.getSfProjectJson()?.get('sourceApiVersion') as string; const request = await createPackageVersionCreateRequest( { diff --git a/src/utils/packageUtils.ts b/src/utils/packageUtils.ts index ab5ae3bef..501152d33 100644 --- a/src/utils/packageUtils.ts +++ b/src/utils/packageUtils.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import { join } from 'path'; import { pipeline as cbPipeline } from 'stream'; import { promisify } from 'util'; -import { Connection, Messages, NamedPackageDir, PackageDir, SfdcUrl, SfError, SfProject } from '@salesforce/core'; +import { Connection, Messages, SfdcUrl, SfError, SfProject } from '@salesforce/core'; import { isNumber, Many, Nullable, Optional } from '@salesforce/ts-types'; import { SaveError } from 'jsforce'; import { Duration } from '@salesforce/kit'; @@ -42,15 +42,15 @@ const ID_REGISTRY = [ }, ]; -export type IdRegistryValue = { prefix: string; label: string }; -export type IdRegistry = { +type IdRegistryValue = { prefix: string; label: string }; +type IdRegistry = { [key: string]: IdRegistryValue; }; export const INSTALL_URL_BASE = new SfdcUrl('https://login.salesforce.com/packaging/installPackage.apexp?p0='); // https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_soslsoql.htm -export const SOQL_WHERE_CLAUSE_MAX_LENGTH = 4000; +const SOQL_WHERE_CLAUSE_MAX_LENGTH = 4000; export const POLL_INTERVAL_SECONDS = 30; @@ -62,9 +62,6 @@ export const DEFAULT_PACKAGE_DIR = { default: true, }; -export const BY_PREFIX = ((): IdRegistry => - Object.fromEntries(ID_REGISTRY.map((id) => [id.prefix, { prefix: id.prefix, label: id.label }])))(); - export const BY_LABEL = ((): IdRegistry => Object.fromEntries( ID_REGISTRY.map((id) => [id.label.replace(/ /g, '_').toUpperCase(), { prefix: id.prefix, label: id.label }]) @@ -79,9 +76,6 @@ export function validateId(idObj: Many, value: string): void { ]); } } -export function getSourceApiVersion(project: SfProject): string { - return project?.getSfProjectJson().get('sourceApiVersion') as string; -} export function validateIdNoThrow(idObj: Many, value: string): IdRegistryValue | boolean { if (!value || (value.length !== 15 && value.length !== 18)) { @@ -229,27 +223,6 @@ export async function getContainerOptions( } return new Map(); } -/** - * Return the Package2Version.HasMetadataRemoved field value for the given Id (05i) - * - * @param packageVersionId package version ID (05i) - * @param connection For tooling query - */ -export async function getHasMetadataRemoved(packageVersionId: string, connection: Connection): Promise { - const query = `SELECT HasMetadataRemoved FROM Package2Version WHERE Id = '${packageVersionId}'`; - - const queryResult = await connection.tooling.query>( - query - ); - if (!queryResult || queryResult.records === null || queryResult.records.length === 0) { - throw messages.createError('errorInvalidIdNoMatchingVersionId', [ - BY_LABEL.PACKAGE_VERSION_ID.label, - packageVersionId, - BY_LABEL.PACKAGE_VERSION_ID.label, - ]); - } - return queryResult.records[0].HasMetadataRemoved; -} /** * Given a list of subscriber package version IDs (04t), return the associated version strings (e.g., Major.Minor.Patch.Build) * @@ -303,7 +276,7 @@ export async function getPackageVersionStrings( * @param replaceToken A placeholder in the query's IN condition that will be replaced with the chunked items * @param connection For tooling query */ -export async function queryWithInConditionChunking>( +async function queryWithInConditionChunking>( query: string, items: string[], replaceToken: string, @@ -343,7 +316,7 @@ export async function queryWithInConditionChunking>( * Returns the number of items that can be included in a quoted comma-separated string (e.g., "'item1','item2'") not exceeding maxLength */ // TODO: this function cannot handle a single item that is longer than maxLength - what to do, since this could be the root cause of an infinite loop? -export function getInClauseItemsCount(items: string[], startIndex: number, maxLength: number): number { +function getInClauseItemsCount(items: string[], startIndex: number, maxLength: number): number { let resultLength = 0; let includedCount = 0; @@ -365,7 +338,7 @@ export function getInClauseItemsCount(items: string[], startIndex: number, maxLe /** * Return a version string in Major.Minor.Patch.Build format, using 0 for any empty part */ -export function concatVersion( +function concatVersion( major: string | number, minor: string | number, patch: string | number, @@ -384,15 +357,6 @@ export function getPackageVersionNumber(package2VersionObj: PackagingSObjects.Pa return version.slice(0, version.lastIndexOf('.')); } -// TODO: replace with sfProject.getPackageDirectoryWithProperty(), still needs to be moved -export function getConfigPackageDirectory( - packageDirs: NamedPackageDir[] | PackageDir[], - lookupProperty: string, - lookupValue: unknown -): NamedPackageDir | PackageDir | undefined { - return packageDirs?.find((pkgDir) => pkgDir[lookupProperty] === lookupValue); -} - /** * Generate package alias json entry for this package version that can be written to sfdx-project.json * @@ -430,13 +394,6 @@ export async function generatePackageAliasEntry( return [packageAlias, packageVersionId]; } -export function formatDate(date: Date): string { - const pad = (num: number): string => (num < 10 ? `0${num}` : `${num}`); - return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad( - date.getMinutes() - )}`; -} - export function combineSaveErrors(sObject: string, crudOperation: string, errors: SaveError[]): SfError { const errorMessages = errors.map((error) => { const fieldsString = error.fields?.length > 0 ? `Fields: [${error.fields.join(', ')}]` : ''; @@ -493,7 +450,7 @@ export async function zipDir(dir: string, zipfile: string): Promise { return; } -export function getElapsedTime(timer: [number, number]): string { +function getElapsedTime(timer: [number, number]): string { const elapsed = process.hrtime(timer); return (elapsed[0] * 1000 + elapsed[1] / 1000000).toFixed(3); } diff --git a/test/package/packageConvert.test.ts b/test/package/packageConvert.test.ts index d26ebe61a..22aafe18a 100644 --- a/test/package/packageConvert.test.ts +++ b/test/package/packageConvert.test.ts @@ -11,14 +11,12 @@ import { expect } from 'chai'; import { instantiateContext, MockTestOrgData, restoreContext, stubContext } from '@salesforce/core/lib/testSetup'; import { Connection, Lifecycle } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; - import { convertPackage, createPackageVersionCreateRequest, findOrCreatePackage2, } from '../../src/package/packageConvert'; import { PackageEvents } from '../../src/interfaces'; -import * as pkgUtils from '../../src/utils/packageUtils'; describe('packageConvert', () => { const $$ = instantiateContext(); @@ -169,9 +167,6 @@ describe('packageConvert', () => { // @ts-ignore $$.SANDBOX.stub(conn.tooling, 'query').resolves({ records: [{ Id: '0Ho3i000000Gmj6YYY' }] }); - // @ts-ignore - $$.SANDBOX.stub(pkgUtils, 'getSourceApiVersion').returns('54.0'); - // @ts-ignore $$.SANDBOX.stub(conn.tooling, 'create').resolves({ success: undefined, errors: [new Error('server error')] }); try { diff --git a/test/utils/packageUtils.test.ts b/test/utils/packageUtils.test.ts index 59e558c39..fa65cef13 100644 --- a/test/utils/packageUtils.test.ts +++ b/test/utils/packageUtils.test.ts @@ -9,19 +9,15 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { assert, expect } from 'chai'; -import { Connection, SfProject } from '@salesforce/core'; -import { instantiateContext, MockTestOrgData, restoreContext, stubContext } from '@salesforce/core/lib/testSetup'; +import { instantiateContext, restoreContext, stubContext } from '@salesforce/core/lib/testSetup'; import { SaveError } from 'jsforce'; import { Duration } from '@salesforce/kit'; import * as JSZIP from 'jszip'; import { applyErrorAction, getPackageVersionNumber, - getInClauseItemsCount, massageErrorMessage, - queryWithInConditionChunking, combineSaveErrors, - getConfigPackageDirectory, zipDir, numberToDuration, } from '../../src/utils/packageUtils'; @@ -38,25 +34,6 @@ describe('packageUtils', () => { restoreContext($$); }); - describe('getConfigPackageDirectory', () => { - it('should through if "packageDirectories" is not present or empty', async () => { - $$.inProject(true); - const project = await SfProject.resolve(); - expect(() => getConfigPackageDirectory(project.getPackageDirectories(), 'default', true)).to.throw; - }); - it('should return default package directory', async () => { - const result = getConfigPackageDirectory( - [ - { name: 'foo', default: true, path: 'default', fullPath: 'fullPath' }, - { name: 'bar', path: 'default', fullPath: 'fullPath' }, - ], - 'default', - true - ); - expect(result).to.have.property('path', 'default'); - expect(result).to.have.property('fullPath', 'fullPath'); - }); - }); describe('getPackage2VersionNumber', () => { it('should return the correct version number', () => { const version = { @@ -69,24 +46,6 @@ describe('packageUtils', () => { expect(result).to.be.equal('1.2.3'); }); }); - describe('getInClauseItemsCount', () => { - it("should return count 1 when each formatted element's length is equal to max length", () => { - const items = ['foo', 'bar', 'baz']; - while (items.length !== 0) { - const result = getInClauseItemsCount(items, 0, 6); - expect(result).to.be.equal(1); - items.pop(); - } - }); - it("should return count 0 when each formatted element's length is greater than max length", () => { - const items = ['foox', 'barx', 'bazx']; - while (items.length !== 0) { - const result = getInClauseItemsCount(items, 0, 6); - expect(result).to.be.equal(0); - items.pop(); - } - }); - }); describe('applyErrorAction', () => { describe('INVALID_TYPE', () => { it('should modify error message if packaging is not enabled', () => { @@ -107,44 +66,9 @@ describe('packageUtils', () => { expect(result.message).to.be.equal('Invalid package type'); }); }); - describe('queryWithInConditionChunking', () => { - it('should run the correct query', async () => { - const testOrg = new MockTestOrgData(); - await $$.stubAuths(testOrg); - const connection = await testOrg.getConnection(); - const result = await queryWithInConditionChunking( - 'select id from Package2Version where id %ID%', - ['foox', 'barx', 'bazx'], - '%ID%', - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - connection as Connection - ); - expect(result).to.be.ok; - }); - it('should fail for item being too large', async () => { - const testOrg = new MockTestOrgData(); - await $$.stubAuths(testOrg); - const connection = await testOrg.getConnection(); - try { - await queryWithInConditionChunking( - 'select id from Package2Version where id %ID%', - ['f'.repeat(4000), 'barx', 'bazx'], - '%ID%', - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - connection as Connection - ); - assert.fail('should have thrown'); - } catch (e) { - expect(e.message).to.be.include('When calculating the number of items to be included in query'); - } - }); - }); describe('getPackageVersionStrings', () => { it.skip('should return the correct version strings', () => {}); }); - describe('getHasMetadataRemoved', () => { - it.skip('should return the correct value', () => {}); - }); describe('getContainerOptions', () => { it.skip('should return the correct value', () => {}); }); From e8aff88f66299bf7d16e89103cfc725f26523572 Mon Sep 17 00:00:00 2001 From: Willie Ruemmele Date: Tue, 8 Nov 2022 10:22:09 -0700 Subject: [PATCH 5/5] refactor: pete's suggestions --- src/package/package.ts | 36 ++++++++++++++----------- src/package/packageConvert.ts | 5 ++-- src/package/packageVersion.ts | 13 --------- src/package/packageVersionCreate.ts | 4 +-- src/package/subscriberPackageVersion.ts | 16 +++++++++++ src/utils/packageUtils.ts | 28 +++++++++++++++++-- test/package/packageTest.nut.ts | 4 +-- 7 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/package/package.ts b/src/package/package.ts index 60a0d9232..ab20b750c 100644 --- a/src/package/package.ts +++ b/src/package/package.ts @@ -7,7 +7,6 @@ import { Connection, Messages, SfError, SfProject } from '@salesforce/core'; import { ConvertPackageOptions, - InstalledPackages, PackageCreateOptions, PackageOptions, PackageSaveResult, @@ -23,6 +22,7 @@ import { createPackage } from './packageCreate'; import { convertPackage } from './packageConvert'; import { listPackageVersions } from './packageVersionList'; import { deletePackage } from './packageDelete'; +import { PackageAncestry } from './packageAncestry'; const packagePrefixes = { PackageId: '0Ho', @@ -107,21 +107,6 @@ export class Package { )?.records; } - /** - * list the packages installed in the org - * - * @param conn: Connection to the org - */ - public static async installedList(conn: Connection): Promise { - try { - const query = - 'SELECT Id, SubscriberPackageId, SubscriberPackage.NamespacePrefix, SubscriberPackage.Name, SubscriberPackageVersion.Id, SubscriberPackageVersion.Name, SubscriberPackageVersion.MajorVersion, SubscriberPackageVersion.MinorVersion, SubscriberPackageVersion.PatchVersion, SubscriberPackageVersion.BuildNumber FROM InstalledSubscriberPackage ORDER BY SubscriberPackageId'; - return (await conn.tooling.query(query)).records; - } catch (err) { - throw applyErrorAction(massageErrorMessage(err as Error)); - } - } - /** * Returns the package versions in the org. * See {@link PackageVersionListOptions} for list options @@ -153,6 +138,25 @@ export class Package { return (await listPackageVersions({ ...opts, ...{ connection } })).records; } + /** + * create a PackageAncestry instance + * + * @param packageId to get version information for + * @param project SfProject instance + * @param connection Hub Org Connection + */ + public static async getAncestry( + packageId: string, + project: SfProject, + connection: Connection + ): Promise { + return PackageAncestry.create({ + packageId, + project, + connection, + }); + } + /** * Convert a 1st generation package to a 2nd generation package. * See {@link ConvertPackageOptions} for conversion options. diff --git a/src/package/packageConvert.ts b/src/package/packageConvert.ts index 144e71df3..bc1042336 100644 --- a/src/package/packageConvert.ts +++ b/src/package/packageConvert.ts @@ -22,7 +22,6 @@ import { import { camelCaseToTitleCase, Duration } from '@salesforce/kit'; import { Many } from '@salesforce/ts-types'; import SettingsGenerator from '@salesforce/core/lib/org/scratchOrgSettingsGenerator'; -import { genUniqueString } from '@salesforce/cli-plugins-testkit'; import * as pkgUtils from '../utils/packageUtils'; import { PackagingSObjects, @@ -31,7 +30,7 @@ import { PackageVersionCreateEventData, PackageEvents, } from '../interfaces'; -import { generatePackageAliasEntry } from '../utils/packageUtils'; +import { generatePackageAliasEntry, uniqid } from '../utils/packageUtils'; import { byId } from './packageVersionCreateRequest'; import * as pvcr from './packageVersionCreateRequest'; import Package2VersionStatus = PackagingSObjects.Package2VersionStatus; @@ -145,7 +144,7 @@ export async function createPackageVersionCreateRequest( packageId: string, apiVersion: string ): Promise { - const uniqueId = genUniqueString(`${packageId}-%s`); + const uniqueId = uniqid({ template: `${packageId}-%s` }); const packageVersTmpRoot = path.join(os.tmpdir(), uniqueId); const packageVersMetadataFolder = path.join(packageVersTmpRoot, 'md-files'); const packageVersBlobDirectory = path.join(packageVersTmpRoot, 'package-version-info'); diff --git a/src/package/packageVersion.ts b/src/package/packageVersion.ts index 8e05f7c4c..38f8921e0 100644 --- a/src/package/packageVersion.ts +++ b/src/package/packageVersion.ts @@ -25,7 +25,6 @@ import { PackageVersionCreate } from './packageVersionCreate'; import { getPackageVersionReport } from './packageVersionReport'; import { getCreatePackageVersionCreateRequestReport } from './packageVersionCreateRequestReport'; import { list } from './packageVersionCreateRequest'; -import { PackageAncestry } from './packageAncestry'; import Package2 = PackagingSObjects.Package2; import Package2VersionStatus = PackagingSObjects.Package2VersionStatus; @@ -92,18 +91,6 @@ export class PackageVersion { } } - public static async getAncestry( - packageId: string, - project: SfProject, - connection: Connection - ): Promise { - return PackageAncestry.create({ - packageId, - project, - connection, - }); - } - /** * Sends a request to create a new package version and optionally polls for * the status of the request until the package version is created or the diff --git a/src/package/packageVersionCreate.ts b/src/package/packageVersionCreate.ts index abc96b785..b7081d596 100644 --- a/src/package/packageVersionCreate.ts +++ b/src/package/packageVersionCreate.ts @@ -23,7 +23,6 @@ import { ComponentSetBuilder, ConvertResult, MetadataConverter } from '@salesfor import SettingsGenerator from '@salesforce/core/lib/org/scratchOrgSettingsGenerator'; import * as xml2js from 'xml2js'; import { PackageDirDependency } from '@salesforce/core/lib/sfProject'; -import { genUniqueString } from '@salesforce/cli-plugins-testkit'; import * as pkgUtils from '../utils/packageUtils'; import { MDFolderForArtifactOptions, @@ -41,6 +40,7 @@ import { getPackageVersionNumber, validateId, VERSION_NUMBER_SEP, + uniqid, copyDir, zipDir, } from '../utils/packageUtils'; @@ -303,7 +303,7 @@ export class PackageVersionCreate { */ private async createPackageVersionCreateRequestFromOptions(): Promise { const preserveFiles = !!(this.options.preserve || process.env.SFDX_PACKAGE2_VERSION_CREATE_PRESERVE); - const uniqueHash = genUniqueString(`${this.packageId}-%s`); + const uniqueHash = uniqid({ template: `${this.packageId}-%s` }); const packageVersTmpRoot = path.join(os.tmpdir(), `${uniqueHash}`); const packageVersMetadataFolder = path.join(packageVersTmpRoot, 'md-files'); const unpackagedMetadataFolder = path.join(packageVersTmpRoot, 'unpackaged-md-files'); diff --git a/src/package/subscriberPackageVersion.ts b/src/package/subscriberPackageVersion.ts index 16f1641f4..2be358387 100644 --- a/src/package/subscriberPackageVersion.ts +++ b/src/package/subscriberPackageVersion.ts @@ -9,6 +9,7 @@ import { Connection, Logger, Messages, sfdc, SfError, SfProject } from '@salesfo import { Duration } from '@salesforce/kit'; import { Optional } from '@salesforce/ts-types'; import { + InstalledPackages, PackageInstallCreateRequest, PackageInstallOptions, PackageType, @@ -152,6 +153,21 @@ export class SubscriberPackageVersion { } } + /** + * list the packages installed in the org + * + * @param conn: Connection to the org + */ + public static async installedList(conn: Connection): Promise { + try { + const query = + 'SELECT Id, SubscriberPackageId, SubscriberPackage.NamespacePrefix, SubscriberPackage.Name, SubscriberPackageVersion.Id, SubscriberPackageVersion.Name, SubscriberPackageVersion.MajorVersion, SubscriberPackageVersion.MinorVersion, SubscriberPackageVersion.PatchVersion, SubscriberPackageVersion.BuildNumber FROM InstalledSubscriberPackage ORDER BY SubscriberPackageId'; + return (await conn.tooling.query(query)).records; + } catch (err) { + throw applyErrorAction(massageErrorMessage(err as Error)); + } + } + /** * Reports on the progress of a package version uninstall. * diff --git a/src/utils/packageUtils.ts b/src/utils/packageUtils.ts index 501152d33..10c22d02b 100644 --- a/src/utils/packageUtils.ts +++ b/src/utils/packageUtils.ts @@ -9,6 +9,8 @@ import * as fs from 'fs'; import { join } from 'path'; import { pipeline as cbPipeline } from 'stream'; import { promisify } from 'util'; +import { randomBytes } from 'crypto'; +import * as util from 'util'; import { Connection, Messages, SfdcUrl, SfError, SfProject } from '@salesforce/core'; import { isNumber, Many, Nullable, Optional } from '@salesforce/ts-types'; import { SaveError } from 'jsforce'; @@ -42,8 +44,8 @@ const ID_REGISTRY = [ }, ]; -type IdRegistryValue = { prefix: string; label: string }; -type IdRegistry = { +export type IdRegistryValue = { prefix: string; label: string }; +export type IdRegistry = { [key: string]: IdRegistryValue; }; @@ -67,6 +69,28 @@ export const BY_LABEL = ((): IdRegistry => ID_REGISTRY.map((id) => [id.label.replace(/ /g, '_').toUpperCase(), { prefix: id.prefix, label: id.label }]) ))(); +/** + * A function to generate a unique id and return it in the context of a template, if supplied. + * + * A template is a string that can contain `${%s}` to be replaced with a unique id. + * If the template contains the "%s" placeholder, it will be replaced with the unique id otherwise the id will be appended to the template. + * + * @param options an object with the following properties: + * - template: a template string. + * - length: the length of the unique id as presented in hexadecimal. + */ +export function uniqid(options?: { template?: string; length?: number }): string { + const uniqueString = randomBytes(Math.ceil((options?.length ?? 32) / 2.0)) + .toString('hex') + .slice(0, options?.length ?? 32); + if (!options?.template) { + return uniqueString; + } + return options.template.includes('%s') + ? util.format(options.template, uniqueString) + : `${options.template}${uniqueString}`; +} + export function validateId(idObj: Many, value: string): void { if (!validateIdNoThrow(idObj, value)) { throw messages.createError('invalidIdOrAlias', [ diff --git a/test/package/packageTest.nut.ts b/test/package/packageTest.nut.ts index c87346b81..4f5b818d4 100644 --- a/test/package/packageTest.nut.ts +++ b/test/package/packageTest.nut.ts @@ -419,7 +419,7 @@ describe('Integration tests for @salesforce/packaging library', () => { it('packageInstalledList returns the correct information', async () => { const connection = scratchOrg.getConnection(); - const result = await Package.installedList(connection); + const result = await SubscriberPackageVersion.installedList(connection); const foundRecord = result.filter((item) => item.SubscriberPackageVersion.Id === subscriberPkgVersionId); expect(result).to.have.length.at.least(1); @@ -492,7 +492,7 @@ describe('Integration tests for @salesforce/packaging library', () => { }); it('gets zero results from packageInstalledList', async () => { - const result = await Package.installedList(scratchOrg.getConnection()); + const result = await SubscriberPackageVersion.installedList(scratchOrg.getConnection()); expect(result).to.have.length(0); }); });