Skip to content

CF CLI Style Guide

Abby Chau edited this page Aug 28, 2019 · 74 revisions

Purpose of this Document

The purpose of this document is to promote a shared understanding of the user experience for the Cloud Foundry Command Line Interface (cf CLI), so that contributors to the CLI can provide a simple and consistent user experience. The audience for this document includes:

  • Developers contributing cf CLI pull requests

  • CF/PCF development teams

  • cf CLI plug-in authors

  • The cf CLI team

Mission Statement

The cf CLI embodies the diversity, friendliness, and openness of the Cloud Foundry Community. The CLI strives to provide a consistent and predictable experience for end users of CF.

General Principles

The following section describes the patterns we consider to be best practices for the cf CLI user experience. While not every existing command follows all of these patterns, our intent is to revise existing commands and create new commands so that they do.

  • When we add functionality to enhance or change existing commands, we must first ensure that functionality is backwards compatible. Do not add functionality that will break existing users without contacting the cf CLI team. Check the latest supported version. Per Semver, backwards compatibility should be maintained for minor releases.

  • Any updates or new commands must be optional additive or fully transparent to the user with all changes behind the scenes. It must also provide system feedback.

  • Idempotent (true for all commands except for create command)

  • All creates, deletes, lists, etc should act in a similar fashion; see more information below

  • Each command should only perform one function; for example, if it is a linking command, it should only create a link, it should not create additional objects. There may be exceptions in cases of creating and uploading a droplet, for example.

  • Targeting requirements should be consistent across new commands

System Feedback & Transparency

We intend to provide users with the following interactions on cf CLI commands:

  • Feedback about initiating a process

  • Feedback when a process completes

  • Quick access to the state of an object

  • Quick access to the state process

The following sequence of commands and output shows examples of how the cf CLI delivers the four interactions mentioned above.

Commands which act on resources that make API calls first give the user feedback that they are about to start something:

  1. The action about to take place;

  2. The resource it is taken on (when applicable and in cyan flavor text);

  3. The org and space the resource is in (when applicable and in cyan flavor text);

  4. The identity (username) assumed on the remote system for the API call (when applicable and in cyan flavor text);

  5. A final "..." to indicate more output is coming.

  6. For "Create"/"delete" and "update" commands a short "OK", after which the command exits with exit code 0.

  7. Output to the user to indicate a subsequent process or step that is about to/should be initiated to confirm the state of the operation.

  8. Optionally, a TIP to indicate which commands to run next and/or a list command that can be retrieved in a subsequent system call in a table and/or key-value display. Add a TIP if the operation, for some reason, is not as transparent to the user as it should be - an example of this is the update-buildpack command, which unbeknownst to the user, can create a buildpack resource with a nil stack.

Note

  • For commands that do not act on a resource, cf login, for example, should not display initial feedback text and does not require the resource, org/space and user details. However does require the final "..." ending and a OK to confirm the operation completed successfully.

