Skip to content

Write Useful Messages

Juliet Shackell edited this page May 23, 2024 · 19 revisions

It’s never too early to start thinking about the messages you display for your users. Messages include:

  • Command summary and description
  • Flag summaries and descriptions
  • Examples
  • Error messages
  • Interactive prompts

Two Flags for Different Levels of Help

Because the full help for sf commands can be long, we provide two flags to control how much of the content is displayed:

  • --help: Displays all the content.
  • -h : Displays a short form of the content. Output includes the command summary and the USAGE and FLAGS sections. It doesn’t include the long command description, examples, and long flag descriptions.

Implementation Guidelines

Every sf command has a corresponding message file that contains all messages related to that command. Message files live in the top-level messages directory of the plug-in.

Message files use Markdown format and end in .md. Name your file to reflect the corresponding command. For example, the filename for the sf project convert source is called convert.source.md.

In the Markdown file, each H1 heading is a key that’s referenced in the command's code. Most commands always have the summary, description, and examples keys. The text after the key's H1 heading is displayed in the --help output.

How to Load Messages

Here's an example of loading messages from the Markdown file hello.world.md in the awesome plugin:

import { Messages } from '@salesforce/core';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('awesome', 'hello.world');

Use the messages.getMessage() or messages.getMessages() methods to reference the H1 keys from the markdown file in your command class:

  public static readonly summary = messages.getMessage('summary');
  public static readonly description = messages.getMessage('description');
  public static readonly examples = messages.getMessages('examples');

The flags.name.* keys correspond to help for the --name flag. Here's how to reference them in the flag definition:

  public static readonly flags = {
    name: Flags.string({
      char: 'n',
      summary: messages.getMessage('flags.name.summary'),
      description: messages.getMessage('flags.name.description'),
      default: 'World',
    }),
  };

Key Names

Here are the H1 key names we typically use in the core Salesforce CLI command message Markdown files. See the message file for the sf deploy metadata command for an example. See the writing guidelines for tips about writing these messages.

  • summary : Required. The short sentence that’s immediately displayed when you run --help or -h.
  • description : Optional. Longer command description displayed in the DESCRIPTION help section.
  • examples : Required. Displayed in the EXAMPLES help section. Each example must have a brief explanation.
  • flags.<flagname>.summary : Required. Short description that’s displayed in the top FLAGS help section.
  • flags.<flagname>.description : Optional. Longer flag description displayed in the FLAG DESCRIPTIONS help section.
  • error.<errorname> : Required. The error message.
  • error.<errorname>.actions : Optional. The suggested action that the user can take to fix the problem.

Displayed Error Messages

The CLI framework automatically prepends the word Error: (or Warning or Info) before the text. For example, if your Markdown file has this:

# error.SandboxNameLength
        
The sandbox name "%s" should be 10 or fewer characters.

At runtime, the resulting error looks like this:

Error: The sandbox name "mysandboxnameisreallylong" should be 10 or fewer characters.

Flag Groups

If your command has many flags, you can group them in the --help output to make it easier to find a particular flag.

How many is too many? That's up to you. Run sf org create scratch to see an example. The help output includes the standard FLAGS and GLOBAL FLAGS groups and the command-specific PACKAGING FLAGS and DEFINITION FILE OVERRIDE FLAGS groups.

