At Ebury, we use Salesforce as our CRM but also as a reconciliation platform for our lending business; to manage our credit line requests, our margin calls, and our onboarding (KYC, AML) processes. But since standard functionality is not enough for us, we have a dedicated team specialised in force.com that builds customisation and applications for our different teams within the company. Our goal is to use this versatile framework to build features that make our sales process quick and effective, and to help our Operation teams to be focused on what is really important for us, our clients, and let the system take care of the rest.
We applied to be one of the lucky members to be part of the Salesforce DX Pilot and we were selected! Salesforce DX Pilot started on the 22nd of February and it is still going on, but I wanted to share with you my impressions so far.
What is Salesforce DX
Salesforce DX is a set of tools and features to develop and deploy applications in an automated, continuous and collaborative way.
One of the main weak points of the Force.com platform is the lack of tools to develop and release apps in an automated way. Not all metadata can be released automatically, and there are many steps and configurations that need manual interaction. This is really a pain. Salesforce DX is here to solve those problems by offering a set of tools to integrate our development processes with our continuous integration and continuous delivery systems.
The main goal of Salesforce DX is to align with the industry standards regarding the life cycle of software development.
These are the highlights of Salesforce DX:
- Scratch Orgs: These are orgs that you can create on the fly to push your new application or changes. These orgs are temporary, currently they expire after 7 days, and are meant to be used only as part of the development. Once the development is finished, the scratch org is meant to be deleted. A scratch org is not a sandbox. A sandbox contains a copy of all your prod metadata while the scratch org doesn’t, it is empty. The scratch org will only have the metadata that you push to it.
- CLI (Command Line Interface): Salesforce has built a complete set of commands to manage the different tools. I just need to thank Salesforce for doing this. I love commands and this is something I really missed in force.com.
- Version Control Systems as “source of truth”, this is opposite to what we have now where the code that sits in our orgs is the source. This is a big step.
- Integration with Continuous Integration (CI) and Continuous Delivery (CD) systems.
- Packages 2.0: Up to now, packages have been used by Independent Software Vendors (ISV) to release their applications. Salesforce is defining a new version of packages to be used by clients internally to facilitate the development and deployment of applications internally. This part is not quite mature yet and there is not much information.
This was all theory about Salesforce DX, now I want to present a practical example.
I will share a standard use case of Salesforce DX. We will assume that we have an existing Force.com application released in our org and we want to add a new feature to it using Salesforce DX. This scenario is quite interesting because when Salesforce DX becomes GA (General Availability), there is something that we would need to think about… What do we do with our existing applications? How do we move them to Salesforce DX?
Based on the assumption that I already have an application in my dev org and I have defined an unmanaged package containing all the components of my application, I’m going to download that application to my local machine using Salesforce DX. I’m going to convert it to the Salesforce DX format. I’m going to upload it to a scratch org and I’m going to do some changes to it.
I won’t go in detail of all the things that are needed, don’t consider this as a precise guide, my intention is that you get a feeling of what can be done with Salesforce DX.
Create a Salesforce DX workspace
First thing that we need to do is to create a Salesforce DX workspace.
$ sfdx force:workspace:create --workspacename ebury
This creates a folder structure with some defaulted configuration files (sfdx-workspace.json, workspace-scratch-def.json).
|ebury/ | config/ | workspace-scratch-def.json | force-app/ | main/ | default/ | sfdx-workspace.json
By default, the Salesforce DX app source code is stored under force-app/admin/default. You can change it by editing sfdx-workspace.json.
Since here is where our code is going to live, following good practices, we should initiate a repository here with our preferred control version system, and push our changes to it. This is not integrated with Salesforce DX, this is something you need to do yourself.
Authenticate an org
Now I need to allow Salesforce DX to access to my dev org to download my application. To do this I use the authentication command.
$ sfdx force:auth:web:login --setalias MyDevOrg
–setalias is used to give a friendly name to the org so it is easy for us to reference it in future commands.
This is attacking the url https://login.salesforce.com defined by default in the sfdx-workspace.json configuration file. If we want to specify a different url we would use the parameter –instanceurl.
When we run this command a Salesforce site is opened in your browser and you are prompted to enter your credentials.
We can check our authorized orgs with the list org command.
$ sfdx force:org:list
=== Organizations Alias Username Organization ID ──────── ───────────────────────── ───────────────── MyDevOrg firstname.lastname@example.org 00D0Y000001fwkvUAA dev-hub-org email@example.com 00D0Y000001K5lVUAS
Retrieve data from a sandbox
Now that we have authorized Salesforce DX to access to our dev org, let’s retrieve our application. I will use the unmanaged package that I have defined in my dev org.
$ sfdx force:mdapi:retrieve -u MyDevOrg -p "Award Nomination" -r myDevOrg-data/
-u MyDevOrg: tells Salesforce DX the org where it has to connect
-p “Award Nomination”: name of the package we are retrieving
-r MyDevOrg-data/: folder to store the downloaded data
The execution of this command downloads a .zip file containing all the components defined in the Award Nomination package under the folder myDevOrg-data/. We need to unzip it.
Convert data to Salesforce DX format
We have to convert that data to the format that Salesforce DX understands.
$ sfdx force:mdapi:convert --rootdir myDevOrg-data/
–rootdit myDevOrg-data/: path to the source code to convert
By default the destination folder for the converted code is force-app/main/default/ as it is defined in the sfdx-workspace.json configuration file. We can define a different destination folder with the parameter -d.
Create a scratch org
Now that we have our application in our local machine converted to the Salesforce DX format let’s create a scratch org and upload our application to it.
To create a scratch org:
$ sfdx force:org:create --definitionfile ./config/workspace-scratch-def.json --setalias MyScratchOrg --setdefaultusername
–definitionfile config/workspace-scratch-def.json: configuration file we are using to create the scratch org. In this file you can define all the features you need for your org (Lightning, Community, Chatter, Opportunity Teams, etc)
–setalias MyScratchOrg: defines an alias for our scratch org
–setdefaultusername: If we don’t specify the username in future commands, by default Salesforce DX will attack to this scratch org.
Open a scratch org
We can open our scratch org directly from the command line. This command opens a window in our browser redirecting it to our scratch org.
$ sfdx force:org:open
Let’s upload our Salesforce DX application to the scratch org.
$ sfdx force:source:push
We are not specifying where our code is, because by default it is looking at force-app/admin/default/ and our code is there. We are not specifying either where to push our code because we defined our scratch org as default on creation.
When we run this command, if we go to the scratch org we can see our application there.
If you have layouts you would need to assign those layouts manually to your admin user.
If you have new fields in your application, you can give them field-level security (FLS) permission manually, or if you have defined a permission set as part of your application you could assign that permission set to your user directly from the console.
Assign a permission set
$ sfdx force:user:permset:assign -n Award_Nomination
This commands assign the Award_Nomination permission set to your admin user.
Source code status
Now that we have our application working in our scratch org we are ready to add a new feature to it. We could edit it in our scratch org directly, for example, adding a new field to the Case, and we could also edit in our local machine editing a class, for example.
We can track the changes that we do to our application with the status command, that tells us where the changes have been done if locally or remotely.
$ sfdx force:source:status
In our example, this would return:
State Full Name Type Workspace Path ────────── ──────── ──────── ─────────────────────────────────── Local Changed NomCntroller ApexClass force-main/default/classes/NomCntroller.cls-meta.xml Local Changed NomCntroller ApexClass force-app/main/default/classes/NomCntroller.cls Remote Changed Case CustomObject force-app/main/default/objects/Case.object-meta.xml
Pull / Push changes
If we have changes remotely and locally we need to synchronise them. We use the push and pull commands to do that.
To upload our local changes we use push.
$ sfdx force:source:push
This time it only uploads the changed files, not all our code again.
If we run the status command now we would see:
$ sfdx force:source:status
State Full Name Type Workspace Path ────────── ──────── ──────── ─────────────────────────────────── Remote Changed Case CustomObject force-app/main/default/objects/Case.object-meta.xml
And to retrieve the changes done in the org we use pull.
$ sfdx force:source:pull
Finally, we can run our tests from the command line.
$ sfdx force:apex:test:run -r human -c
You can specify which tests you want to run with the parameter –classnames.
It returns something like this:
=== Test Results Test Name Outcome Message Runtime (ms) ──────────────────────────────────── ───── ────── ────────── DO_CreateNominationControllerTest.testNominate Pass 1846 === Test Summary Name Value ────────────── ──────────────────────────────────────────── Outcome Passed Tests Ran 1 Passing 1 Failing 0 Pass Rate 100% Fail Rate 0% Test Start Time Jun 10, 2017 1:06 PM Test Execution Time 1846 ms Test Total Time 1846 ms Command Time 8423 ms Test Run Id 7073D000000M9rd Hostname https://fun-innovation-8417-dev-ed.cs70.my.salesforce.com Org Id 00D3D0000008jmdUAA Username firstname.lastname@example.org User Id 0053D000000IH8nQAG === Apex Code Coverage Id Name % Covered Uncovered Lines ────────────── ────────────────────── ──────── ─────────────── 01p3D000000UsJoQAK NomCntroller 100%
And that’s all for now. I hope this post helps to understand what Salesforce DX is and what we can do with it.
I’m really excited about it and I’m sure it will change the way we develop and deploy Force.com applications.