-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[dotnet-cli] prompt for target framework using Spectre.Console
#51509
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jonathanpeppers
wants to merge
21
commits into
main
Choose a base branch
from
dev/peppers/tf-selection
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
48a663a
[dotnet-cli] prompt for target framework using `Spectre.Console`
jonathanpeppers f5b4ff4
Fix for `.sln` file passed in
jonathanpeppers 0c1445e
Use `Interactive` property
jonathanpeppers 78afad3
Update GivenDotnetRunSelectsTargetFramework.cs
jonathanpeppers ea80a04
Remove duplicative tests
jonathanpeppers 36e5271
Better assertion
jonathanpeppers 6f66408
Skip previous TFMs on arm64, x64 passes on these
jonathanpeppers ae1b1d7
Remove ItPrefersExplicitFrameworkOptionOverProperty
jonathanpeppers e18870a
Update src/Cli/dotnet/Commands/Run/RunCommand.cs
jonathanpeppers 9141a23
Sign `Spectre.Console.dll`
jonathanpeppers 3847cfb
small tweaks to enable running against singular-valued targetframewor…
baronfel 18241ce
Add `EnableSearch()` w/ localization support
jonathanpeppers ad8a20e
Pin darc
premun 69864e8
Fix test failure
jonathanpeppers 3e34f5a
Test for 3847cfb9809fce3b6bf5a58b0c68f37e10fa11e9
jonathanpeppers 1be25bf
Merge branch 'main' into dev/peppers/tf-selection
jonathanpeppers e47ba5a
Update RunFileTests.cs
jonathanpeppers 7823fe5
Update GivenDotnetRunSelectsTargetFramework.cs
jonathanpeppers 5f5a8f8
Fix multi-targeted 'dotnet run lib.cs'
jonathanpeppers 6785ac5
Merge branch 'main' into dev/peppers/tf-selection
jonathanpeppers 5ad2287
Update RunFileTests.cs
jonathanpeppers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using Microsoft.Build.Evaluation; | ||
| using Microsoft.Build.Exceptions; | ||
| using Microsoft.DotNet.Cli.Utils; | ||
| using Spectre.Console; | ||
|
|
||
| namespace Microsoft.DotNet.Cli.Commands.Run; | ||
|
|
||
| internal static class TargetFrameworkSelector | ||
| { | ||
| /// <summary> | ||
| /// Evaluates the project to determine if target framework selection is needed. | ||
| /// If the project has multiple target frameworks and none was specified, prompts the user to select one. | ||
| /// </summary> | ||
| /// <param name="projectFilePath">Path to the project file</param> | ||
| /// <param name="globalProperties">Global properties for MSBuild evaluation</param> | ||
| /// <param name="isInteractive">Whether we're running in interactive mode (can prompt user)</param> | ||
| /// <param name="selectedFramework">The selected target framework, or null if not needed</param> | ||
| /// <returns>True if we should continue, false if we should exit with error</returns> | ||
| public static bool TrySelectTargetFramework( | ||
| string projectFilePath, | ||
| Dictionary<string, string> globalProperties, | ||
| bool isInteractive, | ||
| out string? selectedFramework) | ||
| { | ||
| selectedFramework = null; | ||
|
|
||
| // If a framework is already specified, no need to prompt | ||
| if (globalProperties.TryGetValue("TargetFramework", out var existingFramework) && !string.IsNullOrWhiteSpace(existingFramework)) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| // Evaluate the project to get TargetFrameworks | ||
| string targetFrameworks; | ||
| try | ||
| { | ||
| using var collection = new ProjectCollection(globalProperties: globalProperties); | ||
| var project = collection.LoadProject(projectFilePath); | ||
| targetFrameworks = project.GetPropertyValue("TargetFrameworks"); | ||
| } | ||
| catch (InvalidProjectFileException) | ||
| { | ||
| // Invalid project file, return true to continue for normal error handling | ||
| return true; | ||
| } | ||
|
|
||
| // If there's no TargetFrameworks property or only one framework, no selection needed | ||
| if (string.IsNullOrWhiteSpace(targetFrameworks)) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| // parse the TargetFrameworks property and make sure to account for any additional whitespace | ||
| // users may have added for formatting reasons. | ||
| var frameworks = targetFrameworks.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); | ||
|
|
||
| return TrySelectTargetFramework(frameworks, isInteractive, out selectedFramework); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Handles target framework selection when given an array of frameworks. | ||
| /// If there's only one framework, selects it automatically. | ||
| /// If there are multiple frameworks, prompts the user (interactive) or shows an error (non-interactive). | ||
| /// </summary> | ||
| /// <param name="frameworks">Array of target frameworks to choose from</param> | ||
| /// <param name="isInteractive">Whether we're running in interactive mode (can prompt user)</param> | ||
| /// <param name="selectedFramework">The selected target framework, or null if selection was cancelled</param> | ||
| /// <returns>True if we should continue, false if we should exit with error</returns> | ||
| public static bool TrySelectTargetFramework(string[] frameworks, bool isInteractive, out string? selectedFramework) | ||
| { | ||
| // If there's only one framework in the TargetFrameworks, we do need to pick it to force the subsequent builds/evaluations | ||
| // to act against the correct 'view' of the project | ||
| if (frameworks.Length == 1) | ||
| { | ||
| selectedFramework = frameworks[0]; | ||
| return true; | ||
| } | ||
|
|
||
| if (isInteractive) | ||
| { | ||
| selectedFramework = PromptForTargetFramework(frameworks); | ||
| return selectedFramework != null; | ||
| } | ||
| else | ||
| { | ||
| Reporter.Error.WriteLine(string.Format(CliCommandStrings.RunCommandExceptionUnableToRunSpecifyFramework, "--framework")); | ||
| Reporter.Error.WriteLine(); | ||
| Reporter.Error.WriteLine(CliCommandStrings.RunCommandAvailableTargetFrameworks); | ||
| Reporter.Error.WriteLine(); | ||
|
|
||
| for (int i = 0; i < frameworks.Length; i++) | ||
| { | ||
| Reporter.Error.WriteLine($" {i + 1}. {frameworks[i]}"); | ||
| } | ||
|
|
||
| Reporter.Error.WriteLine(); | ||
| Reporter.Error.WriteLine($"{CliCommandStrings.RunCommandExampleText}: dotnet run --framework {frameworks[0]}"); | ||
| Reporter.Error.WriteLine(); | ||
| selectedFramework = null; | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Prompts the user to select a target framework from the available options using Spectre.Console. | ||
| /// </summary> | ||
| private static string? PromptForTargetFramework(string[] frameworks) | ||
| { | ||
| try | ||
| { | ||
| var prompt = new SelectionPrompt<string>() | ||
| .Title($"[cyan]{Markup.Escape(CliCommandStrings.RunCommandSelectTargetFrameworkPrompt)}[/]") | ||
| .PageSize(10) | ||
| .MoreChoicesText($"[grey]({Markup.Escape(CliCommandStrings.RunCommandMoreFrameworksText)})[/]") | ||
| .AddChoices(frameworks) | ||
| .EnableSearch() | ||
| .SearchPlaceholderText(CliCommandStrings.RunCommandSearchPlaceholderText); | ||
|
|
||
| return Spectre.Console.AnsiConsole.Prompt(prompt); | ||
jonathanpeppers marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| catch (Exception) | ||
| { | ||
| // If Spectre.Console fails (e.g., terminal doesn't support it), return null | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.