To implement a flag group, use the helpGroup flag property. This example shows how to add the --no-namespace flag of org create scratch to a group called PACKAGING FLAGS:

  public static readonly flags = {
  ...
      'no-namespace': Flags.boolean({
      char: 'm',
      summary: messages.getMessage('flags.no-namespace.summary'),
      helpGroup: 'Packaging',
    }),

In the actual --help output, the help group Packaging is rendered as PACKAGING FLAGS.

Topic Messages

A topic is a collection or “bucket” of commands within Salesforce CLI. When you use the --help flag on a topic, the output includes the topic summary, a list of sub-topics, and the commands contained in the topic. Here's sample help output for the data topic:

$ sf data --help
Manage records in your org.

USAGE
  $ sf data COMMAND

TOPICS
  data create  Create a record.
  data delete  Delete a single record or multiple records in bulk.
  data export  Export data from your org.
  data get     Get a single record.
  data import  Import data to your org.
  data query   Query records.
  data update  Update a single record.
  data upsert  Upsert many records.

COMMANDS
  data query   Execute a SOQL query.
  data resume  View the status of a bulk data load job or batch.

You write topic summaries in the package.json file in the top-level directory of your plugin; they aren't in the Markdown files in the messages directory like other help messages. In the package.json file, topic summaries live in the topics sub-object of the oclif object and are defined with a description property. Here's a snippet of the package.json file of the plugin-data plugin which specifies the topic summary of the data topic and its subtopics:

      "data": {
        "description": "Manage records in your org.",
        "longDescription": "Use the data commands to manipulate records in your org. Commands are available to help you work with various APIs. Import CSV files with the Bulk API V2. Export and import data with the SObject Tree Save API. Perform simple CRUD operations on individual records with the REST API.",
        "subtopics": {
          "create": {
            "description": "Create a record."
          },
          "delete": {
            "description": "Delete a single record or multiple records in bulk."
          },
          "export": {
            "description": "Export data from your org."
          },
          "get": {
            "description": "Get a single record."
          },
          "import": {
            "description": "Import data to your org."
          },
          "query": {
            "description": "Query records."
          },
          "update": {
            "description": "Update a single record."
          },
          "upsert": {
            "description": "Upsert many records."
          }
        }
      }

Writing Guidelines

While you're free to write your messages in any style you want, we recommend that you follow these guidelines so that your commands feel similar to the core Salesforce CLI commands. See the message file for the sf deploy metadata command for an example.

Commands

Use clear, concise descriptions so that users can easily understand what your commands do.

Command Summary

  • Command summaries start with an imperative verb.
    • For example, a good summary for the sf deploy metadata command is Deploy metadata to an org from your local project.
  • Summaries are mandatory for each command.
  • The summary is the first message that displays when users run --help or -h for a specific command. The summary is also displayed as the first sentence in the DESCRIPTION section when using --help. It's also the message that’s displayed when using --help to list a group of commands.
  • Summaries include just enough information to tell users what the command helps them do, but are as short as possible.
  • Summaries use proper punctuation and capitalization and are complete sentences.
  • In the Markdown file, put the entire command summary in a single line. If the summary contains a newline, only the first line is printed in the --help.

Command Description

  • Command descriptions are optional but highly encouraged. They are displayed in the --help output, but not the -h output.
  • Write them to expand on the summary, provide context about how and when a user runs the command, describe the behavior of the command, and provide other helpful information for the user. Here are some questions to help you pinpoint this other helpful information; not all questions are relevant to all commands.
    • Where does this command fit in a typical developer workflow? Would it help the user to know which commands are typically run before or after?
    • What, if any, are the repercussions of using this command? Is the command destructive? For example, does the command overwrite files in an org? Overwrite local files?
    • Does the command behave unexpectedly when a user specifies a particular combination of flags?
    • Is the command output easy to read, or is it complex enough that you should describe how to interpret it?
    • Is there an operating system-specific gotcha? For example, do Windows users need to use quotes to enclose a value when macOS users don’t?
    • Is there another command that the user might confuse with this one? Do you need to describe the use cases for each command?
  • While there’s no theoretical limit to the length of a long description, try to keep it brief yet comprehensive.
  • Long descriptions use proper punctuation and capitalization and are complete sentences.

Flags

Use clear, concise descriptions so that users can easily understand what the command flags do.

Flag Summary

  • Flag summaries are mandatory for each flag. They are displayed in tabular form in the top FLAGS section of both the --help and -h output.
  • Flag summaries include just enough information to tell users what the flag does, but are as short as possible to minimize wrapping in narrow terminals.
  • For flags that accept a value, the summary describes the value that the user supplies.
    • For example, a good summary for the --manifest flag of the sf project deploy start command is Full file path for manifest (package.xml) of components to deploy.
  • For flags of type Boolean, which alter the behavior of a command but don't accept a value, the summary tells users what the flag makes the command do. Start these descriptions with an imperative verb.
    • For example, the summary for the global --json flag is Format output as json.
  • Flag summaries use proper punctuation and capitalization and are complete sentences.
  • In the Markdown file, put the entire command summary in a single line. If the summary contains a newline, only the first line is printed in the --help.
  • Flag properties that are defined in the command's source code, such as whether the flag is required and its default value, are automatically displayed in the --help. Don't duplicate this information in the flag summary or description.

Flag Description

  • Flag descriptions are optional. They are displayed in the FLAG DESCRIPTIONS section of the --help output. They aren't displayed in the -h output.
  • Write flag descriptions to expand on the summary, provide context and other helpful information for the user.
  • Don’t duplicate information in flag descriptions that’s in your command description.
  • Flag descriptions use proper punctuation and capitalization and are complete sentences.
  • There’s no limit to the length of a flag description, but remember that short is sweet.

Examples

Examples are the best way to help a user understand what a command does. Examples are displayed in the EXAMPLES section of the --help output. They aren't displayed in the -h output.

  • At least one example is required.

  • For each example, provide a brief explanation. Start with an imperative and end with a colon. For example:

    • Deploy the source files in a directory:
  • Use long flag names (--definition-file) in the examples, not short names (-f). Long names make the example more clear.

  • Show an example of using each required flag; you can show multiple required flags in a single example, if it makes "real world" sense.

  • If necessary, provide the context in which the example runs, and the expected outcome. Don’t show the actual output, just a brief description of what it should be. But be judicious and brief.

  • If you provide multiple examples, note how they differ and when to use one over another.

  • Don’t duplicate information in examples that’s already in your command and flag descriptions.

  • If necessary, provide any prerequisites to help users run their own examples. Warn users of any “gotchas” they might encounter. But again, be judicious and brief.

  • To keep the examples operating-system agnostic, use <%= config.bin %> <%= command.id %> instead of sf your-command. The CLI converts this string to the appropriate OS prompt and command name at runtime. See this example.

  • For correct formatting in the --help output, precede the explanation in the Markdown file with "-" and the example itself with two spaces. For example:

    - Deploy the source files in a directory:
    
      <%= config.bin %> <%= command.id %>  --source-dir path/to/source

Error Messages

Mistakes happen. But on the bright side, they’re opportunities to expand our users' knowledge of the CLI by providing them an excellent error message.

  • Use an error message to tell users how to recover from the situation that caused the error.
  • Before writing an error message, find out whether the design can be changed to avoid the error.
  • Tell users concisely, but also completely, what went wrong and what they can do about it. For example:
    • Error message: This command doesn't accept an access token for a username.
    • Action (aka “Try this:”): Specify a username or an alias.
  • Two short sentences are usually 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.
  • Error messages use proper punctuation and capitalization and are complete sentences.
Clone this wiki locally