Having used Gearset in the past, I was looking for an option that would give me more control over Salesforce deployment, not to mention a better price. As a full stack developer, I want the source of truth for my application’s functionality to be my source control repository, so I don’t have to deal with diverging code-bases across environments that are a result of deploying delta change comparisons.
Approach and Result
All code and metadata will be stored in git, and on commit to the
master branch, the pipeline will build the code, run the tests, and upon success, deploy to one or more environments. An overview of the approach looks like this:
The result is a CI/CD pipeline that gives me confidence in the code I’m promoting through environments. The complete project source is available here.
Salesforce DX and Scratch Orgs
To accomplish this way of building and deploying Salesforce applications we’re enabled by Salesforce DX, which gives us some important features:
Raising a Scratch org takes seconds and I found that deploying code and running tests (via Visual Studio Code) seemed to complete much quicker than in the past when deploying/executing against sandboxes/dev orgs. Running a number of test suites via command line is much easier than using Salesforce UI to point-and-click them.
As with all things in Salesforce, there are limits and here’s how they apply to Scratch orgs. In my case I’m operating off Developer Edition (free) which is limited to 6 scratch orgs per day, so for the purposes of this experiment I won’t be creating a scratch org with every pipeline run. Instead I’ve just created a single scratch org and I’ll push & deploy to that.
Building the Application
My application will be the smallest application ever: a field on Contact that tracks how many times the contact has been updated. You can see in the source that the application is split into five parts:
TimesUpdated__c that will track the update count.
TimesUpdated__c field is displayed on layouts
My application will be the smallest application ever: a field on
Contact that tracks how many times the contact has been updated. You can see in the source that the application is split into five parts:
After initialising a git repository and Creating an SFDX project, the implementation occurred in two places as follows.
The Field, Layouts and Profiles were configured directly in Object Manager in a Scratch Org I raised for the purpose of building the application. After this configuration, I ran
sfdx force:source:pull and pulled those updates into my local source.
The Trigger and Tests were written directly in Visual Studio Code (vscode). There are a number of Salesforce extensions for vscode, however the Salesforce Extension Pack includes all the extensions you’ll need. I have mine configured such that when I hit save, the file is automatically pushed to the current (scratch) org.
Once I’m happy the application works in my scratch org, I can commit the changes and push them to GitHub.
Thanks to the capabilities of the Salesforce CLI, we can completely automate via command line our deployment and testing requirements. We could go ahead and write script to install the CLI in a build agent and execute our various tasks however, thanks to sfpowerscripts, we don’t need to. sfpowerscripts is a free collection of Azure Pipeline tasks that wraps SFDX for you, meaning you can just write the pipeline yaml you’re used to as seen here.
The pipeline needs to perform a number of steps in sequence:
Converting these steps into Azure Pipelines yaml syntax looks like this:
There are some typos in sfpowerscript task names but it’s too late, and its beta release cadence means
master (and the associated docs) might reference task versions that are not yet available in the Visual Studio Marketplace. For the latter you can check which versions were specified in
BuildTasks/<taskName>/task.json files at the time of the latest release. Other than this sfpowerscripts just works and is a great Azure Pipelines extension - kudos to its author Azlam Abdulsalam.
The single biggest problem I had was authenticating to the Scratch Org using JWT. The docs are straight-foward however 24 hours after creating the Scratch Org I still couldn’t connect. Turns out the resolution was to ensure you create the Scratch Org after you’ve created the Connected App in the DevHub. I raised and answered the question here. In practice, I would not use JWT to authenticate to the scratch org, rather, I’d just create a new scratch org anytime the pipeline needed one via sfpwowerscript-authenticateorg-task (sic). I’m using a single scratch org here instead to get around the limits on Developer Edition.
Wrapping it up
Thanks to the sfdx-cli and sfpowerscripts it’s pretty easy to set up a Salesforce pipeline in Azure DevOps. The steps above can, and should, be extended to bundle changes into a package and that package deployed across your Salesforce environments and there’s an example of doing just that here.
Otherwise build, deploy and test is automatic and (for this trivial project) complete in under 2 minutes - nice!