diff --git a/command-snapshot.json b/command-snapshot.json index e69e8eb8..9a5b0b02 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:list", @@ -111,9 +119,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 new file mode 100644 index 00000000..5e6f5cfc --- /dev/null +++ b/messages/package_bundle_delete.md @@ -0,0 +1,45 @@ +# 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.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-delete-deny + +The request to delete this package bundle was canceled + +# humanSuccess + +Successfully deleted the package bundle %s. + +# humanError + +Failed to delete the package bundle. diff --git a/messages/package_delete.md b/messages/package_delete.md index b0901367..c3f37800 100644 --- a/messages/package_delete.md +++ b/messages/package_delete.md @@ -22,17 +22,17 @@ 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 +# flags.no-prompt.summary -Undelete a deleted package. +Don't prompt before deleting the package. -# flags.no-prompt.summary +# flags.undelete.summary -Don’t prompt before deleting the package. +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/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 new file mode 100644 index 00000000..cdfbeabf --- /dev/null +++ b/src/commands/package/bundle/delete.ts @@ -0,0 +1,60 @@ +/* + * 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, 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 { + 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, + 'api-version': orgApiVersionFlagWithDeprecations, + 'no-prompt': Flags.boolean({ + char: 'n', + deprecateAliases: true, + aliases: ['noprompt'], + summary: messages.getMessage('flags.no-prompt.summary'), + }), + bundle: Flags.string({ + char: 'b', + summary: messages.getMessage('flags.bundle.summary'), + required: true, + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(PackageBundleDeleteCommand); + 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'); + } + + const connection = flags['target-dev-hub'].getConnection(flags['api-version']); + const result = await PackageBundle.delete(connection, this.project!, flags.bundle); + this.display(result); + return result; + } + + private display(result: BundleSaveResult): void { + this.log(); + 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 );