Table of Contents
Combine multiple Salesforce package.xml
files into a single manifest for deployments. This is useful when:
- Using tools like
sfdx-git-delta
to generate incremental package.xml files - Merging different package.xml files from various sources
- Ensuring a streamlined deployment process in CI/CD workflows
sf plugins install [email protected]
Combine Salesforce manifest files together.
USAGE
$ sf sfpc combine [-f <value>] [-d <value>] [-c <value>] [-v <value>] [-n] [--json]
FLAGS
-f, --package-file=<value> The path to an existing package.xml file.
Can be specified multiple times.
-d, --directory=<value> The path to an existing directory with package.xml files.
Only XML files in the immediate directory will be scanned.
Can be specified multiple times.
-v, --api-version=<value> Specify the API version to use in the combined package.xml.
Must be a float value (e.g., '62.0') and be an active API version.
If not declared, it will default to the max API version found in all inputs.
-n, --no-api-version Intentionally omit the API version in the combined package.xml.
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 is "package.xml".
GLOBAL FLAGS
--json Format output as json.
DESCRIPTION
Combine multiple package files into 1 file.
EXAMPLES
Combine pack1.xml and pack2.xml into package.xml
$ sf sfpc combine -f pack1.xml -f pack2.xml -c package.xml
Combine pack1.xml, pack2.xml, and all package XML files in a directory 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.0" -c package.xml
Combine pack1.xml and pack2.xml into package.xml with no API version declared
$ sf sfpc combine -f pack1.xml -f pack2.xml -n -c package.xml
- The
<name>
elements (metadata types) are converted to lowercase to ensure consistency and avoid duplicates. - The
<members>
elements retain their original case, as Salesforce treats them as case-sensitive. - By default, the highest API version found in the input manifests is used.
- If no
<version>
tag is found, it is omitted from the finalpackage.xml
.
To override the API version behavior:
- Use
-v <version>
to set a specific API version. - Use
-n
to omit the API version entirely.
If a file doesn't match the expected structure or has no <types>
in it, it is skipped with a warning:
Warning: Invalid or empty package.xml: .\test\samples\invalid2.xml
If all packages are invalid or empty, the combined package.xml will be an empty package (no <types>
). You can avoid deploying an empty package by searching the manifest for any <types>
in it before running the deploy command.
sf sfpc combine -f "package/package.xml" -f "package.xml" -c "package.xml"
if grep -q '<types>' ./package.xml ; then
echo "---- Deploying added and modified metadata ----"
sf project deploy start -x package.xml
else
echo "---- No changes to deploy ----"
fi
Salesforce package.xml
files follow this structure:
- Root:
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
- Metadata Types:
<types>
contains:<members>
: Lists metadata item(s) via their API names.<name>
: Metadata type (e.g.,ApexClass
,CustomObject
).
- API Version (Optional):
<version>
specifies the metadata API version.
The example below demonstrates the following use-case:
- Run
sfdx-git-delta
to generate an incrementalpackage/package.xml
- Declare additional metadata in a commit message and create a temporary
package.xml
- Run
sf-package-combiner
to merge both packages intopackage.xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>MyApexClass</members>
<name>ApexClass</name>
</types>
<version>60.0</version>
</Package>
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>MyTrigger</members>
<name>ApexTrigger</name>
</types>
<version>62.0</version>
</Package>
sf sfpc combine -f "package/package.xml" -f "package.xml" -c "package.xml"
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>MyApexClass</members>
<name>apexclass</name>
</types>
<types>
<members>MyTrigger</members>
<name>apextrigger</name>
</types>
<version>62.0</version>
</Package>
#!/bin/bash
set -e
DEPLOY_PACKAGE="package.xml"
# Define a function to build package.xml from commit message
build_package_from_commit() {
local commit_msg="$1"
local output_file="$2"
PACKAGE_FOUND="False"
# Use sed to match and extract the XML package content
package_xml_content=$(echo "$commit_msg" | sed -n '/<Package xmlns=".*">/,/<\/Package>/p')
if [[ -n "$package_xml_content" ]]; then
echo "Found package.xml contents in the commit message."
echo "$package_xml_content" > "$output_file"
PACKAGE_FOUND="True"
else
echo "WARNING: No package.xml contents found in the commit message."
fi
export PACKAGE_FOUND
}
build_package_from_commit "$COMMIT_MSG" "$DEPLOY_PACKAGE"
# create incremental package in default locations
sf sgd source delta --to "HEAD" --from "HEAD~1" --output-dir "."
# combines the sfdx-git-delta package.xml with the package found in the commit message, overwriting the commit message package
if [[ "$PACKAGE_FOUND" == "True" ]]; then
sf sfpc combine -f "package/package.xml" -f "$DEPLOY_PACKAGE" -c "$DEPLOY_PACKAGE"
fi
If you encounter any issues or would like to suggest features, please create an issue.
This project is licensed under the MIT license. Please see the LICENSE file for details.