Outputs

  • The output that follows feedback text depends on the action of the command and the API response:

    • "List" commands display a table with the retrieved information. They follow the table design guidelines defined elsewhere in this guide.

    • "Get" commands display a key-value list with the retrieved information. For resources that include collections within, they may also display a table. For example, app displays a key-value list specific to an app followed by tables with instance details for each process. The key-list design guidelines are defined elsewhere in this guide.

    • "Create"/”delete” and “update” commands display “OK” to clarify the action completed successfully:

      • "Delete" commands on a resource that could not be found display a “Resource 'X' does not exist” warning message together with the “OK” status message that the desired state is considered reached (the resource is gone) but brings attention to the user that they may want to double check the right resource was specified to the command - the command exits with 0 for the same reason.

      • "Create" or “update” commands may display additional information that the user would need to proceed. For example, create-package should display the package information so the user can proceed to set a droplet for the app.

  • Commands that require additional action to take effect on a resource should say so. For example, set-health-check displays a tip that an app restart is required for the change to take effect.

  • Commands that orchestrate others (e.g. push) should display new feedback text for each action it takes, to help the user investigate or report how far the command proceeded and what it was doing in case the output stalls or the command fails.

  • The user should be given feedback again when the process completes. That can either be (For non-list or informational commands):

    • An error message, (eventually) leading to the command aborting with FAILED and exit code 1. We display the FAILED message on the last line of the output. If there is a TIP, then it is outputted after the FAILED, with a blank line in between. Note as a general rule, we check flag options validity first before we make api calls. If there is an error, we should print out the reason for the error.

    • A short OK, possibly with a tip or warning message, after which the command exits with exit code 0. Tips should only be used if the transaction was non-transparent or if there's an additional action the user might want to take on the resource.

    • All errors and warnings should go to STDERR, and should be in plain text

  • Outside of flavor text (see above), we avoid displaying colors. In some critical cases, we display color: for example, if you have an app that's down we show status and instances in color.

  • Fields, rows, headers, should not disappear unless it is a major bump of the CLI - if it exists, it should always display (if we decide to add a column, for example) - for scripting reasons we should stay consistent

  • Idempotent command that doesn't actually run an operation, should output a warning (deleting a space that doesn't exist, for example, should complete successfully but should output a warning to say that the delete did not occur)

  • When two flag combinations cannot be used together, we like to fail fast, however there are cases in which we can't: for example if path and --assign-stack flags are used together the first validation (because we use go flags) is done to check if the path provided is valid, then the command will fail on the flag validation.

  • For some commands, we check for minimum api versions and display an error when the user's version of the API is below the minimum required to use a specific feature. See below for more information.

Output formats

  • Command output is first and foremost optimized for human readers.

  • Some commands are optimized for scripting (e.g. ssh-code) or support flags that optimize output for scripting (e.g. app myapp --guid).

  • Colors can be disabled using a cf config flag or environment variable, and are disabled when the CLI detects it is not in a tty session.

  • The v6 CLI strives for the following: information displayed in tables should not change in order or have new columns inserted, so scripts can use tools such as awk to parse its output.

Showing/Hiding Fields in Output

Avoid removing lines just because they don't have an associated value. Adding/Removing attributes from a key/value table only because it's empty adversely affects a developer's ability to learn about the attributes of an object (e.g., an app). Perhaps knowing the value is empty gives the developer an opportunity to troubleshoot or rectify an issue because they can see an attribute is not defined. Perhaps a developer can discover a feature because the attribute is presented, which gives them an opportunity to explore its purpose.

Inputs

