LinkedIn

Salesforce DevOps using GitHub Actions

 Implementing DevOps for Salesforce projects is a key strategy for project success  now a days. 

We are going to see an example of implementing DevOps process for Salesforce using GitHub Actions.



1. What is DevOps

DevOps is a set of practices/processes and tools to help to build software faster. Below are the major practices followed as part of DevOps:


2. Advantages of DevOps Implementation


3. Basics of GitHub Actions

GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline.

The Components of GitHub Actions


Below are the major components of GitHub Actions


4. Salesforce Use Case

Thank you Salesforce for sample script on how to implement DevOps for Salesforce using Github Actions. You can refer this Salesforce blog to get additional details.

Below is a simple use case that we are trying to solve using Github Actions.



6. Implementation Details

Github Actions will be available under .github/workflows/ within your repository




I implemented above flow in 3 different workflow Actions.


Workflow 1 - Handle Push to Feature Branch

Please make a note of below details:

Event - push
Branch - featurebranch

The above can be mentioned in the script like shown below:
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: featurebranch

And this action contains 2 jobs:

1. Run PMD
2. Create pull-request

1. Run PMD

The code for this can be seen in Salesforce sample App and it is like below:

jobs:
pmd-run:
runs-on: ubuntu-latest
steps:
# Checkout the source code
- name: 'Checkout source code'
uses: actions/checkout@v2
# Install PMD
- name: 'Install PMD'
run: |
PMD_VERSION=`cat pmd/pmd-version.txt`
wget https://github.com/pmd/pmd/releases/download/pmd_releases%2F$PMD_VERSION/pmd-bin-$PMD_VERSION.zip
unzip pmd-bin-$PMD_VERSION.zip -d ~
mv ~/pmd-bin-$PMD_VERSION ~/pmd
~/pmd/bin/run.sh pmd --version
# Run PMD scan
- name: 'Run PMD scan'
run: ~/pmd/bin/run.sh pmd -d force-app -R pmd/ruleset.xml -f text

Instead of this you can add any other code scanning tool.

2. Create pull-request

Most of the time this will be manual since developers will be doing multiple check-in and they will create the pull request only when their feature is ready to be pushed and deployed. But to show the capability of github action I have automated this:

action-pull-request:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Run the Action
if: startsWith(github.ref, 'refs/heads/feature')
uses: devops-infra/action-pull-request@v0.4.2
env:
GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }}
with:
github_token: ${{ secrets.REPO_SCOPED_TOKEN }}
title: Automatic pull request
get_diff: true

Please take a note of some points here:

Whenever you see the below type syntax, that means you are using an exisitng action from marketplace in your script. You can see github actions marketplace here and it is like our AppExchange.

steps:
- name: Checkout repository
uses: actions/checkout@v2

GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }} -
By default github action execution will be creating token, but I manually created Personal Access Token to
sequence another action execution on pull-request creation. You can see how to generate Personal Access Token
here and the value needs to be set under your repository->Setting->Secrets as shown below:


Workflow 2 - Handle pull-request

Event - pull-request
Branch - master

1. Create scratch org

Again code for this is available in Salesforce sample Apps and this step will make sure that the componenets are in
good shape to be deployed.

scratch-org-test:
runs-on: ubuntu-latest
if: ${{ github.actor != 'dependabot[bot]' }}
steps:
# Checkout the source code
- name: 'Checkout source code'
uses: actions/checkout@v2
# Install Salesforce CLI
- name: 'Install Salesforce CLI'
run: |
wget https://developer.salesforce.com/media/salesforce-cli/sfdx/channels/stable/sfdx-linux-x64.tar.xz
mkdir ~/sfdx
tar xJf sfdx-linux-x64.tar.xz -C ~/sfdx --strip-components 1
echo "$HOME/sfdx/bin" >> $GITHUB_PATH
~/sfdx/bin/sfdx version
# Store secret for dev hub
- name: 'Populate auth file with DEVHUB_SFDX_URL secret'
shell: bash
run: |
echo ${{ secrets.DEVHUB_SFDX_URL}} > ./DEVHUB_SFDX_URL.txt
secretFileSize=$(wc -c "./DEVHUB_SFDX_URL.txt" | awk '{print $1}')
if [ $secretFileSize == 1 ]; then
echo "Missing DEVHUB_SFDX_URL secret. Is this workflow running on a fork?";
exit 1;
fi
# Authenticate dev hub
- name: 'Authenticate Dev Hub'
run: sfdx auth:sfdxurl:store -f ./DEVHUB_SFDX_URL.txt -a devhub -d
# Create scratch org
- name: 'Create scratch org'
run: sfdx force:org:create -f config/project-scratch-def.json -a scratch-org -s -d 1
# Deploy source to scratch org
- name: 'Push source to scratch org'
run: sfdx force:source:push

