Since I started working at Frontiers, we've had many technical tasks that were monotonous and repetitive, typical in most technical jobs. One of them was refreshing our Salesforce Sandboxes every time we wanted to start working on a new feature.
Our modus operandi usually is to first refresh a sandbox, copy from Production, then branch our repository's Test branch, push all the metadata to the sandbox, and the finally start working on it until it's finished and a pull request is made.
If you've worked sometime with Salesforce, you are probably aware of how tedious it is to refresh a sandbox from Production and, once it is finished, set all the environment variables in Custom Settings or Custom Metadata. Here is where Aquamon came into play.
After having to do this for a couple of months, I came to the conclusion that this had to be automated. For this, I made a small CLI application which simply connected to Salesforce via the Tooling API and sent a refresh process order with a PostSandboxCopy execution script.
The application is separated in 4 different modules: the first one and most simplistic is the post-copy script, developed in Apex, which lives in Salesforce. This is executed every time a Sandbox is refreshed and simply sets some default values to the custom settings, remote site settings, etc. It can also seed the DB to have some records to work with without having to manually create them.
The post-copy script can look something like this, from the docs:
The rest of the application, I developed in C# with .NET core. It has 3 modules: one for configuration, another one which manages all the connections/requests with the Salesforce Tooling API and a third for the CLI. Since I don't want to make this post extremely long, I'll dig deeper into the Tooling client and skip quickly over the others.
While the Tooling API is not specially complicated to use, there are some perks to it. It has a REST API and a SOAP API, but since we can do everything we need to with the REST API, I took that path.
Now, first is first, and to be able talk to the Salesforce APIs we first need to authenticate. In order to do this, I created a DTO which contains all the authentication data and a small client to do so.
Salesforce's APIs use OAuth, so we only need to POST to
https://login.salesforce.com/services/oauth2/token and get the authentication token which we will later use in all future calls.
Once we're authenticated, in order to create, refresh and poll sandboxes, Salesforce exposes two different entities: the SandboxInfo and the SandboxProcess. To create or refresh sandboxes we would have to create a SandboxInfo record, to check the status, we would poll the SandboxProcess.
All our development is going to oscillate between these two entities: we want a new sandbox? Post a SandboxInfo. Do we want to refresh it? Patch it. Do we want to get the status? Then Get it.
To achieve this, I simply created a DTO for the SandboxInfo, based on the documentation and a SandboxManager class which would make the different calls to the different endpoints. If you notice, we inject the previous ForceClient which has already authenticated us.
Just as a heads up, I added a couple of extra methods to
ForceClient.cs in order to encapsulate all the
Now, all the latter summarizes the interaction with Salesforce. To wire that up in a CLI application, I used the out-of-the-box
Microsoft.Extensions.Configuration to read the configuration and bind it to different POCOs and
Microsoft.Extensions.CommandLineUtils to set up the commands and argument parsing.
If you want to see the whole code, please do visit the github repository here.
On a side note,
Microsoft.Extensions.Configuration is no longer being actively developed, so if I had to re-develop the application I would maybe go for a different option, but if you're interested in it, Nate McMaster has forked it here, which is nice.
As you have seen, interacting with the Salesforce APIs is not very difficult, but it does require getting to know them. At the start it took me a little time to figure out how to query the system, and some other perks related to it like putting together the actual string. Nonetheless, once you get it rolling, it's very easy to keep pumping more stuff out.
Furthermore, I encourage you guys to download it, test it and feel free to give me any feedback! It's a tool I currently use on a daily basis and even though it is still not perfect, it does save me a bunch of time.