Arguments are used to specify the resource on which the action is performed. If there is no ambiguity what resource the action is intended for, or if there is a reasonable default, there is no need for an argument. All other required information should be provided using options with reasonable defaults.

  • Args versus flags

    • Args are required (For example, bind-service - you always need the app name and service name)

    • flags are optional/supplementary to an arg (For bind-service, you could also provide a -c (for json), or --binding-name flags.

    • if you are not 100% sure that args are not going to be required in the future, then make them flags - even if they are required right now

    • Flags are tab completed; args do not do tab completion

  • Raw Inputs versus Files

    • Input file versus raw command line (for cf bind-service, it takes both a valid JSON object either in-line or in a file. create-security-group, on the other hand, only takes a file that contains json). Always make it a file for simplicity.

Command Prerequisites

Commands may have prerequisites - for example, the user is required to be logged in, an API endpoint, org, and space must be targeted, or an API endpoint of a certain minimum version.

The user should be notified immediately when a prerequisite is not satisfied. In this case, the command should abort with an error message clarifying what prerequisite was not met and what the user could do about it. The command shall abort with exit code 1.

Aborting should happen before the initial command feedback text is displayed. For example:

Where possible when multiple subsequent prerequisites are not met, the user should be provided with that feedback as soon as possible; user feedback depends on the prerequisite:

  • Scenario: user is not logged in. Most commands require a user to be logged in, with few exceptions such as cf marketplace. The user should be immediately informed that they are Not logged in. Use 'cf login' or cf login --sso to log in.
  • Scenario: commands that require the user to be targeting an org and space. Most commands require an org and space to be targeted (Examples of exceptions: feature-flags, security-groups). In the case where users are required to be targeted to an org or space, they should be told to target an org and space - not first be told to target an org, and on the subsequent execution fail again and be told to target a space:

Command Structure

Common Command types

Most CF CLI commands fall into five types. To give users a predictable and consistent experience, follow these patterns for each command type.

  1. Create/Add: Examples: create-buildpack, create-space, create-user, create-service

    • Patterns:

      • Display the name of the new item to confirm it was created.

      • If there are additional actions required after the resource is created, add a tip at the end of the output.

      • If the resource already exists, the command should return output to say the resource already exists.

Example: Single resource happy path:

Example: Multi-step resource creation (creating and uploading):

Example: The resource already exists:

  1. Delete:

    • Patterns:

      • Provide a prompt to ask the user to confirm the deletion if the deletion is destructive: it recursively deletes resources. If the user enters 'no' at the prompt, confirm to the user that the resource was not deleted.
      • Display the name of the item to be deleted.
    • Examples: delete-service, unbind-service, unshare-service, delete-space

  2. List:

    • Patterns:

      • Display the name of the item to be displayed.

      • A OK is not required since the returned list or table is confirmation of a successful status

      • See the flavor text output below and the conventions for styling: the headers are lowercase. The list is alphabetized.

    • Examples: apps, marketplace, services, orgs, spaces

  3. Summary:

    • Patterns:

      • Simple key values are displayed for one to one or one to many relationships. For many to many relationships, a table is displayed.

      • Key values are aligned to the longest key name (first column) plus three spaces. Tables are consistent with the section below. Also see the Key/Value Pair Output section for more information.

    • Examples: app, service

    • Anti-patterns: target, api - where we are not listing a resource.

  4. Rename/Update:

    • Patterns:

      • Input is old value then new value.

      • OK should always be displayed when the update is successful. If not, FAILED should be displayed.

    • Examples: rename (app), rename-service, rename-org, update-service, update-buildpack

  5. Link: Examples: bind-service, share-service

    • Patterns:

      • See the Command Naming Conventions below for VERB-NOUN imperatives. Consistency in naming should be adhered to.
      • Linking commands should only create a link, it should not create additional objects.

Command Naming Conventions

Generally, cf CLI’s commands are named in VERB-NOUN, or ACTION-RESOURCE order.

This allows them to be read like an imperative or request: "Computer, start app!", “Delete app helloworld, please”, “Set space role of user@example.com in myorg and myspace to SpaceManager”, etc.

When a command is about a more granular control of the app deployment process (i.e., not just a cf push), we include -app in the command, e.g., cf create-app. (This also ensures command tab completion for cf cr<tab> takes the user to the long list of "create" commands without needing to enter an additional -[tab] step.)

Exceptions:

  • The noun app is omitted from command names when the action is on an app, as the main purpose of the cf CLI is to push and manage apps.

  • For commands that list resources, or show details of a particular resource, the verb is omitted.

  • A few common commands to set up the local environment are single-noun for quick configuration: api, target, config.

  • list-plugin-repos does not omit "list". Maybe to disambiguate with repo-plugins, or simply by error.

Naming of Commands

The command’s verb should match the action taken.

To make it easy for experienced users to remember command names, new commands should not unnecessarily introduce new verbs when an existing command with a suitable synonymous verb exists.

Commands with opposite actions should use antonyms to make it easy for the user to predict the name of the one command from seeing the other. For example, start andstop, bind-service and unbind-service, map-route and unmap-route, install-plugin and uninstall-plugin, etc.

Some flexibility is allowed when a slight variation of the antonym better matches the action, or consequence of an action. For example, reset-space-isolation-segment clears a previously set isolation segment, which causes app placement to default to the org level configured segment.

Command Help

Help index

When the cf command is run without arguments, or with the help subcommand or -h, --help, cf h -a options, an overview of common app developer commands is returned.

Help on command

Every CLI command has its own help page, retrievable using cf cmd -h, cf help cmd, cf cmd --help). Guidelines for this help page are here. They are inspired by man page conventions.

  1. The first line returns the command name and version, followed by its short description.

  2. The second line returns its Usage. Thereafter, the commands are grouped in sections (Examples, Alias (if applicable), Options, See Also). Each section has a header title displayed in bold and all caps, ending with a colon.

