diff --git a/README.md b/README.md index 3f41ea2..907507f 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,17 @@ Combine Salesforce manifest files together. ``` USAGE - $ sf sfpc combine [-f ] [-d ] [-c ] [--json] + $ sf sfpc combine [-f ] [-d ] [-c ] [-v ] [--json] FLAGS - -f, --package-file= The path to an existing package.xml file. + -f, --package-file= The path to an existing package.xml file. This flag can be specified multiple times. - -d, --directory= The path to an existing directory with package.xml files. + -d, --directory= The path to an existing directory with package.xml files. Only XML files in the immediate directory will be scanned. This flag can be specified multiple times. + -v, --api-version= Specify the API version to use in the combined package.xml. + Must be an integer. + Optional. If not declared, it will default to the max API version found in all inputs. -c, --combined-package= The path to save the combined package.xml to. If this value matches one of the input packages, it will overwrite the file. Default name is "package.xml" in the running directory. @@ -62,6 +65,10 @@ EXAMPLES Combine pack1.xml, pack2.xml, and a directory with package XML files into package.xml $ sf sfpc combine -f pack1.xml -f pack2.xml -d "test/sample_dir" -c package.xml + + Combine pack1.xml and pack2.xml into package.xml set at API version 62.0 + + $ sf sfpc combine -f pack1.xml -f pack2.xml -v "62" -c package.xml ``` @@ -70,7 +77,7 @@ EXAMPLES When the packages are combined, the `` elements with the metadata name will be converted to lower-case, ex: `customobject`. This ensures that multiple members of the same metadata name are grouped together in the combined package and that duplicate members are only declared once. The `` elements are case insensitive when read by the Salesforce CLI. However, the `` elements are case sensitive and their cases must match their API names in Salesforce. This tool will not convert the cases of the `` elements, just the `` elements. -The combined package.xml will use the maximum `` tag found in all packages. If none of the packages provided have ``, it will omit this from the combined package.xml. When you deploy a package.xml without an API version, it will check the `sfdx-project.json` file for the `sourceApiVersion`. If both files do not have an API version, it will follow the [sourceApiVersion: Order of Precedence](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_apiversion.htm). +By default, the combined package.xml will use the maximum `` tag found in all packages. If none of the packages provided have ``, it will omit this from the combined package.xml. When you deploy a package.xml without an API version, it will check the `sfdx-project.json` file for the `sourceApiVersion`. If both files do not have an API version, it will follow the [sourceApiVersion: Order of Precedence](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_apiversion.htm). If you'd like to override this default behavior, supply the optional `--api-version`/`-v` flag, which accepts an integer, to explicity set the API verison to use in the combined package.xml. The packages provided must match the expected Salesforce package.xml structure. If you provide an XML which doesn't match the expected structure, it will print this warning and not add it to the output: @@ -82,7 +89,7 @@ If all packages provided don't match the expected structure, the combined packag You can avoid deploying an empty package by searching the package for any `` elements in it. -``` bash +```bash # run deploy command only if the combined package contains metadata sf sfpc -f package/package.xml -f package.xml -c package.xml if grep -q '' ./package.xml ; then @@ -98,10 +105,10 @@ fi Salesforce packages follow this structure: - ``: Root element must be `Package` with the Salesforce namespace. - - ``: This element defines a specific type of metadata component. It is used to group components of the same type, such as Apex classes, triggers, or Visualforce pages. Can be declared multiple times, but must be declared at least once. - - ``: Lists the individual components by their API names within that type. Multiple members can be included under the same type but at least 1 member must be declared in each ``. - - ``: Specifies the type of metadata, such as "ApexClass", "ApexTrigger", or "CustomObject". Must be declared only once in each `` element. - - ``: This optional element specifies the API version of Salesforce metadata that you are working with. It helps ensure compatibility between your metadata and the version of Salesforce you're interacting with. This can only be declared once. + - ``: This element defines a specific type of metadata component. It is used to group components of the same type, such as Apex classes, triggers, or Visualforce pages. Can be declared multiple times, but must be declared at least once. + - ``: Lists the individual components by their API names within that type. Multiple members can be included under the same type but at least 1 member must be declared in each ``. + - ``: Specifies the type of metadata, such as "ApexClass", "ApexTrigger", or "CustomObject". Must be declared only once in each `` element. + - ``: This optional element specifies the API version of Salesforce metadata that you are working with. It helps ensure compatibility between your metadata and the version of Salesforce you're interacting with. This can only be declared once. ## Parsing Strings with Package Contents diff --git a/messages/sfpc.combine.md b/messages/sfpc.combine.md index 930e74e..381587e 100644 --- a/messages/sfpc.combine.md +++ b/messages/sfpc.combine.md @@ -10,6 +10,7 @@ Read multiple package.xml files, then parse them and combine them to create 1 fi - sf sfpc combine -f pack1.xml -f pack2.xml -c package.xml - sf sfpc combine -f pack1.xml -d "test/directory" -c package.xml +- sf sfpc combine -f packag1.xml -f pack2.xml -v 60 -c package.xml # flags.package-file.summary @@ -22,3 +23,7 @@ Combined package file path. # flags.directory.summary Directory to look for package.xml files in. + +# flags.api-version.summary + +Sets the API version to use in the combined package.xml. diff --git a/src/commands/sfpc/combine.ts b/src/commands/sfpc/combine.ts index 8f00d66..3afa10f 100644 --- a/src/commands/sfpc/combine.ts +++ b/src/commands/sfpc/combine.ts @@ -35,6 +35,12 @@ export default class SfpcCombine extends SfCommand { multiple: true, exists: true, }), + 'api-version': Flags.integer({ + summary: messages.getMessage('flags.api-version.summary'), + char: 'v', + required: false, + multiple: false, + }), }; public async run(): Promise { @@ -43,6 +49,7 @@ export default class SfpcCombine extends SfCommand { const files = flags['package-file'] ?? []; const combinedPackage = flags['combined-package']; const directories = flags['directory'] ?? null; + const userApiVersion = flags['api-version'] ?? null; let packageContents: PackageXmlObject[] = []; let apiVersions: string[] = []; const warnings: string[] = []; @@ -68,7 +75,7 @@ export default class SfpcCombine extends SfCommand { }); } - const xmlString = buildPackage(packageContents, apiVersions); + const xmlString = buildPackage(packageContents, apiVersions, userApiVersion); this.log(`Combined package.xml written to: ${combinedPackage}`); await writeFile(combinedPackage, xmlString); return { path: combinedPackage }; diff --git a/src/helpers/buildPackage.ts b/src/helpers/buildPackage.ts index bc8ae2b..53168b8 100644 --- a/src/helpers/buildPackage.ts +++ b/src/helpers/buildPackage.ts @@ -11,12 +11,21 @@ const xmlConf = { attributeNamePrefix: '@_', }; -export function buildPackage(packageContents: PackageXmlObject[], apiVersions: string[]): string { - // Determine the maximum API version from the apiVersions array - const maxVersion = apiVersions.reduce((max, version) => (version > max ? version : max), '0.0'); +export function buildPackage( + packageContents: PackageXmlObject[], + apiVersions: string[], + userApiVersion: number | null +): string { + // If user does not provide an API version flag, determine the maximum API version from the apiVersions array + let apiVersion: string; + if (!userApiVersion) { + apiVersion = apiVersions.reduce((max, version) => (version > max ? version : max), '0.0'); + } else { + apiVersion = userApiVersion.toFixed(1); + } // Combine the parsed package.xml contents - const mergedPackage: PackageXmlObject = { Package: { types: [], version: maxVersion } }; + const mergedPackage: PackageXmlObject = { Package: { types: [], version: apiVersion } }; // Process each parsed package XML for (const pkg of packageContents) { @@ -48,7 +57,7 @@ export function buildPackage(packageContents: PackageXmlObject[], apiVersions: s members: type.members.sort((a, b) => a.localeCompare(b)), name: type.name, })), - version: maxVersion !== '0.0' ? maxVersion : undefined, + version: apiVersion !== '0.0' ? apiVersion : undefined, }, };