Skip to content

Commit a510a7a

Browse files
committed
more comments on terminal and output
1 parent d86bcb4 commit a510a7a

File tree

1 file changed

+78
-11
lines changed

1 file changed

+78
-11
lines changed

documentation/project-docs/cli-guidelines.md

+78-11
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ users have consistent experiences with all `dotnet` commands - even those that d
2323
- [Feed Authentication support](#feed-authentication-support)
2424
- [Contextual behaviors](#contextual-behaviors)
2525
- [Implicit project/solution file discovery](#implicit-projectsolution-file-discovery)
26-
- [Interactive session sniffing](#interactive-session-sniffing)
2726
- [Determining interactive sessions](#determining-interactive-sessions)
2827
- [Interaction patterns](#interaction-patterns)
29-
- [support structured (JSON) output](#support-structured-json-output)
28+
- [Support structured (JSON) output](#support-structured-json-output)
3029
- [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)
3132
- [References](#references)
3233

3334
## Common Options
@@ -47,7 +48,11 @@ The CLI uses MSBuild verbosity level names. Commands should at minimum have supp
4748
* `normal` mode should include high-priority messages in addition to the output
4849
* `diagnostic` mode should include all messages, including low-priority/debug/verbose messages.
4950

50-
If you only support a subset of these values, map the missing ones to the closest semantic match. For example, if you don't support `minimal`, map it to `quiet`. If you don't support `detailed`, map it to `diagnostic`.
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.
5156

5257
### Framework selection
5358

@@ -87,20 +92,28 @@ Short form: `-p <MSBuild property expression(s)>`
8792

8893
Long form: `--property <MSBuild property expression(s)>`
8994

90-
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. At _best_ you should detect and forward along any of these arguments to any MSBuild invocations you make.
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.
9197

9298
### Output modes/formatting
9399

94100
Long form: `--output`
95101

96102
Allowed values: `text`, `json`, others are relevant for your use case
97103

98-
Users value scriptability of CLI commands, and some form of structured output is key to supporting this. JSON is a common structured output format, 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 CSV writer and not just a hand-rolled comma-separated list of values so that you don't break [RFC 4180][4180].
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].
99107

100-
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. 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 array of objects with a named property: `[{"workload_set_version": "1.0.0"}]` instead of `"1.0.0"`.
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"`.
101111

102112
## NuGet-related options
103113

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+
104117
### NuGet.Config File selection
105118

106119
Long form: `--config-file`
@@ -114,36 +127,90 @@ There are two semantics of behaviors that we have adopted in the dotnet CLI: add
114127

115128
Long form: `--add-source <source_uri>`
116129

117-
When this is used, you should load the sources list from the NuGet configuration (using the [libraries][nuget-configuration]) and create a new `PackageSource` to add to that set. This should be additive and not destructive.
130+
When this is used, you should load the sources list from the NuGet configuration (using the [libraries][nuget-configuration]) and create a
131+
new `PackageSource` to add to that set. This should be additive and not destructive.
118132

119133
#### Exclusive package sources
120134

121135
Long form: `--source <source_uri>`
122136

123-
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 for scenarios where you want to ensure that you're only using a specific source for a specific operation.
137+
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
138+
for scenarios where you want to ensure that you're only using a specific source for a specific operation.
124139

125140
### Feed Authentication support
126141

127142
Long form: `--interactive <bool>`
128143
Default value: `true` when in an [interactive session](#determining-interactive-sessions), `false` otherwise
129144

130-
NuGet authentication often requires some interactive action like going to a browser page. You should 'prime' the NuGet credential services by calling `NuGet.Credentials.DefaultCredentialServiceUtility.SetupDefaultCredentialService(ILogger logger, bool nonInteractive)` with the value of `nonInteractive` being the inverted value of this parameter. This will ensure that the credential service is set up correctly for the current session type.
145+
NuGet authentication often requires some interactive action like going to a browser page. You should 'prime' the NuGet credential services by calling
146+
`NuGet.Credentials.DefaultCredentialServiceUtility.SetupDefaultCredentialService(ILogger logger, bool nonInteractive)` with the value of `nonInteractive`
147+
being the inverted value of this parameter. This will ensure that the credential service is set up correctly for the current session type.
131148

132149
## Contextual behaviors
133150

134151
### Implicit project/solution file discovery
135-
### Interactive session sniffing
152+
153+
When a command is run in a directory that contains a project or solution file, the command should automatically use that file as the
154+
target for the command.
155+
If the command is run in a directory that contains multiple project or solution files, the command should fail with an error message
156+
indicating that the user should specify which file to use.
157+
158+
Consider the use of an option like `--project <path to project or solution>` to allow for executing the command against a specific
159+
project or solution file at an arbitrary location - but be aware that many mechanisms in .NET are hierarchical from Current Working
160+
Directory and may have different behaviors when used in this detached mode.
161+
136162
### Determining interactive sessions
137163

164+
Commands should be able to determine if they are running in an interactive session or not. This is important for determining
165+
166+
* whether to prompt the user for input or not,
167+
* what the default value for NuGet's `--interactive` option should be
168+
* how to format output (along with terminfo probing)
169+
170+
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`.
171+
138172
## Interaction patterns
139173

140-
### support structured (JSON) output
174+
### Support structured (JSON) output
175+
176+
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.
177+
See the [`--format`](#output-modesformatting) option for more details. When structured output is requested, the command should output the structured
178+
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
179+
non-structured data.
180+
141181
### StdOut/StdErr usage
142182

183+
StdErr is a perfectly reasonable output channel. It should be the default channel for
184+
185+
* warnings and errors
186+
* verbose logging
187+
* outputs that aren't directly related to the command's primary purpose - for example 'workload manifest update' notices
188+
189+
There is some contention here because older versions of PowerShell treat any stderr output as an error, but this is not the
190+
case in modern PowerShell. If you're writing a command that is intended to be used in PowerShell, you should be aware of this
191+
and ensure that your command behaves correctly in both old and new versions of PowerShell - consider using Powershells various
192+
[output streams][pwsh-output-streams] to encode the semantics of your output.
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+
143209
## References
144210

145211
[Command-line interface guidelines][clig]
146212

147213
[clig]: https://clig.dev/
148214
[4180]: https://www.loc.gov/preservation/digital/formats/fdd/fdd000323.shtml
149215
[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?view=powershell-7.4

0 commit comments

Comments
 (0)