How To Set Up CICD On Bitbucket Pipelines With SalesforceDX And Delta Deployment

Revamping our CICD process with SalesforceDX and Bitbucket Pipeline with the following initial setup.

Authentication method – authorize an org and grab the sfdxurl to be stored as repository variable in Bitbucket

sfdx force:auth:web:login 
sfdx force:org:display --verbose

There would be two token types

force://<refreshToken>@<instanceUrl> 
or 
force://<clientId>:<clientSecret>:<refreshToken>@<instanceUrl>

Copy the SFDX Auth URL which will be the second type. Create a repository variable AUTH_URL in Bitbucket and store the copied value.

Echo the AUTH_URL to a file then authenticate with with sfdxurl:store

echo $AUTH_URL >> /tmp/sfdx_auth.txt
sfdx force:auth:sfdxurl:store -f /tmp/sfdx_auth.txt -s -a dxpipeline

Grab the latest sfdx tool and install.

wget https://developer.salesforce.com/media/salesforce-cli/sfdx-linux-amd64.tar.xz 
mkdir sfdx-cli 
tar xJf sfdx-linux-amd64.tar.xz -C sfdx-cli --strip-components 1 
./sfdx-cli/install

Next, to compare delta files – there is node tool available in github that does delta comparison between hash commit or branch. Install the sfdx-git-delta app

npm install sfdx-git-delta@latest -g

Finally I incorporated these to my git workflow

On a Pull Request – I want to run a delta comparison and do an empty check only that my delta files changes are deployable and does break any unit tests.

First checkout a temporary branch from the feature branch

git checkout -b some-pr-branch

Next, run the tool to create a delta comparison from that branch to the target branch.

sgd --to some-pr-branch --from origin/staging --repo . --output .

The tool should create a package.xml/destructiveChange.xml file based on the diff on their respective directory.

Next convert the source format to mdapi so we can run a transactional deploy.

sfdx force:source:convert --manifest=package/package.xml --outputdir=convert

After conversion, do an empty check deploy and run the unit test

sfdx force:mdapi:deploy --deploydir=convert -c -l RunLocalTests -w 30

Below is the complete Pull Request script.

image: atlassian/default-image:2

pipelines:
  pull-requests:
    'feature/*': # Pull request from feature branch to Staging
      - step:
          name: "Staging Pull Request Validate Package"
          script:
            - echo "QA Pull Request Validation"
            - wget https://developer.salesforce.com/media/salesforce-cli/sfdx-linux-amd64.tar.xz
            - mkdir sfdx-cli
            - tar xJf sfdx-linux-amd64.tar.xz -C sfdx-cli --strip-components 1
            - ./sfdx-cli/install
            - echo $AUTH_URL >> /tmp/sfdx_auth.txt
            - sfdx force:auth:sfdxurl:store -f /tmp/sfdx_auth.txt -s -a dxpipeline
            - npm install sfdx-git-delta@latest -g
            - git checkout -b some-pr-branch          
            - git --no-pager diff --name-status some-pr-branch  origin/staging
            - sgd --to some-pr-branch  --from origin/staging --repo . --output .
            - echo "--- package.xml generated with added and modified metadata ---"
            - cat package/package.xml
            - sfdx force:source:convert --manifest=package/package.xml --outputdir=convert 
            - echo "---- Validating delta package  ----"
            - sfdx force:mdapi:deploy --deploydir=convert -c -l RunLocalTests -w 30

On Push to the branch – I ran similar steps with the only exception that I compare the current branch to the staging branch and not do an empty check or run the test classes as I already ran them.

Below is the complete Push script.

image: atlassian/default-image:2

pipelines:
  pushs:
    staging: 
      - step:
          name: "Deploy to Staging"
          script:
            - echo "Deploy to Staging"
            - wget https://developer.salesforce.com/media/salesforce-cli/sfdx-linux-amd64.tar.xz
            - mkdir sfdx-cli
            - tar xJf sfdx-linux-amd64.tar.xz -C sfdx-cli --strip-components 1
            - ./sfdx-cli/install
            - echo $AUTH_URL >> /tmp/sfdx_auth.txt
            - sfdx force:auth:sfdxurl:store -f /tmp/sfdx_auth.txt -s -a dxpipeline
            - npm install sfdx-git-delta@latest -g
            - git checkout -b dev          
            - git --no-pager diff --name-status some-pr-branch  origin/staging
            - sgd --to dev  --from origin/staging --repo . --output .
            - echo "--- package.xml generated with added and modified metadata ---"
            - cat package/package.xml
            - sfdx force:source:convert --manifest=package/package.xml --outputdir=convert 
            - echo "---- Validating delta package  ----"
            - sfdx force:mdapi:deploy --deploydir=convert -w 30

