CI/CD setup using Azure Devops, Salesforce DX and Visual Studio Code

Howdy Folks !!

Today we are going to set up a very easy CI/CD solution to automate your salesforce deployment process using Azure Devops. I am assuming you guys are already aware of demands and advantages of using version control systems. Salesforce developers community also started adopting these devops practices on a large scale now and using different source control systems for managing their codes. Microsoft Azure is one of such popular version control systems that allow you to create your git repo and manage it.

After finishing this article, you will be able to

  • Add your code to version control system provided by Azure devops
  • Build your own deployment environment for your salesforce development
  • Trigger automatic deployment to your sandboxes or production when you check in code to respective branch on your repo

In your agile development process, you can create new branches for each of your sprint or release. Push all of your changes to these branches. And once you are ready to migrate them to higher environments like QA, UAT or Prod, just merge your pull requests to their respective branches. These branches then automatically initiate your deployment process and migrate your code to respective salesforce org in cloud. Giving you all flexibility of tracking your changes by each developer, feature, sprint or release.

So without further delay, let’s dig into detailed steps of this process.

Software’s required

  • Salesforce command line interface (CLI)
  • Open SSL toolkit for windows or Mac
  • Git UI or GIT CLI
  • Visual Studio Code
  • Salesforce Extension pack for Visual Studio Code

This process will consist 4 steps

  1. Setup Connected App in Salesforce
  2. Create project in Azure Devops
  3. Connect Visual Studio code to Salesforce
  4. Setup pipeline in Azure for automatic deployment

Let’s assume you are using windows, here are the action items for each step. The only difference for mac users will be the tool for generating Open SSL certificate and key. All other processes are going to be the same.

Setup Connected App in Salesforce

We will be using the JWT token based authentication when connecting to salesforce from Azure devops pipeline. So we first have to generate our Self signed certificate for authentication and set it up using a connected app. Keep your Key and certificate files securely as you need to use them while setting up a connected app in each environment.

1.   Setup a dedicated user with all API and metadata permissions for deployment integration. Optionally you can test this with any existing system admin user.

2.   Download the open ssl toolkit from https://code.google.com/archive/p/openssl-for-windows/downloads if you don’t already have one on your system.

3.   Extract zip file contents and navigate to bin folder

4.   Click on openssl application to create your open ssl certificate by following steps mentioned in salesforce documentation here https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_key_and_cert.htm . Grab your server.crt and server.key files. We will be using them to authenticate with salesforce later.

5.   You may need to exclude the “openssl” keyword from each command mentioned in salesforce document.

6.   if you get error for not finding openssl.cnf file while executing this command

req -new -key server.key -out server.csr

execute the following alternate command with the path of openssl.cnf in your extracted folder. You may find this file in the root folder of your open ssl extraction.

req -config "<path to your openssl.cnf file>" -new -key server.key -out server.csr

7.   Now for authentication setup a connected app in salesforce using server.crt file created in step 6 by following steps mentioned here https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_connected_app.htm

8.   Grant access to desired deployment user to new created connected app.

Setup project and git repository in Azure Devops

1.   Login to your azure portal

2.   Create new Azure Devops account if you don’t already have one

3.   Navigate to https://dev.azure.com/

4.   This should take you to your desired devops account

5.   Create a new project by clicking New Project button at top right. Give it a name and save.
Azure new devops project

6.   Click on new created project and navigate to Repos

7.   which should take you to following screen
Azure new repo

8.   Refer this article to create an empty Azure devops project in case the above steps do not work in your case. https://docs.microsoft.com/en-us/azure/devops/organizations/projects/create-project?view=azure-devops&tabs=preview-page

9.   Now Create new folder in your local system and clone repository we just created

execute git clone <repo-url>

10.   If it does not start cloning, use following steps to generate your clone URL using personal access token

11.   Copy that above URL and then click on generate git credentials

12.   This will generate a personal access token for you to use with Git repository

13.   Create a repository access URL using your access token. It should look like this https://<your –personal-access-token>@dev.azure.com/somepath

Setup Visual Studio Code

This is an optional step, if you are already using any other tools to retrieve metadata from salesforce org, you can keep using that and skip this setup of VS code. But if you are not using anything yet, don’t worry, just follow these steps

1.   Assuming you already have installed visual studio code and salesforce extension pack, connect your visual studio code to your salesforce environment by following detailed steps mentioned here https://www.sfdcstop.com/2019/06/how-to-setup-visual-studio-code-for.html

2.   Once your project is created and all sources are retrieved , copy all files to the repository folder created in the previous step.

3.   Add server.key file generated while setting up connected app in root folder or any other path

4.   Push your new code to remote repo

follow this article if you are not familiar with git commands for pushing code https://dev.to/dhruv/essential-git-commands-every-developer-should-know-2fl

This should look as bellow
Azure repo files

Setup Pipeline for automatic deployment

