Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@
"api-version",
"flags-dir",
"ignore-conflicts",
"root-type-with-dependencies",
"json",
"manifest",
"metadata",
Expand Down
16 changes: 12 additions & 4 deletions messages/retrieve.start.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,23 @@ To retrieve multiple metadata components, either use multiple --metadata <name>

- Retrieve specific Apex classes that match a pattern; in this example, retrieve Apex classes whose names contain the string "MyApex":

<%= config.bin %> <%= command.id %> --metadata 'ApexClass:MyApex*'
<%= config.bin %> <%= command.id %> --metadata 'ApexClass:MyApex*'

- Retrieve the source files in the "force-app" directory; if any of the retrieved metadata is of type "Bot", also retrieve all dependent components of the Bot, such as GenAiPlannerBundles, GenAiPlugins, and GenAiFunctions:

<%= config.bin %> <%= command.id %> --source-dir force-app -root-type-with-dependencies Bot

- Retrieve a custom object called ExcitingObject that's in the SBQQ namespace:

sf <%= command.id %> --metadata CustomObject:SBQQ__ExcitingObject
<%= config.bin %> <%= command.id %> --metadata CustomObject:SBQQ__ExcitingObject

- Retrieve all custom objects in the SBQQ namespace by using a wildcard and quotes:

sf <%= command.id %> --metadata 'CustomObject:SBQQ__*'
<%= config.bin %> <%= command.id %> --metadata 'CustomObject:SBQQ__*'

- Retrieve all list views for the Case standard object:

sf <%= command.id %> --metadata 'ListView:Case*'
<%= config.bin %> <%= command.id %> --metadata 'ListView:Case*'

- Retrieve all custom objects and Apex classes found in all defined package directories (both examples are equivalent):

Expand Down Expand Up @@ -113,6 +117,10 @@ Package names to retrieve. Use of this flag is for reference only; don't use it

The metadata of the supplied package name(s) will be retrieved into a child directory of the project. The name of that child directory matches the name of the package. The retrieved metadata is meant for your reference only, don't add it to a source control system for development and deployment. For package development, retrieve the metadata using a manifest (`--manifest` flag) or by targeting a source controlled package directory within your project (`--source-dir` flag).

# flags.root-type-with-dependencies.summary

Metadata type whose dependent types should also be retrieved.

# flags.source-dir.summary

