Salesforce CLI Plug-In Developer Guide - Salesforce, Winter '22 - @salesforcedocs
←
→
Page content transcription
If your browser does not render page correctly, please read the page content below
Salesforce CLI Plug-In Developer Guide Salesforce, Winter ’22 @salesforcedocs Last updated: October 14, 2021
© Copyright 2000–2021 salesforce.com, inc. All rights reserved. Salesforce is a registered trademark of salesforce.com, inc., as are other names and marks. Other marks appearing herein may be trademarks of their respective owners.
CONTENTS Salesforce CLI Plug-In Developer Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Salesforce CLI Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Salesforce CLI Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Get Started with Salesforce CLI Plug-In Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Naming and Messages for Salesforce CLI Plug-Ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Customize Your Salesforce CLI Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Test Your Salesforce CLI Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Debug Your Salesforce CLI Plug-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Best Practices for Salesforce CLI Plug-In Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Resources for Salesforce CLI Plug-In Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
SALESFORCE CLI PLUG-IN DEVELOPER GUIDE Discover how to develop your own plug-ins for Salesforce CLI. Explore the Salesforce CLI architecture. Learn how to generate a plug-in using Salesforce Plug-In Generator, use Salesforce’s libraries to add functionality to your plug-in, and debug issues. Learn about our suggested style guidelines for naming and messages and our recommended best practices for plug-ins. Salesforce CLI Plug-Ins A plug-in adds functionality to Salesforce CLI. Some plug-ins are provided by Salesforce and are installed by default when you install the CLI. Some plug-ins, built by Salesforce and others, you install. When you have a requirement that an existing plug-in doesn’t meet, you can build your own using Node.js. Salesforce CLI Architecture Before you get started with adding functionality to Salesforce CLI, let’s take a high-level look at how the CLI and its dependencies and plug-ins work together. Get Started with Salesforce CLI Plug-In Generation Set up your computer for Salesforce CLI plug-in generation, and then generate a plug-in. Naming and Messages for Salesforce CLI Plug-Ins Before you dive into coding, take some time to plan your naming strategy. And it’s never too early to start thinking about the messages you display for your users. Customize Your Salesforce CLI Plug-In To customize your plug-in, duplicate and update the generated files. You can customize your commands’ parameters, properties, error-handling, and output. Test Your Salesforce CLI Plug-In While you’re coding and customizing your plug-in, be sure to write associated tests for each new feature to ensure that it’s working as you expect. In your test suites, include both unit tests and more complex integration, smoke, and end-to-end tests. To help you with latter, we’ve created a library of testing utilities that you add to your environment as a Yarn developer dependency. Debug Your Salesforce CLI Plug-In We recommend using the Visual Studio Code (VS Code) editor, with Salesforce Extensions for VS Code, for your plug-in development. Included in the .vscode directory of Salesforce Plug-In Generator’s generated plug-ins is a launch.json config file. This config file allows you to attach a debugger to the Node process when running your commands. Best Practices for Salesforce CLI Plug-In Development We suggest that you follow these patterns when developing plug-ins for Salesforce CLI. Resources for Salesforce CLI Plug-In Development Bookmark these resources so that you can refer to them as you develop plug-ins. Salesforce CLI Plug-Ins A plug-in adds functionality to Salesforce CLI. Some plug-ins are provided by Salesforce and are installed by default when you install the CLI. Some plug-ins, built by Salesforce and others, you install. When you have a requirement that an existing plug-in doesn’t meet, you can build your own using Node.js. 1
Salesforce CLI Plug-In Developer Guide What Is a Salesforce CLI Plug-In? What Is a Salesforce CLI Plug-In? A plug-in adds commands or features to Salesforce CLI. For example, the plugin-auth plug-in provides the sfdx auth commands. Salesforce CLI plug-ins are npm (Node.js package manager) packages. Node.js is a JavaScript runtime environment that supports execution outside of a browser. If you prefer strongly typed languages, don’t worry: We recommend that you use TypeScript, which transpiles to JavaScript. Salesforce Plug-In Generator’s sample plug-in uses TypeScript. Why Create a Salesforce CLI Plug-In? The Salesforce CLI core plug-ins provide commands and functionality to meet common needs that customers and partners have. But each team often has specific needs. That’s why Salesforce CLI is extensible. Even at Salesforce, different teams have different requirements. Salesforce teams create plug-ins, Salesforce employees create plug-ins as side projects, and Trailblazers in the Salesforce community create and share plug-ins. Knowledge and Skills for Salesforce CLI Plug-In Development Building a Salesforce CLI plug-in requires different knowledge and skills than most Salesforce development. Before you dive too deeply into plug-in development, familiarize yourself with these areas. What Is a Salesforce CLI Plug-In? A plug-in adds commands or features to Salesforce CLI. For example, the plugin-auth plug-in provides the sfdx auth commands. Salesforce CLI plug-ins are npm (Node.js package manager) packages. Node.js is a JavaScript runtime environment that supports execution outside of a browser. If you prefer strongly typed languages, don’t worry: We recommend that you use TypeScript, which transpiles to JavaScript. Salesforce Plug-In Generator’s sample plug-in uses TypeScript. We recommend using TypeScript instead of JavaScript because it’s strongly typed and thus better suited to large projects. The stronger types give a better IDE experience and reduce common programming mistakes that are easy to make but hard to debug. A user installs a plug-in by running sfdx plugins:install PLUGINNAME , where PLUGINNAME is an npm package on npmjs.com. To see your installed plug-ins and their versions, run sfdx plugins. To see which versions of the core Salesforce-provided plug-ins are installed on your computer, run sfdx plugins --core. Why Create a Salesforce CLI Plug-In? The Salesforce CLI core plug-ins provide commands and functionality to meet common needs that customers and partners have. But each team often has specific needs. That’s why Salesforce CLI is extensible. Even at Salesforce, different teams have different requirements. Salesforce teams create plug-ins, Salesforce employees create plug-ins as side projects, and Trailblazers in the Salesforce community create and share plug-ins. Perhaps you have specific tools that you want to use for code analysis as part of your CI/CD automation process. You could build a plug-in that runs your bespoke code-analysis tool. Creating a plug-in provides the benefits of a consistent user experience and a common framework. One Trailblazer plug-in was developed by the Salesforce’s Tableau CRM team. The team knew that creating environments to develop, test, and share Tableau CRM apps, and converting those apps to templates for distribution, can be time-consuming. So they built the @salesforce/analytics plug-in to use scratch orgs to develop an app in Tableau CRM Analytics Studio. The plug-in imports data to datasets, builds dashboards, and connects everything. The team wrote commands that convert the app to templates and download the template JSON files for further refinement. Thanks to these commands, you can also quickly share the results of your work with other developers using a version control system. Your colleagues can push the template JSON files to their own scratch orgs for further testing and development. Because so much Salesforce functionality is surfaced in APIs, the sky’s the limit as to what you can build. With Salesforce Plug-In Generator, the @salesforce/core library, and the @salesforce/command package, you have the tools you need to get started with Salesforce CLI plug-in development. 2
Salesforce CLI Plug-In Developer Guide Knowledge and Skills for Salesforce CLI Plug-In Development Knowledge and Skills for Salesforce CLI Plug-In Development Building a Salesforce CLI plug-in requires different knowledge and skills than most Salesforce development. Before you dive too deeply into plug-in development, familiarize yourself with these areas. • TypeScript (or at least JavaScript, which TypeScript transpiles to) • Node.js • npm (Node.js Package Manager) • Yarn in modern JavaScript build tools • Salesforce APIs Salesforce CLI Architecture Before you get started with adding functionality to Salesforce CLI, let’s take a high-level look at how the CLI and its dependencies and plug-ins work together. Salesforce CLI Salesforce CLI is an npm package called sfdx-cli. You run it on your local machine or continuous integration (CI) system. It supports the installation of custom plug-ins. Most of the core functionality that Salesforce provides comes from plug-ins. Core Salesforce CLI Plug-Ins The sfdx force commands that you know and love are provided by the core Salesforce-provided plug-ins. These plug-ins are installed by default when you install Salesforce CLI. @salesforce/core Package The @salesforce/core library provides client-side management of Salesforce DX projects, org authentication, connections to Salesforce APIs, and other utilities. Much of the core functionality that power the core Salesforce-provided plug-ins comes from this library. You can use this functionality in your plug-ins, too. @salesforce/command Package The @salesforce/command npm package provides the base command class for Salesforce CLI. Extend this class to give your commands access to common Salesforce CLI parameters, a logger, CLI output formatting, scratch orgs, Dev Hubs, and the user’s Salesforce DX project context. Open CLI Framework (oclif) oclif is an open-source CLI framework developed by Heroku. It powers Heroku CLI, the core Salesforce-provided plug-ins, and Salesforce Plug-In Generator. The plug-ins that you generate with Salesforce Plug-In Generator use the oclif format and can take advantage of the many features that the framework offers. In addition to enabling plug-in creation, this framework enables developers to create their own standalone CLI applications. @salesforce/plugin-generator Salesforce Plug-In Generator, available as a scoped npm package on npmjs, is also a CLI plug-in. An npm package scope is like a namespace. (Many of the commands in the core Salesforce-provided plug-ins are in the force namespace, so they start with sfdx force. The commands in @salesforce/plugin-generator start with sfdx plugins.) With one Salesforce CLI command, Salesforce Plug-In Generator scaffolds a TypeScript project that contains everything you need to get started with building your own CLI plug-in. 3
Salesforce CLI Plug-In Developer Guide Salesforce CLI Salesforce CLI Salesforce CLI is an npm package called sfdx-cli. You run it on your local machine or continuous integration (CI) system. It supports the installation of custom plug-ins. Most of the core functionality that Salesforce provides comes from plug-ins. Use Salesforce CLI for many of your development tasks, such as authorizing to any type of org, creating scratch orgs, synchronizing source code between your scratch orgs and VCS, and running tests. All Salesforce CLI commands start with sfdx. To see which sfdx-cli plug-in version you’re using, run sfdx plugins --core. To see the available sets of commands—also known as namespaces or top-level topics—run sfdx --help. To see a list of all available commands in an easy-to-read format, run sfdx commands. To get started, make sure to review the Before You Begin and Salesforce CLI Configuration and Tips sections in the Salesforce CLI Setup Guide. Salesforce CLI is based on Heroku’s oclif engine. For details about installing the CLI with npm or yarn, and about the CLI’s oclif dependencies, check out the sfdx-cli package details. Core Salesforce CLI Plug-Ins The sfdx force commands that you know and love are provided by the core Salesforce-provided plug-ins. These plug-ins are installed by default when you install Salesforce CLI. These core plug-ins contain commands that support source-driven development, such as creating and managing scratch orgs, synchronizing source code, creating second-generation packaging, and more. These commands are in the force namespace, such as force:project:create. Other core plug-ins contain commands that make it easier to use the CLI and are in their own namespace. For example, commands for setting configuration values (config) or aliases (alias) and authorizing orgs (auth). See the Salesforce CLI Status page for a list of all the core CLI plug-ins, their GitHub repos, and their status. @salesforce/core Package The @salesforce/core library provides client-side management of Salesforce DX projects, org authentication, connections to Salesforce APIs, and other utilities. Much of the core functionality that power the core Salesforce-provided plug-ins comes from this library. You can use this functionality in your plug-ins, too. @salesforce/core is an npm package. You can find it at https://www.npmjs.com/package/@salesforce/core. Its source lives at https://github.com/forcedotcom/sfdx-core. Details about the many commands in the library are in its reference documentation. @salesforce/command Package The @salesforce/command npm package provides the base command class for Salesforce CLI. Extend this class to give your commands access to common Salesforce CLI parameters, a logger, CLI output formatting, scratch orgs, Dev Hubs, and the user’s Salesforce DX project context. The @salesforce/command class extends @oclif/command and is available within plug-ins generated by Salesforce Plug-In Generator. You can find the @salesforce/command package at https://www.npmjs.com/package/@salesforce/command. Its source lives at https://github.com/forcedotcom/cli-packages/tree/develop/packages/command. 4
Salesforce CLI Plug-In Developer Guide Open CLI Framework (oclif) Open CLI Framework (oclif) oclif is an open-source CLI framework developed by Heroku. It powers Heroku CLI, the core Salesforce-provided plug-ins, and Salesforce Plug-In Generator. The plug-ins that you generate with Salesforce Plug-In Generator use the oclif format and can take advantage of the many features that the framework offers. In addition to enabling plug-in creation, this framework enables developers to create their own standalone CLI applications. For details about oclif, see https://oclif.io/. For information about the features that oclif offers, see https://oclif.io/docs/features. For the oclif API reference, see https://oclif.io/docs/commands. @salesforce/plugin-generator Salesforce Plug-In Generator, available as a scoped npm package on npmjs, is also a CLI plug-in. An npm package scope is like a namespace. (Many of the commands in the core Salesforce-provided plug-ins are in the force namespace, so they start with sfdx force. The commands in @salesforce/plugin-generator start with sfdx plugins.) With one Salesforce CLI command, Salesforce Plug-In Generator scaffolds a TypeScript project that contains everything you need to get started with building your own CLI plug-in. Like the core Salesforce-provided plug-ins, @salesforce/plugin-generator is bundled with the Salesforce CLI installation. You can check your installed version by running this command: sfdx plugins --core The @salesforce/plugin-generator plug-in is listed as generator in the output. For details about @salesforce/plugin-generator, see https://www.npmjs.com/package/@salesforce/plugin-generator. Get Started with Salesforce CLI Plug-In Generation Set up your computer for Salesforce CLI plug-in generation, and then generate a plug-in. Prepare Your Computer for Salesforce CLI Plug-In Development Before you use Salesforce Plug-In Generator to create a plug-in, set up these prerequisites. Scaffold a Salesforce CLI Plug-In Use Salesforce Plug-In Generator to create your own plug-in for Salesforce CLI. Prepare Your Computer for Salesforce CLI Plug-In Development Before you use Salesforce Plug-In Generator to create a plug-in, set up these prerequisites. 1. Install or update Node.js. To build a Salesforce CLI plug-in, you need the latest long-term support (LTS) version of Node.js. If you’re new to Node.js development, we suggest that you use nvm (Node Version Manager) to install Node.js. Creationix provides an installation script to install or update nvm. To check your Node.js version, run: node --version If your node version is earlier than 8 (or if you don’t have Node.js installed), run: nvm install node 5
Salesforce CLI Plug-In Developer Guide Scaffold a Salesforce CLI Plug-In 2. Install the Yarn package manager. npm install -g yarn 3. Install TypeScript target es2017. npm install -g typescript Salesforce CLI plug-ins can use JavaScript instead of TypeScript, but the classes in the Salesforce DX Core Library are written in TypeScript. 4. Install or update Salesforce CLI. If you don’t have Salesforce CLI installed on your computer, see Install the Salesforce CLI in the Salesforce CLI Setup Guide. The @salesforce/plugin-generator plug-in is included with Salesforce CLI v6.7.1 and later. To check your Salesforce CLI version, run: sfdx --version If your sfdx-cli version is earlier than 6.7.1, run: sfdx update Scaffold a Salesforce CLI Plug-In Use Salesforce Plug-In Generator to create your own plug-in for Salesforce CLI. 1. Run the plug-in generation command, replacing yourPluginName with the name of your plug-in. sfdx plugins:generate yourPluginName You are prompted for information to populate your new plug-in unless you include the --defaults flag. You can answer the questions or press Enter to use a default value. The generator scaffolds a new Salesforce CLI plug-in and installs the plug-in's npm package dependencies. 2. Change to the new plug-in directory. cd yourPluginName 3. The new plug-in contains an example hello:org command. You can find the code for that command at yourPluginName/src/commands/hello/org.ts. Open the file, and see what it contains. For example, to open the file in Visual Studio Code, run: code src/commands/hello/org.ts The hello:org command imports and extends classes from @salesforce/command. When you add your own commands, you extend @salesforce/command. 4. To run the commands in your in-development plug-in from the directory that your code lives in, precede the commands with bin/run. Look at the --help (-h) output for the sample hello:org command. bin/run hello:org -h 6
Salesforce CLI Plug-In Developer Guide Naming and Messages for Salesforce CLI Plug-Ins 5. Customize your plug-in. (This step might take a while!) To test your functionality along the way, run: bin/run yournamespace:yourcommand 6. When you’re ready (see the Tip) to test-drive your plug-in, link your in-development plug-in to Salesforce CLI. sfdx plugins:link Tip: Save this step until you’re confident that you want to move forward with the plug-in you’re working on. If you decide after running sfdx plugins:link that you want to uninstall your plug-in, run sfdx plugins:uninstall yourPluginName. If your linked plug-in doesn’t compile, sfdx plugins:uninstall yourPluginName will work only after you fix the compilation errors. This command installs your plug-in in Salesforce CLI by creating a symlink to your yourPluginName directory. After you link your plug-in, you can run your commands without using bin/run. For example: sfdx hello:org -h 7. For bonus points, change directories to a Salesforce DX project that has a default scratch org. Run the sample hello:org command (or your favorite command from your plug-in). sfdx hello:org SEE ALSO: Prepare Your Computer for Salesforce CLI Plug-In Development Naming and Messages for Salesforce CLI Plug-Ins Before you dive into coding, take some time to plan your naming strategy. And it’s never too early to start thinking about the messages you display for your users. The core Salesforce-provided commands have this structure. namespace:topic:optionalsubtopic:command oclif supports hyphens and capital letters in command and parameter names, but not in namespaces or topic names. However, names of the core Salesforce-provided commands and their parameters are all lowercase (except for some parameters’ short names), with no hyphens. To reduce cognitive load for your users, choose a capitalization and hyphenation strategy, and follow it consistently. We recommend that all plug-ins follow our core plug-in style guidelines. That way, your users don’t need to learn a new naming system each time they adopt a new plug-in. Namespace Names The namespace for your plug-in is the first part of all your commands. For example, many of the core Salesforce-provided plug-ins use the force namespace, so all their commands start with force:. Namespace is another word for top-level topic; a topic is a set of commands. Topic and Command Names After you choose a namespace, you’re ready to start naming your topics and commands. The names of your command definition files and the directories they live in determine your command and topic names. Parameter Names Each parameter has a long name and a short name. Set these values in your command definition file. 7
Salesforce CLI Plug-In Developer Guide Namespace Names Command and Parameter Descriptions Use clear, concise descriptions so that users can easily understand what your commands and parameters do. Store your descriptions in files within the yourPluginName/messages/ directory. Create a messages file for each command. Examples and Help Text Use the examples property to teach users how to use your commands. Store your help text in the files within the yourPluginName/messages/ directory where you store your description values. Error Messages Use an error message to tell users how to recover from the situation that caused the error. Store your error messages in the same files within the yourPluginName/messages/ directory where you store your description values and help text. Namespace Names The namespace for your plug-in is the first part of all your commands. For example, many of the core Salesforce-provided plug-ins use the force namespace, so all their commands start with force:. Namespace is another word for top-level topic; a topic is a set of commands. Choose a namespace that’s short, easy to type, and unique to your company or project. Pick a namespace that describes the functionality you plan to provide without being so specific that it becomes outdated as your feature set grows. Don’t add commands to the Salesforce-provided namespaces, such as force and plugins. Instead, create your own namespace. Otherwise, your commands can disappear or stop working when we add functionality to the core plug-ins. Topic and Command Names After you choose a namespace, you’re ready to start naming your topics and commands. The names of your command definition files and the directories they live in determine your command and topic names. Style Guidelines for Topic and Command Names The topic and optional subtopic names in Salesforce-provided commands are nouns. Command names are verbs that act on the preceding noun. For example, the force:org:create command has a namespace of force, a topic of org, and a command name of create. The verb create acts on the noun org. The force:apex:class:create command has a namespace of force, a topic of apex, a subtopic of class, and a command name of create. The verb create acts on the noun class, which is a category within apex. How to Set Topic and Command Names A topic name is set by the name of the directory where the topic’s command definition files live. For example, commands for the hello topic in the sample plug-in live in the yourPluginName/src/commands/hello directory. Because your namespace is a top-level topic, set the name of the top-level directory within yourPluginName/src/commands/ to your namespace. To create a subtopic, nest its directory in your yourPluginName/src/commands/ directory. For example, if you wanted to rename the sample hello:org command to hello:my:org, you could add a yourPluginName/src/commands/hello/my/ directory and move the org.ts file into that directory (from yourPluginName/src/commands/hello/) . In this case, hello is the topic, my is the subtopic, and org is the command. (But, that command doesn’t follow the command naming guidelines—and neither does hello:org!) 8
Salesforce CLI Plug-In Developer Guide Parameter Names The name of your command definition file sets your command name. For example, the definition file for the hello:org command is yourPluginName/src/commands/hello/org.ts. Renaming your command definition file renames your command. Parameter Names Each parameter has a long name and a short name. Set these values in your command definition file. Style Guidelines for Parameter Names In the core Salesforce CLI plug-ins, parameter long names are lowercase. When a user runs a command, the long names are prefixed with double hyphens. Short names are a single character, prefixed with one hyphen. Long Names For parameters that accept a value, choose a long name that briefly describes the value. For example, the auth:web:login command’s --instanceurl parameter accepts the login URL of the Salesforce instance that the org lives on. For parameters of type flag, which alter the behavior of a command but don’t accept a value, choose a long name that briefly describes the parameter’s effect. For example, the auth:web:login command’s --setdefaultusername parameter sets the authenticated org as the default username that all commands run against. Short Names A short name is typically the first letter of the long name it represents. If that character is unavailable, use the next prominent sound in the long name or the letter that most distinguishes the long name. In the core Salesforce CLI plug-ins, short names are mandatory for required parameters. For optional parameters, we suggest having a short name if the parameter is used frequently, takes a value, or has a long name that’s more than five characters. To minimize the chances that your users accidentally misuse your commands, consider not giving parameters with destructive behavior a short name. Uppercase short names are permitted, but follow these guidelines. • Use the lowercase version of the short name before using the uppercase version of a letter. • Use the lowercase version for the more commonly used parameter, using an uppercase version of the letter for parameters that are used infrequently. • Try to use the uppercase and lowercase versions of a letter for parameters that have related functionality. • For commands that have parameters related to parents and children (for example, packages and package versions), use uppercase letters for parent-related parameters and lowercase letters for child-related parameters. • Try to capitalize letters that are distinguishable as capitalized versus not capitalized. For example, choose -A (-a) and -G (-g) over -S (-s) and -W (-w). Naming Patterns These names are standardized in the core Salesforce CLI plug-ins. ID values Short name: -i Long name: The type of ID, such as --testrunid If the command can accept more than one type of ID, use -i for the parameter that users provide most frequently. File paths Short name: -f Long name: The type of file, such as --csvfile or --definitionfile For manifest files (for example, package.xml), use -x | --manifest. 9
Salesforce CLI Plug-In Developer Guide Command and Parameter Descriptions Directory paths Short name: -d Long name: The type of directory, such as --outputdir or --sourcedir Names Short name: -n Long name: The type of name, such as --fieldname sObjects Short name: -s Long name: --sobjecttype How to Set Parameter Names Define the names of your parameters in the flagsConfig object in your command definition file. Long names are the names of a flagsConfig attribute, and short names are a char value. For example, Salesforce Plug-In Generator’s sample plug-in includes this code in yourPluginName/src/commands/hello/org.ts. The hello:org command has two custom parameters: -n | --name and -f | --force. protected static flagsConfig: FlagsConfig = { name: flags.string({char: 'n', description: messages.getMessage('nameFlagDescription')}), force: flags.boolean({char: 'f', description: messages.getMessage('forceFlagDescription')}) }; Command and Parameter Descriptions Use clear, concise descriptions so that users can easily understand what your commands and parameters do. Store your descriptions in files within the yourPluginName/messages/ directory. Create a messages file for each command. Style Guidelines for Command and Parameter Descriptions • Each parameter has a description attribute. The value of this attribute displays in the terminal when users run -h | --help for a command or topic. To tell users what the command or parameter does, include enough information but keep your descriptions as short as possible to minimize wrapping in narrow terminals. • description values for core Salesforce CLI plug-ins are lowercase, except for proper nouns and acronyms. Semicolons are acceptable to break up a clause, such as skip validation during package version creation; package versions created without validation can’t be promoted. Do not include end punctuation. • For commands, write a description that starts with an imperative verb. For example, the description value for force:org:create is create a scratch org. The description tells users what the command helps them do. • For parameters that accept a value, the description describes the value that the user supplies. For example, the description for the force:org:create command’s --definitionfile parameter is path to a scratch org definition file. • For parameters of type boolean, which alter the behavior of a command but don’t accept a value, the description tells users what the flag makes the command do. Start these descriptions with an imperative verb. For example, the description for the global --json flag is format output as json. 10
Salesforce CLI Plug-In Developer Guide Examples and Help Text How to Set Command and Parameter Descriptions All command and parameter definitions include a description. To get the value for this description, point to your command’s messages file. For example, the hello:org command’s definition file, yourPluginName/src/commands/hello/org.ts, includes these lines. Pointer to the messages file: // Initialize Messages with the current plugin directory core.Messages.importMessagesDirectory(__dirname); // Load the specific messages for this file. // Messages from @salesforce/command, @salesforce/core, // or any library that is using the messages framework can also be loaded this way. const messages = core.Messages.loadMessages('yourPluginName', 'org'); Definition of the command description (named commandDescription for clarity): public static description = messages.getMessage('commandDescription') Definitions of parameter descriptions (named flagnameFlagDescription for clarity): protected static flagsConfig = { // flag with a value (-n, --name=VALUE) name: flags.string({char: 'n', description: messages.getMessage('nameFlagDescription')}), force: flags.boolean({char: 'f', description: messages.getMessage('forceFlagDescription')}) }; Here are the corresponding messages for hello:org from yourPluginName/messages/org.json. { "commandDescription": "print a greeting and your org IDs", "nameFlagDescription": "name to print", "forceFlagDescription": "example boolean flag", "errorNoOrgResults": "No results found for the org '%s'." } If you prefer to write messages in a .js file instead of a .json file, enclose the message array in module.exports = { }; instead of only in { }. After you update your messages, but before testing the --help output for your commands, run: yarn prepack Examples and Help Text Use the examples property to teach users how to use your commands. Store your help text in the files within the yourPluginName/messages/ directory where you store your description values. Style Guidelines for Help Text At the beginning of your examples value, include usage notes for your command. Describe the prerequisites for running the command, and warn users of any “gotchas” that they might encounter. 11
Salesforce CLI Plug-In Developer Guide Examples and Help Text After your usage notes, include a line of space (two newlines), the word Examples:, another line of space, and then examples of the most common usages of your command. Prefix each line that contains an example with three spaces, followed by $ sfdx. For example: $ sfdx yournamespace:yourcommand --stringparameter "A value" For commands in the core Salesforce-provided plug-ins, the examples value appears both in the -h | --help output and in the Salesforce CLI Command Reference. Don’t duplicate information in examples that’s already in your description values. How to Set Help Text In your command definition file, include an examples property (at the same level as your flagsConfig, but not within it). For that property’s value, include a pointer to your messages file. We suggest naming the element that you’re pointing to commandExamples. public static examples = messages.getMessage('commandExamples'); To include multiline messages in your messages file, use a .js or .ts file (not a .json file), and enclose your message in tick marks (`...`). This example shows the contents of a sample .js messages file for the command yournamespace:yourcommand. module.exports = { commandDescription: 'your command description', commandLongDescription: 'A description of your command', commandExamples: `Here are some usage notes. Providing usage guidelines helps users use this command. Here are some more usage notes. Examples: $ sfdx yournamespace:yourcommand --stringparameter "A value" $ sfdx yournamespace:yourcommand --stringparameter "A value" --aflag`, stringparameterDescription: 'accept a string value', stringparameterLongDescription: 'Accepts a string value. ' + 'This value has letters and numbers in it.', aflagDescription: 'change some behavior', aflagLongDescription: 'Changes the command’s behavior when included. ' + '\nIf you don’t specify this parameter, the behavior is unchanged.', }; Note: Because the sample plug-in uses a .json file for its messages, and .json files can’t contain multiline messages, the sample plug-in stores its examples text directly in the org.ts file. public static examples = [ `$ sfdx hello:org --targetusername myOrg@example.com --targetdevhubusername devhub@org.com Hello world! This is org: MyOrg and I will be around until Tue Mar 20 2018! My hub org id is: 00Dxx000000001234 `, `$ sfdx hello:org --name myname --targetusername myOrg@example.com Hello myname! This is org: MyOrg and I will be around until Tue Mar 20 2018! ` ]; 12
Salesforce CLI Plug-In Developer Guide Error Messages To write messages in a .js file instead of a .json file, enclose the message array in module.exports = { }; instead of only in { }. Error Messages Use an error message to tell users how to recover from the situation that caused the error. Store your error messages in the same files within the yourPluginName/messages/ directory where you store your description values and help text. Style Guidelines for Error Messages Before writing an error message, find out whether the design can be changed to avoid the error. Otherwise, tell users concisely but also completely what went wrong and what they can do about it. Two short sentences are often better than one long one. However, rather than first stating the problem and then the solution, you can sometimes easily imply the problem in the solution. When possible, say what users can do instead of what they can’t. A good error message helps users move on rather than making them feel bad. How to Set Error Messages In the logic that detects an error scenario, use the core.SfdxError() method to add a pointer to your messages file. For example, yourPluginName/src/commands/hello/org.ts includes these lines. This SfdxError shows the org ID for the current org as part of the errorNoOrgResults message. if (!result.records || result.records.length
Salesforce CLI Plug-In Developer Guide Salesforce CLI Command Properties Salesforce CLI Parameters and Arguments To add custom parameters and arguments to your commands, customize the flags and args instance properties. To accept the global Salesforce CLI parameters, set static properties. We suggest that you use flags when you want the user’s input to modify a command’s behavior. When you want the user’s input to be a passed-in value, we suggest using args. Error Handling Errors thrown during the command life cycle are handled for you. If an SfdxError is not thrown, the error handler wraps the error in an SfdxError for consistent error display. SfdxCommand handles runtime errors in the catch method for consistent error-handling formatting and behavior. Display Command Results and Render Tables For complete control over rendering, use the result static property. It’s easy for your command to output results in a table format. Simple table formatting is defined with the tableColumnData static property. Hooks A hook is a piece of code that runs at a specific lifecycle event of a CLI command. Think of a hook as a pause in the CLI command execution. The command executes as usual until it encounters a hook. It pauses while the hook code executes, and then picks up again when the hook code execution is completed. Example Plug-In Customizations For ideas about how to customize your plug-ins, check out plug-ins that the Salesforce Developers community has built. Salesforce CLI Command Properties Control your commands’ behavior with static and instance properties. Static properties toggle Salesforce CLI features, and instance properties give your commands access to orgs, project files, and so on. Static Properties The SfdxCommand library provides static properties for Salesforce CLI features so you can easily turn them off and on. Static properties let your commands do things such as accept or require a username, require a command to run from within a Salesforce DX project, or accept key=value pairs (varargs) as parameters. Customize your command definition file to include these properties. Instance Properties Instance properties give your command convenient access to orgs (including Dev Hubs), project files, parameters, and more. Use these properties in your code to access these items. Static Properties The SfdxCommand library provides static properties for Salesforce CLI features so you can easily turn them off and on. Static properties let your commands do things such as accept or require a username, require a command to run from within a Salesforce DX project, or accept key=value pairs (varargs) as parameters. Customize your command definition file to include these properties. These static properties are available. Username Properties requiresUsername To add -u | --targetusername as a required parameter, and --apiversion as an optional parameter, and to add the supplied org as an instance property that your command can access as this.org, set requiresUsername to true. If the 14
Salesforce CLI Plug-In Developer Guide Salesforce CLI Command Properties user’s Salesforce CLI config contains a default username value, the -u | --targetusername value is optional and overrides the config value. static requiresUsername = true; supportsUsername To add -u | --targetusername and --apiversion to a command as optional parameters, and to add the supplied org (if provided) as an instance property that your command can access as this.org, set supportsUsername to true. static supportsUsername = true; requiresDevhubUsername To add -v | --targetdevhubusername as a required parameter, and --apiversion as an optional parameter, and to add the supplied org as an instance property that your command can access as this.hubOrg, set requiresDevhubUsername to true. If the user’s Salesforce CLI config contains a default Dev Hub username value, the -v | --targetdevhubusername value is optional and overrides the config value. static requiresDevhubUsername = true; supportsDevhubUsername To add -v | --targetdevhubusername and --apiversion to a command as optional parameters, and to add the supplied Dev Hub org as an instance property that your command can access as this.hubOrg, set supportsDevhubUsername to true. static supportsDevhubUsername = true; Other Properties deprecated To mark a command as to-be-deprecated, use the deprecated property. Set the API version to remove the command from, and the command to use instead: protected static deprecated: { version: 49.0, to: other:command } Alternatively, you can override the standard message with your custom message: protected static deprecated: { messageOverride: 'We’re deprecating namespace:command --parameter in v apiversion. Instead, use namespace:command --otherparameter.' } flagsConfig To enable, disable, or override Salesforce CLI parameters, and to configure new parameters, customize this property. protected static flagsConfig: FlagsConfig = { // flag with a value (-n, --name=VALUE) name: flags.string({ char: 'n', description: messages.getMessage('nameFlagDescription') }), force: flags.boolean({ char: 'f', 15
Salesforce CLI Plug-In Developer Guide Salesforce CLI Command Properties description: messages.getMessage('forceFlagDescription') }) }; requiresProject To require a command to run from within a Salesforce DX project, and to have the project object added as an instance property that your command can access as this.project, set requiresProject to true. static requiresProject = true; result Customize this property for full control over command output formatting and display, or to override certain pieces of default display behavior. For more information about table rendering, see table.ts in the oclif/cli-ux repository on GitHub. public static result: SfdxResult = { tableColumnData: { columns: [ { key: 'id', label: 'ID' }, { key: 'name', label: 'Name' }, { key: 'description', label: 'Description' } ] }, display() { if (Array.isArray(this.data) && this.data.length) { if (this.data.length > 100) { // special display for large number of results } else { this.ux.table(this.data, this.tableColumnData); } } } }; tableColumnData Use this string array to define table columns for simple command output table formatting. static tableColumnData = ['id', 'name', 'description']; varargs and VarargsConfig To enable key=value parameter input to the command, set varargs to true. To require at least one vararg, or to define a varargs validator function, use the VarargsConfig object definition. When validation fails, throw an error from the validator function with a helpful error message and action. static varargs = true; static varargs = { required: true, validator: (name, value) => { // Whitelist varargs parameter names if (!myWhitelist.includes(name)) { const errMsg = `Invalid parameter [${name}] found`; const errName = 'InvalidVarargName'; const errAction = `Choose one of these parameter names: ${myWhitelist.join()}`; throw new SfdxError(errMsg, errName, [errAction]); 16
Salesforce CLI Plug-In Developer Guide Salesforce CLI Command Properties } } } Instance Properties Instance properties give your command convenient access to orgs (including Dev Hubs), project files, parameters, and more. Use these properties in your code to access these items. args The args instance property stores the parsed arguments from the command line. If the user inputs a string that isn’t a flag after the command name, the string is treated as an arg. For example, the sfdx plugins:generate command takes an arg that’s the name of your plug-in: sfdx plugins:generate yourPluginName --defaults. For details about args, see Arguments and Varargs. public static args = [{name: 'file'}]; if (this.flags.force && this.args.file) { this.ux.log(`You input --force and a file: ${this.args.file}`); } flags (commonly called parameters) The flags property stores the parsed flags (parameters) from the command line. When users input flag names, long names are prefixed with two hyphens, and short names are prefixed with one hyphen. A flag can have boolean behavior, such as --setdefaultusername, or take a value, like --targetusername. In your command’s run method, this.flags looks something like: this.flags -> { name: 'yourflag', force: true } org The org property represents the org supplied to the command via the -u | --targetusername parameter or the user’s Salesforce CLI config. const conn = this.org.getConnection(); const query = 'Select Name, TrialExpirationDate from Organization'; // The type we are querying for interface Organization { Name: string; TrialExpirationDate: string; } // Query the org const result = await conn.query(query); hubOrg The hubOrg property represents the Dev Hub org supplied to the command via the -v | --targetdevhubusername parameter or the user’s Salesforce CLI config. if (this.hubOrg) { const hubOrgId = this.hubOrg.getOrgId(); this.ux.log(`My hub org ID is: ${hubOrgId}`); } 17
Salesforce CLI Plug-In Developer Guide Salesforce CLI Parameters and Arguments project The project property represents a Salesforce DX project object that represents the project in which the user is running commands. configAggregator The configAggregator property represents a ConfigAggregator object. This object aggregates global and local project config files and environment variables from sfdx-config.json. const aggregator = await ConfigAggregator.create(); console.log(aggregator.getPropertyValue('defaultusername')); logger The logger property represents the Salesforce CLI logger. This logging abstraction is powered by Bunyan. It provides a default logger configuration, which logs to sfdx.log, and a way to create custom loggers based on the same foundation. ux The ux property represents the UX object for command output. The UX methods respect the --json flag, so the output of these methods is suppressed when --json is provided. result The result property represents the result instance where you can manipulate data and formatting after the command's run method has completed. Salesforce CLI Parameters and Arguments To add custom parameters and arguments to your commands, customize the flags and args instance properties. To accept the global Salesforce CLI parameters, set static properties. We suggest that you use flags when you want the user’s input to modify a command’s behavior. When you want the user’s input to be a passed-in value, we suggest using args. Global Salesforce CLI Parameters Salesforce CLI provides global parameters (flags) that your command can accept. sfdx-command enables the --json and --loglevel flags on every command to make continuous integration setup and debugging easier. Your command’s static properties control whether --targetusername and --targetdevhubusername are available. You can also implement other global parameters. Salesforce CLI Parameter Types Choose a parameter type based on the behavior you want that parameter to cause. Using a specific parameter type helps you validate the format of the parameter value that your user supplies. Sample Parameter Definitions Use the flagsConfig static property to enable, disable, or override Salesforce CLI parameters and to configure new parameters. This example illustrates a flagsConfig for a command that accepts an array (-n | --names), a boolean value (-f | --force), a JSON array (-d | --metadata), and --verbose. For this command, --names is required. Arguments and Varargs The args instance property stores the parsed arguments from the command line. If the user inputs a string that isn’t a flag after the command name, the string is treated as an arg. For example, the sfdx plugins:generate command takes an arg that’s the name of your plug-in: sfdx plugins:generate yourPluginName --defaults. Resolution Order of Parameters and Settings Salesforce CLI resolves users’ parameters, environment variables, and settings in this order. Deprecate Parameters and Arguments Here are the instructions to mark a command parameter (flag) for deprecation. 18
Salesforce CLI Plug-In Developer Guide Salesforce CLI Parameters and Arguments Global Salesforce CLI Parameters Salesforce CLI provides global parameters (flags) that your command can accept. sfdx-command enables the --json and --loglevel flags on every command to make continuous integration setup and debugging easier. Your command’s static properties control whether --targetusername and --targetdevhubusername are available. You can also implement other global parameters. These are the global Salesforce CLI parameters. --json Suppresses output from this.ux.* methods, and formats output as JSON. This flag is always enabled on all Salesforce CLI commands. Its value is treated as true if provided, false otherwise. --loglevel Sets the logging level for the command invocation. Logs are stored in $HOME/.sfdx/sfdx.log. This enum flag accepts only known (lowercase) logging options and is available on all Salesforce CLI commands. See the LoggerLevel docs for more information. --apiversion Overrides the default apiVersion for API requests made by the command. This parameter is available when you set the static property supportsUsername, requiresUsername, supportsDevhubUsername, or requiresDevhubUsername to true in your command definition file. Or, use the flags.builtin marker: const flagsConfig: FlagsConfig = { apiversion: flags.builtin() }; -u | --targetusername Sets a username or alias for the target org. Overrides the default target org. This parameter is available when you set the static property supportsUsername or requiresUsername to true in your command definition file. For details about how to accept or require -u | --targetusername, see Static Properties. -v | --targetdevhubusername Sets a username or alias for the target Dev Hub org. Overrides the default Dev Hub org. This parameter is available when you set the static property supportsDevhubUsername or requiresDevhubUsername to true in your command definition file. For details about how to accept or require -v | --targetdevhubusername, see Static Properties. --concise A common flag name to use for writing brief command output to stdout. Your command is responsible for modifying output based on this flag. This flag's value is treated as true if provided, false otherwise. To enable the predefined config for this parameter, use: const flagsConfig: FlagsConfig = { concise: flags.builtin() }; --quiet A common flag name to use for suppressing command output to stdout. Your command is responsible for modifying output based on this flag. This flag's value is treated as true if provided, false otherwise. To enable the predefined config for this parameter, use: const flagsConfig: FlagsConfig = { quiet: flags.builtin() }; 19
Salesforce CLI Plug-In Developer Guide Salesforce CLI Parameters and Arguments --verbose A common flag name to use for more detailed command output to stdout. Your command is responsible for modifying output based on this flag. This flag's value is treated as true if provided, false otherwise. To enable the predefined config for this parameter, use: const flagsConfig: FlagsConfig = { verbose: flags.builtin() }; Salesforce CLI Parameter Types Choose a parameter type based on the behavior you want that parameter to cause. Using a specific parameter type helps you validate the format of the parameter value that your user supplies. You can add parameters that have these Salesforce CLI parameter types. array The parameter expects an array of comma-separated values or separated by a delimiter that you define. You can also define a custom array-element-mapping function with the signature (val: string) => T, which converts a string array element into a custom type T. Sample user input: --yourarrayflag first,second,third or: --yourarrayflag "first name, last name, suffix" or: --yourpathsarrayflag=/tmp/a.txt:/tmp/b.txt Sample flagsConfig property: yourarrayflag: flags.array({ description: 'your description' }) Sample flagsConfig property for a parameter that accepts array of integers: yourintarrayflag: flags.array({ description: 'your description', map: v => parseInt(v, 10) }) Sample flagsConfig property for a parameter that accepts array of colon-delimited paths: yourpathsarrayflag: flags.array({ description: 'your description', delimiter: ':', map: (val: string) => require('path').parse(val) }) The same sample flagsConfig property, with a more succinct definition of map: yourpathsarrayflag: flags.array({ description: 'your description', delimiter: ':', 20
Salesforce CLI Plug-In Developer Guide Salesforce CLI Parameters and Arguments map: require('path').parse }) In your run method, this.flags.yourpathsarrayflag would have the value: [ { root: '/', dir: '/tmp', base: 'a.txt', ext: '.txt', name: 'file' }, { root: '/', dir: '/tmp', base: 'b.txt', ext: '.txt', name: 'file' } ] boolean The parameter doesn’t accept a value. Its value is true if the parameter is supplied, or false otherwise. Sample user input: --yourbooleanflag Sample flagsConfig property: yourbooleanflag: flags.boolean({ description: 'your description' }) In your run method, this.flags.yourbooleanflag would have the value: true date The parameter expects a date. Sample user input: --yourdateflag 01-02-2000 or: --yourdateflag "01-02-2000 GMT" Sample flagsConfig property: yourdateflag: flags.date({ description: 'your description' }) A date input produces a JavaScript Date object containing an absolute ISO date value. In your run method, the value of this.flags.yourdateflag depends on the local system time zone. The Date object for an input of 01/02/2000 GMT would have the value: '2000-01-02T00:00:00.000Z' An input of 01/02/2000 (without a specified time zone) by a user whose system is set to Pacific Standard Time (PST) would produce a Date object with the value: '2000-01-02T00:00:00.000-08:00' datetime The parameter expects a date and time. Sample user input: --yourdatetimeflag "01/02/2000 01:02:34" 21
Salesforce CLI Plug-In Developer Guide Salesforce CLI Parameters and Arguments or: --yourdatetimeflag "01/02/2000 01:02:34 GMT" Sample flagsConfig property: yourdatetimeflag: flags.datetime({ description: 'your description' }) A datetime input produces a JavaScript Date object containing an absolute ISO date value. In your run method, the value of this.flags.yourdatetimeflag depends on the local system time zone. The Date object for an input of 01/02/2000 01:02:34 GMT would have the value: '2000-01-02T01:02:34.000Z' An input of 01/02/2000 01:02:34 (without a specified time zone) by a user whose system is set to Pacific Standard Time (PST) would produce a Date object with the value: '2000-01-02T01:02:34.000-08:00' directory The parameter expects a path to a directory. Sample user input: --yourdirectoryflag /your/path/to Sample flagsConfig property: yourdirectoryflag: flags.directory({ description: 'your description' }) In your run method, this.flags.yourdirectoryflag would have the value: '/your/path/to' email The parameter expects an email address. Sample user input: --youremailflag your.user@example.com Sample flagsConfig property: youremailflag: flags.email({ description: 'your description' }) In your run method, this.flags.youremail would have the value: 'your.user@example.com' enum The parameter expects a string value that’s included in a predefined enumeration of options. Sample user input: --yournenumflag PredefinedOption1 Sample flagsConfig property: yourenumflag: flags.enum({ description: 'your description', 22
You can also read