Skip to content

Commit 0617b51

Browse files
Merge pull request #976 from salesforcecli/t/packaging-distribution/W-18762471/Package-Bundle-List-command
feat: created bundle list command
2 parents bf9becf + 74a16a0 commit 0617b51

File tree

9 files changed

+241
-14
lines changed

9 files changed

+241
-14
lines changed

command-snapshot.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,21 @@
5656
"plugin": "@salesforce/plugin-packaging"
5757
},
5858
{
59-
"alias": ["force:bundle:create"],
60-
"command": "package:bundles:create",
59+
"alias": ["force:package:bundle:create"],
60+
"command": "package:bundle:create",
6161
"flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"],
6262
"flagChars": ["d", "n", "v"],
6363
"flags": ["api-version", "description", "flags-dir", "json", "loglevel", "name", "target-dev-hub"],
6464
"plugin": "@salesforce/plugin-packaging"
6565
},
66+
{
67+
"alias": ["force:package:bundle:list"],
68+
"command": "package:bundle:list",
69+
"flagAliases": ["apiversion", "target-hub-org", "targetdevhubusername"],
70+
"flagChars": ["v"],
71+
"flags": ["api-version", "flags-dir", "json", "loglevel", "target-dev-hub", "verbose"],
72+
"plugin": "@salesforce/plugin-packaging"
73+
},
6674
{
6775
"alias": ["force:package:convert"],
6876
"command": "package:convert",

messages/bundle_create.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
# summary
22

3-
Create a bundle.
3+
Create a package bundle in the Dev Hub org.
44

55
# description
66

7-
First, use this command to create a bunle. Then create a bundle version.
8-
9-
Your --name value must be unique within your namespace.
10-
11-
Run '<%= config.bin %> bundle list to list all bundles in the Dev Hub org.
7+
A package bundle is an artifact that contains one or more 2GP managed packages.
8+
A bundle can be listed on AppExchange, installed, or upgraded as a single artifact.
129

1310
# examples
1411

15-
- Default Use Case
16-
<%= config.bin %> <%= command.id %> --name <bundle_name> --description "<bundle_description>" --target-dev-hub <dev_hub_alias>`
12+
Create a package bundle in the Dev Hub org; uses the Dev Hub org with the username [email protected]:
13+
14+
sf package bundle create --name “Your bundle name” --description "Your bundle description" --target-dev-hub [email protected]
1715

1816
# flags.name.summary
1917

20-
Name of the bundle to create.
18+
Name of the package bundle.
2119

2220
# flags.description.summary
2321

24-
Description of the bundle
22+
Description of the package bundle.

messages/bundle_list.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# summary
2+
3+
List all package bundles in the Dev Hub org.
4+
5+
# examples
6+
7+
List all package bundles in the specified Dev Hub org; uses the Dev Hub org with the username [email protected]:
8+
9+
sf package bundle list --target-dev-hub <dev_hub_alias>
10+
11+
# namespace
12+
13+
Namespace Prefix
14+
15+
# name
16+
17+
Name
18+
19+
# id
20+
21+
Id
22+
23+
# bundle-id
24+
25+
Package Bundle Id
26+
27+
# alias
28+
29+
Alias
30+
31+
# description
32+
33+
Description
34+
35+
# flags.verbose.summary
36+
37+
Display extended bundle detail.
38+
39+
# error-notification-username
40+
41+
Error Notification Username
42+
43+
# createdBy
44+
45+
Created By

schemas/package-bundle-list.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$ref": "#/definitions/BundleListCommandResults",
4+
"definitions": {
5+
"BundleListCommandResults": {
6+
"type": "array",
7+
"items": {
8+
"$ref": "#/definitions/BundleListCommandResult"
9+
}
10+
},
11+
"BundleListCommandResult": {
12+
"$ref": "#/definitions/BundleSObjects.Bundle"
13+
},
14+
"BundleSObjects.Bundle": {
15+
"type": "object",
16+
"properties": {
17+
"BundleName": {
18+
"type": "string"
19+
},
20+
"Description": {
21+
"type": "string"
22+
},
23+
"Id": {
24+
"type": "string"
25+
},
26+
"IsDeleted": {
27+
"type": "boolean"
28+
},
29+
"CreatedDate": {
30+
"type": "string"
31+
},
32+
"CreatedById": {
33+
"type": "string"
34+
},
35+
"LastModifiedDate": {
36+
"type": "string"
37+
},
38+
"LastModifiedById": {
39+
"type": "string"
40+
},
41+
"SystemModstamp": {
42+
"type": "string"
43+
}
44+
},
45+
"required": [
46+
"BundleName",
47+
"Id",
48+
"IsDeleted",
49+
"CreatedDate",
50+
"CreatedById",
51+
"LastModifiedDate",
52+
"LastModifiedById",
53+
"SystemModstamp"
54+
],
55+
"additionalProperties": false
56+
}
57+
}
58+
}

src/commands/package/bundles/create.ts renamed to src/commands/package/bundle/create.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class PackageBundlesCreate extends SfCommand<BundleCreate> {
1818
public static readonly summary = messages.getMessage('summary');
1919
public static readonly description = messages.getMessage('description');
2020
public static readonly examples = messages.getMessages('examples');
21-
public static readonly aliases = ['force:bundle:create'];
21+
public static readonly aliases = ['force:package:bundle:create'];
2222
public static readonly requiresProject = true;
2323
public static readonly flags = {
2424
loglevel,

src/commands/package/bundle/list.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) 2023, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
8+
import { Flags, loglevel, orgApiVersionFlagWithDeprecations, SfCommand } from '@salesforce/sf-plugins-core';
9+
import { Messages } from '@salesforce/core/messages';
10+
import { PackageBundle, BundleSObjects } from '@salesforce/packaging';
11+
import chalk from 'chalk';
12+
import { requiredHubFlag } from '../../../utils/hubFlag.js';
13+
14+
// This is a near copy of the package list command, but with the package bundle class and messages.
15+
// If you are looking to copy this command, mabye make an abstract class for the commands that are similar.(please)
16+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
17+
const messages = Messages.loadMessages('@salesforce/plugin-packaging', 'bundle_list');
18+
19+
export type BundleListCommandResult = BundleSObjects.Bundle;
20+
export type BundleListCommandResults = BundleListCommandResult[];
21+
22+
export class BundleListCommand extends SfCommand<BundleListCommandResults> {
23+
public static readonly summary = messages.getMessage('summary');
24+
public static readonly examples = messages.getMessages('examples');
25+
public static readonly deprecateAliases = true;
26+
public static readonly aliases = ['force:package:bundle:list'];
27+
public static readonly flags = {
28+
loglevel,
29+
'target-dev-hub': requiredHubFlag,
30+
'api-version': orgApiVersionFlagWithDeprecations,
31+
verbose: Flags.boolean({
32+
summary: messages.getMessage('flags.verbose.summary'),
33+
}),
34+
};
35+
36+
public async run(): Promise<BundleListCommandResults> {
37+
const { flags } = await this.parse(BundleListCommand);
38+
const connection = flags['target-dev-hub'].getConnection(flags['api-version']);
39+
const results = await PackageBundle.list(connection);
40+
this.displayResults(results, flags.verbose);
41+
return results;
42+
}
43+
44+
private displayResults(results: BundleListCommandResults, verbose = false): void {
45+
const data = results.map((r) => ({
46+
'Package Bundle Name': r.BundleName,
47+
Id: r.Id,
48+
Description: r.Description,
49+
...(verbose
50+
? {
51+
'Created Date': r.CreatedDate,
52+
'Created By': r.CreatedById,
53+
'Last Modified Date': r.LastModifiedDate,
54+
'Last Modified By': r.LastModifiedById,
55+
'System Modstamp': r.SystemModstamp,
56+
'Is Deleted': r.IsDeleted,
57+
}
58+
: {}),
59+
}));
60+
this.table({ data, title: chalk.blue(`Package Bundles [${results.length}]`) });
61+
}
62+
}

test/commands/bundle/bundleCreate.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { expect } from 'chai';
1111
import { BundleCreateOptions, PackageBundle } from '@salesforce/packaging';
1212
import { stubSfCommandUx } from '@salesforce/sf-plugins-core';
1313
import { Connection, SfProject } from '@salesforce/core';
14-
import { PackageBundlesCreate } from '../../../src/commands/package/bundles/create.js';
14+
import { PackageBundlesCreate } from '../../../src/commands/package/bundle/create.js';
1515

1616
describe('force:bundle:create - tests', () => {
1717
const $$ = new TestContext();
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2025, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
import { Config } from '@oclif/core';
8+
import { TestContext, MockTestOrgData } from '@salesforce/core/testSetup';
9+
import { expect } from 'chai';
10+
import { PackageBundle } from '@salesforce/packaging';
11+
import { stubSfCommandUx } from '@salesforce/sf-plugins-core';
12+
import sinon from 'sinon';
13+
import { BundleListCommand } from '../../../src/commands/package/bundle/list.js';
14+
describe('force:bundle:list - tests', () => {
15+
const $$ = new TestContext();
16+
const testOrg = new MockTestOrgData();
17+
let sfCommandStubs: ReturnType<typeof stubSfCommandUx>;
18+
let listStub: sinon.SinonStub;
19+
const config = new Config({ root: import.meta.url });
20+
21+
beforeEach(async () => {
22+
await $$.stubAuths(testOrg);
23+
await config.load();
24+
sfCommandStubs = stubSfCommandUx($$.SANDBOX);
25+
26+
listStub = $$.SANDBOX.stub(PackageBundle, 'list');
27+
});
28+
29+
afterEach(() => {
30+
$$.restore();
31+
});
32+
33+
it('should list a bundle', async () => {
34+
const cmd = new BundleListCommand(['-v', testOrg.username], config);
35+
36+
listStub.resolves([{ BundleName: 'test-bundle', Id: 'test-id', Description: 'test-description' }]);
37+
38+
await cmd.run();
39+
40+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
41+
expect(sfCommandStubs.table.calledOnce).to.be.true;
42+
});
43+
44+
it('should throw error when test org flag is missing', async () => {
45+
const cmd = new BundleListCommand([], config);
46+
47+
listStub.resolves([{ BundleName: 'test-bundle', Id: 'test-id', Description: 'test-description' }]);
48+
49+
try {
50+
await cmd.run();
51+
expect.fail('Expected error was not thrown');
52+
} catch (error) {
53+
expect((error as Error).message).to.include('No default dev hub found');
54+
}
55+
});
56+
});

0 commit comments

Comments
 (0)