From 0574be591647c9fa8da31d44a734f41a3396fbaa Mon Sep 17 00:00:00 2001 From: sameer-motwani Date: Wed, 11 Jun 2025 17:22:00 -0400 Subject: [PATCH 01/31] feat: adding code coverage option to the convert command --- messages/package_convert.md | 10 +++++++++- src/commands/package/convert.ts | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/messages/package_convert.md b/messages/package_convert.md index e74213a0..86d888b6 100644 --- a/messages/package_convert.md +++ b/messages/package_convert.md @@ -66,7 +66,7 @@ Display verbose command output. # in-progress -Request in progress. Will wait a total of %s more seconds before timing out. Current Status='%s'. +Request in progress. Will wait a total of %s more seconds before timing out. Current Status='%s'. # flags.seed-metadata.summary @@ -83,3 +83,11 @@ Specific released patch version to be converted. # flags.patch-version.description Specify a released patch version as major.minor.patch to convert to a second-generation managed package version. + +# flags.code-coverage.summary + +Calculate and store the code coverage percentage by running the packaged Apex tests included in this package version. + +# flags.code-coverage.description + +Before you can promote and release a managed package version, the Apex code must meet a minimum 75% code coverage requirement. diff --git a/src/commands/package/convert.ts b/src/commands/package/convert.ts index 83863b6e..8c14a86f 100644 --- a/src/commands/package/convert.ts +++ b/src/commands/package/convert.ts @@ -90,6 +90,14 @@ export class PackageConvert extends SfCommand deprecateAliases: true, aliases: ['patchversion'], }), + 'code-coverage': Flags.boolean({ + deprecateAliases: true, + aliases: ['codecoverage'], + char: 'c', + summary: messages.getMessage('flags.code-coverage.summary'), + description: messages.getMessage('flags.code-coverage.description'), + default: false, + }), }; public async run(): Promise { @@ -131,6 +139,7 @@ export class PackageConvert extends SfCommand buildInstance: flags['build-instance'] as string, seedMetadata: flags['seed-metadata'] as string, patchversion: flags['patch-version'] as string, + codecoverage: flags['code-coverage'] as boolean, }, project ); From 07959d18345974793d6dd4e6287c80511d337fb3 Mon Sep 17 00:00:00 2001 From: sameer-motwani Date: Wed, 11 Jun 2025 18:13:38 -0400 Subject: [PATCH 02/31] feat: adding code coverage option to the convert command with snapshot --- command-snapshot.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index d5918a66..a934c706 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -66,9 +66,10 @@ "installationkeybypass", "patchversion", "target-hub-org", - "targetdevhubusername" + "targetdevhubusername", + "codecoverage" ], - "flagChars": ["a", "f", "k", "m", "p", "s", "v", "w", "x"], + "flagChars": ["a", "f", "k", "m", "p", "s", "v", "w", "x", "c"], "flags": [ "api-version", "build-instance", @@ -83,7 +84,8 @@ "seed-metadata", "target-dev-hub", "verbose", - "wait" + "wait", + "code-coverage" ], "plugin": "@salesforce/plugin-packaging" }, From a6cb4d4370f64cfeb110c17f8b4fecc146b47298 Mon Sep 17 00:00:00 2001 From: sameer-motwani Date: Thu, 12 Jun 2025 14:19:01 -0400 Subject: [PATCH 03/31] feat: adding code coverage option to the convert command with snapshot and tests --- test/commands/package/packageConvert.test.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/commands/package/packageConvert.test.ts b/test/commands/package/packageConvert.test.ts index cc2db204..254d6383 100644 --- a/test/commands/package/packageConvert.test.ts +++ b/test/commands/package/packageConvert.test.ts @@ -7,7 +7,12 @@ import { expect } from 'chai'; import { MockTestOrgData, TestContext } from '@salesforce/core/testSetup'; import { Config } from '@oclif/core'; -import { Package, PackageVersionCreateRequestResult, PackagingSObjects } from '@salesforce/packaging'; +import { + Package, + PackageVersionCreateRequestResult, + PackagingSObjects, + type ConvertPackageOptions, +} from '@salesforce/packaging'; import sinon from 'sinon'; import { PackageConvert } from '../../../src/commands/package/convert.js'; import Package2VersionStatus = PackagingSObjects.Package2VersionStatus; @@ -80,8 +85,10 @@ describe('package:convert', () => { ); stubSpinner(cmd); const result = await cmd.run(); - expect(spinnerStartStub.called).to.be.true; + // Check that codecoverage was passed as true + const callArgs = convertStub.getCall(0).args[2] as ConvertPackageOptions; + expect(callArgs.codecoverage).to.equal(false); expect(result).to.deep.equal(pvc); }); it('starts package version create request (success)', async () => { @@ -109,11 +116,14 @@ describe('package:convert', () => { convertStub.restore(); convertStub = $$.SANDBOX.stub(Package, 'convert').resolves(pvc); const cmd = new PackageConvert( - ['-p', CONVERTED_FROM_PACKAGE_ID, '--installation-key', INSTALL_KEY, '-v', 'test@user.com'], + ['-p', CONVERTED_FROM_PACKAGE_ID, '--installation-key', INSTALL_KEY, '-v', 'test@user.com', '-c'], config ); stubSpinner(cmd); const result = await cmd.run(); + // Check that codecoverage was passed as true + const callArgs = convertStub.getCall(0).args[2] as ConvertPackageOptions; + expect(callArgs.codecoverage).to.equal(true); expect(result).to.deep.equal(pvc); }); it('starts package version create request (error)', async () => { From 3a8d8249a1622c36265b50e7ec248439c87b009b Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Thu, 12 Jun 2025 14:04:50 -0600 Subject: [PATCH 04/31] Update test/commands/package/packageConvert.test.ts --- test/commands/package/packageConvert.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/commands/package/packageConvert.test.ts b/test/commands/package/packageConvert.test.ts index 254d6383..3107dab2 100644 --- a/test/commands/package/packageConvert.test.ts +++ b/test/commands/package/packageConvert.test.ts @@ -86,7 +86,7 @@ describe('package:convert', () => { stubSpinner(cmd); const result = await cmd.run(); expect(spinnerStartStub.called).to.be.true; - // Check that codecoverage was passed as true + // Check that codecoverage was passed as false const callArgs = convertStub.getCall(0).args[2] as ConvertPackageOptions; expect(callArgs.codecoverage).to.equal(false); expect(result).to.deep.equal(pvc); From 542cc694738f62f89939d156654d5dcffe7b4937 Mon Sep 17 00:00:00 2001 From: sameer-motwani Date: Fri, 13 Jun 2025 10:38:20 -0400 Subject: [PATCH 05/31] feat: adding code coverage option linking with packaging --- package.json | 2 +- src/commands/package/convert.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index 87047b3c..de95a426 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "@oclif/core": "^4", "@salesforce/core": "^8.12.0", "@salesforce/kit": "^3.2.3", - "@salesforce/packaging": "^4.6.0", + "@salesforce/packaging": "^4.7.0", "@salesforce/sf-plugins-core": "^12.2.2", "chalk": "^5.4.1" }, diff --git a/src/commands/package/convert.ts b/src/commands/package/convert.ts index 8c14a86f..5ced38dc 100644 --- a/src/commands/package/convert.ts +++ b/src/commands/package/convert.ts @@ -91,8 +91,6 @@ export class PackageConvert extends SfCommand aliases: ['patchversion'], }), 'code-coverage': Flags.boolean({ - deprecateAliases: true, - aliases: ['codecoverage'], char: 'c', summary: messages.getMessage('flags.code-coverage.summary'), description: messages.getMessage('flags.code-coverage.description'), From ebd51da9d6607d0bbbe10edcf37fec5924f7b7f8 Mon Sep 17 00:00:00 2001 From: sameer-motwani Date: Fri, 13 Jun 2025 10:53:56 -0400 Subject: [PATCH 06/31] feat: adding code coverage option description to the convert command --- messages/package_convert.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/messages/package_convert.md b/messages/package_convert.md index 86d888b6..e136123c 100644 --- a/messages/package_convert.md +++ b/messages/package_convert.md @@ -12,6 +12,8 @@ To retrieve details about a package version create request, including status and To protect the contents of your package and to prevent unauthorized installation of your package, specify the --installation-key flag. +To promote a package version to released, you must use the --code-coverage parameter. The package must also meet the code coverage requirements. + To list package version creation requests in the org, run "<%= config.bin %> package version create list". # examples From 2473c54646602d89f3de36c60b320e80e3229889 Mon Sep 17 00:00:00 2001 From: svc-cli-bot Date: Fri, 13 Jun 2025 15:53:07 +0000 Subject: [PATCH 07/31] chore(release): 2.16.0 [skip ci] --- CHANGELOG.md | 10 ++++++++ README.md | 69 +++++++++++++++++++++++++++++++--------------------- package.json | 2 +- yarn.lock | 8 +++--- 4 files changed, 56 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d99c810..bec463de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# [2.16.0](https://github.com/salesforcecli/plugin-packaging/compare/2.15.4...2.16.0) (2025-06-13) + +### Features + +- adding code coverage option description to the convert command ([ebd51da](https://github.com/salesforcecli/plugin-packaging/commit/ebd51da9d6607d0bbbe10edcf37fec5924f7b7f8)) +- adding code coverage option linking with packaging ([542cc69](https://github.com/salesforcecli/plugin-packaging/commit/542cc694738f62f89939d156654d5dcffe7b4937)) +- adding code coverage option to the convert command ([0574be5](https://github.com/salesforcecli/plugin-packaging/commit/0574be591647c9fa8da31d44a734f41a3396fbaa)) +- adding code coverage option to the convert command with snapshot ([07959d1](https://github.com/salesforcecli/plugin-packaging/commit/07959d18345974793d6dd4e6287c80511d337fb3)) +- adding code coverage option to the convert command with snapshot and tests ([a6cb4d4](https://github.com/salesforcecli/plugin-packaging/commit/a6cb4d4370f64cfeb110c17f8b4fecc146b47298)) + ## [2.15.4](https://github.com/salesforcecli/plugin-packaging/compare/2.15.3...2.15.4) (2025-06-10) ### Bug Fixes diff --git a/README.md b/README.md index 9bcbf889..4597f4fe 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,12 @@ Convert a managed-released first-generation managed package into a second-genera ``` USAGE $ sf package convert -v -p [--json] [--flags-dir ] [--api-version ] [-k ] [-f - ] [-x] [-w ] [-m ] [--verbose] [-a ] + ] [-x] [-w ] [-m ] [--verbose] [-a ] [-c] FLAGS -a, --patch-version= Specific released patch version to be converted. + -c, --code-coverage Calculate and store the code coverage percentage by running the packaged Apex tests + included in this package version. -f, --definition-file= Path to a definition file that contains features and org preferences that the metadata of the package version depends on. -k, --installation-key= Installation key for key-protected package. @@ -99,6 +101,9 @@ DESCRIPTION To protect the contents of your package and to prevent unauthorized installation of your package, specify the --installation-key flag. + To promote a package version to released, you must use the --code-coverage parameter. The package must also meet the + code coverage requirements. + To list package version creation requests in the org, run "sf package version create list". ALIASES @@ -119,6 +124,14 @@ FLAG DESCRIPTIONS Specify a released patch version as major.minor.patch to convert to a second-generation managed package version. + -c, --code-coverage + + Calculate and store the code coverage percentage by running the packaged Apex tests included in this package + version. + + Before you can promote and release a managed package version, the Apex code must meet a minimum 75% code coverage + requirement. + -f, --definition-file= Path to a definition file that contains features and org preferences that the metadata of the package version @@ -140,7 +153,7 @@ FLAG DESCRIPTIONS --installation-key-bypass flag is required. ``` -_See code: [src/commands/package/convert.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/convert.ts)_ +_See code: [src/commands/package/convert.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/convert.ts)_ ## `sf package create` @@ -219,7 +232,7 @@ FLAG DESCRIPTIONS Org-Dependent Unlocked Packages" in the Salesforce DX Developer Guide. ``` -_See code: [src/commands/package/create.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/create.ts)_ +_See code: [src/commands/package/create.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/create.ts)_ ## `sf package delete` @@ -261,7 +274,7 @@ EXAMPLES $ sf package delete --package 0Ho... --target-dev-hub devhub@example.com ``` -_See code: [src/commands/package/delete.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/delete.ts)_ +_See code: [src/commands/package/delete.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/delete.ts)_ ## `sf package install` @@ -360,7 +373,7 @@ FLAG DESCRIPTIONS - Delete: Delete all removed components that can be safely deleted, and deprecate the other components. ``` -_See code: [src/commands/package/install.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/install.ts)_ +_See code: [src/commands/package/install.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/install.ts)_ ## `sf package install report` @@ -393,7 +406,7 @@ EXAMPLES $ sf package install report --request-id 0Hf... --target-org me@example.com ``` -_See code: [src/commands/package/install/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/install/report.ts)_ +_See code: [src/commands/package/install/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/install/report.ts)_ ## `sf package installed list` @@ -425,7 +438,7 @@ EXAMPLES $ sf package installed list --target-org me@example.com ``` -_See code: [src/commands/package/installed/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/installed/list.ts)_ +_See code: [src/commands/package/installed/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/installed/list.ts)_ ## `sf package list` @@ -463,7 +476,7 @@ EXAMPLES $ sf package list --target-dev-hub devhub@example.com --verbose ``` -_See code: [src/commands/package/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/list.ts)_ +_See code: [src/commands/package/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/list.ts)_ ## `sf package push-upgrade abort` @@ -503,7 +516,7 @@ EXAMPLES $ sf package push-upgrade abort --push-request-id 0DV... --target-dev-hub devhub@example.com ``` -_See code: [src/commands/package/push-upgrade/abort.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/push-upgrade/abort.ts)_ +_See code: [src/commands/package/push-upgrade/abort.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/push-upgrade/abort.ts)_ ## `sf package push-upgrade list` @@ -562,7 +575,7 @@ EXAMPLES $ sf package push-upgrade list --package 033xyz –-status Failed ``` -_See code: [src/commands/package/push-upgrade/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/push-upgrade/list.ts)_ +_See code: [src/commands/package/push-upgrade/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/push-upgrade/list.ts)_ ## `sf package push-upgrade report` @@ -604,7 +617,7 @@ EXAMPLES $ sf package push-upgrade report --push-request-id 0DV... --target-dev-hub devhub@example.com ``` -_See code: [src/commands/package/push-upgrade/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/push-upgrade/report.ts)_ +_See code: [src/commands/package/push-upgrade/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/push-upgrade/report.ts)_ ## `sf package push-upgrade schedule` @@ -686,7 +699,7 @@ FLAG DESCRIPTIONS Overrides the value of the target-dev-hub configuration variable, if set. ``` -_See code: [src/commands/package/push-upgrade/schedule.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/push-upgrade/schedule.ts)_ +_See code: [src/commands/package/push-upgrade/schedule.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/push-upgrade/schedule.ts)_ ## `sf package uninstall` @@ -734,7 +747,7 @@ EXAMPLES $ sf package uninstall --package "Undesirable Package Alias" ``` -_See code: [src/commands/package/uninstall.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/uninstall.ts)_ +_See code: [src/commands/package/uninstall.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/uninstall.ts)_ ## `sf package uninstall report` @@ -767,7 +780,7 @@ EXAMPLES $ sf package uninstall report --request-id 06y... --target-org me@example.com ``` -_See code: [src/commands/package/uninstall/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/uninstall/report.ts)_ +_See code: [src/commands/package/uninstall/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/uninstall/report.ts)_ ## `sf package update` @@ -822,7 +835,7 @@ FLAG DESCRIPTIONS associated with your package. ``` -_See code: [src/commands/package/update.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/update.ts)_ +_See code: [src/commands/package/update.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/update.ts)_ ## `sf package version create` @@ -997,7 +1010,7 @@ FLAG DESCRIPTIONS periods of no output from commands. ``` -_See code: [src/commands/package/version/create.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/create.ts)_ +_See code: [src/commands/package/version/create.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/create.ts)_ ## `sf package version create list` @@ -1058,7 +1071,7 @@ EXAMPLES $ sf package version create list --created-last-days 0 --status Success ``` -_See code: [src/commands/package/version/create/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/create/list.ts)_ +_See code: [src/commands/package/version/create/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/create/list.ts)_ ## `sf package version create report` @@ -1101,7 +1114,7 @@ EXAMPLES $ sf package version create report --package-create-request-id 08c... --target-dev-hub devhub@example.com ``` -_See code: [src/commands/package/version/create/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/create/report.ts)_ +_See code: [src/commands/package/version/create/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/create/report.ts)_ ## `sf package version delete` @@ -1142,7 +1155,7 @@ EXAMPLES $ sf package version delete --package 04t... --target-org devhub@example.com ``` -_See code: [src/commands/package/version/delete.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/delete.ts)_ +_See code: [src/commands/package/version/delete.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/delete.ts)_ ## `sf package version displayancestry` @@ -1202,7 +1215,7 @@ FLAG DESCRIPTIONS You can use the DOT code output in graph visualization software to create tree visualizations. ``` -_See code: [src/commands/package/version/displayancestry.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/displayancestry.ts)_ +_See code: [src/commands/package/version/displayancestry.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/displayancestry.ts)_ ## `sf package version list` @@ -1278,7 +1291,7 @@ EXAMPLES $ sf package version list --packages exp-mgr,exp-mgr-util --released --modified-last-days 0 ``` -_See code: [src/commands/package/version/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/list.ts)_ +_See code: [src/commands/package/version/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/list.ts)_ ## `sf package version promote` @@ -1322,7 +1335,7 @@ EXAMPLES $ sf package version promote --package "Awesome Package Alias" ``` -_See code: [src/commands/package/version/promote.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/promote.ts)_ +_See code: [src/commands/package/version/promote.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/promote.ts)_ ## `sf package version report` @@ -1362,7 +1375,7 @@ EXAMPLES $ sf package version report --package "Your Package Alias" --target-dev-hub devhub@example.com ``` -_See code: [src/commands/package/version/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/report.ts)_ +_See code: [src/commands/package/version/report.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/report.ts)_ ## `sf package version update` @@ -1415,7 +1428,7 @@ EXAMPLES $ sf package version update --package 04t... --version-description "New Package Version Description" ``` -_See code: [src/commands/package/version/update.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package/version/update.ts)_ +_See code: [src/commands/package/version/update.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package/version/update.ts)_ ## `sf package1 version create` @@ -1482,7 +1495,7 @@ FLAG DESCRIPTIONS subscribers. ``` -_See code: [src/commands/package1/version/create.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package1/version/create.ts)_ +_See code: [src/commands/package1/version/create.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package1/version/create.ts)_ ## `sf package1 version create get` @@ -1515,7 +1528,7 @@ EXAMPLES $ sf package1 version create get --request-id 0HD... --target-org myorg@example.com ``` -_See code: [src/commands/package1/version/create/get.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package1/version/create/get.ts)_ +_See code: [src/commands/package1/version/create/get.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package1/version/create/get.ts)_ ## `sf package1 version display` @@ -1549,7 +1562,7 @@ EXAMPLES $ sf package1 version display --package-version-id 04t... --target-org myorg@example.com ``` -_See code: [src/commands/package1/version/display.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package1/version/display.ts)_ +_See code: [src/commands/package1/version/display.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package1/version/display.ts)_ ## `sf package1 version list` @@ -1587,6 +1600,6 @@ FLAG DESCRIPTIONS If not specified, shows all versions for all packages (managed and unmanaged) in the org. ``` -_See code: [src/commands/package1/version/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.15.4/src/commands/package1/version/list.ts)_ +_See code: [src/commands/package1/version/list.ts](https://github.com/salesforcecli/plugin-packaging/blob/2.16.0/src/commands/package1/version/list.ts)_ diff --git a/package.json b/package.json index de95a426..170312e4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@salesforce/plugin-packaging", "description": "SF plugin that support Salesforce Packaging Platform", - "version": "2.15.4", + "version": "2.16.0", "author": "Salesforce", "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { diff --git a/yarn.lock b/yarn.lock index 4f4a4d12..30276d8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1742,10 +1742,10 @@ dependencies: "@salesforce/ts-types" "^2.0.12" -"@salesforce/packaging@^4.6.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@salesforce/packaging/-/packaging-4.6.0.tgz#ae30f6593da66d32b451c879d1eec23dcf664161" - integrity sha512-DAt37E6C0KeVbkIZEiplN6vmqQ5NB58TSYAk6LjX6+ZbvSV4lnBc4mSCDcErmqCn5mWW3fdPvxL8FlyYhmpL4g== +"@salesforce/packaging@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@salesforce/packaging/-/packaging-4.7.0.tgz#550d450486cf28edd7f5c7c76e6bce6e4d76d4e0" + integrity sha512-fYwE0oChQ7MBqeAbi2vq3NZBe2qw0nsXbXdNwgl2ybREDE2RLqWRIB75OGxEa9ARQNrdWOVE7sR81cGLyCIupg== dependencies: "@jsforce/jsforce-node" "^3.6.5" "@salesforce/core" "^8.11.1" From 58cd2f263e47e410d8bb58bc410fa5dc321f0451 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Tue, 10 Jun 2025 14:47:07 -0600 Subject: [PATCH 08/31] feat: added bundle create decided to to add tests yet because package create only has nut and we don't have delete yet --- command-snapshot.json | 8 ++++ messages/bundle_create.md | 24 +++++++++++ schemas/package-bundles-create.json | 16 ++++++++ src/commands/package/bundles/create.ts | 57 ++++++++++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 messages/bundle_create.md create mode 100644 schemas/package-bundles-create.json create mode 100644 src/commands/package/bundles/create.ts diff --git a/command-snapshot.json b/command-snapshot.json index a934c706..005f533e 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -55,6 +55,14 @@ "flags": ["api-version", "flags-dir", "json", "loglevel", "package-id", "target-org"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": ["force:bundle:create"], + "command": "package:bundles:create", + "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], + "flagChars": ["d", "n", "v"], + "flags": ["api-version", "description", "flags-dir", "json", "loglevel", "name", "target-dev-hub"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": ["force:package:convert"], "command": "package:convert", diff --git a/messages/bundle_create.md b/messages/bundle_create.md new file mode 100644 index 00000000..be02d894 --- /dev/null +++ b/messages/bundle_create.md @@ -0,0 +1,24 @@ +# summary + +Create a bundle. + +# description + +First, use this command to create a bunle. Then create a bundle version. + +Your --name value must be unique within your namespace. + +Run '<%= config.bin %> bundle list to list all bundles in the Dev Hub org. + +# examples + +- Default Use Case + <%= config.bin %> <%= command.id %> --name --description "" --target-dev-hub ` + +# flags.name.summary + +Name of the bundle to create. + +# flags.description.summary + +Description of the bundle diff --git a/schemas/package-bundles-create.json b/schemas/package-bundles-create.json new file mode 100644 index 00000000..2049f257 --- /dev/null +++ b/schemas/package-bundles-create.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleCreate", + "definitions": { + "BundleCreate": { + "type": "object", + "properties": { + "Id": { + "type": "string" + } + }, + "required": ["Id"], + "additionalProperties": false + } + } +} diff --git a/src/commands/package/bundles/create.ts b/src/commands/package/bundles/create.ts new file mode 100644 index 00000000..7d43a0a2 --- /dev/null +++ b/src/commands/package/bundles/create.ts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018, 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { BundleCreateOptions, PackageBundle } from '@salesforce/packaging'; +import { Messages } from '@salesforce/core'; +import { requiredHubFlag } from '../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_create'); +export type BundleCreate = { Id: string }; + +export class PackageBundlesCreate extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly aliases = ['force:bundle:create']; + public static readonly requiresProject = true; + public static readonly flags = { + loglevel, + name: Flags.string({ + char: 'n', + summary: messages.getMessage('flags.name.summary'), + required: true, + }), + description: Flags.string({ + char: 'd', + summary: messages.getMessage('flags.description.summary'), + }), + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundlesCreate); + + const options: BundleCreateOptions = { + Description: flags.description ?? '', + BundleName: flags.name, + }; + this.spinner.start(`Creating Bundle with name ${options.BundleName}`); + const result = await PackageBundle.create( + flags['target-dev-hub'].getConnection(flags['api-version']), + this.project!, + options + ); + + this.spinner.stop(); + this.table({ data: [{ name: 'Bundle Id', value: result.Id }], title: 'Ids' }); + + return result; + } +} From 4ec4a4cb6589598052fe862276e82e01b20b6688 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Wed, 11 Jun 2025 12:54:28 -0600 Subject: [PATCH 09/31] feat: test for bundle create changed comments, added test for bundle create --- src/commands/package/bundles/create.ts | 2 +- test/commands/bundle/bundleCreate.test.ts | 72 +++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 test/commands/bundle/bundleCreate.test.ts diff --git a/src/commands/package/bundles/create.ts b/src/commands/package/bundles/create.ts index 7d43a0a2..42dab556 100644 --- a/src/commands/package/bundles/create.ts +++ b/src/commands/package/bundles/create.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, salesforce.com, inc. + * Copyright (c) 2025, 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 diff --git a/test/commands/bundle/bundleCreate.test.ts b/test/commands/bundle/bundleCreate.test.ts new file mode 100644 index 00000000..fcdf8402 --- /dev/null +++ b/test/commands/bundle/bundleCreate.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import * as sinon from 'sinon'; +import { expect } from 'chai'; +import { BundleCreateOptions, PackageBundle } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import { Connection, SfProject } from '@salesforce/core'; +import { PackageBundlesCreate } from '../../../src/commands/package/bundles/create.js'; + +describe('force:bundle:create - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let createStub: sinon.SinonStub<[Connection, SfProject, BundleCreateOptions], Promise<{ Id: string }>>; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + createStub = $$.SANDBOX.stub(PackageBundle, 'create'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should create a bundle', async () => { + const bundleName = 'dummyPackageId'; + const cmd = new PackageBundlesCreate(['-v', testOrg.username, '--name', bundleName], config); + + createStub.resolves({ Id: 'test-id' }); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); + + it('should throw error when name flag is missing', async () => { + const cmd = new PackageBundlesCreate(['-v', testOrg.username], config); + + createStub.resolves({ Id: 'test-id' }); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('Missing required flag name'); + } + }); + + it('should throw error when test org flag is missing', async () => { + const cmd = new PackageBundlesCreate(['--name', 'dummyPackageId'], config); + + createStub.resolves({ Id: 'test-id' }); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('No default dev hub found'); + } + }); +}); From caca9fae77e2456043fd8372b0a922b8afcb3084 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Wed, 11 Jun 2025 15:41:17 -0600 Subject: [PATCH 10/31] feat: created bundle list command near copy and paste of package list command unit test based off of bundle create --- command-snapshot.json | 8 ++++ messages/bundle_list.md | 61 ++++++++++++++++++++++++ schemas/package-bundles-list.json | 58 +++++++++++++++++++++++ src/commands/package/bundles/list.ts | 63 +++++++++++++++++++++++++ test/commands/bundle/bundleList.test.ts | 56 ++++++++++++++++++++++ 5 files changed, 246 insertions(+) create mode 100644 messages/bundle_list.md create mode 100644 schemas/package-bundles-list.json create mode 100644 src/commands/package/bundles/list.ts create mode 100644 test/commands/bundle/bundleList.test.ts diff --git a/command-snapshot.json b/command-snapshot.json index 005f533e..7ae8e239 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -63,6 +63,14 @@ "flags": ["api-version", "description", "flags-dir", "json", "loglevel", "name", "target-dev-hub"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": ["force:bundle:list"], + "command": "package:bundles:list", + "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], + "flagChars": ["v"], + "flags": ["api-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": ["force:package:convert"], "command": "package:convert", diff --git a/messages/bundle_list.md b/messages/bundle_list.md new file mode 100644 index 00000000..31784e0a --- /dev/null +++ b/messages/bundle_list.md @@ -0,0 +1,61 @@ +# summary + +List all bundles in the Dev Hub org. + +# description + +You can view the namespace, IDs, and other details for each bundle. + +# examples + +- List all bundles in the specified Dev Hub org: + + <%= config.bin %> <%= command.id %> --target-dev-hub devhub@example.com + +- List all bundles details in the specified Dev Hub org, and show extended details about each bundle: + + <%= config.bin %> <%= command.id %> --target-dev-hub devhub@example.com --verbose + +# namespace + +Namespace Prefix + +# name + +Name + +# id + +Id + +# bundle-id + +Subscriber bundle Id + +# alias + +Alias + +# description + +Description + +# flags.verbose.summary + +Display extended bundle detail. + +# convertedFrombundleId + +Converted From bundle Id + +# isOrgDependent + +Org-Dependent Unlocked bundle + +# error-notification-username + +Error Notification Username + +# createdBy + +Created By diff --git a/schemas/package-bundles-list.json b/schemas/package-bundles-list.json new file mode 100644 index 00000000..ca27992a --- /dev/null +++ b/schemas/package-bundles-list.json @@ -0,0 +1,58 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleListCommandResults", + "definitions": { + "BundleListCommandResults": { + "type": "array", + "items": { + "$ref": "#/definitions/BundleListCommandResult" + } + }, + "BundleListCommandResult": { + "$ref": "#/definitions/BundleSObjects.Bundle" + }, + "BundleSObjects.Bundle": { + "type": "object", + "properties": { + "BundleName": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Id": { + "type": "string" + }, + "IsDeleted": { + "type": "boolean" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "LastModifiedDate": { + "type": "string" + }, + "LastModifiedById": { + "type": "string" + }, + "SystemModstamp": { + "type": "string" + } + }, + "required": [ + "BundleName", + "Id", + "IsDeleted", + "CreatedDate", + "CreatedById", + "LastModifiedDate", + "LastModifiedById", + "SystemModstamp" + ], + "additionalProperties": false + } + } +} diff --git a/src/commands/package/bundles/list.ts b/src/commands/package/bundles/list.ts new file mode 100644 index 00000000..b0864970 --- /dev/null +++ b/src/commands/package/bundles/list.ts @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages } from '@salesforce/core/messages'; +import { PackageBundle, BundleSObjects } from '@salesforce/packaging'; +import chalk from 'chalk'; +import { requiredHubFlag } from '../../../utils/hubFlag.js'; + +// This is a near copy of the package list command, but with the package bundle class and messages. +// If you are looking to copy this command, mabye make an abstract class for the commands that are similar.(please) +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_list'); + +export type BundleListCommandResult = BundleSObjects.Bundle; +export type BundleListCommandResults = BundleListCommandResult[]; + +export class BundleListCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly deprecateAliases = true; + public static readonly aliases = ['force:bundle:list']; + public static readonly flags = { + loglevel, + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(BundleListCommand); + const connection = flags['target-dev-hub'].getConnection(flags['api-version']); + const results = await PackageBundle.list(connection); + this.displayResults(results, flags.verbose); + return results; + } + + private displayResults(results: BundleListCommandResults, verbose = false): void { + const data = results.map((r) => ({ + 'Bundle Name': r.BundleName, + Id: r.Id, + Description: r.Description, + ...(verbose + ? { + 'Created Date': r.CreatedDate, + 'Created By': r.CreatedById, + 'Last Modified Date': r.LastModifiedDate, + 'Last Modified By': r.LastModifiedById, + 'System Modstamp': r.SystemModstamp, + 'Is Deleted': r.IsDeleted, + } + : {}), + })); + this.table({ data, title: chalk.blue(`Package Bundles [${results.length}]`) }); + } +} diff --git a/test/commands/bundle/bundleList.test.ts b/test/commands/bundle/bundleList.test.ts new file mode 100644 index 00000000..e99b9233 --- /dev/null +++ b/test/commands/bundle/bundleList.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackageBundle } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import sinon from 'sinon'; +import { BundleListCommand } from '../../../src/commands/package/bundles/list.js'; +describe('force:bundle:list - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let listStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + listStub = $$.SANDBOX.stub(PackageBundle, 'list'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should list a bundle', async () => { + const cmd = new BundleListCommand(['-v', testOrg.username], config); + + listStub.resolves([{ BundleName: 'test-bundle', Id: 'test-id', Description: 'test-description' }]); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); + + it('should throw error when test org flag is missing', async () => { + const cmd = new BundleListCommand([], config); + + listStub.resolves([{ BundleName: 'test-bundle', Id: 'test-id', Description: 'test-description' }]); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('No default dev hub found'); + } + }); +}); From 1a2274a7c8f2c4ccf3c56d2c85c82612126651f1 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Fri, 13 Jun 2025 09:50:14 -0600 Subject: [PATCH 11/31] refactor: cahnged folder name for proper command changed bundles to bundle in order to generate proper command --- command-snapshot.json | 8 +-- messages/bundle_list.md | 8 --- schemas/package-bundle-create.json | 16 +++++ schemas/package-bundle-list.json | 58 +++++++++++++++++++ .../package/{bundles => bundle}/create.ts | 2 +- .../package/{bundles => bundle}/list.ts | 2 +- test/commands/bundle/bundleCreate.test.ts | 2 +- test/commands/bundle/bundleList.test.ts | 2 +- 8 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 schemas/package-bundle-create.json create mode 100644 schemas/package-bundle-list.json rename src/commands/package/{bundles => bundle}/create.ts (96%) rename src/commands/package/{bundles => bundle}/list.ts (97%) diff --git a/command-snapshot.json b/command-snapshot.json index 7ae8e239..c81aa306 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -56,16 +56,16 @@ "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:bundle:create"], - "command": "package:bundles:create", + "alias": ["force:package:bundle:create"], + "command": "package:bundle:create", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["d", "n", "v"], "flags": ["api-version", "description", "flags-dir", "json", "loglevel", "name", "target-dev-hub"], "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:bundle:list"], - "command": "package:bundles:list", + "alias": ["force:package:bundle:list"], + "command": "package:bundle:list", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["v"], "flags": ["api-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], diff --git a/messages/bundle_list.md b/messages/bundle_list.md index 31784e0a..98b3b5d2 100644 --- a/messages/bundle_list.md +++ b/messages/bundle_list.md @@ -44,14 +44,6 @@ Description Display extended bundle detail. -# convertedFrombundleId - -Converted From bundle Id - -# isOrgDependent - -Org-Dependent Unlocked bundle - # error-notification-username Error Notification Username diff --git a/schemas/package-bundle-create.json b/schemas/package-bundle-create.json new file mode 100644 index 00000000..2049f257 --- /dev/null +++ b/schemas/package-bundle-create.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleCreate", + "definitions": { + "BundleCreate": { + "type": "object", + "properties": { + "Id": { + "type": "string" + } + }, + "required": ["Id"], + "additionalProperties": false + } + } +} diff --git a/schemas/package-bundle-list.json b/schemas/package-bundle-list.json new file mode 100644 index 00000000..ca27992a --- /dev/null +++ b/schemas/package-bundle-list.json @@ -0,0 +1,58 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleListCommandResults", + "definitions": { + "BundleListCommandResults": { + "type": "array", + "items": { + "$ref": "#/definitions/BundleListCommandResult" + } + }, + "BundleListCommandResult": { + "$ref": "#/definitions/BundleSObjects.Bundle" + }, + "BundleSObjects.Bundle": { + "type": "object", + "properties": { + "BundleName": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Id": { + "type": "string" + }, + "IsDeleted": { + "type": "boolean" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "LastModifiedDate": { + "type": "string" + }, + "LastModifiedById": { + "type": "string" + }, + "SystemModstamp": { + "type": "string" + } + }, + "required": [ + "BundleName", + "Id", + "IsDeleted", + "CreatedDate", + "CreatedById", + "LastModifiedDate", + "LastModifiedById", + "SystemModstamp" + ], + "additionalProperties": false + } + } +} diff --git a/src/commands/package/bundles/create.ts b/src/commands/package/bundle/create.ts similarity index 96% rename from src/commands/package/bundles/create.ts rename to src/commands/package/bundle/create.ts index 42dab556..d7a837ae 100644 --- a/src/commands/package/bundles/create.ts +++ b/src/commands/package/bundle/create.ts @@ -18,7 +18,7 @@ export class PackageBundlesCreate extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); - public static readonly aliases = ['force:bundle:create']; + public static readonly aliases = ['force:package:bundle:create']; public static readonly requiresProject = true; public static readonly flags = { loglevel, diff --git a/src/commands/package/bundles/list.ts b/src/commands/package/bundle/list.ts similarity index 97% rename from src/commands/package/bundles/list.ts rename to src/commands/package/bundle/list.ts index b0864970..99196fff 100644 --- a/src/commands/package/bundles/list.ts +++ b/src/commands/package/bundle/list.ts @@ -24,7 +24,7 @@ export class BundleListCommand extends SfCommand { public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); public static readonly deprecateAliases = true; - public static readonly aliases = ['force:bundle:list']; + public static readonly aliases = ['force:package:bundle:list']; public static readonly flags = { loglevel, 'target-dev-hub': requiredHubFlag, diff --git a/test/commands/bundle/bundleCreate.test.ts b/test/commands/bundle/bundleCreate.test.ts index fcdf8402..3d91c07a 100644 --- a/test/commands/bundle/bundleCreate.test.ts +++ b/test/commands/bundle/bundleCreate.test.ts @@ -11,7 +11,7 @@ import { expect } from 'chai'; import { BundleCreateOptions, PackageBundle } from '@salesforce/packaging'; import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; import { Connection, SfProject } from '@salesforce/core'; -import { PackageBundlesCreate } from '../../../src/commands/package/bundles/create.js'; +import { PackageBundlesCreate } from '../../../src/commands/package/bundle/create.js'; describe('force:bundle:create - tests', () => { const $$ = new TestContext(); diff --git a/test/commands/bundle/bundleList.test.ts b/test/commands/bundle/bundleList.test.ts index e99b9233..128336bf 100644 --- a/test/commands/bundle/bundleList.test.ts +++ b/test/commands/bundle/bundleList.test.ts @@ -10,7 +10,7 @@ import { expect } from 'chai'; import { PackageBundle } from '@salesforce/packaging'; import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; import sinon from 'sinon'; -import { BundleListCommand } from '../../../src/commands/package/bundles/list.js'; +import { BundleListCommand } from '../../../src/commands/package/bundle/list.js'; describe('force:bundle:list - tests', () => { const $$ = new TestContext(); const testOrg = new MockTestOrgData(); From 7fd279d7f8cb1cd145c2ccfa262786d9d9080a89 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Fri, 13 Jun 2025 11:58:51 -0600 Subject: [PATCH 12/31] docs: renamed bundles -> bundle additionally updates messages --- messages/bundle_create.md | 18 ++++----- messages/bundle_list.md | 16 ++------ schemas/package-bundles-create.json | 16 -------- schemas/package-bundles-list.json | 58 ----------------------------- src/commands/package/bundle/list.ts | 3 +- 5 files changed, 13 insertions(+), 98 deletions(-) delete mode 100644 schemas/package-bundles-create.json delete mode 100644 schemas/package-bundles-list.json diff --git a/messages/bundle_create.md b/messages/bundle_create.md index be02d894..3ffdb7a9 100644 --- a/messages/bundle_create.md +++ b/messages/bundle_create.md @@ -1,24 +1,22 @@ # summary -Create a bundle. +Create a package bundle in the Dev Hub org. # description -First, use this command to create a bunle. Then create a bundle version. - -Your --name value must be unique within your namespace. - -Run '<%= config.bin %> bundle list to list all bundles in the Dev Hub org. +A package bundle is an artifact that contains one or more 2GP managed packages. +A bundle can be listed on AppExchange, installed, or upgraded as a single artifact. # examples -- Default Use Case - <%= config.bin %> <%= command.id %> --name --description "" --target-dev-hub ` +Create a package bundle in the Dev Hub org; uses the Dev Hub org with the username devhub@example.com: + +sf package bundle create --name “Your bundle name” --description "Your bundle description" --target-dev-hub devhub@example.com # flags.name.summary -Name of the bundle to create. +Name of the package bundle. # flags.description.summary -Description of the bundle +Description of the package bundle. diff --git a/messages/bundle_list.md b/messages/bundle_list.md index 98b3b5d2..26bd0921 100644 --- a/messages/bundle_list.md +++ b/messages/bundle_list.md @@ -1,20 +1,12 @@ # summary -List all bundles in the Dev Hub org. - -# description - -You can view the namespace, IDs, and other details for each bundle. +List all package bundles in the Dev Hub org. # examples -- List all bundles in the specified Dev Hub org: - - <%= config.bin %> <%= command.id %> --target-dev-hub devhub@example.com - -- List all bundles details in the specified Dev Hub org, and show extended details about each bundle: +List all package bundles in the specified Dev Hub org; uses the Dev Hub org with the username devhub@example.com: - <%= config.bin %> <%= command.id %> --target-dev-hub devhub@example.com --verbose +sf package bundle list --target-dev-hub # namespace @@ -30,7 +22,7 @@ Id # bundle-id -Subscriber bundle Id +Package Bundle Id # alias diff --git a/schemas/package-bundles-create.json b/schemas/package-bundles-create.json deleted file mode 100644 index 2049f257..00000000 --- a/schemas/package-bundles-create.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/BundleCreate", - "definitions": { - "BundleCreate": { - "type": "object", - "properties": { - "Id": { - "type": "string" - } - }, - "required": ["Id"], - "additionalProperties": false - } - } -} diff --git a/schemas/package-bundles-list.json b/schemas/package-bundles-list.json deleted file mode 100644 index ca27992a..00000000 --- a/schemas/package-bundles-list.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/BundleListCommandResults", - "definitions": { - "BundleListCommandResults": { - "type": "array", - "items": { - "$ref": "#/definitions/BundleListCommandResult" - } - }, - "BundleListCommandResult": { - "$ref": "#/definitions/BundleSObjects.Bundle" - }, - "BundleSObjects.Bundle": { - "type": "object", - "properties": { - "BundleName": { - "type": "string" - }, - "Description": { - "type": "string" - }, - "Id": { - "type": "string" - }, - "IsDeleted": { - "type": "boolean" - }, - "CreatedDate": { - "type": "string" - }, - "CreatedById": { - "type": "string" - }, - "LastModifiedDate": { - "type": "string" - }, - "LastModifiedById": { - "type": "string" - }, - "SystemModstamp": { - "type": "string" - } - }, - "required": [ - "BundleName", - "Id", - "IsDeleted", - "CreatedDate", - "CreatedById", - "LastModifiedDate", - "LastModifiedById", - "SystemModstamp" - ], - "additionalProperties": false - } - } -} diff --git a/src/commands/package/bundle/list.ts b/src/commands/package/bundle/list.ts index 99196fff..33b53046 100644 --- a/src/commands/package/bundle/list.ts +++ b/src/commands/package/bundle/list.ts @@ -21,7 +21,6 @@ export type BundleListCommandResults = BundleListCommandResult[]; export class BundleListCommand extends SfCommand { public static readonly summary = messages.getMessage('summary'); - public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); public static readonly deprecateAliases = true; public static readonly aliases = ['force:package:bundle:list']; @@ -44,7 +43,7 @@ export class BundleListCommand extends SfCommand { private displayResults(results: BundleListCommandResults, verbose = false): void { const data = results.map((r) => ({ - 'Bundle Name': r.BundleName, + 'Package Bundle Name': r.BundleName, Id: r.Id, Description: r.Description, ...(verbose From b40caddde7eec1850deeefa8786e5ed2e3df4ef2 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Wed, 18 Jun 2025 16:18:07 -0600 Subject: [PATCH 13/31] feat: created bundle version create additionally made unit tests, and list, and report features --- command-snapshot.json | 44 ++++ messages/bundle_create.md | 22 +- messages/bundle_version_create.md | 65 +++++ messages/bundle_version_create_report.md | 49 ++++ .../package_bundle_version_create_list.md | 73 ++++++ schemas/package-bundle-create.json | 16 -- .../package-bundle-version-create-report.json | 73 ++++++ schemas/package-bundle-version-create.json | 67 +++++ schemas/package-version-create-list.json | 155 +++++------- src/commands/package/bundle/create.ts | 1 + src/commands/package/bundle/version/create.ts | 112 +++++++++ .../package/bundle/version/create/list.ts | 147 +++++++++++ .../package/bundle/version/create/report.ts | 85 +++++++ .../bundle/bundleVersionCreateList.test.ts | 79 ++++++ .../bundle/bundleVersionCreateReport.test.ts | 139 +++++++++++ .../bundle/packageBundleVersionCreate.test.ts | 230 ++++++++++++++++++ 16 files changed, 1245 insertions(+), 112 deletions(-) create mode 100644 messages/bundle_version_create.md create mode 100644 messages/bundle_version_create_report.md create mode 100644 messages/package_bundle_version_create_list.md delete mode 100644 schemas/package-bundle-create.json create mode 100644 schemas/package-bundle-version-create-report.json create mode 100644 schemas/package-bundle-version-create.json create mode 100644 src/commands/package/bundle/version/create.ts create mode 100644 src/commands/package/bundle/version/create/list.ts create mode 100644 src/commands/package/bundle/version/create/report.ts create mode 100644 test/commands/bundle/bundleVersionCreateList.test.ts create mode 100644 test/commands/bundle/bundleVersionCreateReport.test.ts create mode 100644 test/commands/bundle/packageBundleVersionCreate.test.ts diff --git a/command-snapshot.json b/command-snapshot.json index c81aa306..65662935 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -71,6 +71,50 @@ "flags": ["api-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": ["force:package:bundle:version:create"], + "command": "package:bundle:version:create", + "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], + "flagChars": ["b", "p", "v", "w"], + "flags": [ + "api-version", + "bundle", + "definition-file", + "flags-dir", + "json", + "loglevel", + "target-dev-hub", + "verbose", + "wait" + ], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": ["force:package:bundle:version:create:list"], + "command": "package:bundle:version:create:list", + "flagAliases": ["apiversion", "createdlastdays", "target-hub-org", "targetdevhubusername"], + "flagChars": ["c", "s", "v"], + "flags": [ + "api-version", + "created-last-days", + "flags-dir", + "json", + "loglevel", + "show-conversions-only", + "status", + "target-dev-hub", + "verbose" + ], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": ["force:package:bundle:version:create:report"], + "command": "package:bundle:version:create:report", + "flagAliases": ["apiversion", "packagecreaterequestid", "target-hub-org", "targetdevhubusername"], + "flagChars": ["i", "v"], + "flags": ["api-version", "flags-dir", "json", "loglevel", "package-create-request-id", "target-dev-hub"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": ["force:package:convert"], "command": "package:convert", diff --git a/messages/bundle_create.md b/messages/bundle_create.md index 3ffdb7a9..4eb03ee0 100644 --- a/messages/bundle_create.md +++ b/messages/bundle_create.md @@ -11,7 +11,7 @@ A bundle can be listed on AppExchange, installed, or upgraded as a single artifa Create a package bundle in the Dev Hub org; uses the Dev Hub org with the username devhub@example.com: -sf package bundle create --name “Your bundle name” --description "Your bundle description" --target-dev-hub devhub@example.com +sf package bundle create --name "Your bundle name" --description "Your bundle description" --target-dev-hub devhub@example.com # flags.name.summary @@ -20,3 +20,23 @@ Name of the package bundle. # flags.description.summary Description of the package bundle. + +# flags.wait.summary + +Number of minutes to wait for the bundle creation to complete. + +# flags.verbose.summary + +Display extended bundle creation detail. + +# requestInProgress + +Creating bundle. + +# bundleCreateWaitingStatus + +%d minutes remaining until timeout. Create bundle status: %s + +# bundleCreateFinalStatus + +Create bundle status: %s diff --git a/messages/bundle_version_create.md b/messages/bundle_version_create.md new file mode 100644 index 00000000..33130c88 --- /dev/null +++ b/messages/bundle_version_create.md @@ -0,0 +1,65 @@ +# summary + +Create a new package bundle version. + +# description + +Create a new version of a package bundle with the specified components. + +# examples + +Create a new version of a package bundle: + +sf package bundle version create -b MyBundle -p path/to/definition.json + +# flags.bundle.summary + +The name or ID of the package bundle to create a version for. + +# flags.definition-file.summary + +Path to the JSON file containing the list of components to include in the bundle version. + +# flags.wait.summary + +Number of minutes to wait for the command to complete before timing out. + +# flags.verbose.summary + +Show verbose output of the command execution. + +# flags.verbose.description + +Show detailed information about the bundle version creation process. + +# bundleVersionCreateWaitingStatus + +Waiting for bundle version creation to complete. %s minutes remaining. Current status: %s + +# bundleVersionCreateFinalStatus + +Bundle version creation completed with status: %s + +# multipleErrors + +The following errors occurred during bundle version creation:%s + +# InProgress + +Bundle version creation is %s. Use 'sf package bundle version create report -i %s' to check the status later. + +# requestInProgress + +Creating bundle version... + +# packageVersionCreateFinalStatus + +Package version creation completed with status: %s + +# packageVersionCreatePerformingValidations + +Performing validations on the package version... + +# bundleVersionCreateSuccess + +Successfully created bundle version for bundle %s diff --git a/messages/bundle_version_create_report.md b/messages/bundle_version_create_report.md new file mode 100644 index 00000000..bf8d68d0 --- /dev/null +++ b/messages/bundle_version_create_report.md @@ -0,0 +1,49 @@ +# summary + +Report on the status of a package bundle version creation request. + +# description + +Use this command to check the status of a package bundle version creation request. The command returns information about the request, including its current status and details about the package bundle version being created. + +# examples + +- Report on a package bundle version creation request: + + <%= config.bin %> <%= command.id %> --package-create-request-id 0Ho0x0000000000000 + +- Report on a package bundle version creation request using an alias: + + <%= config.bin %> force:package:bundle:version:create:report -i 0Ho0x0000000000000 + +# flags.package-create-request-id.summary + +The ID of the package bundle version creation request to report on. + +# id + +ID + +# status + +Status + +# package-bundle-id + +Package Bundle ID + +# package-bundle-version-id + +Package Bundle Version ID + +# version-name + +Version Name + +# created-date + +Created Date + +# created-by + +Created By diff --git a/messages/package_bundle_version_create_list.md b/messages/package_bundle_version_create_list.md new file mode 100644 index 00000000..dd6f4a3e --- /dev/null +++ b/messages/package_bundle_version_create_list.md @@ -0,0 +1,73 @@ +# summary + +List package version creation requests. + +# description + +Shows the details of each request to create a package bundle version in the Dev Hub org. + +All filter parameters are applied using the AND logical operator (not OR). + +To get information about a specific request, run "<%= config.bin %> package bundle version create report" and supply the request ID. + +# flags.status.summary + +Status of the version creation request, used to filter the list. + +# flags.show-conversions-only.summary + +Filter the list output to display only converted package bundle version. + +# flags.verbose.summary + +Displays additional information at a slight performance cost, such as the version name and number for each package version create request. + +# flags.created-last-days.summary + +Number of days since the request was created, starting at 00:00:00 of first day to now. Use 0 for today. + +# examples + +- List all package bundle version creation requests in your default Dev Hub org: + + <%= config.bin %> <%= command.id %> + +- List package bundle version creation requests from the last 3 days in the Dev Hub org with username devhub@example.com: + + <%= config.bin %> <%= command.id %> --created-last-days 3 --target-dev-hub + +- List package bundle version creation requests with status Error: + + <%= config.bin %> <%= command.id %> --status Error + +- List package bundle version creation requests with status Queued: + + <%= config.bin %> <%= command.id %> --status Queued + +- List package bundle version creation requests with status Success that were created today: + + <%= config.bin %> <%= command.id %> --created-last-days 0 --status Success + +# id + +ID + +# status + +Status + +# package-id + +Package Bundle Id + +# packageVersionId + +Package Bundle Version Id + +# createdBy + +Created By + +# convertedFromVersionId + +Converted From Version Id diff --git a/schemas/package-bundle-create.json b/schemas/package-bundle-create.json deleted file mode 100644 index 2049f257..00000000 --- a/schemas/package-bundle-create.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/BundleCreate", - "definitions": { - "BundleCreate": { - "type": "object", - "properties": { - "Id": { - "type": "string" - } - }, - "required": ["Id"], - "additionalProperties": false - } - } -} diff --git a/schemas/package-bundle-version-create-report.json b/schemas/package-bundle-version-create-report.json new file mode 100644 index 00000000..59ac8e8c --- /dev/null +++ b/schemas/package-bundle-version-create-report.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/ReportCommandResult", + "definitions": { + "ReportCommandResult": { + "type": "array", + "items": { + "$ref": "#/definitions/BundleSObjects.PackageBundleVersionCreateRequestResult" + } + }, + "BundleSObjects.PackageBundleVersionCreateRequestResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string" + }, + "PackageBundleVersionId": { + "type": "string" + }, + "RequestStatus": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionCreateReqStatus" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "Error": { + "type": "array", + "items": { + "type": "string" + } + }, + "PackageBundleId": { + "type": "string" + }, + "VersionName": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + }, + "BundleVersionComponents": { + "type": "string" + }, + "Ancestor": { + "type": ["string", "null"] + } + }, + "required": [ + "BundleVersionComponents", + "CreatedById", + "CreatedDate", + "Id", + "MajorVersion", + "MinorVersion", + "PackageBundleId", + "PackageBundleVersionId", + "RequestStatus", + "VersionName" + ] + }, + "BundleSObjects.PkgBundleVersionCreateReqStatus": { + "type": "string", + "enum": ["Queued", "Success", "Error"] + } + } +} diff --git a/schemas/package-bundle-version-create.json b/schemas/package-bundle-version-create.json new file mode 100644 index 00000000..9b047a8c --- /dev/null +++ b/schemas/package-bundle-version-create.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleSObjects.PackageBundleVersionCreateRequestResult", + "definitions": { + "BundleSObjects.PackageBundleVersionCreateRequestResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string" + }, + "PackageBundleVersionId": { + "type": "string" + }, + "RequestStatus": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionCreateReqStatus" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "Error": { + "type": "array", + "items": { + "type": "string" + } + }, + "PackageBundleId": { + "type": "string" + }, + "VersionName": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + }, + "BundleVersionComponents": { + "type": "string" + }, + "Ancestor": { + "type": ["string", "null"] + } + }, + "required": [ + "BundleVersionComponents", + "CreatedById", + "CreatedDate", + "Id", + "MajorVersion", + "MinorVersion", + "PackageBundleId", + "PackageBundleVersionId", + "RequestStatus", + "VersionName" + ] + }, + "BundleSObjects.PkgBundleVersionCreateReqStatus": { + "type": "string", + "enum": ["Queued", "Success", "Error"] + } + } +} diff --git a/schemas/package-version-create-list.json b/schemas/package-version-create-list.json index 6881ecb9..1e26283c 100644 --- a/schemas/package-version-create-list.json +++ b/schemas/package-version-create-list.json @@ -1,108 +1,73 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/CreateListCommandResult", + "$ref": "#/definitions/PackageBundleVersionCreateRequestResults", "definitions": { - "CreateListCommandResult": { + "PackageBundleVersionCreateRequestResults": { "type": "array", "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "VersionName": { - "type": "string" - }, - "VersionNumber": { - "type": ["string", "null"] - }, - "Id": { - "type": "string" - }, - "Status": { - "$ref": "#/definitions/PackagingSObjects.Package2VersionStatus" - }, - "Package2Id": { - "type": "string" - }, - "Package2Name": { - "type": ["string", "null"] - }, - "Package2VersionId": { - "type": "string" - }, - "SubscriberPackageVersionId": { - "type": ["string", "null"] - }, - "Tag": { - "type": "string" - }, - "Branch": { - "type": "string" - }, - "Error": { - "type": "array", - "items": {} - }, - "CreatedDate": { - "type": "string" - }, - "HasMetadataRemoved": { - "type": ["boolean", "null"] - }, - "HasPassedCodeCoverageCheck": { - "type": ["boolean", "null"] - }, - "CodeCoverage": { - "type": ["number", "null"] - }, - "CreatedBy": { + "$ref": "#/definitions/BundleSObjects.PackageBundleVersionCreateRequestResult" + } + }, + "BundleSObjects.PackageBundleVersionCreateRequestResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string" + }, + "PackageBundleVersionId": { + "type": "string" + }, + "RequestStatus": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionCreateReqStatus" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "Error": { + "type": "array", + "items": { "type": "string" - }, - "ConvertedFromVersionId": { - "type": ["string", "null"] - }, - "TotalNumberOfMetadataFiles": { - "type": ["number", "null"] - }, - "TotalSizeOfMetadataFiles": { - "type": ["number", "null"] } }, - "required": [ - "Branch", - "CodeCoverage", - "ConvertedFromVersionId", - "CreatedBy", - "CreatedDate", - "Error", - "HasMetadataRemoved", - "HasPassedCodeCoverageCheck", - "Id", - "Package2Id", - "Package2Name", - "Package2VersionId", - "Status", - "SubscriberPackageVersionId", - "Tag", - "TotalNumberOfMetadataFiles", - "TotalSizeOfMetadataFiles", - "VersionNumber" - ] - } + "PackageBundleId": { + "type": "string" + }, + "VersionName": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + }, + "BundleVersionComponents": { + "type": "string" + }, + "Ancestor": { + "type": ["string", "null"] + } + }, + "required": [ + "BundleVersionComponents", + "CreatedById", + "CreatedDate", + "Id", + "MajorVersion", + "MinorVersion", + "PackageBundleId", + "PackageBundleVersionId", + "RequestStatus", + "VersionName" + ] }, - "PackagingSObjects.Package2VersionStatus": { + "BundleSObjects.PkgBundleVersionCreateReqStatus": { "type": "string", - "enum": [ - "Queued", - "InProgress", - "Success", - "Error", - "Initializing", - "VerifyingFeaturesAndSettings", - "VerifyingDependencies", - "VerifyingMetadata", - "FinalizingPackageVersion", - "PerformingValidations" - ] + "enum": ["Queued", "Success", "Error"] } } } diff --git a/src/commands/package/bundle/create.ts b/src/commands/package/bundle/create.ts index d7a837ae..63c45c3c 100644 --- a/src/commands/package/bundle/create.ts +++ b/src/commands/package/bundle/create.ts @@ -42,6 +42,7 @@ export class PackageBundlesCreate extends SfCommand { Description: flags.description ?? '', BundleName: flags.name, }; + this.spinner.start(`Creating Bundle with name ${options.BundleName}`); const result = await PackageBundle.create( flags['target-dev-hub'].getConnection(flags['api-version']), diff --git a/src/commands/package/bundle/version/create.ts b/src/commands/package/bundle/version/create.ts new file mode 100644 index 00000000..5a2b4105 --- /dev/null +++ b/src/commands/package/bundle/version/create.ts @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2025, 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { + BundleVersionCreateOptions, + PackageVersionEvents, + BundleSObjects, + PackageBundleVersion, +} from '@salesforce/packaging'; +import { Messages, Lifecycle } from '@salesforce/core'; +import { camelCaseToTitleCase, Duration } from '@salesforce/kit'; +import { requiredHubFlag } from '../../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +// TODO: Update messages +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_version_create'); +export type BundleVersionCreate = BundleSObjects.PackageBundleVersionCreateRequestResult; + +export class PackageBundlesCreate extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly aliases = ['force:package:bundle:version:create']; + public static readonly requiresProject = true; + public static readonly flags = { + loglevel, + bundle: Flags.string({ + char: 'b', + summary: messages.getMessage('flags.bundle.summary'), + required: true, + }), + 'definition-file': Flags.string({ + char: 'p', + summary: messages.getMessage('flags.definition-file.summary'), + required: true, + }), + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + wait: Flags.integer({ + char: 'w', + summary: messages.getMessage('flags.wait.summary'), + default: 0, + }), + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundlesCreate); + const options: BundleVersionCreateOptions = { + connection: flags['target-dev-hub'].getConnection(flags['api-version']), + project: this.project!, + PackageBundle: flags.bundle, + BundleVersionComponentsPath: flags['definition-file'], + MajorVersion: '', + MinorVersion: '', + Ancestor: '', + }; + Lifecycle.getInstance().on( + PackageVersionEvents.create.progress, + // no async methods + // eslint-disable-next-line @typescript-eslint/require-await + async (data: BundleSObjects.PackageBundleVersionCreateRequestResult & { remainingWaitTime: Duration }) => { + if ( + data.RequestStatus !== BundleSObjects.PkgBundleVersionCreateReqStatus.success && + data.RequestStatus !== BundleSObjects.PkgBundleVersionCreateReqStatus.error + ) { + const status = messages.getMessage('bundleVersionCreateWaitingStatus', [ + data.remainingWaitTime.minutes, + data.RequestStatus, + ]); + if (flags.verbose) { + this.log(status); + } else { + this.spinner.status = status; + } + } + } + ); + + const result = await PackageBundleVersion.create({ + ...options, + polling: { + timeout: Duration.minutes(flags.wait), + frequency: Duration.seconds(5), + }, + }); + const finalStatusMsg = messages.getMessage('bundleVersionCreateFinalStatus', [result.RequestStatus]); + if (flags.verbose) { + this.log(finalStatusMsg); + } else { + this.spinner.stop(finalStatusMsg); + } + + switch (result.RequestStatus) { + case BundleSObjects.PkgBundleVersionCreateReqStatus.error: + throw messages.createError('multipleErrors', ['Unknown error']); + case BundleSObjects.PkgBundleVersionCreateReqStatus.success: + this.log(messages.getMessage('bundleVersionCreateSuccess', [result.Id])); + break; + default: + this.log(messages.getMessage('InProgress', [camelCaseToTitleCase(result.RequestStatus as string), result.Id])); + } + return result; + } +} diff --git a/src/commands/package/bundle/version/create/list.ts b/src/commands/package/bundle/version/create/list.ts new file mode 100644 index 00000000..436f2cd4 --- /dev/null +++ b/src/commands/package/bundle/version/create/list.ts @@ -0,0 +1,147 @@ +/* + * 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Connection, Messages } from '@salesforce/core'; +import { + PackageVersion, + getPackageVersionNumber, + BundleSObjects, + PackageBundleVersionCreate, +} from '@salesforce/packaging'; +import chalk from 'chalk'; +import { requiredHubFlag } from '../../../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_bundle_version_create_list'); + +type Status = BundleSObjects.PkgBundleVersionCreateReqStatus; +export type PackageBundleVersionCreateRequestResults = BundleSObjects.PackageBundleVersionCreateRequestResult[]; + +export class PackageVersionCreateListCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly deprecateAliases = true; + public static readonly aliases = ['force:package:bundle:version:create:list']; + public static readonly flags = { + loglevel, + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + 'created-last-days': Flags.integer({ + char: 'c', + deprecateAliases: true, + aliases: ['createdlastdays'], + summary: messages.getMessage('flags.created-last-days.summary'), + }), + status: Flags.custom({ + options: [ + BundleSObjects.PkgBundleVersionCreateReqStatus.queued, + BundleSObjects.PkgBundleVersionCreateReqStatus.success, + BundleSObjects.PkgBundleVersionCreateReqStatus.error, + ], + })({ + char: 's', + summary: messages.getMessage('flags.status.summary'), + }), + 'show-conversions-only': Flags.boolean({ + summary: messages.getMessage('flags.show-conversions-only.summary'), + }), + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + }), + }; + + private connection!: Connection; + + public async run(): Promise { + const { flags } = await this.parse(PackageVersionCreateListCommand); + this.connection = flags['target-dev-hub'].getConnection(flags['api-version']); + let results = await PackageBundleVersionCreate.getCreateStatuses( + this.connection, + flags.status, + flags['created-last-days'] + ); + + if (results.length === 0) { + this.warn('No results found'); + } else { + if (flags.verbose) { + try { + results = await this.fetchVerboseData(results); + } catch (err) { + const errMsg = typeof err === 'string' ? err : err instanceof Error ? err.message : 'unknown error'; + this.warn(`error when retrieving verbose data (package name and version) due to: ${errMsg}`); + } + } + + const data = results.map((r) => ({ + Id: r.Id ?? 'N/A', + Status: r.RequestStatus ?? 'Unknown', + 'Package Bundle Id': r.PackageBundleId ?? 'N/A', + 'Package Bundle Version Id': r.PackageBundleVersionId ?? 'N/A', + 'Created Date': r.CreatedDate ?? 'N/A', + 'Created By': r.CreatedById ?? 'N/A', + ...(flags.verbose + ? { + 'Version Name': r.VersionName ?? 'N/A', + 'Major Version': r.MajorVersion ?? 'N/A', + 'Minor Version': r.MinorVersion ?? 'N/A', + } + : {}), + })); + + this.table({ data, overflow: 'wrap', title: chalk.blue(`Package Version Create Requests [${results.length}]`) }); + } + + return results; + } + + // Queries Package2Version for the name and version number of the packages and adds that data + // to the results. + private async fetchVerboseData( + results: PackageBundleVersionCreateRequestResults + ): Promise { + type VersionDataMap = { + [id: string]: { name: string; version: string }; + }; + + // Filter out any results without a valid PackageBundleVersionId + const validResults = results.filter((r) => r?.PackageBundleVersionId); + if (validResults.length === 0) { + return results; + } + + // Query for the version name and number data + const versionData = await PackageVersion.queryPackage2Version(this.connection, { + fields: ['Id', 'Name', 'MajorVersion', 'MinorVersion', 'PatchVersion', 'BuildNumber'], + whereClause: "WHERE Id IN ('%IDS%')", + whereClauseItems: validResults.map((pvcrr) => pvcrr.PackageBundleVersionId), + }); + + const vDataMap: VersionDataMap = {}; + versionData.forEach((vData) => { + if (vData?.Id) { + const version = getPackageVersionNumber(vData, true); + vDataMap[vData.Id] = { name: vData.Name, version }; + } + }); + + return results.map((pvcrr) => { + if (pvcrr?.PackageBundleVersionId && vDataMap[pvcrr.PackageBundleVersionId]) { + return { + ...pvcrr, + ...{ + VersionName: vDataMap[pvcrr.PackageBundleVersionId].name, + VersionNumber: vDataMap[pvcrr.PackageBundleVersionId].version, + }, + }; + } + return pvcrr; + }); + } +} diff --git a/src/commands/package/bundle/version/create/report.ts b/src/commands/package/bundle/version/create/report.ts new file mode 100644 index 00000000..a4a4c0f0 --- /dev/null +++ b/src/commands/package/bundle/version/create/report.ts @@ -0,0 +1,85 @@ +/* + * 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages } from '@salesforce/core'; +import { BundleSObjects, PackageBundleVersionCreate } from '@salesforce/packaging'; +import chalk from 'chalk'; +import { camelCaseToTitleCase } from '@salesforce/kit'; +import { requiredHubFlag } from '../../../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_version_create_report'); + +export type ReportCommandResult = BundleSObjects.PackageBundleVersionCreateRequestResult[]; + +export class PackageBundleVersionCreateReportCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly deprecateAliases = true; + public static readonly aliases = ['force:package:bundle:version:create:report']; + public static readonly flags = { + loglevel, + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + // eslint-disable-next-line sf-plugin/id-flag-suggestions + 'package-create-request-id': Flags.salesforceId({ + length: 'both', + deprecateAliases: true, + aliases: ['packagecreaterequestid'], + char: 'i', + summary: messages.getMessage('flags.package-create-request-id.summary'), + required: true, + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundleVersionCreateReportCommand); + const result = await PackageBundleVersionCreate.getCreateStatus( + flags['package-create-request-id'], + flags['target-dev-hub'].getConnection(flags['api-version']) + ); + this.display(result); + return [result]; + } + + private display(record: BundleSObjects.PackageBundleVersionCreateRequestResult): void { + const data = [ + { + name: messages.getMessage('id'), + value: record.Id, + }, + { + name: messages.getMessage('status'), + value: camelCaseToTitleCase(record.RequestStatus), + }, + { + name: messages.getMessage('package-bundle-id'), + value: record.PackageBundleId, + }, + { + name: messages.getMessage('package-bundle-version-id'), + value: record.PackageBundleVersionId, + }, + { + name: messages.getMessage('version-name'), + value: record.VersionName, + }, + { + name: messages.getMessage('created-date'), + value: record.CreatedDate, + }, + { + name: messages.getMessage('created-by'), + value: record.CreatedById, + }, + ]; + + this.table({ data, title: chalk.blue('Package Bundle Version Create Request') }); + } +} diff --git a/test/commands/bundle/bundleVersionCreateList.test.ts b/test/commands/bundle/bundleVersionCreateList.test.ts new file mode 100644 index 00000000..a92933c0 --- /dev/null +++ b/test/commands/bundle/bundleVersionCreateList.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackageBundleVersionCreate } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import sinon from 'sinon'; +import { PackageVersionCreateListCommand } from '../../../src/commands/package/bundle/version/create/list.js'; + +describe('bundle:version:create:list - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let getCreateStatusesStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + getCreateStatusesStub = $$.SANDBOX.stub(PackageBundleVersionCreate, 'getCreateStatuses'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should list bundle version create requests', async () => { + const cmd = new PackageVersionCreateListCommand(['--target-dev-hub', testOrg.username], config); + + const mockResults = [ + { + Id: 'test-id-1', + RequestStatus: 'Success', + PackageBundleId: 'bundle-id-1', + PackageBundleVersionId: 'version-id-1', + CreatedDate: '2023-01-01T00:00:00Z', + CreatedById: 'user-id-1', + }, + ]; + + getCreateStatusesStub.resolves(mockResults); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + expect(getCreateStatusesStub.calledOnce).to.be.true; + }); + + it('should show warning when no results found', async () => { + const cmd = new PackageVersionCreateListCommand(['--target-dev-hub', testOrg.username], config); + + getCreateStatusesStub.resolves([]); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.warn.calledOnce).to.be.true; + expect(sfCommandStubs.warn.firstCall.args[0]).to.equal('No results found'); + }); + + it('should throw error when target-dev-hub flag is missing', async () => { + const cmd = new PackageVersionCreateListCommand([], config); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('No default dev hub found'); + } + }); +}); diff --git a/test/commands/bundle/bundleVersionCreateReport.test.ts b/test/commands/bundle/bundleVersionCreateReport.test.ts new file mode 100644 index 00000000..e7d1abfa --- /dev/null +++ b/test/commands/bundle/bundleVersionCreateReport.test.ts @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackageBundleVersionCreate, BundleSObjects } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import sinon from 'sinon'; +import { PackageBundleVersionCreateReportCommand } from '../../../src/commands/package/bundle/version/create/report.js'; + +describe('force:package:bundle:version:create:report - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let getCreateStatusStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + getCreateStatusStub = $$.SANDBOX.stub(PackageBundleVersionCreate, 'getCreateStatus'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should report on a package bundle version creation request', async () => { + const requestId = '0Ho0x0000000000000'; + const mockResult: BundleSObjects.PackageBundleVersionCreateRequestResult = { + Id: requestId, + RequestStatus: BundleSObjects.PkgBundleVersionCreateReqStatus.queued, + PackageBundleId: '0Ho0x0000000000001', + PackageBundleVersionId: '0Ho0x0000000000002', + VersionName: '1.0.0', + MajorVersion: '1', + MinorVersion: '0', + BundleVersionComponents: '[{"packageId": "0Ho0x0000000000001", "versionNumber": "1.0.0"}]', + Error: [], + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + Ancestor: null, + }; + + getCreateStatusStub.resolves(mockResult); + + const cmd = new PackageBundleVersionCreateReportCommand( + ['--package-create-request-id', requestId, '--target-dev-hub', testOrg.username], + config + ); + + await cmd.run(); + + expect(getCreateStatusStub.calledOnce).to.be.true; + expect(getCreateStatusStub.firstCall.args[0]).to.equal(requestId); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); + + it('should report on a package bundle version creation request using alias flag', async () => { + const requestId = '0Ho0x0000000000000'; + const mockResult: BundleSObjects.PackageBundleVersionCreateRequestResult = { + Id: requestId, + RequestStatus: BundleSObjects.PkgBundleVersionCreateReqStatus.success, + PackageBundleId: '0Ho0x0000000000001', + PackageBundleVersionId: '0Ho0x0000000000002', + VersionName: '1.0.0', + MajorVersion: '1', + MinorVersion: '0', + BundleVersionComponents: '[{"packageId": "0Ho0x0000000000001", "versionNumber": "1.0.0"}]', + Error: [], + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + Ancestor: null, + }; + + getCreateStatusStub.resolves(mockResult); + + const cmd = new PackageBundleVersionCreateReportCommand( + ['-i', requestId, '--target-dev-hub', testOrg.username], + config + ); + + await cmd.run(); + + expect(getCreateStatusStub.calledOnce).to.be.true; + expect(getCreateStatusStub.firstCall.args[0]).to.equal(requestId); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); + + it('should throw error when package-create-request-id flag is missing', async () => { + const cmd = new PackageBundleVersionCreateReportCommand(['--target-dev-hub', testOrg.username], config); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('Missing required flag'); + } + }); + + it('should throw error when target-dev-hub flag is missing', async () => { + const requestId = '0Ho0x0000000000000'; + const cmd = new PackageBundleVersionCreateReportCommand(['--package-create-request-id', requestId], config); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('No default dev hub found'); + } + }); + + it('should handle API errors gracefully', async () => { + const requestId = '0Ho0x0000000000000'; + const errorMessage = 'Package bundle version creation request not found'; + + getCreateStatusStub.rejects(new Error(errorMessage)); + + const cmd = new PackageBundleVersionCreateReportCommand( + ['--package-create-request-id', requestId, '--target-dev-hub', testOrg.username], + config + ); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include(errorMessage); + } + }); +}); diff --git a/test/commands/bundle/packageBundleVersionCreate.test.ts b/test/commands/bundle/packageBundleVersionCreate.test.ts new file mode 100644 index 00000000..0a3495a4 --- /dev/null +++ b/test/commands/bundle/packageBundleVersionCreate.test.ts @@ -0,0 +1,230 @@ +/* + * 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 { MockTestOrgData, TestContext } from '@salesforce/core/testSetup'; +import { Config } from '@oclif/core'; +import { assert, expect } from 'chai'; +import { PackageBundleVersion, BundleSObjects } from '@salesforce/packaging'; +import sinon from 'sinon'; +import { SfCommand } from '@salesforce/sf-plugins-core'; +import { PackageBundlesCreate } from '../../../src/commands/package/bundle/version/create.js'; + +const pkgBundleVersionCreateErrorResult: BundleSObjects.PackageBundleVersionCreateRequestResult = { + Id: '08c3i000000fylXXXX', + RequestStatus: BundleSObjects.PkgBundleVersionCreateReqStatus.error, + PackageBundleId: '0Ho3i000000TNHXXXX', + PackageBundleVersionId: '', + VersionName: 'TestBundle@1.0', + MajorVersion: '1', + MinorVersion: '0', + BundleVersionComponents: '[]', + Error: [ + 'PropertyController: Invalid type: Schema.Property__c', + 'SampleDataController: Invalid type: Schema.Property__c', + 'SampleDataController: Invalid type: Schema.Broker__c', + ], + CreatedDate: '2022-11-03 09:21', + CreatedById: '0053i000001ZIyXXXX', + Ancestor: null, +}; + +const pkgBundleVersionCreateSuccessResult: BundleSObjects.PackageBundleVersionCreateRequestResult = { + Id: '08c3i000000fylgAAA', + RequestStatus: BundleSObjects.PkgBundleVersionCreateReqStatus.success, + PackageBundleId: '0Ho3i000000TNHYCA4', + PackageBundleVersionId: '05i3i000000fxw1AAA', + VersionName: 'TestBundle@1.0', + MajorVersion: '1', + MinorVersion: '0', + BundleVersionComponents: '[{"packageId": "0Ho3i000000TNHYCA4", "versionNumber": "1.0.0"}]', + Error: [], + CreatedDate: '2022-11-03 09:46', + CreatedById: '0053i000001ZIyGAAW', + Ancestor: null, +}; + +const pkgBundleVersionCreateQueuedResult: BundleSObjects.PackageBundleVersionCreateRequestResult = { + Id: '08c3i000000fylgBBB', + RequestStatus: BundleSObjects.PkgBundleVersionCreateReqStatus.queued, + PackageBundleId: '0Ho3i000000TNHYCA4', + PackageBundleVersionId: '', + VersionName: 'TestBundle@1.1', + MajorVersion: '1', + MinorVersion: '1', + BundleVersionComponents: '[{"packageId": "0Ho3i000000TNHYCA4", "versionNumber": "1.1.0"}]', + Error: [], + CreatedDate: '2022-11-03 10:00', + CreatedById: '0053i000001ZIyGAAW', + Ancestor: null, +}; + +describe('package:bundle:version:create - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let createStub = $$.SANDBOX.stub(PackageBundleVersion, 'create'); + const config = new Config({ root: import.meta.url }); + + // stubs + let logStub: sinon.SinonStub; + let warnStub: sinon.SinonStub; + + const stubSpinner = (cmd: PackageBundlesCreate) => { + $$.SANDBOX.stub(cmd.spinner, 'start'); + $$.SANDBOX.stub(cmd.spinner, 'stop'); + }; + + before(async () => { + await $$.stubAuths(testOrg); + await config.load(); + }); + + beforeEach(async () => { + logStub = $$.SANDBOX.stub(SfCommand.prototype, 'log'); + warnStub = $$.SANDBOX.stub(SfCommand.prototype, 'warn'); + }); + + afterEach(() => { + $$.restore(); + }); + + describe('package:bundle:version:create', () => { + it('should create a new package bundle version', async () => { + createStub.resolves(pkgBundleVersionCreateSuccessResult); + + const cmd = new PackageBundlesCreate( + ['-b', 'TestBundle', '-p', 'path/to/definition.json', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgAAA', + RequestStatus: 'Success', + PackageBundleId: '0Ho3i000000TNHYCA4', + PackageBundleVersionId: '05i3i000000fxw1AAA', + VersionName: 'TestBundle@1.0', + MajorVersion: '1', + MinorVersion: '0', + BundleVersionComponents: '[{"packageId": "0Ho3i000000TNHYCA4", "versionNumber": "1.0.0"}]', + Error: [], + CreatedDate: '2022-11-03 09:46', + CreatedById: '0053i000001ZIyGAAW', + Ancestor: null, + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(1); + expect(logStub.args[0]).to.deep.equal(['Successfully created bundle version for bundle 08c3i000000fylgAAA']); + }); + + it('should create a new package bundle version with wait option', async () => { + createStub = $$.SANDBOX.stub(PackageBundleVersion, 'create'); + createStub.resolves(pkgBundleVersionCreateSuccessResult); + + const cmd = new PackageBundlesCreate( + ['-b', 'TestBundle', '-p', 'path/to/definition.json', '-w', '10', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgAAA', + RequestStatus: 'Success', + PackageBundleId: '0Ho3i000000TNHYCA4', + PackageBundleVersionId: '05i3i000000fxw1AAA', + VersionName: 'TestBundle@1.0', + MajorVersion: '1', + MinorVersion: '0', + BundleVersionComponents: '[{"packageId": "0Ho3i000000TNHYCA4", "versionNumber": "1.0.0"}]', + Error: [], + CreatedDate: '2022-11-03 09:46', + CreatedById: '0053i000001ZIyGAAW', + Ancestor: null, + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(1); + expect(logStub.args[0]).to.deep.equal(['Successfully created bundle version for bundle 08c3i000000fylgAAA']); + }); + + it('should create a new package bundle version with verbose option', async () => { + createStub = $$.SANDBOX.stub(PackageBundleVersion, 'create'); + createStub.resolves(pkgBundleVersionCreateSuccessResult); + + const cmd = new PackageBundlesCreate( + ['-b', 'TestBundle', '-p', 'path/to/definition.json', '--verbose', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgAAA', + RequestStatus: 'Success', + PackageBundleId: '0Ho3i000000TNHYCA4', + PackageBundleVersionId: '05i3i000000fxw1AAA', + VersionName: 'TestBundle@1.0', + MajorVersion: '1', + MinorVersion: '0', + BundleVersionComponents: '[{"packageId": "0Ho3i000000TNHYCA4", "versionNumber": "1.0.0"}]', + Error: [], + CreatedDate: '2022-11-03 09:46', + CreatedById: '0053i000001ZIyGAAW', + Ancestor: null, + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(2); + expect(logStub.args[0]).to.deep.equal(['Bundle version creation completed with status: Success']); + expect(logStub.args[1]).to.deep.equal(['Successfully created bundle version for bundle 08c3i000000fylgAAA']); + }); + + it('should handle queued status', async () => { + createStub = $$.SANDBOX.stub(PackageBundleVersion, 'create'); + createStub.resolves(pkgBundleVersionCreateQueuedResult); + + const cmd = new PackageBundlesCreate( + ['-b', 'TestBundle', '-p', 'path/to/definition.json', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgBBB', + RequestStatus: 'Queued', + PackageBundleId: '0Ho3i000000TNHYCA4', + PackageBundleVersionId: '', + VersionName: 'TestBundle@1.1', + MajorVersion: '1', + MinorVersion: '1', + BundleVersionComponents: '[{"packageId": "0Ho3i000000TNHYCA4", "versionNumber": "1.1.0"}]', + Error: [], + CreatedDate: '2022-11-03 10:00', + CreatedById: '0053i000001ZIyGAAW', + Ancestor: null, + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(1); + expect(logStub.args[0]).to.deep.equal([ + "Bundle version creation is Queued. Use 'sf package bundle version create report -i 08c3i000000fylgBBB' to check the status later.", + ]); + }); + + it('should report multiple errors', async () => { + createStub = $$.SANDBOX.stub(PackageBundleVersion, 'create'); + createStub.resolves(pkgBundleVersionCreateErrorResult); + try { + const cmd = new PackageBundlesCreate( + ['-b', 'TestBundle', '-p', 'path/to/definition.json', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + await cmd.run(); + assert.fail('the above should throw multiple errors'); + } catch (e) { + expect((e as Error).message).to.equal( + 'The following errors occurred during bundle version creation:Unknown error' + ); + } + }); + }); +}); From 0011cc6b8bb70b6f205c374e4bc935f75fda9c51 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Thu, 19 Jun 2025 07:51:52 -0600 Subject: [PATCH 14/31] style: renamed bundle message file for consistency --- ...dle_version_create_list.md => bundle_version_create_list.md} | 0 src/commands/package/bundle/version/create/list.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename messages/{package_bundle_version_create_list.md => bundle_version_create_list.md} (100%) diff --git a/messages/package_bundle_version_create_list.md b/messages/bundle_version_create_list.md similarity index 100% rename from messages/package_bundle_version_create_list.md rename to messages/bundle_version_create_list.md diff --git a/src/commands/package/bundle/version/create/list.ts b/src/commands/package/bundle/version/create/list.ts index 436f2cd4..fdef8427 100644 --- a/src/commands/package/bundle/version/create/list.ts +++ b/src/commands/package/bundle/version/create/list.ts @@ -17,7 +17,7 @@ import chalk from 'chalk'; import { requiredHubFlag } from '../../../../../utils/hubFlag.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); -const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_bundle_version_create_list'); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_version_create_list'); type Status = BundleSObjects.PkgBundleVersionCreateReqStatus; export type PackageBundleVersionCreateRequestResults = BundleSObjects.PackageBundleVersionCreateRequestResult[]; From e3edf8438b09f042d117776c4469aabea0d1774c Mon Sep 17 00:00:00 2001 From: Dawson David Date: Fri, 20 Jun 2025 11:31:37 -0600 Subject: [PATCH 15/31] style: added Bundle to list class --- messages/bundle_version_create.md | 6 +- .../package-bundle-version-create-list.json | 73 +++++++++ schemas/package-version-create-list.json | 155 +++++++++++------- .../package/bundle/version/create/list.ts | 10 +- .../bundle/bundleVersionCreateList.test.ts | 8 +- .../bundle/packageBundleVersionCreate.test.ts | 2 +- 6 files changed, 183 insertions(+), 71 deletions(-) create mode 100644 schemas/package-bundle-version-create-list.json diff --git a/messages/bundle_version_create.md b/messages/bundle_version_create.md index 33130c88..135cb7da 100644 --- a/messages/bundle_version_create.md +++ b/messages/bundle_version_create.md @@ -38,7 +38,7 @@ Waiting for bundle version creation to complete. %s minutes remaining. Current s # bundleVersionCreateFinalStatus -Bundle version creation completed with status: %s +Package Bundle version creation completed with status: %s # multipleErrors @@ -54,11 +54,11 @@ Creating bundle version... # packageVersionCreateFinalStatus -Package version creation completed with status: %s +Package Bundle version creation completed with status: %s # packageVersionCreatePerformingValidations -Performing validations on the package version... +Performing validations on the package bundle version... # bundleVersionCreateSuccess diff --git a/schemas/package-bundle-version-create-list.json b/schemas/package-bundle-version-create-list.json new file mode 100644 index 00000000..1e26283c --- /dev/null +++ b/schemas/package-bundle-version-create-list.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/PackageBundleVersionCreateRequestResults", + "definitions": { + "PackageBundleVersionCreateRequestResults": { + "type": "array", + "items": { + "$ref": "#/definitions/BundleSObjects.PackageBundleVersionCreateRequestResult" + } + }, + "BundleSObjects.PackageBundleVersionCreateRequestResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string" + }, + "PackageBundleVersionId": { + "type": "string" + }, + "RequestStatus": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionCreateReqStatus" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "Error": { + "type": "array", + "items": { + "type": "string" + } + }, + "PackageBundleId": { + "type": "string" + }, + "VersionName": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + }, + "BundleVersionComponents": { + "type": "string" + }, + "Ancestor": { + "type": ["string", "null"] + } + }, + "required": [ + "BundleVersionComponents", + "CreatedById", + "CreatedDate", + "Id", + "MajorVersion", + "MinorVersion", + "PackageBundleId", + "PackageBundleVersionId", + "RequestStatus", + "VersionName" + ] + }, + "BundleSObjects.PkgBundleVersionCreateReqStatus": { + "type": "string", + "enum": ["Queued", "Success", "Error"] + } + } +} diff --git a/schemas/package-version-create-list.json b/schemas/package-version-create-list.json index 1e26283c..6881ecb9 100644 --- a/schemas/package-version-create-list.json +++ b/schemas/package-version-create-list.json @@ -1,73 +1,108 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/PackageBundleVersionCreateRequestResults", + "$ref": "#/definitions/CreateListCommandResult", "definitions": { - "PackageBundleVersionCreateRequestResults": { + "CreateListCommandResult": { "type": "array", "items": { - "$ref": "#/definitions/BundleSObjects.PackageBundleVersionCreateRequestResult" - } - }, - "BundleSObjects.PackageBundleVersionCreateRequestResult": { - "type": "object", - "additionalProperties": false, - "properties": { - "Id": { - "type": "string" - }, - "PackageBundleVersionId": { - "type": "string" - }, - "RequestStatus": { - "$ref": "#/definitions/BundleSObjects.PkgBundleVersionCreateReqStatus" - }, - "CreatedDate": { - "type": "string" - }, - "CreatedById": { - "type": "string" - }, - "Error": { - "type": "array", - "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "VersionName": { + "type": "string" + }, + "VersionNumber": { + "type": ["string", "null"] + }, + "Id": { + "type": "string" + }, + "Status": { + "$ref": "#/definitions/PackagingSObjects.Package2VersionStatus" + }, + "Package2Id": { + "type": "string" + }, + "Package2Name": { + "type": ["string", "null"] + }, + "Package2VersionId": { + "type": "string" + }, + "SubscriberPackageVersionId": { + "type": ["string", "null"] + }, + "Tag": { "type": "string" + }, + "Branch": { + "type": "string" + }, + "Error": { + "type": "array", + "items": {} + }, + "CreatedDate": { + "type": "string" + }, + "HasMetadataRemoved": { + "type": ["boolean", "null"] + }, + "HasPassedCodeCoverageCheck": { + "type": ["boolean", "null"] + }, + "CodeCoverage": { + "type": ["number", "null"] + }, + "CreatedBy": { + "type": "string" + }, + "ConvertedFromVersionId": { + "type": ["string", "null"] + }, + "TotalNumberOfMetadataFiles": { + "type": ["number", "null"] + }, + "TotalSizeOfMetadataFiles": { + "type": ["number", "null"] } }, - "PackageBundleId": { - "type": "string" - }, - "VersionName": { - "type": "string" - }, - "MajorVersion": { - "type": "string" - }, - "MinorVersion": { - "type": "string" - }, - "BundleVersionComponents": { - "type": "string" - }, - "Ancestor": { - "type": ["string", "null"] - } - }, - "required": [ - "BundleVersionComponents", - "CreatedById", - "CreatedDate", - "Id", - "MajorVersion", - "MinorVersion", - "PackageBundleId", - "PackageBundleVersionId", - "RequestStatus", - "VersionName" - ] + "required": [ + "Branch", + "CodeCoverage", + "ConvertedFromVersionId", + "CreatedBy", + "CreatedDate", + "Error", + "HasMetadataRemoved", + "HasPassedCodeCoverageCheck", + "Id", + "Package2Id", + "Package2Name", + "Package2VersionId", + "Status", + "SubscriberPackageVersionId", + "Tag", + "TotalNumberOfMetadataFiles", + "TotalSizeOfMetadataFiles", + "VersionNumber" + ] + } }, - "BundleSObjects.PkgBundleVersionCreateReqStatus": { + "PackagingSObjects.Package2VersionStatus": { "type": "string", - "enum": ["Queued", "Success", "Error"] + "enum": [ + "Queued", + "InProgress", + "Success", + "Error", + "Initializing", + "VerifyingFeaturesAndSettings", + "VerifyingDependencies", + "VerifyingMetadata", + "FinalizingPackageVersion", + "PerformingValidations" + ] } } } diff --git a/src/commands/package/bundle/version/create/list.ts b/src/commands/package/bundle/version/create/list.ts index fdef8427..b974d244 100644 --- a/src/commands/package/bundle/version/create/list.ts +++ b/src/commands/package/bundle/version/create/list.ts @@ -22,7 +22,7 @@ const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_v type Status = BundleSObjects.PkgBundleVersionCreateReqStatus; export type PackageBundleVersionCreateRequestResults = BundleSObjects.PackageBundleVersionCreateRequestResult[]; -export class PackageVersionCreateListCommand extends SfCommand { +export class PackageBundleVersionCreateListCommand extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); @@ -59,7 +59,7 @@ export class PackageVersionCreateListCommand extends SfCommand { - const { flags } = await this.parse(PackageVersionCreateListCommand); + const { flags } = await this.parse(PackageBundleVersionCreateListCommand); this.connection = flags['target-dev-hub'].getConnection(flags['api-version']); let results = await PackageBundleVersionCreate.getCreateStatuses( this.connection, @@ -95,7 +95,11 @@ export class PackageVersionCreateListCommand extends SfCommand { const $$ = new TestContext(); @@ -32,7 +32,7 @@ describe('bundle:version:create:list - tests', () => { }); it('should list bundle version create requests', async () => { - const cmd = new PackageVersionCreateListCommand(['--target-dev-hub', testOrg.username], config); + const cmd = new PackageBundleVersionCreateListCommand(['--target-dev-hub', testOrg.username], config); const mockResults = [ { @@ -55,7 +55,7 @@ describe('bundle:version:create:list - tests', () => { }); it('should show warning when no results found', async () => { - const cmd = new PackageVersionCreateListCommand(['--target-dev-hub', testOrg.username], config); + const cmd = new PackageBundleVersionCreateListCommand(['--target-dev-hub', testOrg.username], config); getCreateStatusesStub.resolves([]); @@ -67,7 +67,7 @@ describe('bundle:version:create:list - tests', () => { }); it('should throw error when target-dev-hub flag is missing', async () => { - const cmd = new PackageVersionCreateListCommand([], config); + const cmd = new PackageBundleVersionCreateListCommand([], config); try { await cmd.run(); diff --git a/test/commands/bundle/packageBundleVersionCreate.test.ts b/test/commands/bundle/packageBundleVersionCreate.test.ts index 0a3495a4..4ac8d278 100644 --- a/test/commands/bundle/packageBundleVersionCreate.test.ts +++ b/test/commands/bundle/packageBundleVersionCreate.test.ts @@ -174,7 +174,7 @@ describe('package:bundle:version:create - tests', () => { }); expect(warnStub.callCount).to.equal(0); expect(logStub.callCount).to.equal(2); - expect(logStub.args[0]).to.deep.equal(['Bundle version creation completed with status: Success']); + expect(logStub.args[0]).to.deep.equal(['Package Bundle version creation completed with status: Success']); expect(logStub.args[1]).to.deep.equal(['Successfully created bundle version for bundle 08c3i000000fylgAAA']); }); From 4f4a6a04eedef92fff91859c5d5e8e2143c2e78f Mon Sep 17 00:00:00 2001 From: Dawson David Date: Mon, 23 Jun 2025 11:33:18 -0600 Subject: [PATCH 16/31] feat: added package version list --- command-snapshot.json | 11 +- messages/bundle_version_create.md | 4 + messages/bundle_version_list.md | 45 ++++++ schemas/package-bundle-version-list.json | 113 ++++++++++++++ src/commands/package/bundle/version/create.ts | 5 + src/commands/package/bundle/version/list.ts | 138 ++++++++++++++++++ .../commands/bundle/bundleVersionList.test.ts | 104 +++++++++++++ 7 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 messages/bundle_version_list.md create mode 100644 schemas/package-bundle-version-list.json create mode 100644 src/commands/package/bundle/version/list.ts create mode 100644 test/commands/bundle/bundleVersionList.test.ts diff --git a/command-snapshot.json b/command-snapshot.json index 65662935..5d5f4733 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -75,11 +75,12 @@ "alias": ["force:package:bundle:version:create"], "command": "package:bundle:version:create", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], - "flagChars": ["b", "p", "v", "w"], + "flagChars": ["b", "d", "p", "v", "w"], "flags": [ "api-version", "bundle", "definition-file", + "description", "flags-dir", "json", "loglevel", @@ -115,6 +116,14 @@ "flags": ["api-version", "flags-dir", "json", "loglevel", "package-create-request-id", "target-dev-hub"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": ["force:package:bundle:version:list"], + "command": "package:bundle:version:list", + "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], + "flagChars": ["v"], + "flags": ["api-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": ["force:package:convert"], "command": "package:convert", diff --git a/messages/bundle_version_create.md b/messages/bundle_version_create.md index 135cb7da..d42d96ad 100644 --- a/messages/bundle_version_create.md +++ b/messages/bundle_version_create.md @@ -32,6 +32,10 @@ Show verbose output of the command execution. Show detailed information about the bundle version creation process. +# flags.description.summary + +Description of the package bundle version. + # bundleVersionCreateWaitingStatus Waiting for bundle version creation to complete. %s minutes remaining. Current status: %s diff --git a/messages/bundle_version_list.md b/messages/bundle_version_list.md new file mode 100644 index 00000000..0d58230c --- /dev/null +++ b/messages/bundle_version_list.md @@ -0,0 +1,45 @@ +# summary + +List all package bundle versions in the Dev Hub org. + +# examples + +List all package bundle versions in the specified Dev Hub org; uses the Dev Hub org with the username devhub@example.com: + +sf package bundle version list --target-dev-hub + +# namespace + +Namespace Prefix + +# name + +Name + +# id + +Id + +# bundle-id + +Package Bundle Id + +# alias + +Alias + +# description + +Description + +# flags.verbose.summary + +Display extended bundle detail. + +# error-notification-username + +Error Notification Username + +# createdBy + +Created By diff --git a/schemas/package-bundle-version-list.json b/schemas/package-bundle-version-list.json new file mode 100644 index 00000000..37c23994 --- /dev/null +++ b/schemas/package-bundle-version-list.json @@ -0,0 +1,113 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/PackageBundleVersionResults", + "definitions": { + "PackageBundleVersionResults": { + "type": "array", + "items": { + "$ref": "#/definitions/BundleSObjects.BundleVersion" + } + }, + "BundleSObjects.BundleVersion": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "PackageBundle": { + "$ref": "#/definitions/BundleSObjects.Bundle" + }, + "VersionName": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + }, + "Ancestor": { + "anyOf": [ + { + "$ref": "#/definitions/BundleSObjects.BundleVersion" + }, + { + "type": "null" + } + ] + }, + "IsReleased": { + "type": "boolean" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "LastModifiedDate": { + "type": "string" + }, + "LastModifiedById": { + "type": "string" + } + }, + "required": [ + "Id", + "PackageBundle", + "VersionName", + "MajorVersion", + "MinorVersion", + "IsReleased", + "CreatedDate", + "CreatedById", + "LastModifiedDate", + "LastModifiedById" + ], + "additionalProperties": false + }, + "BundleSObjects.Bundle": { + "type": "object", + "properties": { + "BundleName": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Id": { + "type": "string" + }, + "IsDeleted": { + "type": "boolean" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "LastModifiedDate": { + "type": "string" + }, + "LastModifiedById": { + "type": "string" + }, + "SystemModstamp": { + "type": "string" + } + }, + "required": [ + "BundleName", + "Id", + "IsDeleted", + "CreatedDate", + "CreatedById", + "LastModifiedDate", + "LastModifiedById", + "SystemModstamp" + ], + "additionalProperties": false + } + } +} diff --git a/src/commands/package/bundle/version/create.ts b/src/commands/package/bundle/version/create.ts index 5a2b4105..111d8f47 100644 --- a/src/commands/package/bundle/version/create.ts +++ b/src/commands/package/bundle/version/create.ts @@ -34,6 +34,10 @@ export class PackageBundlesCreate extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly deprecateAliases = true; + public static readonly aliases = ['force:package:bundle:version:list']; + public static readonly flags = { + loglevel, + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + }), + }; + + private connection!: Connection; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundleVersionListCommand); + this.connection = flags['target-dev-hub'].getConnection(flags['api-version']); + let results = await PackageBundleVersion.list(this.connection); + + if (results.length === 0) { + this.warn('No results found'); + } else { + if (flags.verbose) { + try { + results = await this.fetchVerboseData(results); + } catch (err) { + const errMsg = typeof err === 'string' ? err : err instanceof Error ? err.message : 'unknown error'; + this.warn(`error when retrieving verbose data (package name and version) due to: ${errMsg}`); + } + } + + const data = results.map((r) => ({ + 'Bundle Name': r.PackageBundle.BundleName ?? 'N/A', + 'Bundle Id': r.PackageBundle.Id ?? 'N/A', + 'Bundle Version Number': String(r.MajorVersion ?? 'N/A') + '.' + String(r.MinorVersion ?? 'N/A'), + 'Bundle Version Id': r.Id ?? 'N/A', + 'Bundle Version Name': r.VersionName ?? 'N/A', + 'Bundle Version Description': r.PackageBundle.Description ?? 'N/A', + ...(flags.verbose + ? { + 'Ancestor Id': r.Ancestor?.Id ?? 'N/A', + 'Ancestor Name': r.Ancestor?.PackageBundle.BundleName ?? 'N/A', + 'Ancestor Version Name': r.Ancestor?.VersionName ?? 'N/A', + 'Ancestor Version': + String(r.Ancestor?.MajorVersion ?? 'N/A') + '.' + String(r.Ancestor?.MinorVersion ?? 'N/A'), + 'Created Date': r.CreatedDate ?? 'N/A', + 'Created By': r.CreatedById ?? 'N/A', + 'Last Modified Date': r.LastModifiedDate ?? 'N/A', + 'Last Modified By': r.LastModifiedById ?? 'N/A', + } + : {}), + })); + + this.table({ + data, + overflow: 'wrap', + title: chalk.blue(`Package Bundle Version List [${results.length}]`), + }); + } + + return results; + } + + // Queries Package2Version for the name and version number of the packages and adds that data + // to the results. + private async fetchVerboseData(results: PackageBundleVersionResults): Promise { + type VersionDataMap = { + [id: string]: { name: string; version: string }; + }; + + // Filter out any results without a valid PackageBundleVersionId + const validResults = results.filter((r) => r?.Id); + if (validResults.length === 0) { + return results; + } + + // Query for the version name and number data + const versionData = await PackageVersion.queryPackage2Version(this.connection, { + fields: [ + 'Id', + 'Name', + 'MajorVersion', + 'MinorVersion', + 'PatchVersion', + 'BuildNumber', + 'CreatedDate', + 'CreatedById', + 'LastModifiedDate', + 'LastModifiedById', + 'SystemModstamp', + ], + whereClause: "WHERE Id IN ('%IDS%')", + whereClauseItems: validResults.map((pvcrr) => pvcrr.Id), + }); + + const vDataMap: VersionDataMap = {}; + versionData.forEach((vData) => { + if (vData?.Id) { + const version = getPackageVersionNumber(vData, true); + vDataMap[vData.Id] = { name: vData.Name, version }; + } + }); + + return results.map((pvcrr) => { + if (pvcrr?.Id && vDataMap[pvcrr.Id]) { + return { + ...pvcrr, + ...{ + VersionName: vDataMap[pvcrr.Id].name, + VersionNumber: vDataMap[pvcrr.Id].version, + }, + }; + } + return pvcrr; + }); + } +} diff --git a/test/commands/bundle/bundleVersionList.test.ts b/test/commands/bundle/bundleVersionList.test.ts new file mode 100644 index 00000000..4d02ab26 --- /dev/null +++ b/test/commands/bundle/bundleVersionList.test.ts @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackageBundleVersion } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import sinon from 'sinon'; +import { PackageBundleVersionListCommand } from '../../../src/commands/package/bundle/version/list.js'; +describe('package:bundle:version:list - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let listStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + listStub = $$.SANDBOX.stub(PackageBundleVersion, 'list'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should list a bundle', async () => { + const cmd = new PackageBundleVersionListCommand(['-v', testOrg.username], config); + + listStub.resolves([ + { + Id: 'test-version-id', + PackageBundle: { + Id: 'test-bundle-id', + BundleName: 'test-bundle', + Description: undefined, + IsDeleted: false, + CreatedDate: '2025-01-01T00:00:00.000Z', + CreatedById: 'test-user-id', + LastModifiedDate: '2025-01-01T00:00:00.000Z', + LastModifiedById: 'test-user-id', + SystemModstamp: '2025-01-01T00:00:00.000Z', + }, + VersionName: 'test-version', + MajorVersion: '1', + MinorVersion: '0', + CreatedDate: '2025-01-01T00:00:00.000Z', + CreatedById: 'test-user-id', + LastModifiedDate: '2025-01-01T00:00:00.000Z', + LastModifiedById: 'test-user-id', + Ancestor: null, + IsReleased: false, + }, + ]); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); + + it('should throw error when test org flag is missing', async () => { + const cmd = new PackageBundleVersionListCommand([], config); + + listStub.resolves([ + { + Id: 'test-version-id', + PackageBundle: { + Id: 'test-bundle-id', + BundleName: 'test-bundle', + Description: undefined, + IsDeleted: false, + CreatedDate: '2025-01-01T00:00:00.000Z', + CreatedById: 'test-user-id', + LastModifiedDate: '2025-01-01T00:00:00.000Z', + LastModifiedById: 'test-user-id', + SystemModstamp: '2025-01-01T00:00:00.000Z', + }, + VersionName: 'test-version', + MajorVersion: '1', + MinorVersion: '0', + CreatedDate: '2025-01-01T00:00:00.000Z', + CreatedById: 'test-user-id', + LastModifiedDate: '2025-01-01T00:00:00.000Z', + LastModifiedById: 'test-user-id', + Ancestor: null, + IsReleased: false, + }, + ]); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('No default dev hub found'); + } + }); +}); From 4c302996b604552309f945d313777abe7c7cdbf7 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Mon, 23 Jun 2025 13:38:03 -0600 Subject: [PATCH 17/31] fix: removed N/A injection from plugin --- src/commands/package/bundle/version/list.ts | 29 ++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/commands/package/bundle/version/list.ts b/src/commands/package/bundle/version/list.ts index 75ed239f..4682f92e 100644 --- a/src/commands/package/bundle/version/list.ts +++ b/src/commands/package/bundle/version/list.ts @@ -51,23 +51,22 @@ export class PackageBundleVersionListCommand extends SfCommand ({ - 'Bundle Name': r.PackageBundle.BundleName ?? 'N/A', - 'Bundle Id': r.PackageBundle.Id ?? 'N/A', - 'Bundle Version Number': String(r.MajorVersion ?? 'N/A') + '.' + String(r.MinorVersion ?? 'N/A'), - 'Bundle Version Id': r.Id ?? 'N/A', - 'Bundle Version Name': r.VersionName ?? 'N/A', - 'Bundle Version Description': r.PackageBundle.Description ?? 'N/A', + 'Bundle Name': r.PackageBundle.BundleName, + 'Bundle Id': r.PackageBundle.Id, + 'Bundle Version Number': String(r.MajorVersion) + '.' + String(r.MinorVersion), + 'Bundle Version Id': r.Id, + 'Bundle Version Name': r.VersionName, + 'Bundle Version Description': r.PackageBundle.Description, ...(flags.verbose ? { - 'Ancestor Id': r.Ancestor?.Id ?? 'N/A', - 'Ancestor Name': r.Ancestor?.PackageBundle.BundleName ?? 'N/A', - 'Ancestor Version Name': r.Ancestor?.VersionName ?? 'N/A', - 'Ancestor Version': - String(r.Ancestor?.MajorVersion ?? 'N/A') + '.' + String(r.Ancestor?.MinorVersion ?? 'N/A'), - 'Created Date': r.CreatedDate ?? 'N/A', - 'Created By': r.CreatedById ?? 'N/A', - 'Last Modified Date': r.LastModifiedDate ?? 'N/A', - 'Last Modified By': r.LastModifiedById ?? 'N/A', + 'Ancestor Id': r.Ancestor?.Id, + 'Ancestor Name': r.Ancestor?.PackageBundle.BundleName, + 'Ancestor Version Name': r.Ancestor?.VersionName, + 'Ancestor Version': String(r.Ancestor?.MajorVersion) + '.' + String(r.Ancestor?.MinorVersion), + 'Created Date': r.CreatedDate, + 'Created By': r.CreatedById, + 'Last Modified Date': r.LastModifiedDate, + 'Last Modified By': r.LastModifiedById, } : {}), })); From 7f0a57890c5433a2a3815377fe0a8ba65e393e28 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Mon, 23 Jun 2025 13:58:15 -0600 Subject: [PATCH 18/31] fix: removed force alias --- command-snapshot.json | 2 +- src/commands/package/bundle/version/list.ts | 69 +-------------------- 2 files changed, 3 insertions(+), 68 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index 5d5f4733..0e109da1 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -117,7 +117,7 @@ "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:package:bundle:version:list"], + "alias": [], "command": "package:bundle:version:list", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["v"], diff --git a/src/commands/package/bundle/version/list.ts b/src/commands/package/bundle/version/list.ts index 4682f92e..ef716567 100644 --- a/src/commands/package/bundle/version/list.ts +++ b/src/commands/package/bundle/version/list.ts @@ -7,7 +7,7 @@ import { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; import { Connection, Messages } from '@salesforce/core'; -import { PackageVersion, getPackageVersionNumber, BundleSObjects, PackageBundleVersion } from '@salesforce/packaging'; +import { BundleSObjects, PackageBundleVersion } from '@salesforce/packaging'; import chalk from 'chalk'; import { requiredHubFlag } from '../../../../utils/hubFlag.js'; @@ -20,8 +20,6 @@ export class PackageBundleVersionListCommand extends SfCommand { const { flags } = await this.parse(PackageBundleVersionListCommand); this.connection = flags['target-dev-hub'].getConnection(flags['api-version']); - let results = await PackageBundleVersion.list(this.connection); + const results = await PackageBundleVersion.list(this.connection); if (results.length === 0) { this.warn('No results found'); } else { - if (flags.verbose) { - try { - results = await this.fetchVerboseData(results); - } catch (err) { - const errMsg = typeof err === 'string' ? err : err instanceof Error ? err.message : 'unknown error'; - this.warn(`error when retrieving verbose data (package name and version) due to: ${errMsg}`); - } - } - const data = results.map((r) => ({ 'Bundle Name': r.PackageBundle.BundleName, 'Bundle Id': r.PackageBundle.Id, @@ -80,58 +69,4 @@ export class PackageBundleVersionListCommand extends SfCommand { - type VersionDataMap = { - [id: string]: { name: string; version: string }; - }; - - // Filter out any results without a valid PackageBundleVersionId - const validResults = results.filter((r) => r?.Id); - if (validResults.length === 0) { - return results; - } - - // Query for the version name and number data - const versionData = await PackageVersion.queryPackage2Version(this.connection, { - fields: [ - 'Id', - 'Name', - 'MajorVersion', - 'MinorVersion', - 'PatchVersion', - 'BuildNumber', - 'CreatedDate', - 'CreatedById', - 'LastModifiedDate', - 'LastModifiedById', - 'SystemModstamp', - ], - whereClause: "WHERE Id IN ('%IDS%')", - whereClauseItems: validResults.map((pvcrr) => pvcrr.Id), - }); - - const vDataMap: VersionDataMap = {}; - versionData.forEach((vData) => { - if (vData?.Id) { - const version = getPackageVersionNumber(vData, true); - vDataMap[vData.Id] = { name: vData.Name, version }; - } - }); - - return results.map((pvcrr) => { - if (pvcrr?.Id && vDataMap[pvcrr.Id]) { - return { - ...pvcrr, - ...{ - VersionName: vDataMap[pvcrr.Id].name, - VersionNumber: vDataMap[pvcrr.Id].version, - }, - }; - } - return pvcrr; - }); - } } From 693bba72c9a13e8e86f885af4f154dee24c95617 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Mon, 23 Jun 2025 14:04:23 -0600 Subject: [PATCH 19/31] fix: generated new schemas From 34da2e4174aacf22beb60cbd2bd1cde78f031843 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Tue, 24 Jun 2025 09:09:38 -0600 Subject: [PATCH 20/31] feat: non tested implementation of package bundle version report --- command-snapshot.json | 8 + messages/bundle_version_report.md | 25 +++ schemas/package-bundle-version-report.json | 107 ++++++++++ src/commands/package/bundle/version/report.ts | 193 ++++++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 messages/bundle_version_report.md create mode 100644 schemas/package-bundle-version-report.json create mode 100644 src/commands/package/bundle/version/report.ts diff --git a/command-snapshot.json b/command-snapshot.json index 0e109da1..8b4c9b9b 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -124,6 +124,14 @@ "flags": ["api-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": [], + "command": "package:bundle:version:report", + "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], + "flagChars": ["p", "v"], + "flags": ["api-version", "bundle-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": ["force:package:convert"], "command": "package:convert", diff --git a/messages/bundle_version_report.md b/messages/bundle_version_report.md new file mode 100644 index 00000000..6864411b --- /dev/null +++ b/messages/bundle_version_report.md @@ -0,0 +1,25 @@ +# summary + +Retrieve details about a package bundle version in the Dev Hub org. + +# description + +Use this command to retrieve detailed information about a package bundle version, including its bundle information, version details, and ancestor information if available. + +# examples + +- Retrieve details about the package bundle version with the specified ID from your default Dev Hub org: + + <%= config.bin %> <%= command.id %> --bundle-version 0Ho0x0000000000000 + +- Retrieve details about the package bundle version with verbose output: + + <%= config.bin %> <%= command.id %> --bundle-version 0Ho0x0000000000000 --verbose + +# flags.bundleVersion.summary + +ID of the package bundle version to retrieve details for. + +# flags.verbose.summary + +Display extended package bundle version details. diff --git a/schemas/package-bundle-version-report.json b/schemas/package-bundle-version-report.json new file mode 100644 index 00000000..772bf5e3 --- /dev/null +++ b/schemas/package-bundle-version-report.json @@ -0,0 +1,107 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleSObjects.BundleVersion", + "definitions": { + "BundleSObjects.BundleVersion": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "PackageBundle": { + "$ref": "#/definitions/BundleSObjects.Bundle" + }, + "VersionName": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + }, + "Ancestor": { + "anyOf": [ + { + "$ref": "#/definitions/BundleSObjects.BundleVersion" + }, + { + "type": "null" + } + ] + }, + "IsReleased": { + "type": "boolean" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "LastModifiedDate": { + "type": "string" + }, + "LastModifiedById": { + "type": "string" + } + }, + "required": [ + "Id", + "PackageBundle", + "VersionName", + "MajorVersion", + "MinorVersion", + "IsReleased", + "CreatedDate", + "CreatedById", + "LastModifiedDate", + "LastModifiedById" + ], + "additionalProperties": false + }, + "BundleSObjects.Bundle": { + "type": "object", + "properties": { + "BundleName": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Id": { + "type": "string" + }, + "IsDeleted": { + "type": "boolean" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "LastModifiedDate": { + "type": "string" + }, + "LastModifiedById": { + "type": "string" + }, + "SystemModstamp": { + "type": "string" + } + }, + "required": [ + "BundleName", + "Id", + "IsDeleted", + "CreatedDate", + "CreatedById", + "LastModifiedDate", + "LastModifiedById", + "SystemModstamp" + ], + "additionalProperties": false + } + } +} diff --git a/src/commands/package/bundle/version/report.ts b/src/commands/package/bundle/version/report.ts new file mode 100644 index 00000000..79018577 --- /dev/null +++ b/src/commands/package/bundle/version/report.ts @@ -0,0 +1,193 @@ +/* + * 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages } from '@salesforce/core/messages'; +import { PackageBundleVersion, BundleSObjects, PackagingSObjects } from '@salesforce/packaging'; +import chalk from 'chalk'; +import { requiredHubFlag } from '../../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_version_report'); + +export class PackageBundleVersionReportCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly flags = { + loglevel, + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + 'bundle-version': Flags.string({ + char: 'p', + summary: messages.getMessage('flags.bundleVersion.summary'), + required: true, + }), + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundleVersionReportCommand); + const connection = flags['target-dev-hub'].getConnection(flags['api-version']); + const results = await PackageBundleVersion.report(connection, flags['bundle-version']); + const componentPackages = await PackageBundleVersion.componentPackages(connection, flags['bundle-version']); + + if (!results) { + throw new Error(`No bundle version found with ID: ${flags['bundle-version']}`); + } + + const massagedResults = this.massageResultsForDisplay(results); + this.display(massagedResults, flags.verbose); + this.displayComponentPackages(componentPackages); + return massagedResults; + } + + private display(record: BundleSObjects.BundleVersion, verbose: boolean): void { + if (this.jsonEnabled()) { + return; + } + + // transform the results into a table + const displayRecords = [ + { + key: 'Bundle Name', + value: record.PackageBundle.BundleName, + }, + { + key: 'Bundle ID', + value: record.PackageBundle.Id, + }, + { + key: 'Version ID', + value: record.Id, + }, + { + key: 'Version Name', + value: record.VersionName, + }, + { + key: 'Major Version', + value: record.MajorVersion, + }, + { + key: 'Minor Version', + value: record.MinorVersion, + }, + { + key: 'Description', + value: record.PackageBundle.Description ?? 'N/A', + }, + { + key: 'Released', + value: record.IsReleased ? 'Yes' : 'No', + }, + { + key: 'Created Date', + value: record.CreatedDate, + }, + { + key: 'Created By', + value: record.CreatedById, + }, + { + key: 'Last Modified Date', + value: record.LastModifiedDate, + }, + { + key: 'Last Modified By', + value: record.LastModifiedById, + }, + ]; + + // Add ancestor information if available + if (record.Ancestor) { + displayRecords.push( + { + key: 'Ancestor ID', + value: record.Ancestor.Id, + }, + { + key: 'Ancestor Version', + value: `${record.Ancestor.MajorVersion}.${record.Ancestor.MinorVersion}`, + }, + { + key: 'Ancestor Bundle Name', + value: record.Ancestor.PackageBundle.BundleName, + } + ); + } else { + displayRecords.push({ + key: 'Ancestor', + value: 'N/A', + }); + } + + // Add verbose information if requested + if (verbose) { + displayRecords.push( + { + key: 'Bundle Deleted', + value: record.PackageBundle.IsDeleted ? 'Yes' : 'No', + }, + { + key: 'Bundle System Modstamp', + value: record.PackageBundle.SystemModstamp, + } + ); + } + + this.filterVerboseRecords(record, displayRecords, verbose); + + this.table({ data: displayRecords, title: chalk.blue('Package Bundle Version') }); + } + + // eslint-disable-next-line class-methods-use-this + private filterVerboseRecords( + bundleRecord: BundleSObjects.BundleVersion, + displayRecords: Array>, + verbose: boolean + ): void { + if (!verbose) { + // Remove verbose fields for non-verbose output + const verboseKeys = ['Bundle Deleted', 'Bundle System Modstamp']; + displayRecords.splice( + 0, + displayRecords.length, + ...displayRecords.filter((displayRecord) => !verboseKeys.includes(displayRecord.key as string)) + ); + } + } + + // eslint-disable-next-line class-methods-use-this + private massageResultsForDisplay(results: BundleSObjects.BundleVersion): BundleSObjects.BundleVersion { + // For bundle versions, the data is already in the correct format + // Just return the results as they are + return results; + } + + private displayComponentPackages(componentPackages: PackagingSObjects.SubscriberPackageVersion[]): void { + if (this.jsonEnabled()) { + return; + } + + if (componentPackages.length === 0) { + this.log(chalk.yellow('No component packages found for this bundle version.')); + return; + } + + const displayRecords = componentPackages.map((component) => ({ + 'Package Name': component.Name, + 'Package Version Number': `${component.MajorVersion}.${component.MinorVersion}.${component.PatchVersion}.${component.BuildNumber}`, + 'Package Version Id': component.Id, + 'Package Subscriber Id': component.SubscriberPackageId, + })); + + this.table({ data: displayRecords, title: chalk.blue('Component Packages') }); + } +} From 55ac9efdae8b3bc2162cf32666ace1254e2a5ca1 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Wed, 25 Jun 2025 10:49:40 -0600 Subject: [PATCH 21/31] feat: created package bundle version report --- command-snapshot.json | 10 +- messages/bundle_version_list.md | 4 +- messages/bundle_version_report.md | 14 +- src/commands/package/bundle/create.ts | 1 - src/commands/package/bundle/list.ts | 2 - src/commands/package/bundle/version/create.ts | 1 - .../package/bundle/version/create/list.ts | 2 - .../package/bundle/version/create/report.ts | 2 - src/commands/package/bundle/version/report.ts | 5 +- src/commands/package/install.ts | 2 +- src/commands/package/push-upgrade/report.ts | 1 + test/commands/bundle/bundleCreate.test.ts | 2 +- test/commands/bundle/bundleList.test.ts | 2 +- .../bundle/bundleVersionCreateList.test.ts | 2 +- .../bundle/bundleVersionCreateReport.test.ts | 2 +- .../bundle/bundleVersionReport.test.ts | 347 ++++++++++++++++++ 16 files changed, 365 insertions(+), 34 deletions(-) create mode 100644 test/commands/bundle/bundleVersionReport.test.ts diff --git a/command-snapshot.json b/command-snapshot.json index 8b4c9b9b..7147f72b 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -56,7 +56,7 @@ "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:package:bundle:create"], + "alias": [], "command": "package:bundle:create", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["d", "n", "v"], @@ -64,7 +64,7 @@ "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:package:bundle:list"], + "alias": [], "command": "package:bundle:list", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["v"], @@ -72,7 +72,7 @@ "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:package:bundle:version:create"], + "alias": [], "command": "package:bundle:version:create", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["b", "d", "p", "v", "w"], @@ -91,7 +91,7 @@ "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:package:bundle:version:create:list"], + "alias": [], "command": "package:bundle:version:create:list", "flagAliases": ["apiversion", "createdlastdays", "target-hub-org", "targetdevhubusername"], "flagChars": ["c", "s", "v"], @@ -109,7 +109,7 @@ "plugin": "@salesforce/plugin-packaging" }, { - "alias": ["force:package:bundle:version:create:report"], + "alias": [], "command": "package:bundle:version:create:report", "flagAliases": ["apiversion", "packagecreaterequestid", "target-hub-org", "targetdevhubusername"], "flagChars": ["i", "v"], diff --git a/messages/bundle_version_list.md b/messages/bundle_version_list.md index 0d58230c..c20fc6b4 100644 --- a/messages/bundle_version_list.md +++ b/messages/bundle_version_list.md @@ -4,9 +4,9 @@ List all package bundle versions in the Dev Hub org. # examples -List all package bundle versions in the specified Dev Hub org; uses the Dev Hub org with the username devhub@example.com: +List package bundle versions in the Dev Hub org with the username devhub@example.com: -sf package bundle version list --target-dev-hub +sf package bundle version list --bundle “Your bundle name or ID” --target-dev-hub devhub@example.com # namespace diff --git a/messages/bundle_version_report.md b/messages/bundle_version_report.md index 6864411b..32529e91 100644 --- a/messages/bundle_version_report.md +++ b/messages/bundle_version_report.md @@ -2,21 +2,13 @@ Retrieve details about a package bundle version in the Dev Hub org. -# description - -Use this command to retrieve detailed information about a package bundle version, including its bundle information, version details, and ancestor information if available. - # examples -- Retrieve details about the package bundle version with the specified ID from your default Dev Hub org: - - <%= config.bin %> <%= command.id %> --bundle-version 0Ho0x0000000000000 - -- Retrieve details about the package bundle version with verbose output: +Retrieve details about the package bundle version; uses the Dev Hub org with the username devhub@example.com: - <%= config.bin %> <%= command.id %> --bundle-version 0Ho0x0000000000000 --verbose +sf package bundle version report --bundle-version "Your bundle version name or ID" --target-dev-hub devhub@example.com -# flags.bundleVersion.summary +# flags.bundle-version.summary ID of the package bundle version to retrieve details for. diff --git a/src/commands/package/bundle/create.ts b/src/commands/package/bundle/create.ts index 63c45c3c..dcf0e6a3 100644 --- a/src/commands/package/bundle/create.ts +++ b/src/commands/package/bundle/create.ts @@ -18,7 +18,6 @@ export class PackageBundlesCreate extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); - public static readonly aliases = ['force:package:bundle:create']; public static readonly requiresProject = true; public static readonly flags = { loglevel, diff --git a/src/commands/package/bundle/list.ts b/src/commands/package/bundle/list.ts index 33b53046..db552ad6 100644 --- a/src/commands/package/bundle/list.ts +++ b/src/commands/package/bundle/list.ts @@ -22,8 +22,6 @@ export type BundleListCommandResults = BundleListCommandResult[]; export class BundleListCommand extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly examples = messages.getMessages('examples'); - public static readonly deprecateAliases = true; - public static readonly aliases = ['force:package:bundle:list']; public static readonly flags = { loglevel, 'target-dev-hub': requiredHubFlag, diff --git a/src/commands/package/bundle/version/create.ts b/src/commands/package/bundle/version/create.ts index 111d8f47..a8037283 100644 --- a/src/commands/package/bundle/version/create.ts +++ b/src/commands/package/bundle/version/create.ts @@ -25,7 +25,6 @@ export class PackageBundlesCreate extends SfCommand { public static readonly summary = messages.getMessage('summary'); - public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); public static readonly flags = { loglevel, @@ -24,7 +23,7 @@ export class PackageBundleVersionReportCommand extends SfCommand { enableRss = await this.confirm({ message: promptMsg }); } if (enableRss) { - request.EnableRss = enableRss; + Object.assign(request, { EnableRss: enableRss }); } } } diff --git a/src/commands/package/push-upgrade/report.ts b/src/commands/package/push-upgrade/report.ts index caecd67d..d26c2e37 100644 --- a/src/commands/package/push-upgrade/report.ts +++ b/src/commands/package/push-upgrade/report.ts @@ -39,6 +39,7 @@ export class PackagePushUpgradeReportCommand extends SfCommand { +describe('package:bundle:create - tests', () => { const $$ = new TestContext(); const testOrg = new MockTestOrgData(); let sfCommandStubs: ReturnType; diff --git a/test/commands/bundle/bundleList.test.ts b/test/commands/bundle/bundleList.test.ts index 128336bf..420014c0 100644 --- a/test/commands/bundle/bundleList.test.ts +++ b/test/commands/bundle/bundleList.test.ts @@ -11,7 +11,7 @@ import { PackageBundle } from '@salesforce/packaging'; import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; import sinon from 'sinon'; import { BundleListCommand } from '../../../src/commands/package/bundle/list.js'; -describe('force:bundle:list - tests', () => { +describe('package:bundle:list - tests', () => { const $$ = new TestContext(); const testOrg = new MockTestOrgData(); let sfCommandStubs: ReturnType; diff --git a/test/commands/bundle/bundleVersionCreateList.test.ts b/test/commands/bundle/bundleVersionCreateList.test.ts index 3e7ecd30..8fa398dd 100644 --- a/test/commands/bundle/bundleVersionCreateList.test.ts +++ b/test/commands/bundle/bundleVersionCreateList.test.ts @@ -12,7 +12,7 @@ import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; import sinon from 'sinon'; import { PackageBundleVersionCreateListCommand } from '../../../src/commands/package/bundle/version/create/list.js'; -describe('bundle:version:create:list - tests', () => { +describe('package:bundle:version:create:list - tests', () => { const $$ = new TestContext(); const testOrg = new MockTestOrgData(); let sfCommandStubs: ReturnType; diff --git a/test/commands/bundle/bundleVersionCreateReport.test.ts b/test/commands/bundle/bundleVersionCreateReport.test.ts index e7d1abfa..e87e96c5 100644 --- a/test/commands/bundle/bundleVersionCreateReport.test.ts +++ b/test/commands/bundle/bundleVersionCreateReport.test.ts @@ -12,7 +12,7 @@ import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; import sinon from 'sinon'; import { PackageBundleVersionCreateReportCommand } from '../../../src/commands/package/bundle/version/create/report.js'; -describe('force:package:bundle:version:create:report - tests', () => { +describe('package:bundle:version:create:report - tests', () => { const $$ = new TestContext(); const testOrg = new MockTestOrgData(); let sfCommandStubs: ReturnType; diff --git a/test/commands/bundle/bundleVersionReport.test.ts b/test/commands/bundle/bundleVersionReport.test.ts new file mode 100644 index 00000000..55c47e26 --- /dev/null +++ b/test/commands/bundle/bundleVersionReport.test.ts @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackageBundleVersion, BundleSObjects, PackagingSObjects } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import sinon from 'sinon'; +import { PackageBundleVersionReportCommand } from '../../../src/commands/package/bundle/version/report.js'; + +describe('package:bundle:version:report - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let reportStub: sinon.SinonStub; + let componentPackagesStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + reportStub = $$.SANDBOX.stub(PackageBundleVersion, 'report'); + componentPackagesStub = $$.SANDBOX.stub(PackageBundleVersion, 'componentPackages'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should report on a package bundle version', async () => { + const bundleVersionId = '0Ho0x0000000000000'; + const mockBundleVersion: BundleSObjects.BundleVersion = { + Id: bundleVersionId, + IsReleased: false, + PackageBundle: { + Id: '0Ho0x0000000000001', + BundleName: 'Test Bundle', + Description: 'Test bundle description', + IsDeleted: false, + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + SystemModstamp: '2025-01-01T00:00:00.000+0000', + }, + VersionName: '1.0.0', + MajorVersion: '1', + MinorVersion: '0', + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + Ancestor: null, + }; + + const mockComponentPackages: PackagingSObjects.SubscriberPackageVersion[] = [ + { + Id: '04t0000000000001', + Name: 'Test Package 1', + MajorVersion: 1, + MinorVersion: 0, + PatchVersion: 0, + BuildNumber: 1, + SubscriberPackageId: '0330000000000001', + Description: 'Test package 1 description', + PublisherName: 'Test Publisher', + IsDeprecated: false, + IsPasswordProtected: false, + IsBeta: false, + IsOrgDependent: false, + Package2ContainerOptions: 'Managed', + IsSecurityReviewed: true, + ReleaseState: 'Released', + IsManaged: true, + AppExchangePackageName: 'Test Package 1', + AppExchangeDescription: 'Test package 1 description', + AppExchangePublisherName: 'Test Publisher', + AppExchangeLogoUrl: 'https://test.com/logo1.png', + ReleaseNotesUrl: 'https://test.com/releasenotes1', + PostInstallUrl: 'https://test.com/postinstall1', + RemoteSiteSettings: { settings: [] }, + CspTrustedSites: { settings: [] }, + Profiles: { destinationProfiles: [], sourceProfiles: [] }, + Dependencies: { ids: [] }, + InstallValidationStatus: 'NO_ERRORS_DETECTED', + }, + { + Id: '04t0000000000002', + Name: 'Test Package 2', + MajorVersion: 2, + MinorVersion: 0, + PatchVersion: 0, + BuildNumber: 1, + SubscriberPackageId: '0330000000000002', + Description: 'Test package 2 description', + PublisherName: 'Test Publisher', + IsDeprecated: false, + IsPasswordProtected: false, + IsBeta: false, + IsOrgDependent: false, + Package2ContainerOptions: 'Managed', + IsSecurityReviewed: true, + ReleaseState: 'Released', + IsManaged: true, + AppExchangePackageName: 'Test Package 2', + AppExchangeDescription: 'Test package 2 description', + AppExchangePublisherName: 'Test Publisher', + AppExchangeLogoUrl: 'https://test.com/logo2.png', + ReleaseNotesUrl: 'https://test.com/releasenotes2', + PostInstallUrl: 'https://test.com/postinstall2', + RemoteSiteSettings: { settings: [] }, + CspTrustedSites: { settings: [] }, + Profiles: { destinationProfiles: [], sourceProfiles: [] }, + Dependencies: { ids: [] }, + InstallValidationStatus: 'NO_ERRORS_DETECTED', + }, + ]; + + reportStub.resolves(mockBundleVersion); + componentPackagesStub.resolves(mockComponentPackages); + + const cmd = new PackageBundleVersionReportCommand( + ['--bundle-version', bundleVersionId, '--target-dev-hub', testOrg.username], + config + ); + + await cmd.run(); + + expect(reportStub.calledOnce).to.be.true; + expect(reportStub.firstCall.args[1]).to.equal(bundleVersionId); + expect(componentPackagesStub.calledOnce).to.be.true; + expect(componentPackagesStub.firstCall.args[1]).to.equal(bundleVersionId); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledTwice).to.be.true; + }); + + it('should report on a package bundle version with verbose output', async () => { + const bundleVersionId = '0Ho0x0000000000000'; + const mockBundleVersion: BundleSObjects.BundleVersion = { + Id: bundleVersionId, + IsReleased: true, + PackageBundle: { + Id: '0Ho0x0000000000001', + BundleName: 'Test Bundle', + Description: 'Test bundle description', + IsDeleted: false, + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + SystemModstamp: '2025-01-01T00:00:00.000+0000', + }, + VersionName: '2.0.0', + MajorVersion: '2', + MinorVersion: '0', + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + Ancestor: { + Id: '0Ho0x0000000000001', + PackageBundle: { + Id: '0Ho0x0000000000002', + BundleName: 'Test Bundle', + Description: 'Test bundle description', + IsDeleted: false, + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + SystemModstamp: '2025-01-01T00:00:00.000+0000', + }, + VersionName: '1.0.0', + MajorVersion: '1', + MinorVersion: '0', + IsReleased: true, + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + Ancestor: null, + }, + }; + + const mockComponentPackages: PackagingSObjects.SubscriberPackageVersion[] = [ + { + Id: '04t0000000000001', + Name: 'Test Package 1', + MajorVersion: 1, + MinorVersion: 0, + PatchVersion: 0, + BuildNumber: 1, + SubscriberPackageId: '0330000000000001', + Description: 'Test package 1 description', + PublisherName: 'Test Publisher', + IsDeprecated: false, + IsPasswordProtected: false, + IsBeta: false, + IsOrgDependent: false, + Package2ContainerOptions: 'Managed', + IsSecurityReviewed: true, + ReleaseState: 'Released', + IsManaged: true, + AppExchangePackageName: 'Test Package 1', + AppExchangeDescription: 'Test package 1 description', + AppExchangePublisherName: 'Test Publisher', + AppExchangeLogoUrl: 'https://test.com/logo1.png', + ReleaseNotesUrl: 'https://test.com/releasenotes1', + PostInstallUrl: 'https://test.com/postinstall1', + RemoteSiteSettings: { settings: [] }, + CspTrustedSites: { settings: [] }, + Profiles: { destinationProfiles: [], sourceProfiles: [] }, + Dependencies: { ids: [] }, + InstallValidationStatus: 'NO_ERRORS_DETECTED', + }, + ]; + + reportStub.resolves(mockBundleVersion); + componentPackagesStub.resolves(mockComponentPackages); + + const cmd = new PackageBundleVersionReportCommand( + ['--bundle-version', bundleVersionId, '--target-dev-hub', testOrg.username, '--verbose'], + config + ); + + await cmd.run(); + + expect(reportStub.calledOnce).to.be.true; + expect(reportStub.firstCall.args[1]).to.equal(bundleVersionId); + expect(componentPackagesStub.calledOnce).to.be.true; + expect(componentPackagesStub.firstCall.args[1]).to.equal(bundleVersionId); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledTwice).to.be.true; + }); + + it('should throw error when bundle-version flag is missing', async () => { + const cmd = new PackageBundleVersionReportCommand(['--target-dev-hub', testOrg.username], config); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('Missing required flag'); + } + }); + + it('should throw error when target-dev-hub flag is missing', async () => { + const bundleVersionId = '0Ho0x0000000000000'; + const cmd = new PackageBundleVersionReportCommand(['--bundle-version', bundleVersionId], config); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('No default dev hub found'); + } + }); + + it('should handle API errors gracefully', async () => { + const bundleVersionId = '0Ho0x0000000000000'; + const errorMessage = 'Package bundle version not found'; + + reportStub.rejects(new Error(errorMessage)); + + const cmd = new PackageBundleVersionReportCommand( + ['--bundle-version', bundleVersionId, '--target-dev-hub', testOrg.username], + config + ); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include(errorMessage); + } + }); + + it('should handle case when no bundle version is found', async () => { + const bundleVersionId = '0Ho0x0000000000000'; + + reportStub.resolves(null); + + const cmd = new PackageBundleVersionReportCommand( + ['--bundle-version', bundleVersionId, '--target-dev-hub', testOrg.username], + config + ); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include(`No bundle version found with ID: ${bundleVersionId}`); + } + }); + + it('should handle case when no component packages are found', async () => { + const bundleVersionId = '0Ho0x0000000000000'; + const mockBundleVersion: BundleSObjects.BundleVersion = { + Id: bundleVersionId, + IsReleased: false, + PackageBundle: { + Id: '0Ho0x0000000000001', + BundleName: 'Test Bundle', + Description: 'Test bundle description', + IsDeleted: false, + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + SystemModstamp: '2025-01-01T00:00:00.000+0000', + }, + VersionName: '1.0.0', + MajorVersion: '1', + MinorVersion: '0', + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + LastModifiedDate: '2025-01-01T00:00:00.000+0000', + LastModifiedById: '0050x0000000000001', + Ancestor: null, + }; + + const mockComponentPackages: PackagingSObjects.SubscriberPackageVersion[] = []; + + reportStub.resolves(mockBundleVersion); + componentPackagesStub.resolves(mockComponentPackages); + + const cmd = new PackageBundleVersionReportCommand( + ['--bundle-version', bundleVersionId, '--target-dev-hub', testOrg.username], + config + ); + + await cmd.run(); + + expect(reportStub.calledOnce).to.be.true; + expect(reportStub.firstCall.args[1]).to.equal(bundleVersionId); + expect(componentPackagesStub.calledOnce).to.be.true; + expect(componentPackagesStub.firstCall.args[1]).to.equal(bundleVersionId); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); +}); From 2f731a06d6e23782a6d6eaff6968d2e5821d1a5a Mon Sep 17 00:00:00 2001 From: Dawson David Date: Wed, 25 Jun 2025 15:46:09 -0600 Subject: [PATCH 22/31] style: use getcomponent Packges now, reverted changes made in non bundle files --- src/commands/package/bundle/version/report.ts | 2 +- src/commands/package/install.ts | 2 +- src/commands/package/push-upgrade/report.ts | 1 - test/commands/bundle/bundleVersionReport.test.ts | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/commands/package/bundle/version/report.ts b/src/commands/package/bundle/version/report.ts index d5e447be..d6c8ed61 100644 --- a/src/commands/package/bundle/version/report.ts +++ b/src/commands/package/bundle/version/report.ts @@ -42,7 +42,7 @@ export class PackageBundleVersionReportCommand extends SfCommand { enableRss = await this.confirm({ message: promptMsg }); } if (enableRss) { - Object.assign(request, { EnableRss: enableRss }); + request.EnableRss = enableRss; } } } diff --git a/src/commands/package/push-upgrade/report.ts b/src/commands/package/push-upgrade/report.ts index d26c2e37..caecd67d 100644 --- a/src/commands/package/push-upgrade/report.ts +++ b/src/commands/package/push-upgrade/report.ts @@ -39,7 +39,6 @@ export class PackagePushUpgradeReportCommand extends SfCommand { sfCommandStubs = stubSfCommandUx($$.SANDBOX); reportStub = $$.SANDBOX.stub(PackageBundleVersion, 'report'); - componentPackagesStub = $$.SANDBOX.stub(PackageBundleVersion, 'componentPackages'); + componentPackagesStub = $$.SANDBOX.stub(PackageBundleVersion, 'getComponentPackages'); }); afterEach(() => { From 2b49dbafbdce01180b76959dca506e47db6d9849 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Wed, 2 Jul 2025 15:07:13 -0600 Subject: [PATCH 23/31] feat: created pakcage bundle install command --- command-snapshot.json | 36 +- messages/bundle_install.md | 54 +++ messages/bundle_install_list.md | 69 ++++ messages/bundle_install_report.md | 53 +++ schemas/package-bundle-install-list.json | 58 +++ schemas/package-bundle-install-report.json | 58 +++ schemas/package-bundle-install.json | 52 +++ schemas/package-bundle-version-report.json | 353 +++++++++++++++++- src/commands/package/bundle/install.ts | 120 ++++++ src/commands/package/bundle/install/list.ts | 86 +++++ src/commands/package/bundle/install/report.ts | 95 +++++ src/commands/package/bundle/version/report.ts | 16 +- test/commands/bundle/bundleInstall.test.ts | 223 +++++++++++ .../commands/bundle/bundleInstallList.test.ts | 96 +++++ .../bundle/bundleInstallReport.test.ts | 129 +++++++ 15 files changed, 1486 insertions(+), 12 deletions(-) create mode 100644 messages/bundle_install.md create mode 100644 messages/bundle_install_list.md create mode 100644 messages/bundle_install_report.md create mode 100644 schemas/package-bundle-install-list.json create mode 100644 schemas/package-bundle-install-report.json create mode 100644 schemas/package-bundle-install.json create mode 100644 src/commands/package/bundle/install.ts create mode 100644 src/commands/package/bundle/install/list.ts create mode 100644 src/commands/package/bundle/install/report.ts create mode 100644 test/commands/bundle/bundleInstall.test.ts create mode 100644 test/commands/bundle/bundleInstallList.test.ts create mode 100644 test/commands/bundle/bundleInstallReport.test.ts diff --git a/command-snapshot.json b/command-snapshot.json index 7147f72b..8d158c02 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -63,6 +63,40 @@ "flags": ["api-version", "description", "flags-dir", "json", "loglevel", "name", "target-dev-hub"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": [], + "command": "package:bundle:install", + "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername", "targetusername", "u"], + "flagChars": ["b", "o", "v", "w"], + "flags": [ + "api-version", + "bundle", + "flags-dir", + "json", + "loglevel", + "target-dev-hub", + "target-org", + "verbose", + "wait" + ], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": [], + "command": "package:bundle:install:list", + "flagAliases": ["apiversion", "createdlastdays", "target-hub-org", "targetdevhubusername"], + "flagChars": ["c", "s", "v"], + "flags": ["api-version", "created-last-days", "flags-dir", "json", "loglevel", "status", "target-org", "verbose"], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": [], + "command": "package:bundle:install:report", + "flagAliases": ["apiversion", "packageinstallrequestid", "target-hub-org", "targetdevhubusername"], + "flagChars": ["i", "v"], + "flags": ["api-version", "flags-dir", "json", "loglevel", "package-install-request-id", "target-org", "verbose"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": [], "command": "package:bundle:list", @@ -128,7 +162,7 @@ "alias": [], "command": "package:bundle:version:report", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], - "flagChars": ["p", "v"], + "flagChars": ["b", "v"], "flags": ["api-version", "bundle-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"], "plugin": "@salesforce/plugin-packaging" }, diff --git a/messages/bundle_install.md b/messages/bundle_install.md new file mode 100644 index 00000000..48ecb5ac --- /dev/null +++ b/messages/bundle_install.md @@ -0,0 +1,54 @@ +# summary + +Install a package bundle version in the target org. + +# description + +Install a specific version of a package bundle in the target org. During developer preview, bundles can be installed only in scratch orgs. + +# examples + +Install a package bundle version in a scratch org: + +sf package bundle install --bundle MyPkgBundle1@0.1 --target-org my-scratch-org --wait 10 + +# flags.bundle.summary + +Package bundle version to install (format: BundleName@Version). + +# flags.target-org.summary + +Target org for the bundle installation. + +# flags.wait.summary + +Number of minutes to wait for the installation to complete. + +# flags.verbose.summary + +Display extended installation detail. + +# requestInProgress + +Installing bundle. + +# bundleInstallWaitingStatus + +%d minutes remaining until timeout. Install status: %s + +# bundleInstallFinalStatus + +Install status: %s + +# bundleInstallSuccess + +Successfully installed bundle [%s] + +# bundleInstallError + +Encountered errors installing the bundle! %s + +# bundleInstallInProgress + +Bundle installation is currently %s. You can continue to query the status using +sf package bundle install:report -i %s -o %s diff --git a/messages/bundle_install_list.md b/messages/bundle_install_list.md new file mode 100644 index 00000000..87893af8 --- /dev/null +++ b/messages/bundle_install_list.md @@ -0,0 +1,69 @@ +# summary + +List package bundle installation requests. + +# description + +Shows the details of each request to install a package bundle version in the target org. + +All filter parameters are applied using the AND logical operator (not OR). + +To get information about a specific request, run "<%= config.bin %> package bundle install report" and supply the request ID. + +# flags.status.summary + +Status of the installation request, used to filter the list. + +# flags.verbose.summary + +Displays additional information at a slight performance cost, such as validation text for each package bundle install request. + +# flags.created-last-days.summary + +Number of days since the request was created, starting at 00:00:00 of first day to now. Use 0 for today. + +# examples + +- List all package bundle installation requests in your default Dev Hub org: + + <%= config.bin %> <%= command.id %> + +- List package bundle installation requests from the last 3 days in the Dev Hub org with username devhub@example.com: + + <%= config.bin %> <%= command.id %> --created-last-days 3 --target-dev-hub + +- List package bundle installation requests with status Error: + + <%= config.bin %> <%= command.id %> --status Error + +- List package bundle installation requests with status Queued: + + <%= config.bin %> <%= command.id %> --status Queued + +- List package bundle installation requests with status Success that were created today: + + <%= config.bin %> <%= command.id %> --created-last-days 0 --status Success + +# id + +ID + +# status + +Status + +# package-bundle-version-id + +Package Bundle Version ID + +# development-organization + +Development Organization + +# created-by + +Created By + +# validation-error + +Validation Error diff --git a/messages/bundle_install_report.md b/messages/bundle_install_report.md new file mode 100644 index 00000000..dd687597 --- /dev/null +++ b/messages/bundle_install_report.md @@ -0,0 +1,53 @@ +# summary + +Report on the status of a package bundle installation request. + +# description + +Use this command to check the status of a package bundle installation request. The command returns information about the request, including its current status and details about the package bundle version being installed. + +# examples + +- Report on a package bundle installation request: + + <%= config.bin %> <%= command.id %> --package-install-request-id 0Ho0x0000000000000 + +- Report on a package bundle installation request using an alias: + + <%= config.bin %> force:package:bundle:install:report -i 0Ho0x0000000000000 + +# flags.package-install-request-id.summary + +The ID of the package bundle installation request to report on. + +# id + +ID + +# status + +Status + +# package-bundle-version-id + +Package Bundle Version ID + +# development-organization + +Development Organization + +# validation-error + +Validation Error + +# created-date + +Created Date + +# created-by + +Created By + +# flags.verbose.summary + +Show verbose output. diff --git a/schemas/package-bundle-install-list.json b/schemas/package-bundle-install-list.json new file mode 100644 index 00000000..a3f37cc9 --- /dev/null +++ b/schemas/package-bundle-install-list.json @@ -0,0 +1,58 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/PackageBundleInstallRequestResults", + "definitions": { + "PackageBundleInstallRequestResults": { + "type": "array", + "items": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionInstallReqResult" + } + }, + "BundleSObjects.PkgBundleVersionInstallReqResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string" + }, + "InstallStatus": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionInstallReqStatus" + }, + "ValidationError": { + "type": "string" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "Error": { + "type": "array", + "items": { + "type": "string" + } + }, + "PackageBundleVersionID": { + "type": "string" + }, + "DevelopmentOrganization": { + "type": "string" + } + }, + "required": [ + "CreatedById", + "CreatedDate", + "DevelopmentOrganization", + "Id", + "InstallStatus", + "PackageBundleVersionID", + "ValidationError" + ] + }, + "BundleSObjects.PkgBundleVersionInstallReqStatus": { + "type": "string", + "enum": ["Queued", "Success", "Error"] + } + } +} diff --git a/schemas/package-bundle-install-report.json b/schemas/package-bundle-install-report.json new file mode 100644 index 00000000..c1a2e381 --- /dev/null +++ b/schemas/package-bundle-install-report.json @@ -0,0 +1,58 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/ReportCommandResult", + "definitions": { + "ReportCommandResult": { + "type": "array", + "items": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionInstallReqResult" + } + }, + "BundleSObjects.PkgBundleVersionInstallReqResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string" + }, + "InstallStatus": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionInstallReqStatus" + }, + "ValidationError": { + "type": "string" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "Error": { + "type": "array", + "items": { + "type": "string" + } + }, + "PackageBundleVersionID": { + "type": "string" + }, + "DevelopmentOrganization": { + "type": "string" + } + }, + "required": [ + "CreatedById", + "CreatedDate", + "DevelopmentOrganization", + "Id", + "InstallStatus", + "PackageBundleVersionID", + "ValidationError" + ] + }, + "BundleSObjects.PkgBundleVersionInstallReqStatus": { + "type": "string", + "enum": ["Queued", "Success", "Error"] + } + } +} diff --git a/schemas/package-bundle-install.json b/schemas/package-bundle-install.json new file mode 100644 index 00000000..7d4be399 --- /dev/null +++ b/schemas/package-bundle-install.json @@ -0,0 +1,52 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionInstallReqResult", + "definitions": { + "BundleSObjects.PkgBundleVersionInstallReqResult": { + "type": "object", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string" + }, + "InstallStatus": { + "$ref": "#/definitions/BundleSObjects.PkgBundleVersionInstallReqStatus" + }, + "ValidationError": { + "type": "string" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "Error": { + "type": "array", + "items": { + "type": "string" + } + }, + "PackageBundleVersionID": { + "type": "string" + }, + "DevelopmentOrganization": { + "type": "string" + } + }, + "required": [ + "CreatedById", + "CreatedDate", + "DevelopmentOrganization", + "Id", + "InstallStatus", + "PackageBundleVersionID", + "ValidationError" + ] + }, + "BundleSObjects.PkgBundleVersionInstallReqStatus": { + "type": "string", + "enum": ["Queued", "Success", "Error"] + } + } +} diff --git a/schemas/package-bundle-version-report.json b/schemas/package-bundle-version-report.json index 772bf5e3..0004bafc 100644 --- a/schemas/package-bundle-version-report.json +++ b/schemas/package-bundle-version-report.json @@ -1,10 +1,17 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/BundleSObjects.BundleVersion", + "$ref": "#/definitions/BundleVersionReportResult", "definitions": { - "BundleSObjects.BundleVersion": { + "BundleVersionReportResult": { "type": "object", + "additionalProperties": false, "properties": { + "componentPackages": { + "type": "array", + "items": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageVersion" + } + }, "Id": { "type": "string" }, @@ -47,19 +54,293 @@ } }, "required": [ + "CreatedById", + "CreatedDate", "Id", + "IsReleased", + "LastModifiedById", + "LastModifiedDate", + "MajorVersion", + "MinorVersion", "PackageBundle", "VersionName", + "componentPackages" + ] + }, + "PackagingSObjects.SubscriberPackageVersion": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "SubscriberPackageId": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "PublisherName": { + "type": "string" + }, + "MajorVersion": { + "type": "number" + }, + "MinorVersion": { + "type": "number" + }, + "PatchVersion": { + "type": "number" + }, + "BuildNumber": { + "type": "number" + }, + "ReleaseState": { + "type": "string" + }, + "IsManaged": { + "type": "boolean" + }, + "IsDeprecated": { + "type": "boolean" + }, + "IsPasswordProtected": { + "type": "boolean" + }, + "IsBeta": { + "type": "boolean" + }, + "Package2ContainerOptions": { + "$ref": "#/definitions/PackageType" + }, + "IsSecurityReviewed": { + "type": "boolean" + }, + "IsOrgDependent": { + "type": "boolean" + }, + "AppExchangePackageName": { + "type": "string" + }, + "AppExchangeDescription": { + "type": "string" + }, + "AppExchangePublisherName": { + "type": "string" + }, + "AppExchangeLogoUrl": { + "type": "string" + }, + "ReleaseNotesUrl": { + "type": "string" + }, + "PostInstallUrl": { + "type": "string" + }, + "RemoteSiteSettings": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageRemoteSiteSettings" + }, + "CspTrustedSites": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageCspTrustedSites" + }, + "Profiles": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageProfiles" + }, + "Dependencies": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageDependencies" + }, + "InstallValidationStatus": { + "$ref": "#/definitions/PackagingSObjects.InstallValidationStatus" + } + }, + "required": [ + "Id", + "SubscriberPackageId", + "Name", + "Description", + "PublisherName", "MajorVersion", "MinorVersion", - "IsReleased", - "CreatedDate", - "CreatedById", - "LastModifiedDate", - "LastModifiedById" + "PatchVersion", + "BuildNumber", + "ReleaseState", + "IsManaged", + "IsDeprecated", + "IsPasswordProtected", + "IsBeta", + "Package2ContainerOptions", + "IsSecurityReviewed", + "IsOrgDependent", + "AppExchangePackageName", + "AppExchangeDescription", + "AppExchangePublisherName", + "AppExchangeLogoUrl", + "ReleaseNotesUrl", + "PostInstallUrl", + "RemoteSiteSettings", + "CspTrustedSites", + "Profiles", + "Dependencies", + "InstallValidationStatus" ], "additionalProperties": false }, + "PackageType": { + "type": "string", + "enum": ["Managed", "Unlocked"] + }, + "PackagingSObjects.SubscriberPackageRemoteSiteSettings": { + "type": "object", + "properties": { + "settings": { + "type": "array", + "items": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageRemoteSiteSetting" + } + } + }, + "required": ["settings"], + "additionalProperties": false + }, + "PackagingSObjects.SubscriberPackageRemoteSiteSetting": { + "type": "object", + "properties": { + "secure": { + "type": "boolean" + }, + "url": { + "type": "string" + } + }, + "required": ["secure", "url"], + "additionalProperties": false + }, + "PackagingSObjects.SubscriberPackageCspTrustedSites": { + "type": "object", + "properties": { + "settings": { + "type": "array", + "items": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageCspTrustedSite" + } + } + }, + "required": ["settings"], + "additionalProperties": false + }, + "PackagingSObjects.SubscriberPackageCspTrustedSite": { + "type": "object", + "properties": { + "endpointUrl": { + "type": "string" + } + }, + "required": ["endpointUrl"], + "additionalProperties": false + }, + "PackagingSObjects.SubscriberPackageProfiles": { + "type": "object", + "properties": { + "destinationProfiles": { + "type": "array", + "items": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageDestinationProfile" + } + }, + "sourceProfiles": { + "type": "array", + "items": { + "$ref": "#/definitions/PackagingSObjects.SubscriberPackageSourceProfile" + } + } + }, + "required": ["destinationProfiles", "sourceProfiles"], + "additionalProperties": false + }, + "PackagingSObjects.SubscriberPackageDestinationProfile": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "noAccess": { + "type": "boolean" + }, + "profileId": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": ["description", "displayName", "name", "noAccess", "profileId", "type"], + "additionalProperties": false + }, + "PackagingSObjects.SubscriberPackageSourceProfile": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": ["label", "value"], + "additionalProperties": false + }, + "PackagingSObjects.SubscriberPackageDependencies": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "object", + "properties": { + "subscriberPackageVersionId": { + "type": "string" + } + }, + "required": ["subscriberPackageVersionId"], + "additionalProperties": false + } + } + }, + "required": ["ids"], + "additionalProperties": false + }, + "PackagingSObjects.InstallValidationStatus": { + "type": "string", + "enum": [ + "NO_ERRORS_DETECTED", + "BETA_INSTALL_INTO_PRODUCTION_ORG", + "CANNOT_INSTALL_EARLIER_VERSION", + "CANNOT_UPGRADE_BETA", + "CANNOT_UPGRADE_UNMANAGED", + "DEPRECATED_INSTALL_PACKAGE", + "EXTENSIONS_ON_LOCAL_PACKAGES", + "PACKAGE_NOT_INSTALLED", + "PACKAGE_HAS_IN_DEV_EXTENSIONS", + "INSTALL_INTO_DEV_ORG", + "NO_ACCESS", + "PACKAGING_DISABLED", + "PACKAGING_NO_ACCESS", + "PACKAGE_UNAVAILABLE", + "PACKAGE_UNAVAILABLE_CRC", + "PACKAGE_UNAVAILABLE_ZIP", + "UNINSTALL_IN_PROGRESS", + "UNKNOWN_ERROR", + "NAMESPACE_COLLISION" + ] + }, "BundleSObjects.Bundle": { "type": "object", "properties": { @@ -102,6 +383,64 @@ "SystemModstamp" ], "additionalProperties": false + }, + "BundleSObjects.BundleVersion": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "PackageBundle": { + "$ref": "#/definitions/BundleSObjects.Bundle" + }, + "VersionName": { + "type": "string" + }, + "MajorVersion": { + "type": "string" + }, + "MinorVersion": { + "type": "string" + }, + "Ancestor": { + "anyOf": [ + { + "$ref": "#/definitions/BundleSObjects.BundleVersion" + }, + { + "type": "null" + } + ] + }, + "IsReleased": { + "type": "boolean" + }, + "CreatedDate": { + "type": "string" + }, + "CreatedById": { + "type": "string" + }, + "LastModifiedDate": { + "type": "string" + }, + "LastModifiedById": { + "type": "string" + } + }, + "required": [ + "Id", + "PackageBundle", + "VersionName", + "MajorVersion", + "MinorVersion", + "IsReleased", + "CreatedDate", + "CreatedById", + "LastModifiedDate", + "LastModifiedById" + ], + "additionalProperties": false } } } diff --git a/src/commands/package/bundle/install.ts b/src/commands/package/bundle/install.ts new file mode 100644 index 00000000..bd8f2cab --- /dev/null +++ b/src/commands/package/bundle/install.ts @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, 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 { + Flags, + loglevel, + orgApiVersionFlagWithDeprecations, + requiredOrgFlagWithDeprecations, + SfCommand, +} from '@salesforce/sf-plugins-core'; +import { BundleSObjects, BundleInstallOptions, PackageBundleInstall } from '@salesforce/packaging'; +import { Messages, Lifecycle } from '@salesforce/core'; +import { camelCaseToTitleCase, Duration } from '@salesforce/kit'; +import { requiredHubFlag } from '../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_install'); +export type BundleInstall = BundleSObjects.PkgBundleVersionInstallReqResult; + +export class PackageBundlesInstall extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly requiresProject = true; + public static readonly flags = { + loglevel, + bundle: Flags.string({ + char: 'b', + summary: messages.getMessage('flags.bundle.summary'), + required: true, + }), + 'target-org': requiredOrgFlagWithDeprecations, + 'api-version': orgApiVersionFlagWithDeprecations, + 'target-dev-hub': requiredHubFlag, + wait: Flags.integer({ + char: 'w', + summary: messages.getMessage('flags.wait.summary'), + default: 0, + }), + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundlesInstall); + + // Get the target org connection + const targetOrg = flags['target-org']; + const targetDevHub = flags['target-dev-hub']; + const connection = targetOrg.getConnection(flags['api-version']); + + const options: BundleInstallOptions = { + connection, + project: this.project!, + PackageBundleVersion: flags.bundle, + DevelopmentOrganization: targetDevHub.getOrgId() ?? '', + }; + + // Set up lifecycle events for progress tracking + Lifecycle.getInstance().on( + 'bundle-install-progress', + // no async methods + // eslint-disable-next-line @typescript-eslint/require-await + async (data: BundleSObjects.PkgBundleVersionInstallReqResult & { remainingWaitTime: Duration }) => { + if ( + data.InstallStatus !== BundleSObjects.PkgBundleVersionInstallReqStatus.success && + data.InstallStatus !== BundleSObjects.PkgBundleVersionInstallReqStatus.error + ) { + const status = messages.getMessage('bundleInstallWaitingStatus', [ + data.remainingWaitTime.minutes, + data.InstallStatus, + ]); + if (flags.verbose) { + this.log(status); + } else { + this.spinner.status = status; + } + } + } + ); + + const result = await PackageBundleInstall.installBundle(connection, this.project!, { + ...options, + polling: { + timeout: Duration.minutes(flags.wait), + frequency: Duration.seconds(5), + }, + }); + + const finalStatusMsg = messages.getMessage('bundleInstallFinalStatus', [result.InstallStatus]); + if (flags.verbose) { + this.log(finalStatusMsg); + } else { + this.spinner.stop(finalStatusMsg); + } + + switch (result.InstallStatus) { + case BundleSObjects.PkgBundleVersionInstallReqStatus.error: + throw messages.createError('bundleInstallError', [result.ValidationError || 'Unknown error']); + case BundleSObjects.PkgBundleVersionInstallReqStatus.success: + this.log(messages.getMessage('bundleInstallSuccess', [result.Id])); + break; + default: + this.log( + messages.getMessage('bundleInstallInProgress', [ + camelCaseToTitleCase(result.InstallStatus as string), + result.Id, + targetOrg.getUsername() ?? '', + ]) + ); + } + + return result; + } +} diff --git a/src/commands/package/bundle/install/list.ts b/src/commands/package/bundle/install/list.ts new file mode 100644 index 00000000..dc108470 --- /dev/null +++ b/src/commands/package/bundle/install/list.ts @@ -0,0 +1,86 @@ +/* + * 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Connection, Messages } from '@salesforce/core'; +import { BundleSObjects, PackageBundleInstall } from '@salesforce/packaging'; +import chalk from 'chalk'; +import { requiredHubFlag } from '../../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_install_list'); + +type Status = BundleSObjects.PkgBundleVersionInstallReqStatus; +export type PackageBundleInstallRequestResults = BundleSObjects.PkgBundleVersionInstallReqResult[]; + +export class PackageBundleInstallListCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly flags = { + loglevel, + 'target-org': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + 'created-last-days': Flags.integer({ + char: 'c', + deprecateAliases: true, + aliases: ['createdlastdays'], + summary: messages.getMessage('flags.created-last-days.summary'), + }), + status: Flags.custom({ + options: [ + BundleSObjects.PkgBundleVersionInstallReqStatus.queued, + BundleSObjects.PkgBundleVersionInstallReqStatus.success, + BundleSObjects.PkgBundleVersionInstallReqStatus.error, + ], + })({ + char: 's', + summary: messages.getMessage('flags.status.summary'), + }), + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + }), + }; + + private connection!: Connection; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundleInstallListCommand); + this.connection = flags['target-org'].getConnection(flags['api-version']); + const results = await PackageBundleInstall.getInstallStatuses( + this.connection, + flags.status, + flags['created-last-days'] + ); + + if (results.length === 0) { + this.warn('No results found'); + } else { + const data = results.map((r) => ({ + Id: r.Id ?? 'N/A', + Status: r.InstallStatus ?? 'Unknown', + 'Package Bundle Version Id': r.PackageBundleVersionID ?? 'N/A', + 'Development Organization': r.DevelopmentOrganization ?? 'N/A', + 'Created Date': r.CreatedDate ?? 'N/A', + 'Created By': r.CreatedById ?? 'N/A', + ...(flags.verbose + ? { + 'Validation Error': r.ValidationError ?? 'N/A', + } + : {}), + })); + + this.table({ + data, + overflow: 'wrap', + title: chalk.blue(`Package Bundle Install Requests [${results.length}]`), + }); + } + + return results; + } +} diff --git a/src/commands/package/bundle/install/report.ts b/src/commands/package/bundle/install/report.ts new file mode 100644 index 00000000..da5b0729 --- /dev/null +++ b/src/commands/package/bundle/install/report.ts @@ -0,0 +1,95 @@ +/* + * 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages } from '@salesforce/core'; +import { BundleSObjects, PackageBundleInstall } from '@salesforce/packaging'; +import chalk from 'chalk'; +import { camelCaseToTitleCase } from '@salesforce/kit'; +import { requiredHubFlag } from '../../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_install_report'); + +export type ReportCommandResult = BundleSObjects.PkgBundleVersionInstallReqResult[]; + +export class PackageBundleInstallReportCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly flags = { + loglevel, + 'target-org': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + // eslint-disable-next-line sf-plugin/id-flag-suggestions + 'package-install-request-id': Flags.salesforceId({ + length: 'both', + deprecateAliases: true, + aliases: ['packageinstallrequestid'], + char: 'i', + summary: messages.getMessage('flags.package-install-request-id.summary'), + required: true, + }), + verbose: Flags.boolean({ + summary: messages.getMessage('flags.verbose.summary'), + required: false, + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundleInstallReportCommand); + const result = await PackageBundleInstall.getInstallStatus( + flags['package-install-request-id'], + flags['target-org'].getConnection(flags['api-version']) + ); + this.display(result, flags.verbose); + return [result]; + } + + private display(record: BundleSObjects.PkgBundleVersionInstallReqResult, verbose: boolean): void { + const data = [ + { + name: messages.getMessage('id'), + value: record.Id, + }, + { + name: messages.getMessage('status'), + value: camelCaseToTitleCase(record.InstallStatus), + }, + { + name: messages.getMessage('package-bundle-version-id'), + value: record.PackageBundleVersionID ?? 'N/A', + }, + { + name: messages.getMessage('development-organization'), + value: record.DevelopmentOrganization, + }, + { + name: messages.getMessage('validation-error'), + value: record.ValidationError ?? 'N/A', + }, + { + name: messages.getMessage('created-date'), + value: record.CreatedDate, + }, + { + name: messages.getMessage('created-by'), + value: record.CreatedById, + }, + ...(verbose + ? [ + { + name: 'ValidationError', + value: record.ValidationError ?? 'N/A', + }, + ] + : []), + ]; + + this.table({ data, title: chalk.blue('Package Bundle Install Request') }); + } +} diff --git a/src/commands/package/bundle/version/report.ts b/src/commands/package/bundle/version/report.ts index d6c8ed61..1bb22265 100644 --- a/src/commands/package/bundle/version/report.ts +++ b/src/commands/package/bundle/version/report.ts @@ -13,8 +13,11 @@ import { requiredHubFlag } from '../../../../utils/hubFlag.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_version_report'); +export type BundleVersionReportResult = BundleSObjects.BundleVersion & { + componentPackages: PackagingSObjects.SubscriberPackageVersion[]; +}; -export class PackageBundleVersionReportCommand extends SfCommand { +export class PackageBundleVersionReportCommand extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly examples = messages.getMessages('examples'); public static readonly flags = { @@ -22,7 +25,7 @@ export class PackageBundleVersionReportCommand extends SfCommand { + public async run(): Promise { const { flags } = await this.parse(PackageBundleVersionReportCommand); const connection = flags['target-dev-hub'].getConnection(flags['api-version']); const results = await PackageBundleVersion.report(connection, flags['bundle-version']); @@ -43,8 +46,13 @@ export class PackageBundleVersionReportCommand extends SfCommand { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + const testHubOrg = new MockTestOrgData(); + let installStub = $$.SANDBOX.stub(PackageBundleInstall, 'installBundle'); + const config = new Config({ root: import.meta.url }); + + // stubs + let logStub: sinon.SinonStub; + let warnStub: sinon.SinonStub; + + const stubSpinner = (cmd: PackageBundlesInstall) => { + $$.SANDBOX.stub(cmd.spinner, 'start'); + $$.SANDBOX.stub(cmd.spinner, 'stop'); + $$.SANDBOX.stub(cmd.spinner, 'status').value(''); + }; + + before(async () => { + await $$.stubAuths(testOrg, testHubOrg); + await config.load(); + }); + + beforeEach(async () => { + logStub = $$.SANDBOX.stub(SfCommand.prototype, 'log'); + warnStub = $$.SANDBOX.stub(SfCommand.prototype, 'warn'); + }); + + afterEach(() => { + $$.restore(); + }); + + describe('package:bundle:install', () => { + it('should install a package bundle version successfully', async () => { + installStub.resolves(pkgBundleInstallSuccessResult); + + const cmd = new PackageBundlesInstall( + ['-b', 'TestBundle@1.0', '--target-org', 'test@org.org', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgAAA', + InstallStatus: 'Success', + PackageBundleVersionID: '1Q83i000000fxw1AAA', + DevelopmentOrganization: '00D3i000000TNHYCA4', + ValidationError: '', + CreatedDate: '2022-11-03 09:46', + CreatedById: '0053i000001ZIyGAAW', + Error: [], + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(1); + expect(logStub.args[0]).to.deep.equal(['Successfully installed bundle [08c3i000000fylgAAA]']); + }); + + it('should install a package bundle version with wait option', async () => { + installStub = $$.SANDBOX.stub(PackageBundleInstall, 'installBundle'); + installStub.resolves(pkgBundleInstallSuccessResult); + + const cmd = new PackageBundlesInstall( + ['-b', 'TestBundle@1.0', '--target-org', 'test@org.org', '--target-dev-hub', 'test@hub.org', '-w', '10'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgAAA', + InstallStatus: 'Success', + PackageBundleVersionID: '1Q83i000000fxw1AAA', + DevelopmentOrganization: '00D3i000000TNHYCA4', + ValidationError: '', + CreatedDate: '2022-11-03 09:46', + CreatedById: '0053i000001ZIyGAAW', + Error: [], + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(1); + expect(logStub.args[0]).to.deep.equal(['Successfully installed bundle [08c3i000000fylgAAA]']); + }); + + // This test does very little to test the verbose command except make sure that it is there. + it('should install a package bundle version with verbose option', async () => { + installStub = $$.SANDBOX.stub(PackageBundleInstall, 'installBundle'); + installStub.resolves(pkgBundleInstallSuccessResult); + + const cmd = new PackageBundlesInstall( + ['-b', 'TestBundle@1.0', '--target-org', 'test@org.org', '--target-dev-hub', 'test@hub.org', '--verbose'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgAAA', + InstallStatus: 'Success', + PackageBundleVersionID: '1Q83i000000fxw1AAA', + DevelopmentOrganization: '00D3i000000TNHYCA4', + ValidationError: '', + CreatedDate: '2022-11-03 09:46', + CreatedById: '0053i000001ZIyGAAW', + Error: [], + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(2); + expect(logStub.args[0]).to.deep.equal(['Install status: Success']); + expect(logStub.args[1]).to.deep.equal(['Successfully installed bundle [08c3i000000fylgAAA]']); + }); + + it('should handle queued status', async () => { + installStub = $$.SANDBOX.stub(PackageBundleInstall, 'installBundle'); + installStub.resolves(pkgBundleInstallQueuedResult); + + const cmd = new PackageBundlesInstall( + ['-b', 'TestBundle@1.0', '--target-org', 'test@org.org', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + const res = await cmd.run(); + expect(res).to.deep.equal({ + Id: '08c3i000000fylgBBB', + InstallStatus: 'Queued', + PackageBundleVersionID: '1Q83i000000fxw1AAA', + DevelopmentOrganization: '00D3i000000TNHYCA4', + ValidationError: '', + CreatedDate: '2022-11-03 10:00', + CreatedById: '0053i000001ZIyGAAW', + Error: [], + }); + expect(warnStub.callCount).to.equal(0); + expect(logStub.callCount).to.equal(1); + expect(logStub.args[0]).to.deep.equal([ + 'Bundle installation is currently Queued. You can continue to query the status using\nsf package bundle install:report -i 08c3i000000fylgBBB -o test@org.org', + ]); + }); + + it('should handle error status', async () => { + installStub = $$.SANDBOX.stub(PackageBundleInstall, 'installBundle'); + installStub.resolves(pkgBundleInstallErrorResult); + + try { + const cmd = new PackageBundlesInstall( + ['-b', 'TestBundle@1.0', '--target-org', 'test@org.org', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + await cmd.run(); + assert.fail('the above should throw an error'); + } catch (e) { + expect((e as Error).message).to.equal( + 'Encountered errors installing the bundle! Installation failed due to validation errors' + ); + } + }); + + it('should handle error status with unknown error', async () => { + const errorResult = { ...pkgBundleInstallErrorResult, ValidationError: '' }; + installStub = $$.SANDBOX.stub(PackageBundleInstall, 'installBundle'); + installStub.resolves(errorResult); + + try { + const cmd = new PackageBundlesInstall( + ['-b', 'TestBundle@1.0', '--target-org', 'test@org.org', '--target-dev-hub', 'test@hub.org'], + config + ); + stubSpinner(cmd); + await cmd.run(); + assert.fail('the above should throw an error'); + } catch (e) { + expect((e as Error).message).to.equal('Encountered errors installing the bundle! Unknown error'); + } + }); + }); +}); diff --git a/test/commands/bundle/bundleInstallList.test.ts b/test/commands/bundle/bundleInstallList.test.ts new file mode 100644 index 00000000..ddeb9580 --- /dev/null +++ b/test/commands/bundle/bundleInstallList.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackageBundleInstall, BundleSObjects } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import sinon from 'sinon'; +import { PackageBundleInstallListCommand } from '../../../src/commands/package/bundle/install/list.js'; + +describe('package:bundle:install:list - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let getInstallStatusesStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + getInstallStatusesStub = $$.SANDBOX.stub(PackageBundleInstall, 'getInstallStatuses'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should list bundle install requests', async () => { + const cmd = new PackageBundleInstallListCommand(['--target-org', testOrg.username], config); + + const mockResults: BundleSObjects.PkgBundleVersionInstallReqResult[] = [ + { + Id: 'test-id-1', + InstallStatus: BundleSObjects.PkgBundleVersionInstallReqStatus.success, + PackageBundleVersionID: 'bundle-version-id-1', + DevelopmentOrganization: 'dev-org-1', + CreatedDate: '2023-01-01T00:00:00Z', + CreatedById: 'user-id-1', + ValidationError: '', + Error: [], + }, + ]; + + getInstallStatusesStub.resolves(mockResults); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + expect(getInstallStatusesStub.calledOnce).to.be.true; + }); + + it('should show warning when no results found', async () => { + const cmd = new PackageBundleInstallListCommand(['--target-org', testOrg.username], config); + + getInstallStatusesStub.resolves([]); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.warn.calledOnce).to.be.true; + expect(sfCommandStubs.warn.firstCall.args[0]).to.equal('No results found'); + }); + + // This test does very little to test the verbose command except make sure that it is there. + it('should handle verbose flag', async () => { + const cmd = new PackageBundleInstallListCommand(['--target-org', testOrg.username, '--verbose'], config); + + const mockResults: BundleSObjects.PkgBundleVersionInstallReqResult[] = [ + { + Id: 'test-id-1', + InstallStatus: BundleSObjects.PkgBundleVersionInstallReqStatus.error, + PackageBundleVersionID: 'bundle-version-id-1', + DevelopmentOrganization: 'dev-org-1', + CreatedDate: '2023-01-01T00:00:00Z', + CreatedById: 'user-id-1', + ValidationError: 'Installation failed', + Error: ['Test error'], + }, + ]; + + getInstallStatusesStub.resolves(mockResults); + + await cmd.run(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + expect(getInstallStatusesStub.calledOnce).to.be.true; + }); +}); diff --git a/test/commands/bundle/bundleInstallReport.test.ts b/test/commands/bundle/bundleInstallReport.test.ts new file mode 100644 index 00000000..ce5a985b --- /dev/null +++ b/test/commands/bundle/bundleInstallReport.test.ts @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025, 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 { Config } from '@oclif/core'; +import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup'; +import { expect } from 'chai'; +import { PackageBundleInstall, BundleSObjects } from '@salesforce/packaging'; +import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import sinon from 'sinon'; +import { PackageBundleInstallReportCommand } from '../../../src/commands/package/bundle/install/report.js'; + +describe('package:bundle:install:report - tests', () => { + const $$ = new TestContext(); + const testOrg = new MockTestOrgData(); + let sfCommandStubs: ReturnType; + let getInstallStatusStub: sinon.SinonStub; + const config = new Config({ root: import.meta.url }); + + beforeEach(async () => { + await $$.stubAuths(testOrg); + await config.load(); + sfCommandStubs = stubSfCommandUx($$.SANDBOX); + + getInstallStatusStub = $$.SANDBOX.stub(PackageBundleInstall, 'getInstallStatus'); + }); + + afterEach(() => { + $$.restore(); + }); + + it('should report on a package bundle installation request', async () => { + const requestId = '0Ho0x0000000000000'; + const mockResult: BundleSObjects.PkgBundleVersionInstallReqResult = { + Id: requestId, + InstallStatus: BundleSObjects.PkgBundleVersionInstallReqStatus.queued, + PackageBundleVersionID: '0Ho0x0000000000001', + DevelopmentOrganization: 'test-org@example.com', + ValidationError: '', + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + Error: [], + }; + + getInstallStatusStub.resolves(mockResult); + + const cmd = new PackageBundleInstallReportCommand( + ['--package-install-request-id', requestId, '--target-org', testOrg.username], + config + ); + + await cmd.run(); + + expect(getInstallStatusStub.calledOnce).to.be.true; + expect(getInstallStatusStub.firstCall.args[0]).to.equal(requestId); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); + + it('should report on a package bundle installation request using alias flag', async () => { + const requestId = '0Ho0x0000000000000'; + const mockResult: BundleSObjects.PkgBundleVersionInstallReqResult = { + Id: requestId, + InstallStatus: BundleSObjects.PkgBundleVersionInstallReqStatus.success, + PackageBundleVersionID: '0Ho0x0000000000001', + DevelopmentOrganization: 'test-org@example.com', + ValidationError: '', + CreatedDate: '2025-01-01T00:00:00.000+0000', + CreatedById: '0050x0000000000001', + Error: [], + }; + + getInstallStatusStub.resolves(mockResult); + + const cmd = new PackageBundleInstallReportCommand(['-i', requestId, '--target-org', testOrg.username], config); + + await cmd.run(); + + expect(getInstallStatusStub.calledOnce).to.be.true; + expect(getInstallStatusStub.firstCall.args[0]).to.equal(requestId); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(sfCommandStubs.table.calledOnce).to.be.true; + }); + + it('should throw error when package-install-request-id flag is missing', async () => { + const cmd = new PackageBundleInstallReportCommand(['--target-org', testOrg.username], config); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('Missing required flag'); + } + }); + + // This test: should be rewritten once we have a unfied devhub and bundle, and should be rewritten to be "No default org found" + it('should throw error when target-dev-hub flag is missing', async () => { + const requestId = '0Ho0x0000000000000'; + const cmd = new PackageBundleInstallReportCommand(['--package-install-request-id', requestId], config); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include('No default dev hub found'); + } + }); + + it('should handle API errors gracefully', async () => { + const requestId = '0Ho0x0000000000000'; + const errorMessage = 'Package bundle installation request not found'; + + getInstallStatusStub.rejects(new Error(errorMessage)); + + const cmd = new PackageBundleInstallReportCommand( + ['--package-install-request-id', requestId, '--target-org', testOrg.username], + config + ); + + try { + await cmd.run(); + expect.fail('Expected error was not thrown'); + } catch (error) { + expect((error as Error).message).to.include(errorMessage); + } + }); +}); From f06169af098a00f8c70c7f646a9d80222ad1601e Mon Sep 17 00:00:00 2001 From: Dawson David Date: Fri, 27 Jun 2025 13:39:06 -0600 Subject: [PATCH 24/31] feat: bare bones package bundle delete --- messages/package_bundle_delete.md | 51 +++++++++++++++++++++++ src/commands/package/bundle/delete.ts | 59 +++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 messages/package_bundle_delete.md create mode 100644 src/commands/package/bundle/delete.ts diff --git a/messages/package_bundle_delete.md b/messages/package_bundle_delete.md new file mode 100644 index 00000000..d49fdd98 --- /dev/null +++ b/messages/package_bundle_delete.md @@ -0,0 +1,51 @@ +# summary + +Delete a package bundle. + +# description + +Specify the ID or alias of the package bundle you want to delete. + +Delete package bundles. Before you delete a package bundle, first delete all associated package bundle versions. + +# examples + +- Delete a package bundle using its alias from your default Dev Hub org: + + <%= config.bin %> <%= command.id %> --bundle "Your Bundle Alias" + +- Delete a package bundle using its ID from the specified Dev Hub org: + + <%= config.bin %> <%= command.id %> --bundle 1Fl... --target-dev-hub devhub@example.com + +# flags.bundle.summary + +ID (starts with 1Fl) or alias of the package bundle to delete. + +# flags.undelete.summary + +Undelete a deleted package bundle. + +# flags.no-prompt.summary + +Don't prompt before deleting the package bundle. + +# prompt-delete + +Deleted package bundles can't be recovered. + +Do you want to continue? (y/n) + +# prompt-undelete + +This will undelete the package bundle, which may result in unintended consequences for customers. Proceed with caution. + +Do you want to continue? (y/n) + +# prompt-delete-deny + +The request to delete this package bundle was canceled + +# humanSuccess + +Successfully deleted the package bundle. diff --git a/src/commands/package/bundle/delete.ts b/src/commands/package/bundle/delete.ts new file mode 100644 index 00000000..c4d7a285 --- /dev/null +++ b/src/commands/package/bundle/delete.ts @@ -0,0 +1,59 @@ +/* + * 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 { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; +import { Messages } from '@salesforce/core/messages'; +import { PackageBundle } from '@salesforce/packaging'; +import { requiredHubFlag } from '../../../utils/hubFlag.js'; + +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); +const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_bundle_delete'); + +export class PackageBundleDeleteCommand extends SfCommand { + public static readonly summary = messages.getMessage('summary'); + public static readonly description = messages.getMessage('description'); + public static readonly examples = messages.getMessages('examples'); + public static readonly flags = { + loglevel, + 'target-dev-hub': requiredHubFlag, + 'api-version': orgApiVersionFlagWithDeprecations, + 'no-prompt': Flags.boolean({ + char: 'n', + deprecateAliases: true, + aliases: ['noprompt'], + summary: messages.getMessage('flags.no-prompt.summary'), + }), + bundle: Flags.string({ + char: 'p', + summary: messages.getMessage('flags.bundle.summary'), + required: true, + }), + undelete: Flags.boolean({ + summary: messages.getMessage('flags.undelete.summary'), + hidden: true, + default: false, + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundleDeleteCommand); + const message = messages.getMessage(flags.undelete ? 'prompt-undelete' : 'prompt-delete'); + const accepted = flags['no-prompt'] || flags.json ? true : await this.confirm({ message }); + if (!accepted) { + throw messages.createError('prompt-delete-deny'); + } + + const connection = flags['target-dev-hub'].getConnection(flags['api-version']); + await PackageBundle.delete(connection, flags.bundle); + this.display(); + } + + private display(): void { + this.log(); + this.logSuccess(messages.getMessage('humanSuccess')); + } +} From b92cd39665bd0887c1f279eadc88dd8000387628 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Mon, 30 Jun 2025 09:02:20 -0600 Subject: [PATCH 25/31] feat: created package bundle delete additionally made package bundle version create report flags make more sense refactor: rebase --- command-snapshot.json | 12 +++- messages/bundle_version_create_report.md | 6 +- messages/package_bundle_delete.md | 6 +- schemas/package-bundle-delete.json | 72 +++++++++++++++++++ src/commands/package/bundle/delete.ts | 22 +++--- .../package/bundle/version/create/report.ts | 12 ++-- .../bundle/bundleCreateAndDelete.nut.ts | 58 +++++++++++++++ .../bundle/bundleVersionCreateReport.test.ts | 8 +-- 8 files changed, 172 insertions(+), 24 deletions(-) create mode 100644 schemas/package-bundle-delete.json create mode 100644 test/commands/bundle/bundleCreateAndDelete.nut.ts diff --git a/command-snapshot.json b/command-snapshot.json index 8d158c02..ca8a9abe 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -99,6 +99,14 @@ }, { "alias": [], + "command": "package:bundle:delete", + "flagAliases": ["apiversion", "noprompt", "target-hub-org", "targetdevhubusername"], + "flagChars": ["b", "n", "v"], + "flags": ["api-version", "bundle", "flags-dir", "json", "loglevel", "no-prompt", "target-dev-hub", "undelete"], + "plugin": "@salesforce/plugin-packaging" + }, + { + "alias": ["force:package:bundle:list"], "command": "package:bundle:list", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["v"], @@ -145,9 +153,9 @@ { "alias": [], "command": "package:bundle:version:create:report", - "flagAliases": ["apiversion", "packagecreaterequestid", "target-hub-org", "targetdevhubusername"], + "flagAliases": ["apiversion", "bundleversioncreaterequestid", "target-hub-org", "targetdevhubusername"], "flagChars": ["i", "v"], - "flags": ["api-version", "flags-dir", "json", "loglevel", "package-create-request-id", "target-dev-hub"], + "flags": ["api-version", "bundle-version-create-request-id", "flags-dir", "json", "loglevel", "target-dev-hub"], "plugin": "@salesforce/plugin-packaging" }, { diff --git a/messages/bundle_version_create_report.md b/messages/bundle_version_create_report.md index bf8d68d0..c57c777c 100644 --- a/messages/bundle_version_create_report.md +++ b/messages/bundle_version_create_report.md @@ -16,7 +16,7 @@ Use this command to check the status of a package bundle version creation reques <%= config.bin %> force:package:bundle:version:create:report -i 0Ho0x0000000000000 -# flags.package-create-request-id.summary +# flags.bundle-version-create-request-id.summary The ID of the package bundle version creation request to report on. @@ -28,11 +28,11 @@ ID Status -# package-bundle-id +# bundle-id Package Bundle ID -# package-bundle-version-id +# bundle-version-id Package Bundle Version ID diff --git a/messages/package_bundle_delete.md b/messages/package_bundle_delete.md index d49fdd98..f6e982cd 100644 --- a/messages/package_bundle_delete.md +++ b/messages/package_bundle_delete.md @@ -48,4 +48,8 @@ The request to delete this package bundle was canceled # humanSuccess -Successfully deleted the package bundle. +Successfully deleted the package bundle %s. + +# humanError + +Failed to delete the package bundle. diff --git a/schemas/package-bundle-delete.json b/schemas/package-bundle-delete.json new file mode 100644 index 00000000..4e4c10ea --- /dev/null +++ b/schemas/package-bundle-delete.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/BundleSaveResult", + "definitions": { + "BundleSaveResult": { + "$ref": "#/definitions/SaveResult" + }, + "SaveResult": { + "anyOf": [ + { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "const": true + }, + "id": { + "type": "string" + }, + "errors": { + "type": "array", + "items": { + "not": {} + } + } + }, + "required": ["success", "id", "errors"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "const": false + }, + "id": { + "not": {} + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/definitions/SaveError" + } + } + }, + "required": ["success", "errors"], + "additionalProperties": false + } + ] + }, + "SaveError": { + "type": "object", + "properties": { + "errorCode": { + "type": "string" + }, + "message": { + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["errorCode", "message"], + "additionalProperties": false + } + } +} diff --git a/src/commands/package/bundle/delete.ts b/src/commands/package/bundle/delete.ts index c4d7a285..80886592 100644 --- a/src/commands/package/bundle/delete.ts +++ b/src/commands/package/bundle/delete.ts @@ -7,16 +7,17 @@ import { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core/messages'; -import { PackageBundle } from '@salesforce/packaging'; +import { PackageBundle, BundleSaveResult } from '@salesforce/packaging'; import { requiredHubFlag } from '../../../utils/hubFlag.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_bundle_delete'); -export class PackageBundleDeleteCommand extends SfCommand { +export class PackageBundleDeleteCommand extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); + public static readonly requiresProject = true; public static readonly flags = { loglevel, 'target-dev-hub': requiredHubFlag, @@ -28,7 +29,7 @@ export class PackageBundleDeleteCommand extends SfCommand { summary: messages.getMessage('flags.no-prompt.summary'), }), bundle: Flags.string({ - char: 'p', + char: 'b', summary: messages.getMessage('flags.bundle.summary'), required: true, }), @@ -39,7 +40,7 @@ export class PackageBundleDeleteCommand extends SfCommand { }), }; - public async run(): Promise { + public async run(): Promise { const { flags } = await this.parse(PackageBundleDeleteCommand); const message = messages.getMessage(flags.undelete ? 'prompt-undelete' : 'prompt-delete'); const accepted = flags['no-prompt'] || flags.json ? true : await this.confirm({ message }); @@ -48,12 +49,17 @@ export class PackageBundleDeleteCommand extends SfCommand { } const connection = flags['target-dev-hub'].getConnection(flags['api-version']); - await PackageBundle.delete(connection, flags.bundle); - this.display(); + const result = await PackageBundle.delete(connection, this.project!, flags.bundle); + this.display(result); + return result; } - private display(): void { + private display(result: BundleSaveResult): void { this.log(); - this.logSuccess(messages.getMessage('humanSuccess')); + if ((result as { success: boolean }).success) { + this.logSuccess(messages.getMessage('humanSuccess', [(result as { id: string }).id])); + } else { + this.error(messages.getMessage('humanError')); + } } } diff --git a/src/commands/package/bundle/version/create/report.ts b/src/commands/package/bundle/version/create/report.ts index 81ce204d..cb822c71 100644 --- a/src/commands/package/bundle/version/create/report.ts +++ b/src/commands/package/bundle/version/create/report.ts @@ -26,12 +26,12 @@ export class PackageBundleVersionCreateReportCommand extends SfCommand { const { flags } = await this.parse(PackageBundleVersionCreateReportCommand); const result = await PackageBundleVersionCreate.getCreateStatus( - flags['package-create-request-id'], + flags['bundle-version-create-request-id'], flags['target-dev-hub'].getConnection(flags['api-version']) ); this.display(result); @@ -57,11 +57,11 @@ export class PackageBundleVersionCreateReportCommand extends SfCommand { + let session: TestSession; + let bundleName: string; + before(async () => { + session = await TestSession.create({ + devhubAuthStrategy: 'AUTO', + project: { name: 'bundleCreateDelete' }, + }); + }); + + after(async () => { + await session?.clean(); + }); + describe('create/delete - human results', () => { + before(async () => { + bundleName = `test-bundle-${Date.now()}`; + }); + it('should create a bundle - human readable results', () => { + const command = `package:bundle:create --name ${bundleName} -v ${session.hubOrg.username}`; + const output = execCmd(command, { ensureExitCode: 0 }).shellOutput.stdout; + expect(output).to.contain('Ids'); + expect(output).to.match(/Bundle Id\s+?|1Fl/); + }); + it('should delete a bundle - human readable results', () => { + const command = `package:bundle:delete -b ${bundleName} -v ${session.hubOrg.username} --no-prompt`; + const output = execCmd(command, { ensureExitCode: 0 }).shellOutput.stdout; + expect(output).to.contain('Successfully deleted the package bundle'); + }); + }); + describe('create/delete - json results', () => { + before(async () => { + bundleName = `test-bundle-${Date.now()}`; + }); + it('should create a bundle - json results', () => { + const command = `package:bundle:create --name ${bundleName} -v ${session.hubOrg.username} --json`; + const output = execCmd<{ Id: string }>(command, { ensureExitCode: 0 }).jsonOutput; + expect(output?.status).to.equal(0); + expect(output?.result).to.have.property('Id'); + expect(output?.result?.Id).to.match(/1Fl.{12,15}/); + }); + it('should delete a bundle - json results', () => { + const command = `package:bundle:delete -b ${bundleName} -v ${session.hubOrg.username} --json`; + const output = execCmd<{ id: string; success: boolean; errors: [] }>(command, { ensureExitCode: 0 }).jsonOutput; + expect(output?.result?.id).to.match(/1Fl.{12,15}/); + expect(output?.result?.success).to.be.true; + }); + }); +}); diff --git a/test/commands/bundle/bundleVersionCreateReport.test.ts b/test/commands/bundle/bundleVersionCreateReport.test.ts index e87e96c5..e6dfc883 100644 --- a/test/commands/bundle/bundleVersionCreateReport.test.ts +++ b/test/commands/bundle/bundleVersionCreateReport.test.ts @@ -51,7 +51,7 @@ describe('package:bundle:version:create:report - tests', () => { getCreateStatusStub.resolves(mockResult); const cmd = new PackageBundleVersionCreateReportCommand( - ['--package-create-request-id', requestId, '--target-dev-hub', testOrg.username], + ['--bundle-version-create-request-id', requestId, '--target-dev-hub', testOrg.username], config ); @@ -83,7 +83,7 @@ describe('package:bundle:version:create:report - tests', () => { getCreateStatusStub.resolves(mockResult); const cmd = new PackageBundleVersionCreateReportCommand( - ['-i', requestId, '--target-dev-hub', testOrg.username], + ['--bundle-version-create-request-id', requestId, '--target-dev-hub', testOrg.username], config ); @@ -108,7 +108,7 @@ describe('package:bundle:version:create:report - tests', () => { it('should throw error when target-dev-hub flag is missing', async () => { const requestId = '0Ho0x0000000000000'; - const cmd = new PackageBundleVersionCreateReportCommand(['--package-create-request-id', requestId], config); + const cmd = new PackageBundleVersionCreateReportCommand(['--bundle-version-create-request-id', requestId], config); try { await cmd.run(); @@ -125,7 +125,7 @@ describe('package:bundle:version:create:report - tests', () => { getCreateStatusStub.rejects(new Error(errorMessage)); const cmd = new PackageBundleVersionCreateReportCommand( - ['--package-create-request-id', requestId, '--target-dev-hub', testOrg.username], + ['--bundle-version-create-request-id', requestId, '--target-dev-hub', testOrg.username], config ); From 3d689021560ec5889b6a3101eb0c00ef2ea0162d Mon Sep 17 00:00:00 2001 From: Dawson David Date: Mon, 30 Jun 2025 14:19:23 -0600 Subject: [PATCH 26/31] fix: removed undelete --- command-snapshot.json | 8 -------- messages/package_delete.md | 4 ---- 2 files changed, 12 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index ca8a9abe..5a59fa70 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -237,14 +237,6 @@ ], "plugin": "@salesforce/plugin-packaging" }, - { - "alias": ["force:package:delete"], - "command": "package:delete", - "flagAliases": ["apiversion", "noprompt", "target-hub-org", "targetdevhubusername"], - "flagChars": ["n", "p", "v"], - "flags": ["api-version", "flags-dir", "json", "loglevel", "no-prompt", "package", "target-dev-hub", "undelete"], - "plugin": "@salesforce/plugin-packaging" - }, { "alias": ["force:package:install"], "command": "package:install", diff --git a/messages/package_delete.md b/messages/package_delete.md index b0901367..ad00f093 100644 --- a/messages/package_delete.md +++ b/messages/package_delete.md @@ -22,10 +22,6 @@ Delete unlocked and second-generation managed packages. Before you delete a pack ID (starts with 0Ho) or alias of the package to delete. -# flags.undelete.summary - -Undelete a deleted package. - # flags.no-prompt.summary Don’t prompt before deleting the package. From 21c98fce8aab75abba31322c6bdcc1ac8a799988 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Mon, 30 Jun 2025 14:31:06 -0600 Subject: [PATCH 27/31] fix: deleted message from wrong file --- command-snapshot.json | 10 +++++++++- messages/package_bundle_delete.md | 10 ---------- messages/package_delete.md | 8 ++++++-- src/commands/package/bundle/delete.ts | 7 +------ 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index 5a59fa70..cb6dfbe5 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -102,7 +102,7 @@ "command": "package:bundle:delete", "flagAliases": ["apiversion", "noprompt", "target-hub-org", "targetdevhubusername"], "flagChars": ["b", "n", "v"], - "flags": ["api-version", "bundle", "flags-dir", "json", "loglevel", "no-prompt", "target-dev-hub", "undelete"], + "flags": ["api-version", "bundle", "flags-dir", "json", "loglevel", "no-prompt", "target-dev-hub"], "plugin": "@salesforce/plugin-packaging" }, { @@ -237,6 +237,14 @@ ], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": ["force:package:delete"], + "command": "package:delete", + "flagAliases": ["apiversion", "noprompt", "target-hub-org", "targetdevhubusername"], + "flagChars": ["n", "p", "v"], + "flags": ["api-version", "flags-dir", "json", "loglevel", "no-prompt", "package", "target-dev-hub", "undelete"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": ["force:package:install"], "command": "package:install", diff --git a/messages/package_bundle_delete.md b/messages/package_bundle_delete.md index f6e982cd..5e6f5cfc 100644 --- a/messages/package_bundle_delete.md +++ b/messages/package_bundle_delete.md @@ -22,10 +22,6 @@ Delete package bundles. Before you delete a package bundle, first delete all ass ID (starts with 1Fl) or alias of the package bundle to delete. -# flags.undelete.summary - -Undelete a deleted package bundle. - # flags.no-prompt.summary Don't prompt before deleting the package bundle. @@ -36,12 +32,6 @@ Deleted package bundles can't be recovered. Do you want to continue? (y/n) -# prompt-undelete - -This will undelete the package bundle, which may result in unintended consequences for customers. Proceed with caution. - -Do you want to continue? (y/n) - # prompt-delete-deny The request to delete this package bundle was canceled diff --git a/messages/package_delete.md b/messages/package_delete.md index ad00f093..c3f37800 100644 --- a/messages/package_delete.md +++ b/messages/package_delete.md @@ -24,11 +24,15 @@ ID (starts with 0Ho) or alias of the package to delete. # flags.no-prompt.summary -Don’t prompt before deleting the package. +Don't prompt before deleting the package. + +# flags.undelete.summary + +Undelete a deleted package. # prompt-delete -Deleted packages can’t be recovered. +Deleted packages can't be recovered. Do you want to continue? (y/n) diff --git a/src/commands/package/bundle/delete.ts b/src/commands/package/bundle/delete.ts index 80886592..cdfbeabf 100644 --- a/src/commands/package/bundle/delete.ts +++ b/src/commands/package/bundle/delete.ts @@ -33,16 +33,11 @@ export class PackageBundleDeleteCommand extends SfCommand { summary: messages.getMessage('flags.bundle.summary'), required: true, }), - undelete: Flags.boolean({ - summary: messages.getMessage('flags.undelete.summary'), - hidden: true, - default: false, - }), }; public async run(): Promise { const { flags } = await this.parse(PackageBundleDeleteCommand); - const message = messages.getMessage(flags.undelete ? 'prompt-undelete' : 'prompt-delete'); + const message = messages.getMessage('prompt-delete'); const accepted = flags['no-prompt'] || flags.json ? true : await this.confirm({ message }); if (!accepted) { throw messages.createError('prompt-delete-deny'); From 11865ff72d8739ff11a29219af3fa4f86aca288b Mon Sep 17 00:00:00 2001 From: dawson-david-salesforce Date: Mon, 7 Jul 2025 13:15:01 -0600 Subject: [PATCH 28/31] Update list.ts --- src/commands/package/bundle/install/list.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/package/bundle/install/list.ts b/src/commands/package/bundle/install/list.ts index dc108470..0847e943 100644 --- a/src/commands/package/bundle/install/list.ts +++ b/src/commands/package/bundle/install/list.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, salesforce.com, inc. + * Copyright (c) 2025, 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 From 0d6b5ab90ce4ddb40165fa133f6158a96fa4af6d Mon Sep 17 00:00:00 2001 From: dawson-david-salesforce Date: Mon, 7 Jul 2025 13:19:30 -0600 Subject: [PATCH 29/31] Update report.ts --- src/commands/package/bundle/install/report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/package/bundle/install/report.ts b/src/commands/package/bundle/install/report.ts index da5b0729..0a8762dc 100644 --- a/src/commands/package/bundle/install/report.ts +++ b/src/commands/package/bundle/install/report.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, salesforce.com, inc. + * Copyright (c) 2025, 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 From 3c2a780d35174bd7e6ec0ab969156d9a34650623 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Fri, 11 Jul 2025 13:18:09 -0600 Subject: [PATCH 30/31] fix: hide comments and rebase --- command-snapshot.json | 25 ++++++++++++------------- src/commands/package/bundle/delete.ts | 6 ++++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index cb6dfbe5..01cfe009 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -63,6 +63,14 @@ "flags": ["api-version", "description", "flags-dir", "json", "loglevel", "name", "target-dev-hub"], "plugin": "@salesforce/plugin-packaging" }, + { + "alias": [], + "command": "package:bundle:delete", + "flagAliases": ["apiversion", "noprompt", "target-hub-org", "targetdevhubusername"], + "flagChars": ["b", "n", "v"], + "flags": ["api-version", "bundle", "flags-dir", "json", "loglevel", "no-prompt", "target-dev-hub"], + "plugin": "@salesforce/plugin-packaging" + }, { "alias": [], "command": "package:bundle:install", @@ -99,14 +107,6 @@ }, { "alias": [], - "command": "package:bundle:delete", - "flagAliases": ["apiversion", "noprompt", "target-hub-org", "targetdevhubusername"], - "flagChars": ["b", "n", "v"], - "flags": ["api-version", "bundle", "flags-dir", "json", "loglevel", "no-prompt", "target-dev-hub"], - "plugin": "@salesforce/plugin-packaging" - }, - { - "alias": ["force:package:bundle:list"], "command": "package:bundle:list", "flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"], "flagChars": ["v"], @@ -185,13 +185,13 @@ "installationkeybypass", "patchversion", "target-hub-org", - "targetdevhubusername", - "codecoverage" + "targetdevhubusername" ], - "flagChars": ["a", "f", "k", "m", "p", "s", "v", "w", "x", "c"], + "flagChars": ["a", "c", "f", "k", "m", "p", "s", "v", "w", "x"], "flags": [ "api-version", "build-instance", + "code-coverage", "definition-file", "flags-dir", "installation-key", @@ -203,8 +203,7 @@ "seed-metadata", "target-dev-hub", "verbose", - "wait", - "code-coverage" + "wait" ], "plugin": "@salesforce/plugin-packaging" }, diff --git a/src/commands/package/bundle/delete.ts b/src/commands/package/bundle/delete.ts index cdfbeabf..e2b661dc 100644 --- a/src/commands/package/bundle/delete.ts +++ b/src/commands/package/bundle/delete.ts @@ -14,6 +14,8 @@ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'package_bundle_delete'); export class PackageBundleDeleteCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); @@ -51,8 +53,8 @@ export class PackageBundleDeleteCommand extends SfCommand { private display(result: BundleSaveResult): void { this.log(); - if ((result as { success: boolean }).success) { - this.logSuccess(messages.getMessage('humanSuccess', [(result as { id: string }).id])); + if (result.success) { + this.logSuccess(messages.getMessage('humanSuccess', [result.id])); } else { this.error(messages.getMessage('humanError')); } From e0831f163ac04d34ec3bad297aaf406563c3c974 Mon Sep 17 00:00:00 2001 From: Dawson David Date: Fri, 11 Jul 2025 13:24:40 -0600 Subject: [PATCH 31/31] fix: actually hid commands this time --- src/commands/package/bundle/create.ts | 2 ++ src/commands/package/bundle/install.ts | 2 ++ src/commands/package/bundle/install/list.ts | 2 ++ src/commands/package/bundle/install/report.ts | 2 ++ src/commands/package/bundle/list.ts | 2 ++ src/commands/package/bundle/version/create.ts | 2 ++ src/commands/package/bundle/version/create/list.ts | 2 ++ src/commands/package/bundle/version/create/report.ts | 2 ++ src/commands/package/bundle/version/list.ts | 2 ++ src/commands/package/bundle/version/report.ts | 2 ++ 10 files changed, 20 insertions(+) diff --git a/src/commands/package/bundle/create.ts b/src/commands/package/bundle/create.ts index dcf0e6a3..4f4fba5e 100644 --- a/src/commands/package/bundle/create.ts +++ b/src/commands/package/bundle/create.ts @@ -15,6 +15,8 @@ const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_c export type BundleCreate = { Id: string }; export class PackageBundlesCreate extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/install.ts b/src/commands/package/bundle/install.ts index bd8f2cab..6ef79416 100644 --- a/src/commands/package/bundle/install.ts +++ b/src/commands/package/bundle/install.ts @@ -22,6 +22,8 @@ const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_i export type BundleInstall = BundleSObjects.PkgBundleVersionInstallReqResult; export class PackageBundlesInstall extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/install/list.ts b/src/commands/package/bundle/install/list.ts index 0847e943..ce136f1f 100644 --- a/src/commands/package/bundle/install/list.ts +++ b/src/commands/package/bundle/install/list.ts @@ -18,6 +18,8 @@ type Status = BundleSObjects.PkgBundleVersionInstallReqStatus; export type PackageBundleInstallRequestResults = BundleSObjects.PkgBundleVersionInstallReqResult[]; export class PackageBundleInstallListCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/install/report.ts b/src/commands/package/bundle/install/report.ts index 0a8762dc..9f08aa0b 100644 --- a/src/commands/package/bundle/install/report.ts +++ b/src/commands/package/bundle/install/report.ts @@ -18,6 +18,8 @@ const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_i export type ReportCommandResult = BundleSObjects.PkgBundleVersionInstallReqResult[]; export class PackageBundleInstallReportCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/list.ts b/src/commands/package/bundle/list.ts index db552ad6..eb27bfbb 100644 --- a/src/commands/package/bundle/list.ts +++ b/src/commands/package/bundle/list.ts @@ -20,6 +20,8 @@ export type BundleListCommandResult = BundleSObjects.Bundle; export type BundleListCommandResults = BundleListCommandResult[]; export class BundleListCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly examples = messages.getMessages('examples'); public static readonly flags = { diff --git a/src/commands/package/bundle/version/create.ts b/src/commands/package/bundle/version/create.ts index a8037283..ba7d5ffe 100644 --- a/src/commands/package/bundle/version/create.ts +++ b/src/commands/package/bundle/version/create.ts @@ -22,6 +22,8 @@ const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_v export type BundleVersionCreate = BundleSObjects.PackageBundleVersionCreateRequestResult; export class PackageBundlesCreate extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/version/create/list.ts b/src/commands/package/bundle/version/create/list.ts index 6c37a50c..46d75b26 100644 --- a/src/commands/package/bundle/version/create/list.ts +++ b/src/commands/package/bundle/version/create/list.ts @@ -23,6 +23,8 @@ type Status = BundleSObjects.PkgBundleVersionCreateReqStatus; export type PackageBundleVersionCreateRequestResults = BundleSObjects.PackageBundleVersionCreateRequestResult[]; export class PackageBundleVersionCreateListCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/version/create/report.ts b/src/commands/package/bundle/version/create/report.ts index cb822c71..c5b7455c 100644 --- a/src/commands/package/bundle/version/create/report.ts +++ b/src/commands/package/bundle/version/create/report.ts @@ -18,6 +18,8 @@ const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_v export type ReportCommandResult = BundleSObjects.PackageBundleVersionCreateRequestResult[]; export class PackageBundleVersionCreateReportCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/version/list.ts b/src/commands/package/bundle/version/list.ts index ef716567..cdf050d1 100644 --- a/src/commands/package/bundle/version/list.ts +++ b/src/commands/package/bundle/version/list.ts @@ -17,6 +17,8 @@ const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_v export type PackageBundleVersionResults = BundleSObjects.BundleVersion[]; export class PackageBundleVersionListCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); diff --git a/src/commands/package/bundle/version/report.ts b/src/commands/package/bundle/version/report.ts index 1bb22265..099a43d3 100644 --- a/src/commands/package/bundle/version/report.ts +++ b/src/commands/package/bundle/version/report.ts @@ -18,6 +18,8 @@ export type BundleVersionReportResult = BundleSObjects.BundleVersion & { }; export class PackageBundleVersionReportCommand extends SfCommand { + public static readonly hidden = true; + public static state = 'beta'; public static readonly summary = messages.getMessage('summary'); public static readonly examples = messages.getMessages('examples'); public static readonly flags = {