Sdk: Thoughts regarding the dotnet cli UX

Created on 24 Mar 2017  Â·  14Comments  Â·  Source: dotnet/sdk

Thoughts regarding the dotnet cli UX

Yesterday I decided to have a look at the UX for the dotnet cli, and came to the conclusion that there are some things that I think might be possible to simplify, to make it easier for new people to adopt. The CLI is probably the first thing that people see when starting out with .NET Core, unless you are using VS, and because if this, I think it needs to be simple and easy to understand.

So here are some thoughts after looking through the UX.

dotnet

Just typing dotnet without any arguments currently returns a fairly large amount of text that probably isn't very useful for a lot of people. So my suggestion is to simplify this view by making it shorter, and easier to read

C:\Users\Chris>dotnet

Usage: dotnet [options | path-to-application]

options:
  -v|--version          Display .NET CLI Version Number
  -i|--install          Install runtime
  -d|--diagnostics      Enable diagnostic output
  -ri|--runtime-info    Display Runtime Information

path-to-application:
  The path to a .NET Core managed application, dll or exe file to execute.

Version:
  Runtime:   1.1.0
  SDK:       1.0.1

To install SDK, run dotnet install --sdk

As you can see, the text is much shorter than the current one, making it easier to digest. To shorten it down, the options segment has removed, and is instead available through --help.

The information about the host configuration environment has been removed, and I suggest having that in the documentation instead. It seems like something a very small amount of people will use, so having it here is not useful for most people.

Version information has been moved to the bottom, as in most cases it is less important than the rest of the information. It also includes both runtime and SDK versions, as both versions are of interest in a lot of cases. Having one version here, and another when typing --version is confusing to me. The build hash has also been removed to make the information less verbose. The hash is not useful to more than a small group of people, so I suggest just moving it to the release notes instead.

I also suggest removing the text about installing the SDK, as it is not possible to click the link for obvious reasons, and copy pasting it is just cumbersome. Instead of having the text and copy pasting the URL, I suggest adding a new command called install with an argument like --sdk. Running just install installs the latest runtime instead of the SDK, making it easy to install new runtimes on servers etc, and by adding --sdk it changes and installs the latest SDK instead. Optionally it installs the specified version, if a specific version is provided.

If the install command is too complicated, at least changing the URL to a better URL would be good.

dotnet --runtime-info

I also suggest adding a new option called --runtime-info, which gives the user access to runtime information previously available through --info (which is removed). It is just a bit more clear to me what runtime-info means, opposed to info.

C:\Users\Chris>dotnet --runtime-info
OS Name:     Windows
OS Version:  10.0.14393
OS Platform: Windows
RID:         win10-x64

dotnet --help

Today, typing dotnet --help returns a lot of useful information, but I think the content could be simplified a bit. Something like this

C:\Users\Chris>dotnet -h

Usage: dotnet [command] [command-arguments] [options]

Runtime Commands:
  -v|--version          Display .NET CLI and SDK Version Number
  -i|--install          Install runtime
  -d|--diagnostics      Enable diagnostic output
  -ri|--runtime-info    Display Runtime Information

SDK Commands:
  new           Initialize .NET projects.
  restore       Restore dependencies specified in the .NET project.
  run           Compiles and immediately executes a .NET project.
  build         Builds a .NET project.
  publish       Publishes a .NET project for deployment (including the runtime).
  test          Runs unit tests using the test runner specified in the project.
  pack          Creates a NuGet package.
  migrate       Migrates a project.json based project to a msbuild based project.
  clean         Clean build output(s).
  sln           Modify solution (SLN) files.
  add           Add reference to the project
  remove        Remove reference from the project
  list          List reference in the project
  nuget         Provides additional NuGet commands.
  msbuild       Runs Microsoft Build Engine (MSBuild).
  vstest        Runs Microsoft Test Execution Command Line Tool.

Options:
  -v|--verbose                     Enable verbose output
  -h|--help                        Show help
  --fx-version <version>           Version of the installed runtime version to use to run the application.
  --additionalprobingpath <path>   Path containing probing policy and assemblies to probe for.