Note - sfdx auth:sfdxurl:store -f ./DEVHUB_SFDX_URL.txt -a devhub -d

For this also value of DEVHUB_SFDX_URL should be stored under Secrets. Here it mentions how to generate this value.

2. Run Test Class

Once the scratch org is created next step is to run test class and verify the success

# Run Apex tests in scratch org
- name: 'Run Apex tests'
run: sfdx force:apex:test:run -c -r human -d ./tests/apex -w 20
# Delete temporary test file that Codecov is unable to parse
- name: 'Delete coverage file (temporary step)'
run: rm ./tests/apex/test-result-707*-codecoverage.json
# Upload code coverage data
- name: 'Upload code coverage for Apex to Codecov.io'
uses: codecov/codecov-action@v2.0.2
with:
flags: Apex
# Housekeeping
- name: 'Delete scratch org'
if: always()
run: sfdx force:org:delete -p -u scratch-org

3. Workflow 3 - Handle Merge to Master

Once scratch org creation and run test is success, reviewer can verify these steps under action and he can
approve and merge this pull request

So merge to master is also considered as push to master and we can execute actions based on that

event - push
branch - master

name: Merge
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: master
# Jobs to be executed

Job - Deploy

jobs:
deploy-acc:
runs-on: ubuntu-latest
steps:
# Checkout the source code
- name: 'Checkout source code'
uses: actions/checkout@v2
# Install Salesforce CLI
- name: 'Install Salesforce CLI'
run: |
wget https://developer.salesforce.com/media/salesforce-cli/sfdx/channels/stable/sfdx-linux-x64.tar.xz
mkdir ~/sfdx
tar xJf sfdx-linux-x64.tar.xz -C ~/sfdx --strip-components 1
echo "$HOME/sfdx/bin" >> $GITHUB_PATH
~/sfdx/bin/sfdx version
# Store secret for acc org
- name: 'Populate auth file with ACC_SFDX_URL secret'
shell: bash
run: |
echo ${{ secrets.ACC_SFDX_URL}} > ./ACC_SFDX_URL.txt
secretFileSize=$(wc -c "./ACC_SFDX_URL.txt" | awk '{print $1}')
if [ $secretFileSize == 1 ]; then
echo "Missing ACC_SFDX_URL secret. Is this workflow running on a fork?";
exit 1;
fi
# Authenticate acc
- name: 'Authenticate Acc'
run: sfdx auth:sfdxurl:store -f ./ACC_SFDX_URL.txt -a meeraacc -d
# Deploy source to Acc org
- name: 'Push source to Acc org'
run: sfdx force:source:deploy -u <username> -p force-app/main/default

This is one of the simplest flow that we can do, but in reality this needs to be modified to handle all complex scenarios.

6. Execution Details

Now let us see this in Action.

1. Push changes to featurebranch

You will be able to see executed action details under Actions:



You can see 2 workflows run on push to featurebranch:

1. On commit and push of apex class-> run PMD and pull-request creation



When you open one of the job, you can see step details and time taken to complete that step in detail:




You can further open each step and see additional details:




You can also see the created pull-request


2. On pull-request creation - create scratch org and run test class

It is a single job with multiple steps and you can see the details below:


3. Manually approve and merge pull-request to master

This will initiate deploy operation to specified org:



You can see the changes deployed to destination org successfully:














So a cycle of operations completed now.

7.Advantages with github Actions



 

Comments

  1. This is great article Meera. You nailed it .

    ReplyDelete
  2. very informative blog and useful article thank you for sharing
    Mulesoft Training in Hyderabad
    Mulesoft Online Training

    ReplyDelete
  3. Great Very good content meera, I am using Jenkins through salesforce getting errors any solution you have (Salesforce DevOps connecting Jenkins to salesforce)

    ReplyDelete
  4. Can we do delta deployments ?

    ReplyDelete
  5. Hi Meera ,
    Great blog .
    I had a doubt whenever i reterive package.xml via cli from org , in vscode it always shows as all components are different , eventhough there is no difference

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete

Post a Comment

Popular posts from this blog

Subscribing to Salesforce Platform Events using External Java Client - CometD

Send Data from Salesforce to Data Cloud using Ingestion API and Flow

How to develop reusable Invocable Apex methods for Flows