Common global environment variables (if any) are displayed last, for example, see the push help text.

If required, you may also display a TIP after the USAGE information (see update-buildpack) if there are important gotchas that the user should be aware of.

In rare occasions, a WARNING section may appear - see cf login -h - to alert users of any security-related information they should be aware of.

In cases where a required argument is not provided, if too many args are provided for a command, the CLI will exit immediately and return the help text for the command.

Compatibility with CF releases

The cf CLI has a policy regarding supporting a range of CF deployment versions here.

Some commands require a minimum version of an API endpoint; these include newer commands such as bind-service, and assigning a stack to update-buildpack.

Users are notified when executing a command for a feature not available in their targeted CF endpoint. The CLI aborts with Failed and exit code 1, and states the required API version for the command, flag or value specified, and if available and relevant, the current API version. For example, Using FEATURE requires CF API version 3.25.0 or higher. Your target is 3.4.0. (See buildpacks functionality for cf push app -b ruby_buildpack -b python_buildpack for an example of the message.)

Using Env Vars

Environment variables are only used in select cases, and used sparingly - at times only passwords are set as environment variables. For example, you can set export CF_USERNAME="$USERNAME" and export CF_PASSWORD="$PASSWORD" and run cf auth to log in.

Machine Output Format

Make sure when not in a tty session, do not output colors. All other output should be identical. Moving forward, we will attempt to make this easier to parse.

Tables or Key/Value Pairs

Guidance:

Simple key values are displayed for one to one or one to many relationships. For many to many relationships, a table is displayed.

  • Use tables when returning attributes for multiple objects.

  • Use key/value pairs when returning attributes for one object.

Tables

Guidance:

When displaying a table:

  • Column headers are bold and lowercase (top row)

  • Columns are separated by at least three spaces

  • If there isn’t a value for a field, it’s left empty

  • If there are no values for a table, it’s replaced with a text explanation.

Key/Value Pair Output

Guidance:

When displaying a key/value pair:

  • Key value (in left column) is always lowercase

  • The value of every field is aligned; columns are separated by at least three spaces from the longest key (such as "requested state")

  • If there isn’t a value for a field, the key is displayed but the value is left empty (such as "isolation segment" and "space quota")

Time Format

current time formats cf version 6.23.1+a70deb38f.2017-01-13

The format for displaying time depends on how the user expects to use this information.

Guideline

Location Purpose Desired format Example
"Last timestamp" in `cf app myapp` Was the app pushed recently? Was it last Friday morning or last month? - CLI user’s TZ - Localized - Include weekday Thu 03 May 16:24:50 PDT 2018
`cf logs myapp` Compare log time entries, correlate with other logs - Compact - Consistent width - App/Server TZ 2018-05-08T15:43:12.41-0700

Colors

The CF CLI design team reviewed flavor text and provided guidance below after a round of research for accessibility.

  • Don't add flavor text to anything outside of the following convention:
  • intro output text - resource to be acted upon (app name, for example), org name, space name, role (admin, for example), user name are in cyan
  • OK is green
  • Failed is red
  • Down apps in the cf app display in red flavor text
  • table output - headers are in white and bold
  • Accessibility is important

Example of color blind friendly colors as described above:

Warnings, error messages, TIP are in plain text.

Plugins

For information regarding developing plugins, see Developing cf CLI Plugins.