To make the help section easier to digest, I think removing the CLI version information, which is available through --version, makes sense. Once again, having 2 diferent versions popping up in different scenarios is confusing...

I think removing the arguments information would be good as well. Currently it only duplicated the "usage row", and having it twice can be a little confusing and does not really give anything more to the user.

Renaming the "Host options" "Runtime Commands" would probably make them a bit easier to understand. And to make it consistent, this section replicates the information shown when running dotnet.

I would also suggest grouping all SDK commands into one section, as there is no real need to keep them separate. It only takes up space, and even though there might be technical differences between them, the average user probably doesn't care.

Common Options can also be renamed to just Options, and moved to the end. Moving them to the end of the text, is in line with where they are used...

dotnet version

I would also suggest changing the experience around getting the versioning information.

Instead of having --version, I suggest introducing a new command called version. Having this as a command makes it more flexible as arguments can be added if needed. Running it without arguments displays the below information, containing both all available runtime versions, as well as latest SDK version and root path.

C:\Users\Chris>dotnet version

Runtime Versions:
  1.1.0
  1.0.1
  1.0.0

SDK Version:
  1.1.0 

Root path:   
  C:\Program Files\dotnet\

Having dotnet version return all installed runtime versions as well as the latest SDK would make a lot of sense to me. It explains the difference version numbers better, than showing different numbers depending on what you are doing. I also suggest having the Root Path in here (currently called base path)

However, I would suggest keeping dotnet --version for backwards compatibility, but having it undocumented in an attempt to get people to use the new command instead.

Adding a --sdk-version argument allows tooling to get an easily parsable string instead of having to parse the above verbose information.

C:\Users\Chris>dotnet version --sdk-version
1.1.0 

Any thoughts? Feedback? Comments?

Most helpful comment

I like the idea, as long as we don't remove the existing commands (--info and --version). I am fine taking them out of the help options, but we should keep them in case people (and particularly CI) depend on them.

Though I don't see much value in --runtime-info versus --info. I would rather just keep --info.

I agree with the other changes though.

cc @gkhanna79 for the proposed host changes.

All 14 comments

If the install command is too complicated, at least changing the URL to a better URL would be good.

I expect that it would be too complicated, considering all the various ways you can install .Net Core. For example, what should dotnet install --sdk do if you downloaded the .tar.gz containing the runtime and extracted it to some directory?

I agree that the current URL (http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409, source) is way too long to retype, especially considering that http://dot.net/core leads to the same page.

I would also suggest changing the experience around getting the versioning information.

See https://github.com/dotnet/cli/issues/3773 for a recent discussion about this.

Yeah, it is not the simplest thing I guess. How about having the command start the download of the file for you, or at least pop-up a browser window with the correct URL? I just feel that a text link in a terminal isn't the best UX. Having it work something like the PS script that was used previously for the install would have been nice and simple...

I had missed the discussion about versioning. It seems like I am not alone to think it needs some modifications at least... :)

I like this direction. It reduces noise w/o much (if any) loss of useful information.

Given how much feedback we have had in this area, I think we should implement this or a derivative of it for 2.0. Most of it is a re-packing of what we already have. Some of it, specifically the install parts, needs more thought. If we initially go for the browser approach (like dotnet help) then it would be cheap. That's a conversation.

Anyone not like this direction/proposal?

I like the idea, as long as we don't remove the existing commands (--info and --version). I am fine taking them out of the help options, but we should keep them in case people (and particularly CI) depend on them.

Though I don't see much value in --runtime-info versus --info. I would rather just keep --info.

I agree with the other changes though.

cc @gkhanna79 for the proposed host changes.

@ChrisKlug Thoughts on --runtime-info and --info? What was your motivation for changing that name?

Thanks for the suggestions. Sounds like we have a winner! I saw some community likes, which is good.

I like the idea, as long as we don't remove the existing commands (--info and --version). I am fine taking them out of the help options, but we should keep them in case people (and particularly CI) depend on them

