The Tanzu CLI aims to provide a consistent experience for users of the Tanzu portfolio.
This document is intended to provide direction for designing Tanzu CLI plugins so that they adhere to established patterns.
Two checklists to help contributors design and develop styleguide-consistent commands are available.
- The design-stage checklist is meant to be used prior to implementation.
- The build-stage checklist is meant to be used during implementation.
- Default to human-readable output, but support plaintext and json/yaml options
- Use straightforward, simple language and syntax
- Use machine-readable output where it does not impact usability
- Consistent language, structure, and as much as possible, behaviors across interfaces
- Invest time in your help and error text
- Provide examples
- Command line completion should be used whenever possible
- Provide context info whenever possible (ie feedback messages, etc)
- Most APIs should be made declarative, and the CLI commands should supply basic
apply
operations on those data models
- Avoid complex client logic, maintaining state; prefer server side logic
- We should not exclude users by deprioritizing accessibility
- Features like search filters and output limits are useful for folks using assistive technology
- Screen-readers and automation are both served by being thoughtful with the use of non-machine-readable characters (emojis, ascii spinners, etc.)
The Tanzu CLI uses the following pattern
tanzu [global flags] noun [sub-noun] verb RESOURCE-NAME [flags]
Example
tanzu cluster create NAME
tanzu management-cluster kubeconfig get --admin
The global flags are maintained in this repository need to apply meaningfully to most, if not all, plugin commands, hence care has to be taken when any changes to them are made. Any request to add or remove a flag has to be preceded with the filing of a feature request explaining the rationale. The change, should it be implemented, will be accompanied by a clear deprecation notice.
It is highly recommended that any new nouns introduced by plugins be added to the Shared Taxonomy
Compound words should be -
delimited
management-cluster not managementcluster nor managementCluster
Nouns should not be combined with verbs
tanzu app get, not tanzu app-get
Use the standard CRUD verbs whenever possible
- Tanzu CLI uses
create, delete, get, list, update
If at all possible, use pre-existing verbs from the Shared Taxonomy.
- Opposing commands should take the form of antonyms
Example
‘assign quota’ and ‘unassign quota’
Plugin specific sub-nouns do not need to be reviewed by the governance group. Please review the Shared Taxonomy when using sub-nouns, and make sure you're using the noun consistently if it's already being used.
Commands should not nest more than two layers of sub-nouns:
- Yes:
tanzu plugin-name noun sub-noun verb --flags
… - No:
tanzu plugin-name noun sub-noun sub-sub-noun verb --flags
…
- There should no more than 1 positional argument
- Ideally, the positional argument should be the name/subject of the thing the command refers to (not some other flaggable property)
Example
tanzu cluster create CLUSTER-NAME [flags]
-
Use standard names for flags if there is an appropriate one in the Shared Taxonomy)
-
When using flags to specify different aspects of the same object, including the object name in the flag can be helpful.
tanzu foo list --bar --bar-uid "..."
andtanzu foo list --bar-name --bar-uid "..."
are both in use, choose whichever pattern makes more sense for your plugin. -
Where possible, set reasonable defaults for flag-able options that align with expected workflows
-
A user should only be required to explicitly set a max of 2 flags
-
Add as many flags as necessary to configure the command
-
Consider supporting the use of a config file if the number of flags exceeds 5
-
Flags should be tab completed. The Tanzu CLI uses the cobra framework, which has tooling to help with this Cobra shell completion docs
The Tanzu CLI follows kubectl patterns for specifying resource units.
CPU units
m (millicpu)
Example
# 100m, .1, 1
$tanzu apps workload update <name> --limit-cpu 8
Memory units
E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki.
Example
# 128974848, 129e6, 129M , 123Mi
$tanzu apps workload update <name> --limit-memory 16G
The Tanzu CLI follows go patterns for specifying time duration.
Time units
ns, us (or µs), ms, s, m, h
Example
# 300ms, -1.5h or 2h45m
$ tanzu apps workload delete <name> --wait-timeout 10m
- If you are prompting for a secret, do not echo it in the terminal when the user types
- Commands should accept secrets via environment variables
- Commands should not prompt when TTY is not present
- Support verbosity flags
- Provide a way to deactivate interactive prompting (
--quiet
,--force
,--yes
)
Available for plugins written in golang.
CLI commands should utilize the plugin runtime component library for interactive features like prompts or table printing.
Available input components:
- Select : for seek a choice among a list of alternatives
- Question : for seeking an interactive response to a simple question
- Prompt : for seeking an interactive response to a question with a good amount of configurability
Useful for everyone, critical to the usability of screen-readers and automation
Support verbosity flags (-v
, --verbose
).
--format
to define preferred output
- Useful for humans and machine users, ie table, value, json, csv, yaml, etc
--filter
- To refine the output criteria
For list commands, consider supporting --limit
to set a maximum number of responses.
--page-size
to define the number of resources per page if using pagination--sort-by
to specify what field to organize the list by
If using color to communicate information, don't let it be the only indicator.
- To protect against unintended destructive actions, the CLI should confirm user intentions before executing commands such as ‘delete’
- It can be helpful to describe the impact of an action if not obvious
- The default action should be to cancel if no input is provided
Example
$ tanzu cluster delete MY_CLUSTER
This action impacts all apps in this cluster. Deleting the cluster will remove associated apps
Really delete the cluster MY_CLUSTER [y/N]
MY_CLUSTER has not been deleted
- To deactivate all interactive prompts when running cli commands (helpful for scripting purposes) the CLI should support a --yes or -y, option
Example
tanzu cluster delete MY_CLUSTER --yes
When executing a command, repeat back the command and context to the user.
Example
$ tanzu app create NAME
Creating app NAME in namespace NAMESPACE as user USERNAME
or
$ tanzu app create NAME
Creating app NAME using context KUBECONFIG-CONTEXT-NAME
For long running processes, don't go for a long period without output to the user. Outputting something like ’Processing…’, or a spinner can go a long way towards reassuring the user that their command went through.
The OutputWriterSpinner in plugin runtime component library is a useful component to use to indicate in the output that some operations are long-running.
In the confirmation feedback, include a notice for experimental or beta commands.
Example
“Warning: This is a EXPERIMENTAL command and may change without notice.”
“Warning: This is a BETA command and may change without notice.”
- Primary output for both human and machine users.
- Output for messages, warnings, errors.
- Stderr output is shown to the user, but not included when piping commands together.
- When a command succeeds without error, the process should exit with code.
- When a command fails for any reason (invalid flags, failed API request, etc.), the process should exit with code.
- When a multi-step command fails at any step, the process should exit with code.
- When an operation is meant to be idempotent (like creating a resource that already exists, or deleting a resource that’s already been deleted), the process should exit with code.
- Exit 0 - the command was successful issued AND
- Return a line telling the user how to check status of the command
- Feedback could be an error message with exit code 1 OR
- Confirmation of completion (i.e. “OK”, “done”) with exit code 0
- Tables are the default output format for list commands
- Column headers are upper case
- Columns are separated by three spaces from the longest key/value
- If there aren’t any values for a column, the column heading should be displayed and values left empty - don’t conditionally remove or hide a column
- If there are no values for a table, the table is replaced with a message, like ‘No apps found’
Example
NAME STATUS CPU MEM NAMESPACE WORKSPACE
calculator-app running 53% 18% mortgage-calc-dev
calculator-bpp running 93% 21% mortgage-calc-test
calculator-cpp running 23% 77% mortgage-calc
The OutputWriter component in plugin runtime component library is a useful component for producing consistent tabular output.
The Tanzu CLI, like kubectl uses the ISO 8601 standard for date and time
- Compact, consistent width, app/server's timezone
Example
2021-03-02T15:43:12.41-0700
- The key is shown first, followed by a colon
- Values are left-aligned
- Value column separated by three spaces from the longest key
- If no value for a key, key is displayed, value left empty
Example
name: mortgage-calculator-app
namespace: mortgage-cal-dev
workspace: mort-calc-dev
status:
url: http://myapplicationurl.com
- Color is helpful to highlight important information or to convey status, however it should be an enhancement to the text, and not be relied on as the sole source of a given bit of information because it can be deactivated in a user's terminal or may not be accessible to automation or screenreaders. Making status text red when it says
not ready
is ok because without the red, the status can still be determined. If, for example, the name of the resource was made red when not-ready it would not be possible to know the state of the resource if color was deactivated. - Colors can be deactivated using an environment variable (NO_COLOR=TRUE)
- Colors are always deactivated when the session is not a TTY session. This allows for the piping of CLI output into other commands (e.g. grep) or machine reading without including stray color characters (pending issue #369)
- Usage tips are always in plain text, even when referencing text that might normally be colorized
-
Red = warning, danger
The word 'Warning:' or 'Error:' is colorized and bold, the message is plain text
-
Green = success, informational
Confirmation of completion when a command runs is colorized and bold.
- Cyan = stability, calm, informationa
In command feedback: resources, and user name is colorized and bold.
Interactive prompting: user input is colorized, as is the preceding question mark.
- Deactivate if stdout is not an interactive terminal
- The component library can provide this check
- Currently no standards or guidance
- Deactivate if stdout is not an interactive terminal
- The component library can provide this check
- Available for plugins written in golang
CLI commands should utilize the plugin runtime component library for output functionality like table printing.
Available output components:
- OutputWriter: This component in plugin runtime component library is a useful component for producing consistent tabular output, as well as product output of sequential data in json or yaml format.
- OutputWriterSpinner: This component in useful in augmenting log output with a spinner to indicate long-running activity.
Commands will display help if passed -h, --help, or if no options are passed and a command expects them.
- A github link or website URL in the top level help encourage user feedback
Example
$tanzu package -h
Tanzu package management
Additional documentation is available at https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/1.3/vmware-tanzu-kubernetes-grid-13/GUID-tanzu-cli-reference.html
...
Flags:
-h, --help help for package
--log-file string Log file path
- If possible, the text should fit on an 80 character wide screen, to prevent word wrap that makes it harder to read.
- Description text begins with a capital letter and does not end with a period Example
Available command groups:
Build
apps Applications on Kubernetes
Manage
integration Get available integrations and their information from registry
Run
cluster Kubernetes cluster operations
kubernetes-release Kubernetes release operations
management-cluster Kubernetes management cluster operations
package Tanzu package management
Example
$ tanzu login -h
# Login to TKG management cluster using endpoint
tanzu login --endpoint "https://login.example.com" --name mgmt-cluster
# Login to TKG management cluster by using kubeconfig path and context for the management cluster
tanzu login --kubeconfig path/to/kubeconfig --context path/to/context --name mgmt-cluster
# Login to an existing server
tanzu login --server mgmt-cluster
Use output warnings sparingly. When used often they can create a lot of noise and users may learn to ignore them.
Try to write clear and concise errors, which tell the user what action (if any) must be taken. Ideally users won’t have to ask for help or check documentation to recover.
Make errors informative. A great error message should contain the following
- Error code / Error title, if applicable
- Error description - what happened
- How to fix the error
- URL to documentation for user’s specific error, if applicable
Example
$ myapp dump -o myfile.out
Error: EPERM - Invalid permissions on myfile.out
Cannot write to myfile.out, file does not have write permissions
Fix with: chmod +w myfile.out
https://github.com/tanzu/core/help/2323
$ tanzu namespace get EXAMPLE
Error: Namespace EXAMPLE not found. Try 'tanzu namespace list' to see available options
Use context in error messages to ease recovery
- If a parameter is invalid or missing, it is a chance to be helpful by telling the user exactly what was missed
"You forgot to enter the --name, apps in this namespace include App1, App2, etc..."
Make it easy to submit bug reports and feedback
- Consider including a github URL, or link to a form in error or help text
- If possible pre-populate form information to make the report as useful while not burdening the user
For information about developing plugins, see the Plugin Development Guide
A styleguide is never done, and should change to meet the changing needs.
To propose changes please create an issue labelled documentation
, and outline the proposal.