Easy Salesforce Deployments Using Slack and GitHub
The Problem
I have always wished that Salesforce deployments were easier. As a developer, I have seen so many days wasted due to its tedious and error-prone deployment process.
A typical Salesforce deploy looks something like this:
- Modify some code.
- Record which files you deleted, added, and modified.
- Log into a sandbox where the code lives.
- Create a changeset.
- Manually select each component you wish to deploy.
- Select the target where you want to deploy the changeset.
- Log into the target org where you sent your changeset.
- Find your changeset.
- Hit deploy.
As you can see this is a pretty long list. Each step must be performed manually and the entire process is prone to error. If you want to deploy to multiple environments then you have to repeat this entire process for each one.
I have encountered many issues with this process, including:
- Changesets with missing components. The need to track every modified file manually can result in incomplete changesets that have to be rebuilt and reapplied to the target org.
- The target org must have the correct permissions and configuration to accept changesets.
- Since the code lives, is tested, and is “deployed” in Salesforce, it allows code to live outside of version control. This makes it really easy to overwrite other people’s work if you are working from a stale sandbox.
- The changesets take time to propagate to the target orgs so you end up spending a lot of time just waiting for Salesforce to do its thing.
The Solution
I wanted to use the same deployment system that we use for everything else at PagerDuty. We use an in-house deployment system named Igor controlled through our Lita bot called OfficerURL (URL for short). URL allows us to deploy our code with a single command in Slack.
!deploy salesforce <branch:default is master> to <environment>
So, for example, to deploy the master branch of our Salesforce code to production we would type:
!deploy salesforce to production
The bot will then tell us whether it succeeded or failed. It also links us to the deployment logs in Igor.
Here is a screenshot of an actual Salesforce deployment I did recently:
It’s really that easy.
The setup
At a high level, our bot / deployer duo does the following:
- Checks out the project’s GitHub repository.
- Switches to the branch specified.
- Runs a deployment script in the checked out repo, providing it the deployment target.
- Notifies us of the deployment’s success or failure based on the script’s exit code.
The tool that enabled this workflow is https://github.com/neowit/tooling-force.com.
A major advantage of this tool is that it enables deployments that remove components in Salesforce that no longer exist in the working directory. In effect it makes Salesforce’s copy of the project match your working directory as much as possible. Most other tools only deploy the files in the working directory; they don’t remove components in Salesforce that no longer exist locally. This can result in code remaining active in Salesforce when it should have been removed entirely.
The following is the command that runs when you deploy through chat:
java -jar path.to.jar
--action=deployAllDestructive
--config=path.to.properties
--projectPath=.
--responseFilePath=/dev/stdout
--maxPollRequests=200
--specificTypes=./src/package.xml
--typesFileFormat=packageXml | tee deploy.stdout
grep 'RESULT=SUCCESS' deploy.stdout
You can download a jar of the tool at https://github.com/neowit/tooling-force.com/releases.
Note that the path.to.properties has a variable that represents the environment to deploy to so that we can deploy to multiple environments.
The properties file:
sf.username=username
sf.password=password
sf.serverurl=https://login.salesforce.com or https://test.salesforce.com
The package.xml file is checked into git and specifies which components to deploy. I use:
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>*</members>
<name>ApexClass</name>
</types>
<types>
<members>*</members>
<name>ApexComponent</name>
</types>
<types>
<members>*</members>
<name>ApexPage</name>
</types>
<types>
<members>*</members>
<name>ApexTrigger</name>
</types>
<types>
<members>*</members>
<name>StaticResource</name>
</types>
<version>34.0</version>
</Package>
Credits
This would have been harder to implement without our awesome DevTools team. They maintain the bot that provides common functionality such as handling the git checkout, status notifications, and logging when running a deploy script.
Also thanks to Andrey Gavrikov (neowit on GitHub) for providing the tooling-force.com command line application which enables easy Salesforce deployments from a folder.