diff --git a/command-snapshot.json b/command-snapshot.json index 69009d712..3f8979637 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -239,6 +239,7 @@ "flagChars": ["c", "d", "m", "n", "p", "t"], "flags": [ "api-version", + "exclude-metadata", "flags-dir", "from-org", "include-packages", diff --git a/messages/manifest.generate.md b/messages/manifest.generate.md index be2d55498..5fcd969cf 100644 --- a/messages/manifest.generate.md +++ b/messages/manifest.generate.md @@ -19,6 +19,8 @@ Use --name to specify a custom name for the generated manifest if the pre-define To include multiple metadata components, either set multiple --metadata flags or a single --metadata flag with multiple names separated by spaces. Enclose names that contain spaces in one set of double quotes. The same syntax applies to --include-packages and --source-dir. +To build a manifest from the metadata in an org use the --from-org flag optionally combining it with the --metadata flag to only include certain metadata types, or the --exclude-metadata flag to exclude certain metadata types. When building a manifest from an org, the command makes many API calls concurrently to discover the metadata that exists in the org. To limit the number of concurrent requests use the `SF_LIST_METADATA_BATCH_SIZE` environment variable and set it to a size that works best for your org and environment. If you are experiencing timeouts and/or inconsistent manifest contents then setting this environment variable should improve accuracy. However, the command will take longer to run since it sends fewer requests at a time. + # examples - Create a manifest for deploying or retrieving all Apex classes and custom objects: @@ -37,10 +39,22 @@ To include multiple metadata components, either set multiple --metadata f $ <%= config.bin %> <%= command.id %> --from-org test@myorg.com --include-packages unlocked +- Create a manifest from specific metadata types in an org: + + $ <%= config.bin %> <%= command.id %> --from-org test@myorg.com --metadata ApexClass,CustomObject,CustomLabels + +- Create a manifest from all metadata components in an org excluding specific metadata types: + + $ <%= config.bin %> <%= command.id %> --from-org test@myorg.com --exclude-metadata StandardValueSet + # flags.include-packages.summary Package types (managed, unlocked) whose metadata is included in the manifest; by default, metadata in managed and unlocked packages is excluded. Metadata in unmanaged packages is always included. +# flags.exclude-metadata.summary + +Metadata types (types only; not names) to exclude when building a manifest from an org. + # flags.from-org.summary Username or alias of the org that contains the metadata components from which to build a manifest. diff --git a/package.json b/package.json index 4f39be226..7f00484d9 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@salesforce/kit": "^3.2.3", "@salesforce/plugin-info": "^3.4.23", "@salesforce/sf-plugins-core": "^12.0.11", - "@salesforce/source-deploy-retrieve": "^12.10.2", + "@salesforce/source-deploy-retrieve": "12.10.4-dev-17431548.0", "@salesforce/source-tracking": "^7.1.17", "@salesforce/ts-types": "^2.0.12", "ansis": "^3.3.2", diff --git a/src/commands/project/generate/manifest.ts b/src/commands/project/generate/manifest.ts index 3d04f9d37..a38c9979f 100644 --- a/src/commands/project/generate/manifest.ts +++ b/src/commands/project/generate/manifest.ts @@ -38,7 +38,7 @@ export type ManifestGenerateCommandResult = { path: string; }; -const xorFlags = ['metadata', 'source-dir', 'from-org']; +const atLeastOneOfFlags = ['metadata', 'source-dir', 'from-org']; export class ManifestGenerate extends SfCommand { public static readonly summary = messages.getMessage('summary'); @@ -53,14 +53,14 @@ export class ManifestGenerate extends SfCommand { metadata: arrayWithDeprecation({ char: 'm', summary: messages.getMessage('flags.metadata.summary'), - exactlyOne: xorFlags, + exclusive: ['source-dir'], }), 'source-dir': arrayWithDeprecation({ char: 'p', aliases: ['sourcepath'], deprecateAliases: true, summary: messages.getMessage('flags.source-dir.summary'), - exactlyOne: xorFlags, + exclusive: ['metadata'], }), name: Flags.string({ char: 'n', @@ -85,11 +85,18 @@ export class ManifestGenerate extends SfCommand { char: 'c', dependsOn: ['from-org'], }), + 'exclude-metadata': Flags.string({ + multiple: true, + delimiter: ',', + summary: messages.getMessage('flags.exclude-metadata.summary'), + dependsOn: ['from-org'], + exclusive: ['metadata'], + }), 'from-org': Flags.custom({ summary: messages.getMessage('flags.from-org.summary'), - exactlyOne: xorFlags, aliases: ['fromorg'], deprecateAliases: true, + exclusive: ['source-dir'], parse: async (input: string | undefined) => (input ? Org.create({ aliasOrUsername: input }) : undefined), })(), 'output-dir': Flags.string({ @@ -102,6 +109,12 @@ export class ManifestGenerate extends SfCommand { public async run(): Promise { const { flags } = await this.parse(ManifestGenerate); + + // We need at least one of these flags (but could be more than 1): 'metadata', 'source-dir', 'from-org' + if (!Object.keys(flags).some((f) => atLeastOneOfFlags.includes(f))) { + throw Error(`provided flags must include at least one of: ${atLeastOneOfFlags.toString()}`); + } + // convert the manifesttype into one of the "official" manifest names // if no manifesttype flag passed, use the manifestname?flag // if no manifestname flag, default to 'package.xml' @@ -114,12 +127,14 @@ export class ManifestGenerate extends SfCommand { const componentSet = await ComponentSetBuilder.build({ apiversion: flags['api-version'] ?? (await getSourceApiVersion()), sourcepath: flags['source-dir'], - metadata: flags.metadata - ? { - metadataEntries: flags.metadata, - directoryPaths: await getPackageDirs(), - } - : undefined, + metadata: + flags.metadata ?? flags['exclude-metadata'] + ? { + metadataEntries: flags.metadata ?? [], + directoryPaths: await getPackageDirs(), + excludedEntries: flags['exclude-metadata'], + } + : undefined, org: flags['from-org'] ? { username: flags['from-org'].getUsername() as string, diff --git a/test/tsconfig.json b/test/tsconfig.json index a5f451cf0..b62002f08 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -2,6 +2,10 @@ "extends": "@salesforce/dev-config/tsconfig-test-strict-esm", "include": ["./**/*.ts"], "compilerOptions": { - "skipLibCheck": true + "skipLibCheck": true, + "baseUrl": "..", + "paths": { + "@salesforce/source-deploy-retrieve": ["node_modules/@salesforce/source-deploy-retrieve"] + } } } diff --git a/tsconfig.json b/tsconfig.json index 1fa9d6311..5dbc2628b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,10 @@ "outDir": "lib", "rootDir": "src", "skipLibCheck": true, - "baseUrl": "." + "baseUrl": ".", + "paths": { + "@salesforce/source-deploy-retrieve": ["node_modules/@salesforce/source-deploy-retrieve"] + } }, "include": ["./src/**/*.ts"] } diff --git a/yarn.lock b/yarn.lock index 297108949..7e031d39c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1671,6 +1671,25 @@ cli-progress "^3.12.0" terminal-link "^3.0.0" +"@salesforce/source-deploy-retrieve@12.10.4-dev-17431548.0": + version "12.10.4-dev-17431548.0" + resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.10.4-dev-17431548.0.tgz#3d1214fa7b69c9e4eaf68912cad198d55208b15c" + integrity sha512-tAvqDNp3Oa0QDGhs1rJCOJQYvRO7pfKxzWutjVN2g7fbxn/ej5U5ZX6hKfCp411+NmI7MsN5wUpjQOs185h0mA== + dependencies: + "@salesforce/core" "^8.8.0" + "@salesforce/kit" "^3.2.2" + "@salesforce/ts-types" "^2.0.12" + fast-levenshtein "^3.0.0" + fast-xml-parser "^4.5.0" + got "^11.8.6" + graceful-fs "^4.2.11" + ignore "^5.3.2" + isbinaryfile "^5.0.2" + jszip "^3.10.1" + mime "2.6.0" + minimatch "^9.0.5" + proxy-agent "^6.4.0" + "@salesforce/source-deploy-retrieve@^12.10.2", "@salesforce/source-deploy-retrieve@^12.7.4": version "12.10.2" resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.10.2.tgz#c3737f3751f84cb4754b666edd83c014c91b87bb"