Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
61 changes: 61 additions & 0 deletions messages/bundle_list.md
Original file line number Diff line number Diff line change
@@ -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.
Comment thread
dawson-david-salesforce marked this conversation as resolved.
Outdated

# 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
Comment thread
dawson-david-salesforce marked this conversation as resolved.
Outdated

# alias

Alias

# description

Description

# flags.verbose.summary

Display extended bundle detail.

# convertedFrombundleId

Converted From bundle Id
Comment thread
dawson-david-salesforce marked this conversation as resolved.
Outdated

# isOrgDependent

Org-Dependent Unlocked bundle

# error-notification-username
Comment thread
dawson-david-salesforce marked this conversation as resolved.

Error Notification Username

# createdBy

Created By
58 changes: 58 additions & 0 deletions schemas/package-bundles-list.json
Original file line number Diff line number Diff line change
@@ -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
}
}
}
63 changes: 63 additions & 0 deletions src/commands/package/bundles/list.ts
Original file line number Diff line number Diff line change
@@ -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<BundleListCommandResults> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we mark this as beta?

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<BundleListCommandResults> {
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,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you will go over this with Dileep, but let's figure out what fields to show.

}
: {}),
}));
this.table({ data, title: chalk.blue(`Package Bundles [${results.length}]`) });
}
}
56 changes: 56 additions & 0 deletions test/commands/bundle/bundleList.test.ts
Original file line number Diff line number Diff line change
@@ -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<typeof stubSfCommandUx>;
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');
}
});
});
Loading