Would it be possible to distinguish interactive use from non-interactive use of dotnet --version? If we can determine that it's an interactive session that just ran dotnet --version, we could print a warning or something informing them about dotnet version. Otherwise, I think the confusion behind dotnet --version being misleading (and now conflicting with dotnet version) will remain.

Agree I don't see a reason to have a compound option like --runtime-info. I think --info exists now and shows good stuff. Add to that if you want.

C:\Users\scott> dotnet --info
.NET Command Line Tools (1.0.0)

Product Information:
 Version:            1.0.0
 Commit SHA-1 hash:  e53429feb4

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.15061
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\1.0.0

The reason to look at the rename from --info to --runtime-info was that I found it to be more explicit in what it returned.

It also made more sense when removing the version information from --info, which was another part of the suggestion. Currently --info includes versioning information for the "product", which I assume is the SDK version in this case? I found that confusing, both because of the naming, "Product Information", not really making sense, and because of the duplication of versioning information. Having versioning in one place, and runtime information in another, keeps each of the commands "clean", and removes repetition.

But sure, it could all be added to --info as such. but can we then at least rename the "Product Information" to something more descriptive, like "SDK Information"?

C:\Users\scott> dotnet --info
SDK Information:
  Version:                       1.0.0
  Commit SHA-1 hash:  e53429feb4

Runtime Environment:
  OS Name:     Windows
  OS Version:  10.0.15061
  OS Platform: Windows
  RID:         win10-x64
  Base Path:   C:\Program Files\dotnet\sdk\1.0.0

The main problem in my opinion is that version numbers are included all over the place, without a good explanation what they are versioning. There is a version at the top of the return for each command. There is a version available through --version. There is a version when passing no argument. There is a version when passing --info. In one place it is called Product version, in another Microsoft .NET Core Shared Framework Host version, in yet another .NET Command Line Tools version, and finally, in --version it has no definition at all, just a number. That is somewhat confusing to me at least...

One option is to keep --version as-is and then put the information currently proposed for version in --info. The problem I see with that is that it isn't intuitive to use --info to get version information. I'd still like keep --version as-is for compat reasons.

Here's another proposal:

  • Make --info a catch-all of .NET Core information. It is OK to duplicate with other options as long as it is consistent. This is basically the dotnet systeminfo (Windows). This is also like docker info. The value is that this can be the one place to look if you want to find something and the one screen of data to share to share with others to get help.
  • Adopt version as the primary command for version information. I think we need a top-level command for versions, not just an argument. There are multiple pivots that I can imagine: runtime vs sdk and stable vs pre-release. This would allow a command like dotnet version --runtime --stable.

Another interesting once is dotnet inspect which could point to either a csproj file or a binary. This would be the same as docker inspect.

As a brand new user to the CLI, running dotnet --version and not seeing what I expected was frustrating. However, I did run dotnet first to see how to find the version (even though -v, --version is pretty standard across the CLI ecosystem), and if there was dotnet version available, that would have solved my issue and been clearer with the multitude of versions to keep track of. Definitely +1 to dotnet version and deprecating/hiding --version to replace with specific "filter" parameters as @richlander suggested for CI systems or automation.

