sfdx-git-delta
Generate the sfdx content in source format and destructive change from two git commits
What is SFDX-Git-Delta?
SFDX-Git-Delta (*a.k.a. sgd*) helps Technical Architects accomplish 2 things with their CI deployments:
- Make deployments faster, by identifying the metadata that has been changed since a reference commit.
- Automate destructive deployments, by listing the deleted (or renamed) metadata in a destructivePackage.xml
Is it for you?
If you are not a Salesforce Architect or Developer, probably not, sorry.
If you are a Technical Architect or Developer, then it’s a very useful tool for you, when the 3 conditions below are met:
Your Salesforce project uses a git repo as the source of truth.
➕
You use the Source (DX) format in the repo.
➕
You have a CI/CD pipeline (Jenkins, Bitbucket Pipelines, GitLab CI, GitHub Actions, Azure DevOps...) that handles the deployment of the sources to the Salesforce org(s).
DISCLAIMER:
⚠️ SFDX-Git-Delta is not an officially supported tool ⚠️
👷 Use it at your own risk, wear a helmet, and test it first before adding it to your pipeline 🔥
How to install it?
npm install sfdx-git-delta@latest -g
If you run your CI jobs inside a Docker image (which is very common), you can add sgd to your image, such as in this example: https://hub.docker.com/r/mehdisfdc/sfdx-cli-gitlab/dockerfile
To see the full list and description of the sgd options, run sgd --help
-V, --version output the version number
-t, --to [sha] commit sha to where the diff is done [HEAD] (default: "HEAD")
-f, --from [sha] commit sha from where the diff is done [git rev-list —max-parents=0 HEAD]
-o, --output [dir] source package specific output [./output] (default: "./output")
-a, --api-version [version] salesforce API version [48] (default: "48")
-r, --repo [dir] git repository location [./repo] (default: "./repo")
-d, --generate-delta generate delta files in [./output] folder
-h, --help output usage information
Prerequisites
Works in Unix like system.
Windows is not tested.
Git command line is required on the system where the command line is running.
How to use it?
TLDR;
sgd --to HEAD --from HEAD^ --repo . --output .
echo "--- package.xml generated with added and modified metadata ---"
cat package/package.xml
echo
echo "---- Deploying added and modified metadata ----"
sfdx force:source:deploy -x package/package.xml
echo "--- destructiveChanges.xml generated with deleted metadata ---"
cat destructiveChanges/destructiveChanges.xml
echo
echo "--- Deleting removed metadata ---"
sfdx force:mdapi:deploy -d destructiveChanges --ignorewarnings
Scenario:
Let’s take a look at the following scenario:
The CI pipelines deploys the sources to Production anytime there is a new commit in the master branch.
In our example, the latest commit to master is composed of:
- Apex Class added: TriggerHandler
- Apex Class added: TriggerHandler_Test
- Apex Class modified: TestDataFactory
- Apex Class deleted: AnotherTriggerFramework
In this situation, we would expect the CI pipeline to:
- Deploy to Production only 3 classes (no matter how much metadata is present in the force-app folder): TriggerHandler; TriggerHandler_Test; TestDataFactory
- Delete from Production 1 classe: AnotherTriggerFramework
So let’s do it!
Run the sgd command:
From the project repo folder, the CI pipeline will run the following command
sgd --to HEAD --from HEAD^ --repo . --output .
which means:
Analyse the difference between HEAD (latest commit) and HEAD^ (previous commit), from the current folder, and output the result in the same folder.
The sgd
command produces 2 usefull artefacts:
1) A package.xml
file, inside a package
folder. This package.xml file contains only the metadata that has been added and changed, and that needs to be deployed in the target org.
Content of the package.xml
file in our scenario:
2) A destructivePackage.xml
file, inside a destructivePackage
folder. This destructivePackage.xml file contains only the metadata that has been removed or renamed, and that needs to be deleted from the target org. Note: the destructivePackage
folder also contains a minimal package.xml file because deploying destructive changes requires a package.xml (even an empty one) in the payload.
Content of the destructivePackage.xml
file in our scenario:
In addition, we could also have generated a copy of the force-app folder with only the added and changed metadata, by using the --generate-delta (-d)
option (more on that later).
Deploy only the added/modified metadata:
The CI pipeline can use the package/package.xml
file to deploy only this subset of metadata:
echo "--- package.xml generated with added and modified metadata ---"
cat package/package.xml
echo
echo "---- Deploying added and modified metadata ----"
sfdx force:source:deploy -x package/package.xml
Delete the removed metadata:
The CI pipeline can use the destructiveChanges
folder to deploy the corresponding destructive change:
echo "--- destructiveChanges.xml generated with deleted metadata ---"
cat destructiveChanges/destructiveChanges.xml
echo
echo "--- Deleting removed metadata ---"
sfdx force:mdapi:deploy -d destructiveChanges --ignorewarnings
And voilà! 🥳
Advanced use-case: Generating a folder containing only the added/modified sources
Using a package.xml file to deploy a subset of the metadata is propably the simpliest approach to delta deployments. But there are some situations where you may want to have the actual source files related to all the components that have been changed recently.
One example is to speed up object deployments: the package.xml approach will result on the entire sub-folder for a given object to be deployed. On the opposite, having a copy of the actual sources added/modified allows you to chirchugically deploy only the modified components.
This is where the --generate-delta (-d)
option comes handy!
Let's use this option with our previous example:
mkdir changed-sources
sgd --to HEAD --from HEAD^ --repo . --output changed-sources/ --generate-delta
In addition to the package
and destructiveChanges
folders, the sgd
command will also produce a copy of the added/changed files in the ouput folder.
Content of the output folder when using the --generate-delta option, with the same scenario as above:
Javascript Module
var sgd = require('sfdx-git-delta');
const work = sgd({
'to':'', // commit sha to where the diff is done. Default : HEAD
'from':'', // commit sha from where the diff is done. Default : git rev-list --max-parents=0 HEAD
'output':'', // source package specific output. Default : ./output
'apiVersion':'', // salesforce API version. Default : 46
'repo':'' // git repository location. Default : ./repo
});
console.log(JSON.stringify(work));
/* {
* config: config,
* diffs: { package: {...}, destructiveChanges: {...} },
* warnings: []
* }
*/
Built With
- commander - The complete solution for node.js command-line interfaces, inspired by Ruby's commander.
- fast-xml-parser - Validate XML, Parse XML to JS/JSON and vise versa, or parse XML to Nimn rapidly without C/C++ based libraries and no callback
- fs-extra - Node.js: extra methods for the fs object like copy(), remove(), mkdirs().
- xmlbuilder - An XML builder for node.js similar to java-xmlbuilder.
Versioning
SemVer is used for versioning.
Authors
Contributing
Contributions are what make the trailblazer community such an amazing place. I regard this component as a way to inspire and learn from others. Any contributions you make are greatly appreciated.
See contributing.md for lwcc principles.
License
This project is licensed under the MIT License - see the LICENSE.md file for details