Developing Plugins for the Salesforce CLI
With almost every technology we build here at Salesforce, it’s not enough to provide great tools and capabilities, but to also provide for the extension and customization of these tools and technologies. It’s no different with the Salesforce CLI. Working closely with the Heroku team, we now have a robust and easy to use framework for creating your own CLI commands.
At TrailheaDX 2018 we announced the launch of our Plugin Development beta program, and we know developers have been wanting to know more about this program. This post provides more details on Plugin Development, shares some early best practices, and provides some of the driving philosophy behind why we’re building plugins for the Salesforce CLI.
The response to our launch so far has been very positive. It is important to keep in mind that we’re currently in the beta phase of releasing this feature. That means that, while you can use and trust this feature for your current development, we’re still working hard to deliver the highest quality developer experience. This developer experience includes usability and reliability, but also encompasses security and trust.
Embrace your shell
The primary value of the Salesforce CLI really revolves around its scriptability. One of the keys to successful use of the CLI is to embrace your shell and get comfortable with writing scripts. This means not just running one command after the other, but processing the output of various commands to add logic to your scripts. The analogy that I like to use, for you Lightning Component developers, is the commands in the CLI are akin to Lightning Base Components and the scripts that bring them together are your Lightning App Builder.
Now you wouldn’t necessarily want to re-invent the <lightning:recordViewForm /> component to add functionality to your app, nor should you try to re-implement commands like source:push and source:pull. While the functionality to do this is available for a plugin through the ‘sfdx-core’ library, (this is injected into your plugin project code to streamline access to Salesforce DX projects, configuration and scratch org management), there is usually more going on with these aggregate commands than meets the eye.
Rather than think about “customizing” a command like this, it is better to think about “supplementing” that step in a script with your own command. For instance, if before every push to a scratch org, you would like to run some custom lint-ing on your Apex Code, Visualforce or Lightning Components, create a plugin that runs your lint-ing code rather than trying to re-implement the push command. Then in your script, you can run your new plugin and if the lint-ing result is acceptable, run the push command.
It is perfectly acceptable to create utility scripts that encapsulate your push process. Below is a common setup script for a new DX environment.
sfdx force:org:create -f config/project-scratch-def.json --setalias steam1 --setdefaultusername -v email@example.com
sfdx force:user:permset:assign -n dreamhouse
sfdx force:data:tree:import -p data/sample-data-plan.json
If you want to learn more about scripting the Salesforce CLI, check out this blog post from our Getting Started with Salesforce DX series.
Another take on the scripting approach is the ability to “spawn” or execute a command from within your plugin command. In this case, the advantage is that you are controlling when a standard CLI command is run and processing the results within your plugin. Essentially, you are reducing what might be two plugins to a single plugin.
Along these lines, we also have as a roadmap item called “plugin hooks.” Plugin hooks will provide a more reliable way to ensure that a plugin, like the one I mentioned above, will be “associated” with another command. Initially these hooks will direct the CLI to “listen” for certain command-related events. Then once your plugin has registered itself as a handler for a command/event combination, control will be passed to your plugin. The first iteration of these hooks will allow before and after command execution.
Now, from our example above, rather than rely on the script to invoke your plugin before the push command, the CLI will invoke it for you. By creating the plugin to be scripted, it should be an easy task to convert the plugin to also be CLI command hook. You will be in good position to take advantage of the hooks rather than ripping out the “re-invented” push command.
On the subject of “forward looking statements,” I want to talk a little bit about namespaces or topics. First, let me define the terms in a little more detail.
The Salesforce CLI is invoked using the command ‘sfdx’. The output of this command is a simple list of the topics that are available. Since topics can be nested, we will refer to the top-level topic as the “namespace” of the plugin. This namespace is very important in determining what the commands within that topic will do and who provided that command. For Salesforce DX, all of the commands are under the ‘force’ namespace (top-level topic). This topic is currently reserved for Salesforce use by convention. During the beta period we will be working on protecting this top-level topic and a couple of others as yet to be determined. We are doing this to protect both users of the CLI and developers of plugins.
How does this protect users of the CLI? This will provide confidence that any command below the ‘force’ namespace is one that is written and approved by Salesforce. In other words, this is part of the product that we have provided. In the future, you may want to install community-developed plugins and there needs to be a way to distinguish one plugin from another.
How does this protect plugin developers? We reserve the right to any topic within the ‘force’ namespace. If you as a developer were to develop a plugin command like ‘force:super:cool:stuff,’ one day we as a product team might decide that ‘super’ is a topic that is appropriate and would then obscure or override that topic, thereby rendering your plugin useless. That would be a bummer.
A last word on trusted plugins: Currently, the Salesforce-provided plugins are signed. All software provided to the public should have some code-signing mechanism. You can see this in the Mac OS when you download a program from the Web. It is checked to see if it is signed and you are prompted as to whether or not you want that code to run on your machine. Plugins are no different and need the same type of transparency. When you install a plugin that is not signed by Salesforce, you will get a prompted warning that it is not signed. At that point you may install it or not depending on your confidence in the author of the plugin. Read here on how to handle these warnings in a CI/CD environment using plugin whitelisting. Providing the ability to sign your plugins is also an item on our roadmap so that your plugins can be trusted by other users in the future.
These are just a couple of the details that we want you to be aware of as you embark on the fun and exciting path to building your plugins. To provide you hands-on experience, we’ll walk you through the steps of creating and coding your first plugin in an upcoming blog post.
We’re excited about the results of the beta period as we head towards a robust plugin program and a vibrant community of plugin developers!
To learn more about the Salesforce CLI, check out the Trailhead Quick Start on Salesforce DX.
About the author
Sr. Dir. Product Management, Salesforce
Dave is currently the Senior Director of Product Management at Salesforce, responsible for Salesforce CLI and Source-Driven Development. A fifteen-year veteran at Salesforce, Dave was previously responsible for global developer evangelism at Salesforce and has retained a passion for developer success on the Salesforce Platform.