To put the current situation in perspective of a real-world example (I'll put new terms in quotes):

I've installed the "SDK", ".NET Core SDK (contains .NET Core 1.0 and 1.1)" from the website.

".NET Core SDK"
".NET Core 1.0 and 1.1"

I did a build of a project, and got this:

info: Exec
info:   program: dotnet
info:   commandline: test --no-build --configuration Debug -f netcoreapp1.1
info:   workingdir: test/Microsoft.AspNetCore.Authentication.Test
The specified framework 'Microsoft.NETCore.App', version '1.1.2' was not found.
  - Check application dependencies and target a framework version installed at:
      /Users/Bart/.dotnet/shared/Microsoft.NETCore.App
  - The following versions are installed:
      1.0.0
      1.1.0
      1.1.1
  - Alternatively, install the framework version '1.1.2'.
fail: Exit code 131 from dotnet

"-f netcoreapp1.1"
"framework 'Microsoft.NETCore.App', version '1.1.2'"

Ok, so what "version" do I have? First attempt:

Bart$Barts-Air ~/Documents/Repos/AspNet/Security ➜  dotnet

Microsoft .NET Core Shared Framework Host

  Version  : 1.1.0
  Build    : 928f77c4bc3f49d892459992fb6e1d5542cb5e86

"Microsoft .NET Core Shared Framework Host" "Version: 1.1.0"

1.1.0? I was expecting to see (latest) 1.1.1?

Bart$Barts-Air ~/Documents/Repos/AspNet/Security ➜  dotnet --version
1.0.4

dotnet's program version 1.0.4

Huh, different? What does 1.0.4 refer to? I need more info:

Bart$Barts-Air ~/Documents/Repos/AspNet/Security ➜  dotnet --info
.NET Command Line Tools (1.0.4)

Product Information:
 Version:            1.0.4
 Commit SHA-1 hash:  af1e6684fd

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  10.12
 OS Platform: Darwin
 RID:         osx.10.12-x64
 Base Path:   /usr/local/share/dotnet/sdk/1.0.4

".NET Command Line Tools (1.0.4)"
"Product Information: Version: 1.0.4"
"Base Path: /usr/local/share/dotnet/sdk/1.0.4"

Ah ok, so the CLI, "Product" and SDK (in path) are the same at 1.0.4.

But where is framework (runtime) 1.1.1?

Searching the code repo, I find this global.json file that looks like this:

{
    "projects": ["src"],
    "sdk": {
      "version": "1.0.0-preview2-1-003177"
    }
}

"sdk" "version"

Still not able to find the runtimes.

Ok, let's follow-up with that suggestion in the first error message.
I go to the website, and download "Runtime" ".NET Core 1.1.2 runtime (Current)".

"Runtime"

After installing, I try all the above commands and they all return the exact same versions.

In my eternal search for 1.1.2, I follow the path mentioned in the initial error message, and I find these folders (shortened for readability):

Bart$Barts-Air ~/.dotnet ➜  find .
./host/fxr/1.0.1
./host/fxr/1.1.0
./optimizationdata/1.0.0-preview2-003131
./optimizationdata/1.0.0-preview2-003148
./optimizationdata/1.0.0-preview2-1-003177
./optimizationdata/1.0.3
./optimizationdata/1.0.4
./sdk/1.0.0-preview2-1-003177
./shared/Microsoft.NETCore.App/1.0.0
./shared/Microsoft.NETCore.App/1.1.0
./shared/Microsoft.NETCore.App/1.1.1

So "sdk" is "1.0.0-preview2-1-003177"? That appears to match the global.json file. However, what is "optimizationdata" that seems to be the actual version of the dotnet command? That isn't the SDK?
Also, the "host" is 1.1.0, what seems to match with the parameterless CLI output "Microsoft .NET Core Shared Framework Host", however, that's apparently different than "shared" (as in "Microsoft .NET Core Shared Framework Host"?

For fun, I also follow the path mentioned as the Base Path of dotnet --info:

Bart$Barts-Air /usr/local/share/dotnet ➜  find .
./host/fxr/1.0.1
./host/fxr/1.1.0
./sdk/1.0.0-preview2-003131
./sdk/1.0.0-preview2-003148
./sdk/1.0.3
./sdk/1.0.4
./shared/Microsoft.NETCore.App/1.0.1
./shared/Microsoft.NETCore.App/1.0.2
./shared/Microsoft.NETCore.App/1.0.4
./shared/Microsoft.NETCore.App/1.0.5
./shared/Microsoft.NETCore.App/1.1.1
./shared/Microsoft.NETCore.App/1.1.2

Getting somewhere, there's Microsoft.NETCore.App 1.1.2 "framework"! Since the global.json refers to SDK "1.0.0-preview2-1-003177" which is not in this folder (but in the previous folder), maybe that's why the project is not building?


I hope to make clear with this that the UX also includes messaging used on the website, error messages and program versions. The terms SDK, Runtime, Framework, Host, Product all seem to be used interchangeably.

If there are so many differentiations, the CLI should give a clear indication with the current parameterless and --help commands where to find all information:

E.g:

Bart$Barts-Air ~ ➜  dotnet
.NET Command Line Tools (1.0.4)
Microsoft .NET Core Shared Framework Host (1.1.0) 928f77c4bc3f49d892459992fb6e1d5542cb5e86
Usage: dotnet [common-options] [[options] path-to-application]

Common Options:
  --help                   Display full usage documentation for the .NET CLI
  --version                Display .NET CLI version number
  --hosts                  Display all installed Shared Framework Hosts
  --frameworks             Display all installed frameworks for use in the Shared Framework Host
  --sdks                   Display all installed .NET Core SDKs


[...]
Bart$Barts-Air ~ ➜  dotnet --help
.NET Command Line Tools (1.0.4)
Usage: dotnet [host-options] [command] [arguments] [common-options]

Arguments:
  [command]             The command to execute
  [arguments]           Arguments to pass to the command
  [host-options]        Options specific to dotnet (host)
  [common-options]      Options common to all commands

Common options:
  -v|--verbose          Enable verbose output
  -h|--help             Displays this help

Host options (passed before the command):
  -d|--diagnostics      Enable diagnostic output
  --version             Display .NET CLI version number
  --info                Display .NET CLI platform information
  --hosts               Display all installed Shared Framework Hosts
  --frameworks          Display all installed frameworks for use in the Shared Framework Host
  --sdks                Display all installed .NET Core SDKs

Commands:
[...]



md5-7d2b969d54f381d247aa836726b44d16



Bart$Barts-Air ~ ➜  dotnet --hosts
Microsoft .NET Core Shared Framework Host 1.0.1 818f77b3ab2f38e78932323fc82dbd812825322
Microsoft .NET Core Shared Framework Host 1.1.0 928f77c4bc3f49d892459992fb6e1d5542cb5e86 * default



md5-7d2b969d54f381d247aa836726b44d16



Bart$Barts-Air ~ ➜  dotnet --frameworks
Microsoft.NETCore.App 1.0.1
Microsoft.NETCore.App 1.0.2
Microsoft.NETCore.App 1.0.4
Microsoft.NETCore.App 1.0.5
Microsoft.NETCore.App 1.1.1
Microsoft.NETCore.App 1.1.2 * default



md5-7d2b969d54f381d247aa836726b44d16



Bart$Barts-Air ~/Documents/Repos/AspNet/Security/src ➜  dotnet --sdks
.NET Core SDK 1.0.0-preview2-003131
.NET Core SDK 1.0.0-preview2-003148
.NET Core SDK 1.0.0-preview2-1-003177 * current
.NET Core SDK 1.0.3
.NET Core SDK 1.0.4
* with global.json in ~/Documents/Repos/AspNet/Security

Note that --version and --info can remain unchanged. @livarcocc ;-)

Btw, little lightbulb moment here; the current dotnet and dotnet --help show different descriptions for --version, what I think is the root cause of a lot of confusion.

Regarding the version binding: There is a great design issue at https://github.com/dotnet/designs/issues/3
TL;DR Portable apps will no longer require the latest patch version of the runtime that the SDK knows about when building (implemented in https://github.com/dotnet/sdk/pull/1222).
Tried to give that a write-up at https://stackoverflow.com/questions/44240029/determine-which-net-core-runtime-is-needed

Linking https://github.com/dotnet/core-setup/issues/675 as that added --list-runtimes and --list-sdks implemented in the host (not the CLI)

We have add the commands steve mentioned above and dotnet --info is also displaying that information now.

Given that, going to close this issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

davkean picture davkean  Â·  163Comments

idavis picture idavis  Â·  57Comments

ericstj picture ericstj  Â·  54Comments

NinoFloris picture NinoFloris  Â·  99Comments

ghost picture ghost  Â·  210Comments