Skip to content

Commit

Permalink
feat: add optional api-version flag
Browse files Browse the repository at this point in the history
  • Loading branch information
mcarvin8 committed Nov 22, 2024
1 parent 3c4d154 commit ff05d2e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 15 deletions.
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@ Combine Salesforce manifest files together.

```
USAGE
$ sf sfpc combine [-f <value>] [-d <value>] [-c <value>] [--json]
$ sf sfpc combine [-f <value>] [-d <value>] [-c <value>] [-v <value>] [--json]
FLAGS
-f, --package-file=<value> The path to an existing package.xml file.
-f, --package-file=<value> The path to an existing package.xml file.
This flag can be specified multiple times.
-d, --directory=<value> The path to an existing directory with package.xml files.
-d, --directory=<value> 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=<value> 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=<value> 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.
Expand All @@ -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
```

<!-- commandsstop -->
Expand All @@ -70,7 +77,7 @@ EXAMPLES

When the packages are combined, the `<name>` elements with the metadata name will be converted to lower-case, ex: `<name>customobject</name>`. 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 `<name>` elements are case insensitive when read by the Salesforce CLI. However, the `<members>` elements are case sensitive and their cases must match their API names in Salesforce. This tool will not convert the cases of the `<members>` elements, just the `<name>` elements.

The combined package.xml will use the maximum `<version>` tag found in all packages. If none of the packages provided have `<version>`, 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 `<version>` tag found in all packages. If none of the packages provided have `<version>`, 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:

Expand All @@ -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 `<types>` 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 '<types>' ./package.xml ; then
Expand All @@ -98,10 +105,10 @@ fi
Salesforce packages follow this structure:

- `<Package xmlns="http://soap.sforce.com/2006/04/metadata">`: Root element must be `Package` with the Salesforce namespace.
- `<types>`: 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.
- `<members>`: 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 `<types>`.
- `<name>`: Specifies the type of metadata, such as "ApexClass", "ApexTrigger", or "CustomObject". Must be declared only once in each `<types>` element.
- `<version>`: 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.
- `<types>`: 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.
- `<members>`: 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 `<types>`.
- `<name>`: Specifies the type of metadata, such as "ApexClass", "ApexTrigger", or "CustomObject". Must be declared only once in each `<types>` element.
- `<version>`: 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

Expand Down
5 changes: 5 additions & 0 deletions messages/sfpc.combine.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
9 changes: 8 additions & 1 deletion src/commands/sfpc/combine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export default class SfpcCombine extends SfCommand<SfpcCombineResult> {
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<SfpcCombineResult> {
Expand All @@ -43,6 +49,7 @@ export default class SfpcCombine extends SfCommand<SfpcCombineResult> {
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[] = [];
Expand All @@ -68,7 +75,7 @@ export default class SfpcCombine extends SfCommand<SfpcCombineResult> {
});
}

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 };
Expand Down
19 changes: 14 additions & 5 deletions src/helpers/buildPackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
},
};

Expand Down

0 comments on commit ff05d2e

Please sign in to comment.