Skip to content

Commit 1f2e9a4

Browse files
authored
Outline of CLI UX/Option/behavior expectations for the dotnet CLI (#43938)
1 parent cf2c97a commit 1f2e9a4

File tree

1 file changed

+216
-0
lines changed

1 file changed

+216
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
## CLI Guidelines for the dotnet CLI and related commands
2+
3+
The `dotnet` CLI is the entrypoint for the .NET experience for all users, and as such it needs to be usable, performance, and consistent.
4+
This document outlines a series of UX guidelines, CLI grammars, and behavioral expectations for the `dotnet` CLI and related commands so that
5+
users have consistent experiences with all `dotnet` commands - even those that do not ship directly with the SDK like dotnet tools.
6+
7+
- [CLI Guidelines for the dotnet CLI and related commands](#cli-guidelines-for-the-dotnet-cli-and-related-commands)
8+
- [Common Options](#common-options)
9+
- [Verbosity](#verbosity)
10+
- [Framework selection](#framework-selection)
11+
- [RID selection](#rid-selection)
12+
- [Explicit RID](#explicit-rid)
13+
- [OS-specific RID](#os-specific-rid)
14+
- [Architecture-specific RID](#architecture-specific-rid)
15+
- [SDK-matching RID](#sdk-matching-rid)
16+
- [MSBuild Properties](#msbuild-properties)
17+
- [Output modes/formatting](#output-modesformatting)
18+
- [NuGet-related options](#nuget-related-options)
19+
- [NuGet.Config File selection](#nugetconfig-file-selection)
20+
- [Package source management](#package-source-management)
21+
- [Additive package sources](#additive-package-sources)
22+
- [Exclusive package sources](#exclusive-package-sources)
23+
- [Feed Authentication support](#feed-authentication-support)
24+
- [Contextual behaviors](#contextual-behaviors)
25+
- [Implicit project/solution file discovery](#implicit-projectsolution-file-discovery)
26+
- [Determining interactive sessions](#determining-interactive-sessions)
27+
- [Interaction patterns](#interaction-patterns)
28+
- [Support structured (JSON) output](#support-structured-json-output)
29+
- [StdOut/StdErr usage](#stdoutstderr-usage)
30+
- [Advanced terminal output capabilities](#advanced-terminal-output-capabilities)
31+
- [Disabling advanced terminal output capabilities](#disabling-advanced-terminal-output-capabilities)
32+
- [References](#references)
33+
34+
## Common Options
35+
36+
These options are present on a (sub)set of commands, and should be consistent in their behavior and usage regardless of the context in which they are used. Users expect these kinds of options to be generally available and will often unconsciously reach for them as best guesses/first attempts.
37+
38+
### Verbosity
39+
40+
Short Form: `-v`
41+
42+
Long Form: `--verbosity`
43+
44+
Allowed values: `[q]uiet`, `[m]inimal`, `[n]ormal`, `[d]etailed`, `[diag]nostic`
45+
46+
The CLI uses MSBuild verbosity level names. Commands should at minimum have support for three of these:
47+
* `quiet` mode should output nothing except the specific data output of the command.
48+
* `normal` mode should include high-priority messages in addition to the output
49+
* `diagnostic` mode should include all messages, including low-priority/debug/verbose messages.
50+
51+
If you only support a subset of these values, map the missing ones to the closest semantic match.
52+
For example, if you don't support `minimal`, map it to `quiet`. If you don't support `detailed`, map it to `diagnostic`.
53+
54+
For feedback on when to write to stderr or stdout, see the [StdOut/StdErr usage](#stdoutstderr-usage) section.
55+
For guidance on laying out output for users, see the [Advanced terminal output capabilities](#advanced-terminal-output-capabilities) section.
56+
57+
### Framework selection
58+
59+
Short form: `-f <TFM>`
60+
61+
Long form: `--framework <TFM>`
62+
63+
### RID selection
64+
65+
#### Explicit RID
66+
67+
Short form: `-r <RID>`
68+
69+
Long form: `--runtime <RID>`
70+
71+
#### OS-specific RID
72+
73+
Short form: `-o <OS>`
74+
75+
Long form: `--os <OS>`
76+
77+
#### Architecture-specific RID
78+
79+
Short form: `-a <ARCH>`
80+
81+
Long form: `--arch <ARCH>`
82+
83+
#### SDK-matching RID
84+
85+
Short form: `--ucr`
86+
87+
Long form: `--use-current-runtime`
88+
89+
### MSBuild Properties
90+
91+
Short form: `-p <MSBuild property expression(s)>`
92+
93+
Long form: `--property <MSBuild property expression(s)>`
94+
95+
If at all possible we _strongly encourage_ not parsing the `<MSBuild property expression(s)>` syntax yourself. It is much more complex than you think it is.
96+
At _best_ you should detect and forward along any of these arguments to any MSBuild invocations you make.
97+
98+
### Output modes/formatting
99+
100+
Long form: `--format`
101+
102+
Allowed values: `text`, `json`, others are relevant for your use case
103+
104+
Users value scriptability of CLI commands, and some form of structured output is key to supporting this. JSON is a common structured output format,
105+
but other formats may be more appropriate for your use case. If you use a structured format like `csv`, please for the love of Turing use a proper
106+
CSV writer and not just a hand-rolled comma-separated list of values so that you don't break [RFC 4180][4180].
107+
108+
When you write JSON outputs you are explicitly creating a data contract with users. Be _very intentional_ about changes to the format of this contract.
109+
Design up-front for extensibility. For example, instead of just emitting a list of versions as an array of strings, consider emitting them as an
110+
array of objects with a named property: `[{"workload_set_version": "1.0.0"}]` instead of `"1.0.0"`.
111+
112+
## NuGet-related options
113+
114+
NuGet is key to delivering package management and security functionality to end users. We should strive to make the NuGet experience as consistent
115+
as possible across all `dotnet` commands, by following the same patterns and behaviors.
116+
117+
### NuGet.Config File selection
118+
119+
Long form: `--config-file`
120+
121+
Default value: directory-based probing implemented in the [`NuGet.Configuration`][nuget-configuration] library
122+
123+
### Package source management
124+
125+
There are two semantics of behaviors that we have adopted in the dotnet CLI: additive and exclusive package sources.
126+
127+
#### Additive package sources
128+
129+
Long form: `--add-source <source_uri>`
130+
131+
When this is used, you should load the sources list from the NuGet configuration (using the [libraries][nuget-configuration]) and create a
132+
new `PackageSource` to add to that set. This should be additive and not destructive.
133+
134+
#### Exclusive package sources
135+
136+
Long form: `--source <source_uri>`
137+
138+
When this is used, you should ONLY use the sources supplied by this parameter and ignore any sources in the NuGet configuration. This is useful
139+
for scenarios where you want to ensure that you're only using a specific source for a specific operation.
140+
141+
### Feed Authentication support
142+
143+
Long form: `--interactive <bool>`
144+
145+
Default value: `true` when in an [interactive session](#determining-interactive-sessions), `false` otherwise
146+
147+
NuGet authentication often requires some interactive action like going to a browser page. You should 'prime' the NuGet credential services by calling
148+
`NuGet.Credentials.DefaultCredentialServiceUtility.SetupDefaultCredentialService(ILogger logger, bool nonInteractive)` with the value of `nonInteractive`
149+
being the inverted value of this parameter. This will ensure that the credential service is set up correctly for the current session type.
150+
151+
## Contextual behaviors
152+
153+
### Implicit project/solution file discovery
154+
155+
When a command is run in a directory that contains a project or solution file, the command should automatically use that file as the
156+
target for the command.
157+
If the command is run in a directory that contains multiple project or solution files, the command should fail with an error message
158+
indicating that the user should specify which file to use.
159+
160+
Consider the use of an option like `--project <path to project or solution>` to allow for executing the command against a specific
161+
project or solution file at an arbitrary location - but be aware that many mechanisms in .NET are hierarchical from Current Working
162+
Directory and may have different behaviors when used in this detached mode.
163+
164+
### Determining interactive sessions
165+
166+
Commands should be able to determine if they are running in an interactive session or not. This is important for determining
167+
168+
* whether to prompt the user for input or not,
169+
* what the default value for NuGet's `--interactive` option should be
170+
* how to format output (along with terminfo probing)
171+
172+
In general the easiest way to check this is if the `stdin` file descriptor is a TTY, or in .NET Terms: `Console.IsInputRedirected` is `false`.
173+
174+
## Interaction patterns
175+
176+
### Support structured (JSON) output
177+
178+
All commands should support structured (JSON) output. This is a key part of the CLI experience and allows for easier scripting and automation of the CLI.
179+
See the [`--format`](#output-modesformatting) option for more details. When structured output is requested, the command should output the structured
180+
data to `stdout` and any non-structured data to `stderr` - this is to make it easier to parse the structured data without having to deal with the
181+
non-structured data.
182+
183+
### StdOut/StdErr usage
184+
185+
StdErr is a perfectly reasonable output channel. It should be the default channel for
186+
187+
* warnings and errors
188+
* verbose logging
189+
* outputs that aren't directly related to the command's primary purpose - for example 'workload manifest update' notices
190+
191+
There is some contention here because older versions of PowerShell treat any stderr output as an error, but this is not the
192+
case in modern PowerShell (> 7.3) via the [$PSNativeCommandUseErrorActionPreference](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_preference_variables#psnativecommanduseerroractionpreference) preference setting.
193+
194+
### Advanced terminal output capabilities
195+
196+
You are encouraged to make use of advanced terminal capabilities like colors, weights, and other formatting options to make your output
197+
more readable. Instead of writing entire lines of text as a single color, consider how the use of color and formatting present the
198+
output to the user. When performing long-running operations, provide a progress bar or ticker or some other form of feedback to the user.
199+
200+
DO NOT rely entirely on color to convey information. Colorblind users will not be able to distinguish between different colors. Instead,
201+
consider color, symbols, and layout holistically to convey information.
202+
203+
### Disabling advanced terminal output capabilities
204+
205+
If stderr or stdout are redirected, do not emit color/weight/progress on those channels.
206+
If NO_COLOR is set, do not emit color/weight/progress on any channel.
207+
If TERM is `dumb`, do not emit color/weight/progress on any channel.
208+
209+
## References
210+
211+
[Command-line interface guidelines][clig]
212+
213+
[clig]: https://clig.dev/
214+
[4180]: https://www.loc.gov/preservation/digital/formats/fdd/fdd000323.shtml
215+
[nuget-configuration]: https://nuget.org/packages/NuGet.Configuration
216+
[pwsh-output-streams]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_output_streams

0 commit comments

Comments
 (0)