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.

A Salesforce pipeline in Azure DevOps

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:

An overview of the approach

The result is a CI/CD pipeline that gives me confidence in the code I’m promoting through environments. The source is available here and the build results are 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:

  • Source-driven development
  • Scratch orgs
    • Lets us (very) quickly raise and destroy environments.
  • Salesforce CLI (sfdx)

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:

  • Field
    • The field TimesUpdated__c that will track the update count.
  • Trigger
    • The apex code that updates the TimesUpdated__c field.
  • Tests
    • A couple of apex tests that prove my code is operating as I expect it to be.
  • Layouts
    • How the TimesUpdated__c field is displayed on layouts
  • Profiles
    • The access various profiles have to updating the TimesUpdated__c field.

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.

Pushing and pulling between disk and Scratch Org

Azure Pipelines

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 is pretty simple as seen here and, includes the following steps:

  • Pull source from git master
  • Install sfdx-cli
  • Authenticate DevHub
  • Authenticate Scratch Org
  • Deploy source to Scratch Org
  • Run tests
  • Validate test coverage

Troubleshooting

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!

Those links one last time:

Salesforce Icon by Icons8