This document aims 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:
This document represents the desired state of the CLI. If existing commands are inconsistent with what is written here, let's discuss whether they can be updated. Going forward, new commands should adhere as closely as possible to these guidelines. To keep plugins consistent with the user experience of the core CLI, plugin authors are encouraged to follow these guidelines as well.
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.
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.
0
and OK
when the intended state is unchanged after you run a command. Examples include:
create-space
(or create-route
, create-org
, etc) when the resource already existsdelete-buildpack
(or delete
app, delete-org
, delete-private-domain
, etc) when the resource does not existThe CLI should do whatever it takes to fail in the least amount of time for the end-user. This includes checking the inputs and command setup as well as server-side validation that resources to be acted upon are available/accessible. Some places where client-side validation is relevant are on invalid flags and incorrect command prerequisites. Some places where server-side validation is relevant are on resource unavailable.
When flag combinations are invalid, we prefer to fail fast, printing the error and the command help text. However, there are cases in which we simply can't. For example, consider update-buildpack
. If --path
and --assign-stack
flags are used together, the initial syntax (go flag) validation may succeed because the path provided is valid, but will subsequently fail on semantic flag validation. The guidance is to fail as fast as is practical.
Commands may have prerequisites - for example, the user is required to be logged in, must be targeting an org or space, or must be using an API endpoint of a certain minimum version.
The user should be notified immediately when a prerequisite is not satisfied. Where possible, the command should abort with an error message clarifying which prerequisite was not met and what the user can do about it. The command shall abort with exit code 1
.
Commands may be executed against a resource that's not available - for example, the user executes a command against a resource that doesn't exist within the targeted org/space or to which the user doesn't have the right to access.
The user should be notified immediately when the resource cannot be acted upon. Where possible, the command should abort with an error message clarifying which resource was unavailable. The command shall abort with exit code 1
.
Examples:
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. When multiple subsequent prerequisites are not met, the user should be provided with that feedback. 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:
Where possible, if not all arguments are provided (requirements for running commands), aborting should happen before the initial command feedback text is displayed. For example:
Scenario: user misspells resource name(s). The CLI should validate the existence of required resource(s) and abort with immediate feedback when unavailable (especially in cases where a user-prompt/response is required prior to command execution because taking the user all the way through the prompt only to fail subsequently is sub-optimal UX).
We intend to provide users with the following interactions on cf CLI commands:
Commands which act on resources that make API calls first give the user feedback that they are about to start something:
Creating
)space new-space
)in org some-org
)as some-user
)...
to indicate more output is coming.When commands complete, they should output information according to these rules:
OK
after which the command exits with exit code 0.TIP
to indicate which commands to run next to get more information or perform additional operations on the resource. 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 null
stack.Note: Commands that do not act on a resource, (cf login
, for example) do not need to display initial feedback text or echo the resource, org/space and user details. However, they do require the final "..." ending and an OK
to confirm the operation completed successfully.
Example: A command which performs three distinct tasks, with an OK
after each one:
When adding new flags to a command, consider the idea of making impossible states unrepresentable. For example, when we implemented rolling pushes, we added --strategy rolling
rather than --rolling
. This allows us to add more possible values for the --strategy
flag in the future which are mutually exclusive with rolling
. If we had added --rolling
, then we would need to add another flag for the new strategy (--something-else
), and then we would need to add validation to make sure users can't pass mutually exclusive flags together (--rolling --something-else
). It's easier to implement, document, and understand if the flags are already designed to prevent mutually exclusive states.
This can often be thought of as adding an "enum-style" flag (a flag which takes a value), rather than several "boolean-style" flags (since then we need to think about all combinations of presence/absence of the boolean flags).
Most CF CLI commands fall into six types. To give users a predictable and consistent experience, follow these patterns for each command type.
Command naming conventionsGenerally, 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.
For CRUD related to resources, we include the resource name in the command -buildpack
, e.g., cf create-buildpack
. (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.).
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.
Exceptions:
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. The exception is with create-app
.api
, target
, config
.list-plugin-repos
does not omit "list". Maybe to disambiguate with repo-plugins
, or simply by error.Example commands: create-buildpack, create-space, create-user, create-service
Patterns:
TIP
at the end of the output.Example: Single resource happy path:
Example: Multi-step resource creation (creating and uploading):
Example: The resource already exists:
These commands show information related to a specific resource.
Examples: app
, service
Patterns:
OK
should not be printed, since the printing of the resource summary already indicates success.target
, api
- where we are not listing a resource.Example: Showing app summary with process summaries:
These commands show a list of resources, perhaps with some additional information about each resource.
Examples: apps
, marketplace
, services
, orgs
, spaces
Patterns:
OK
should not be printed, since the printing of the table already indicates success.No apps found
.There are exceptions to these patterns which are important to discuss:
cf routes --orglevel
will show routes for multiple spaces, and the order of that table is listed by space, not alphabetically.cf marketplace --no-plans
hides the plans
columncf org-users -a
removes the role-related rows and lists all users in the organization including the OrgUser roleExample: List of apps presented as a table:
Examples: rename
(app), rename-service
, rename-org
, update-service
, update-buildpack
Patterns:
OK
should always be displayed when the update is successful. If not, FAILED
should be displayed.Examples: delete-service
, unbind-service
, unshare-service
, delete-space
Patterns:
Examples: bind-service
, share-service
Patterns:
Because it's difficult to remember which argument should be provided first, second, third, and because submitting a command with mis-ordered arguments could have undesired consequences, commands with more than one required input should be designed with a single positional argument.
cf bind-service
requires both SERVICE_INSTANCE_NAME and APP_NAME. SERVICE_INSTANCE_NAME should be the arg because the action and noun refer directly to the service, not the app - If it was bind-app
, then it would make sense for APP_NAME to be the arg.cf revision APP_NAME --revision REVISION_NUMBER
can be run without --revision
because returning the app's current deployed revision would be a logical command response when no specific revision was specified.For information on flag validation, see section about failing fast. For information on flag design, see flag design.
bind-service
requires the app name and service name)-c
(for json), or --binding-name
flags)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.
ssh-code
) or support flags that optimize output for scripting (e.g. app myapp --guid
).awk
to parse its output.All commands should adhere to the following rules for exit codes:
0
.1
.1
.0
.Roughly, whenever an OK
is printed, the exit code should be 0
. Whenever a FAILED
is printed, the exit code should be 1
. But note that there are success cases (exit code 0
) that do not print OK
.
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.
Tables vs. key/value pairsUse tables when returning a list of multiple objects, possibly with information about those objects in table columns.
Use key/value pairs when returning attributes for one object.
Simple key/value pairs are displayed for one to one or one to many relationships. For many to many relationships, a table is displayed.
When displaying a table:
No apps found
.Example: Table with columns
Example: Empty table with message
When displaying a key/value pair:
requested state
)isolation segment:
and space quota:
)The format for displaying time depends on the context: How do we expect the user to be using this information?
Optimized for human readability:
Last timestamp
in cf app myapp
outputThu 03 May 16:24:50 PDT 2018
Optimized for machine readability:
cf logs myapp
output2018-05-08T15:43:12.41-0700
See current time formats as of cf version 6.23.1+a70deb38f.2017-01-13
Some commands use colors to highlight parts of the output. We sometimes refer to the colored text as "flavor text."
Colors can be disabled using a cf config
flag or environment variable (CF_COLOR=false
).
Colors are always disabled when the session is not a TTY session. This allows for the piping of CLI output into other commands (e.g. grep
) without including stray color characters.
Warnings, error messages, TIP
s are in plain text.
Don't add flavor text to anything outside of the following convention:
resource
to be acted upon (app name, for example), org name
, space name
, role
(admin, for example), user name
are in cyanOK
is greenFAILED
is redcf app
output, DOWN
is redThe design team reviewed flavor text and provided the guidance above after a round of research for accessibility. Accessibility is important. Example of color-blind friendly colors in output:
Help text is important for discoverability of commands, args, and flags. Care should be taken to ensure the help text is accurate and clear.
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.
Every CLI command has its own help page, retrievable using cf cmd -h
, cf help cmd
, cf cmd --help
). For information on the help page syntax, see the CF CLI Help Guidelines. They are inspired by man page conventions.
The first line returns the command name and version, followed by its short description.
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 releasesThe 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.)
For information regarding developing plugins, see developing cf CLI Plugins.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4