Now we are moving towards the final and main step of this process. This is very important to understand what we are doing here.

  1. In your Azure devops project, navigate to pipelines
    Azure start new pipeline
  2. Create new project using Azure Repos Git option
    Azure new pipeline source
  3. Select Starter Pipeline
  4. Click on the Variables button at top. 
  5. Here we are going to define Connected App’s client Id, instance URL and Salesforce user name
    Azure pipeline variables
  6. salesforceProdClientId grabbed from connected app defined in earlier process
  7. salesforceProdInstanceURL can be either your custom salesforce url or https://login.salesforce.com in case of production or dev org and https://test.salesforce.com in case of sandbox
  8. salesforceProdUserName will be your user name of dedicated deployment user
  9. Optionally define a similar set of variables for other environments. Following code is assuming that you have other 2 branches for UAT and QA environment.
  10. Download and Copy following code and replace contents of your pipeline file that you are editing. (azure-pipeline.yml)
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
  batch: "true"
  branches:
    include:
      - master
      - uat
      - qa
  paths:
    exclude:
      - README.md
      - azure-pipelines.yml
pr:
  autoCancel: "true"
  branches:
    include:
      - master
      - uat
      - qa
  paths:
    exclude:
      - README.md
jobs:
- job: ProdDeploy
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
  steps:
    - task: UseNode@1
    - bash: 
        npm install sfdx-cli --global
      displayName: Install Salesforce CLI
    - bash: 
        sfdx force:auth:jwt:grant --clientid $(salesforceProdClientid) --jwtkeyfile ./buildfiles/server.key --username $(salesforceProdUsername) --instanceurl $(salesforceProdInstanceUrl) -a prod
      displayName: Authorize salesforce org
    - bash: 
        sfdx force:source:convert -d ./src
      displayName: Convert to deploy source
    - bash: 
        sfdx force:mdapi:deploy -l RunLocalTests -c -d ./src -u prod -w 10
      displayName: Run validation on source code
    - bash: 
        sfdx force:mdapi:deploy -d ./src -u prod -w 10
      displayName: Deploy source code to Production
- job: UATDeploy
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/uat'))
  steps:
    - task: UseNode@1
    - bash: 
        npm install sfdx-cli --global
      displayName: Install Salesforce CLI
    - bash: 
        sfdx force:auth:jwt:grant --clientid $(salesforceUATClientid) --jwtkeyfile ./buildfiles/server.key --username $(salesforceUATUsername) --instanceurl $(salesforceUATInstanceurl) -a uat
      displayName: Authorize salesforce org
    - bash: 
        sfdx force:source:convert -d ./src
      displayName: Convert to deploy source
    - bash: 
        sfdx force:mdapi:deploy -l RunLocalTests -c -d ./src -u uat -w 10
      displayName: Run validation on source code
    - bash: 
        sfdx force:mdapi:deploy -d ./src -u uat -w 10
      displayName: Deploy source code to UAT
- job: QADeploy
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/qa'))
  steps:
    - task: UseNode@1
    - bash: 
        npm install sfdx-cli --global
      displayName: Install Salesforce CLI
    - bash: 
        sfdx force:auth:jwt:grant --clientid $(salesforceQAclientid) --jwtkeyfile ./buildfiles/server.key --username $(salesforceQAusername) --instanceurl $(salesforceQAinstanceurl) -a qa
      displayName: Authorize salesforce org
    - bash: 
        sfdx force:source:convert -d ./src
      displayName: Convert to deploy source
    - bash: 
        sfdx force:mdapi:deploy -l RunLocalTests -c -d ./src -u qa -w 10
      displayName: Run validation on source code to QA
    - bash: 
        sfdx force:mdapi:deploy -d ./src -u qa -w 10
      displayName: Deploy source code

Let me explain what’s going on here,

Trigger : defines which of the available branches should trigger the automated deployment

Pr : defines only Pull request of given branches should run the pipeline jobs

Job : each of the jobs defined here gives steps to execute on CLI. But each of these jobs have a condition bound to it, which decides where to deploy the code. So if code is merged to QA branch, execute steps for QA org deployment. Similarly if code is merged to master branch, execute steps for Production deployment.

Steps : this tells the actions / commands to execute.

  1. We first install Node js
  2. Then we install sfdx cli using nodes npm install command
  3. Authorize to salesforce org using JWT login flow. In this specific step, we are using the variables we defined earlier to authorize to environment
  4. Convert the project to a deployable source. As we are using Visual Studio code and new extensions to retrieve the code, file structure of this folder is not in directly deployable format. So we first have to change this folder to a deployable source folder.
  5. If you have retrieved your source code using some other metadata tool, you can remove this step 4 line from given code, so that it will not attempt to convert the source again
  6. After converting the source, we are trying to validate the code against target org before actually attempting the deployment
  7. Once validation step is succeeded, we execute command to do final deployment of source folder

WOOHOO !!

That’s it ! Well done, You have just configured an automatic deployment pipeline for your project.

Post a comment if you do not understand or are stuck or need more information on this setup.