Hope you find this useful. Hit me up on the comments below for any questions.

How To Use Javascript Promise with Aura/Lightning Components

Javascript Promises has been around for a while but only got the chance to use it on a current project I am working on.

In analogy you make a promise and either you fulfill or break your promise.

In Javascript Promises context these translate to “resolve” meaning promise is fulfilled or “reject” which means promise was broken and can be caused by an error.

A good use case for in Lightning is handling responses from asynchronous operations in which you pass a callback function. Then that callback function can make another asynchronous operation. Keep on nesting and you can easily eventually end with what they sometimes call callback hell as your code can be hard to manage.

Let’s dive into a creating Javascript Promise

I defined this as a helper method. It calls an apex method and depending on response and getState I mapped it to either resolve or reject.

Here I assigned a variable to the returned Promise in the javascript controller. The helper returns one parameter which is the response which I can access on the .then statement.

Here we called the p variable followed by a .then and the special callback function for Aura which is $A.getCallback. You can then chain another promise by calling and returning that promise. The next then can accept a parameter from the previous promise.

With Promises, this is more readable than a nested callback and easier to manage.

I hope you find this basic tip useful. Hit the comments below if you have questions.

How To Generate a Self-Signed SSL Certificate With SAN

For development and integration use cases you may need to create or renew a self-signed certificate and store the certificate to your web server host or pass the certificate to your target system to trust only connections from an app using the certificate.

If you are storing the certificate on your webserver and enabled only secured connection via HTTPS on your server.

Chrome may not recognize the SSL certificate as secure without SAN (Subject Alternative Name).

Prerequisite: You should have openssl installed on your machine. Check and download from https://www.openssl.org/source/

To create one in command do the following steps:

Create a configuration file: eg. req.cnf

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = NZ
ST = AU
L = Auckland
O = Quonsepto
OU = MyDivision
CN = localhost
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost

Next from the terminal or command prompt run the following:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -config req.cnf -sha256

You can then generated certificate and it should be compatible with Chrome.

Check this video for sample installing on a locally hosted node app.

Milestone Reached! 1000 Subscribers in my Youtube Channel

Finally, thanks to viewers and subscribers to my channel. Just Another Dang How To Channel – a channel where I share how-to tech videos. A small milestone for me but super happy. It’s been a roller coaster ride reaching this milestone.

June 8, 2020

I started the channel way back Feb 2017 when Youtube didn’t have a strict Partner Program policy, you can upload videos and immediately earn from your videos. Then a few months after that, the policy changed to have at least 100,000 channel views for channel to be able to be monetized, I didnt meet the criteria and my channel got demonetized, I persevered, I kept sharing videos and eventually met the requirement.

But on Feb 2018 Youtube again changed policy which wiped out all small channels, new requirements were to have at least 1000 subscribers, and 4000 hours channel watch time for 365 days. I was gutted and lost interest. I abandoned the channel for several months but my watch time kept growing. Last year April 2019, I decided to revive it as my channel met the 4000 hours criteria. I had about 600 subs at that time. 1 year and 2 months later I finally reached 1000 subscribers.

My takeaway is to don’t give up and keep on persevering. Rome wasn’t built in a day. As of this writing, I am already now at 1004 subscribers and waiting for approval. Next goal up, get 2500 subscribers.

If you haven’t yet, please subscribe to my Youtube channel.

How To Use Map Object In Aura Lightning Component

By Salesforce documentation, you can define several collection types including a Map.

A Map collection allows you have a key/value pair where the key is unique. Declaring such is easy by adding the following

<aura:attribute type="Map" name="fooMap" />

But in your controller, if you try to do any Map functions such as keys(), set(key, value), values(), you get an error such as:

set is not a function 

or

values is not a function.

What is happening in Lightning is even if you declared it as Map it is treated as an Object. It took me a while to figure this out.

To get around this “limitation” I manually assigned a map in the controller and then I was able to do Map functions. You can do this either on init or before you use the component Map.

Hope you find this tip useful.