File paths for source to retrieve from the org.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@salesforce/kit": "^4.0.0",
"@salesforce/plugin-info": "^4.0.0",
"@salesforce/sf-plugins-core": "^13.0.0",
"@salesforce/source-deploy-retrieve": "^13.0.0",
"@salesforce/source-deploy-retrieve": "^13.1.0",
"@salesforce/source-tracking": "^8.0.0",
"@salesforce/ts-types": "^3.0.0",
"ansis": "^3.17.0",
Expand Down
12 changes: 11 additions & 1 deletion src/commands/project/retrieve/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ export default class RetrieveMetadata extends SfCommand<RetrieveResultJson> {
description: messages.getMessage('flags.package-name.description'),
multiple: true,
}),
'root-type-with-dependencies': Flags.string({
summary: messages.getMessage('flags.root-type-with-dependencies.summary'),
multiple: true,
options: ['Bot', 'AiAgentDefinitionVersion'],
}),
'output-dir': Flags.directory({
char: 'r',
summary: messages.getMessage('flags.output-dir.summary'),
Expand Down Expand Up @@ -556,7 +561,12 @@ const buildRetrieveOptions = async (
merge: true,
packageOptions: flags['package-name'],
format,
...(hasRootTypesWithDependencies(flags, apiVersion) ? { rootTypesWithDependencies: ['Bot'] } : {}),
...((): { rootTypesWithDependencies?: string[] } => {
const auto = hasRootTypesWithDependencies(flags, apiVersion) ? ['Bot'] : [];
const explicit = flags['root-type-with-dependencies'] ?? [];
const merged = [...new Set([...auto, ...explicit])];
return merged.length ? { rootTypesWithDependencies: merged } : {};
})(),
...(format === 'metadata'
? {
singlePackage: flags['single-package'],
Expand Down
31 changes: 31 additions & 0 deletions test/commands/retrieve/start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,37 @@ describe('project retrieve start', () => {
ensureRetrieveArgs({ format: 'source', rootTypesWithDependencies: ['Bot'] });
});

it('should pass along rootTypesWithDependencies from the --root-type-with-dependencies flag', async () => {
const metadata = ['ApexClass:MyClass'];
const result = await RetrieveMetadata.run([
'--metadata',
metadata[0],
'--root-type-with-dependencies',
'Bot',
'--root-type-with-dependencies',
'AiAgentDefinitionVersion',
'--json',
]);
expect(result).to.deep.equal(expectedResults);
ensureRetrieveArgs({ format: 'source', rootTypesWithDependencies: ['Bot', 'AiAgentDefinitionVersion'] });
});

it('should merge --root-type-with-dependencies with auto-detected Bot for pseudo-types', async () => {
const metadata = ['Agent:My_Agent'];
const apiversion = '64.0';
const result = await RetrieveMetadata.run([
'--metadata',
metadata[0],
'--api-version',
apiversion,
'--root-type-with-dependencies',
'AiAgentDefinitionVersion',
'--json',
]);
expect(result).to.deep.equal(expectedResults);
ensureRetrieveArgs({ format: 'source', rootTypesWithDependencies: ['Bot', 'AiAgentDefinitionVersion'] });
});

it('should pass along metadata and org for pseudo-type wildcard matching', async () => {
const metadata = ['ApexClass', 'Agent'];
const result = await RetrieveMetadata.run(['--metadata', metadata[0], '--metadata', metadata[1], '--json']);
Expand Down
28 changes: 7 additions & 21 deletions test/nuts/manifest/manifestCreate.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,27 +147,13 @@ describe('project generate manifest', () => {
);
const manifestContents = fs.readFileSync(join(session.project.dir, manifestName), 'utf-8');

const expectedManifestContents =
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<Package xmlns="http://soap.sforce.com/2006/04/metadata">\n' +
' <types>\n' +
' <members>FileUtilities</members>\n' +
' <members>FileUtilitiesTest</members>\n' +
' <name>ApexClass</name>\n' +
' </types>\n' +
' <types>\n' +
' <members>Create_property</members>\n' +
' <name>Flow</name>\n' +
' </types>\n' +
' <types>\n' +
' <members>dreamhouse</members>\n' +
' <members>sfdcInternalInt__sfdc_nc_constraints_engine_deploy</members>\n' +
' <members>sfdcInternalInt__sfdc_scrt2</members>\n' +
' <name>PermissionSet</name>\n' +
' </types>\n' +
' <version>64.0</version>\n' +
'</Package>\n';
expect(manifestContents).to.equal(expectedManifestContents);
expect(manifestContents).to.include('<name>ApexClass</name>');
expect(manifestContents).to.include('<members>FileUtilities</members>');
expect(manifestContents).to.include('<members>FileUtilitiesTest</members>');
expect(manifestContents).to.include('<name>Flow</name>');
expect(manifestContents).to.include('<members>Create_property</members>');
expect(manifestContents).to.include('<name>PermissionSet</name>');
expect(manifestContents).to.include('<members>dreamhouse</members>');
});

it('should produce a manifest from an excluded list of metadata in an org', async () => {
Expand Down
32 changes: 6 additions & 26 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1027,22 +1027,7 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"

"@jsforce/jsforce-node@^3.10.17":
version "3.10.17"
resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.10.17.tgz#c8f0a9d3b88925d45b297f2a9dac8af2a17c47ee"
integrity sha512-gYWiK0Y68dMUTdlPjkF+Bw3r7pmfTbqzs7/6ZChg2Md14NyzXk/usp+y8hHj6vc1SF3s7e6j5OUzUasYF5RJWQ==
dependencies:
"@sindresorhus/is" "^4"
base64url "^3.0.1"
csv-parse "^5.5.2"
csv-stringify "^6.6.0"
faye "^1.4.0"
form-data "^4.0.4"
multistream "^3.1.0"
undici "^8.5.0"
xml2js "^0.6.2"

"@jsforce/jsforce-node@^3.10.19":
"@jsforce/jsforce-node@^3.10.17", "@jsforce/jsforce-node@^3.10.19":
version "3.10.19"
resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.10.19.tgz#ccbc539c12f4f7dff9cfdcc6cfb8f07bd840f731"
integrity sha512-k7i2Tntu1fLvkMtRcKDFU64/Fr2M692ECtbwIGX6hcOh5mj+jrMa1tlvcdwffxAMl+lPYCXnY2bjErxWmP84zA==
Expand Down Expand Up @@ -1487,10 +1472,10 @@
proxy-agent "^6.5.0"
yaml "^2.9.0"

"@salesforce/source-deploy-retrieve@^13.0.0":
version "13.0.0"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-13.0.0.tgz#dcdaf8461d6ad7af937f5b9daf38844e3933247f"
integrity sha512-MBqBM9Waewh+tCR89KlDHEGaUJ9cAjwS2FIyIn+Zq/NwW7aRucyCF25MWs4gSHeFsBiNUGyGtxlIt+2oWNUIlw==
"@salesforce/source-deploy-retrieve@^13.0.0", "@salesforce/source-deploy-retrieve@^13.1.0":
version "13.1.0"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-13.1.0.tgz#f9f0427e46bcca60bd39974779bf816e17357ca1"
integrity sha512-oSOuinhSMkP1t1F0IzwX6NKgcirSl2ROV2v4GcYb1QOp0tFS9NGpofNMuViTFNoxmBdvrKv5mUT19OdrBMyeWw==
dependencies:
"@salesforce/core" "^9.0.0"
"@salesforce/kit" "^4.0.0"
Expand Down Expand Up @@ -6481,12 +6466,7 @@ path-exists@^4.0.0:
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==

path-expression-matcher@^1.5.0:
version "1.6.1"
resolved "https://registry.yarnpkg.com/path-expression-matcher/-/path-expression-matcher-1.6.1.tgz#fb190513954875d7e1b05c8caabe7fdd0a4cd75b"
integrity sha512-h7bxdzhHk8Knyc4Tj+jMaa7fEEoUJy7p1qtbVgkYg1Uhpe5Np5VuGXCRZnkZvU+Q42M1vStt0ifa3ueykRJPmQ==

path-expression-matcher@^1.6.2:
path-expression-matcher@^1.5.0, path-expression-matcher@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz#567c73c07197e9dcef24e90edcdc571056599168"
integrity sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==
Expand Down
Loading