Implements target framework selection for multi-targeted projects#53466
Implements target framework selection for multi-targeted projects#53466tmat wants to merge 3 commits intodotnet:release/10.0.3xxfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates dotnet watch to handle target framework selection for multi-targeted projects by treating --framework/-f as a watch-specific option (not auto-forwarded), explicitly forwarding it when invoking restore/build/run, and prompting interactively when needed after restore/project-graph load.
Changes:
- Reworked watch/build pipeline to restore first, then load the project graph to detect multi-targeting and select a TFM, then build with
--no-restore. - Added a simple interactive target framework selection prompt and updated console input handling to support numeric selection.
- Updated Hot Reload/logging behavior to operate on inner-build project nodes (TFM-specific instances) and include project display names in diagnostics.
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| test/dotnet-watch.Tests/Watch/NoRestoreTests.cs | Updates assertions to expect explicit --framework forwarding. |
| test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs | Adjusts context setup for removal of context-level TargetFramework. |
| test/dotnet-watch.Tests/TestUtilities/TestProcessRunner.cs | Allows falling back to base runner if no custom impl is provided. |
| test/dotnet-watch.Tests/TestUtilities/TestOptions.cs | Updates ProjectRepresentation creation to handle --file scenarios. |
| test/dotnet-watch.Tests/TestUtilities/TestConsole.cs | Adds queued key support to avoid prompt/keypress race in tests. |
| test/dotnet-watch.Tests/HotReload/TargetFrameworkSelectionPromptTests.cs | New tests for framework selection prompt state/behavior. |
| test/dotnet-watch.Tests/HotReload/SourceFileUpdateTests.cs | Updates expected message when build fails. |
| test/dotnet-watch.Tests/HotReload/SourceFileUpdateTests.HotReloadNotSupported.cs | Updates output expectations to include project display prefix. |
| test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs | Switches trigger to new “runtime launcher created” notification. |
| test/dotnet-watch.Tests/HotReload/ProjectUpdateTests.cs | Updates output expectations to include project display prefix. |
| test/dotnet-watch.Tests/HotReload/MauiHotReloadTests.cs | Adds coverage for interactive TFM selection behavior and verifies only selected TFM is built. |
| test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs | Updates ProjectGraphFactory parameter naming and context changes. |
| test/dotnet-watch.Tests/HotReload/BuildProjectsTests.cs | Refactors tests to validate restore/build sequencing and TFM selection. |
| test/dotnet-watch.Tests/HotReload/AutoRestartTests.cs | Updates assertions for project display prefixes and message descriptors. |
| test/dotnet-watch.Tests/HotReload/AspireHotReloadTests.cs | Updates assertions for project display prefixes in Aspire scenarios. |
| test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs | Runs iteration env-var test in both Hot Reload and non-HR modes. |
| test/dotnet-watch.Tests/CommandLine/CommandLineOptionsTests.cs | Updates expected forwarding behavior (no longer forwarding --framework as a property). |
| test/dotnet-watch.Tests/Build/ProjectGraphFactoryTests.cs | Updates ProjectGraphFactory parameter naming. |
| test/dotnet-watch.Tests/Browser/BrowserTests.cs | Updates rude-edit diagnostic expectations to include project display prefix. |
| src/Dotnet.Watch/dotnet-watch/Watch/StaticFileHandler.cs | Switches to graph helper API for resolving project nodes. |
| src/Dotnet.Watch/dotnet-watch/Watch/BuildEvaluator.cs | Explicitly injects --framework into subcommand invocation args. |
| src/Dotnet.Watch/dotnet-watch/Program.cs | Removes context-level TargetFramework assignment. |
| src/Dotnet.Watch/dotnet-watch/CommandLine/DotnetWatchCommandDefinition.cs | Adds watch-level --framework/-f option and updates watch-option classification. |
| src/Dotnet.Watch/dotnet-watch/CommandLine/CommandLineOptions.cs | Stops auto-forwarding --framework; plumbs it into ProjectOptions.TargetFramework. |
| src/Dotnet.Watch/Watch/UI/TargetFrameworkSelectionPrompt.cs | New prompt component to select a TFM interactively. |
| src/Dotnet.Watch/Watch/UI/RestartPrompt.cs | Updates input handling to consume ConsoleKeyInfo. |
| src/Dotnet.Watch/Watch/UI/PhysicalConsole.cs | Adds numeric key mapping for prompt input. |
| src/Dotnet.Watch/Watch/UI/IReporter.cs | Adds new message descriptors/events and adjusts diagnostic formatting. |
| src/Dotnet.Watch/Watch/UI/ConsoleInputReader.cs | Returns ConsoleKeyInfo to preserve key char and modifiers. |
| src/Dotnet.Watch/Watch/Process/RunningProject.cs | Exposes running project TFM via helper method. |
| src/Dotnet.Watch/Watch/Process/ProjectLauncher.cs | Explicitly forwards --framework to the launched command. |
| src/Dotnet.Watch/Watch/HotReload/HotReloadDotNetWatcher.cs | Major refactor: restore->graph load->TFM select->build; updated evaluation/rebuild flow. |
| src/Dotnet.Watch/Watch/HotReload/CompilationHandler.cs | Associates rude-edit diagnostics with project display and updates running-project mapping. |
| src/Dotnet.Watch/Watch/Context/ProjectOptions.cs | Adds TargetFramework to per-project launch options. |
| src/Dotnet.Watch/Watch/Context/DotNetWatchContext.cs | Removes context-level TargetFramework in favor of per-project option. |
| src/Dotnet.Watch/Watch/Build/ProjectGraphUtilities.cs | Adds graph-node helpers and excludes outer-build nodes in traversal. |
| src/Dotnet.Watch/Watch/Build/ProjectGraphFactory.cs | Renames parameter for virtual-project TFM; adds graph load timing log. |
| src/Dotnet.Watch/Watch/Build/LoadedProjectGraph.cs | Stores only inner-build nodes and exposes build-file set. |
| src/Dotnet.Watch/Watch/Build/EvaluationResult.cs | Adjusts evaluation API to accept a pre-loaded graph and filter by selected root TFM. |
| src/Dotnet.Watch/Watch.Aspire/Server/AspireWatcherLauncher.cs | Removes context-level TargetFramework wiring. |
| src/Dotnet.Watch/HotReloadClient/Web/StaticWebAssetsManifest.cs | Uses structured log event for missing manifest file. |
| src/Dotnet.Watch/HotReloadClient/Logging/LogEvents.cs | Adds new ManifestFileNotFound log event. |
test/dotnet-watch.Tests/HotReload/SourceFileUpdateTests.HotReloadNotSupported.cs
Outdated
Show resolved
Hide resolved
src/Dotnet.Watch/dotnet-watch/CommandLine/DotnetWatchCommandDefinition.cs
Show resolved
Hide resolved
jonathanpeppers
left a comment
There was a problem hiding this comment.
Looks good, but I wonder about the project references, where $(TargetFramework) wouldn't match exactly.
src/Dotnet.Watch/dotnet-watch/CommandLine/DotnetWatchCommandDefinition.cs
Show resolved
Hide resolved
| // msbuild workspace doesn't set TFM if the project is not multi-targeted | ||
| var tfm = HotReloadService.GetTargetFramework(project); |
There was a problem hiding this comment.
Is this a Roslyn bug that should be fixed?
There was a problem hiding this comment.
Not a bug. Currently it's in the project name set by the project system and we regex match it. For single-TFM project the project system doesn't even pass us the TFM.
It'd be certainly better if the project system always passed us TFM as a separate property and it was a first class property of Roslyn's Project type.
There was a problem hiding this comment.
I have wanted that recently too (dotnet/roslyn#82102)
There was a problem hiding this comment.
Nice. It's possible you might need to change project system.
See tests in 135c143 |
Change command line parsing to treat
--frameworkoption as watch-specific option, not auto-forwarded to a subcommand or build. Forward the option explicitly when invoking the subcommand/build.Refactor
BuildProjectsAsyncto allow for target framework detection. If--frameworkis not specified, we do not know whether a project is multi-targeting until we load it. We can only load it correctly after it's been restored. We do not want to load it multiple times.Therefore, split the build to 3 steps:
dotnet restoreon project graph roots,dotnet build --no-restoreon project graph roots.Add
TargetFrameworkSelectionPrompt, which implements a simple framework selection TUI. This will be replaced in future with more sophisticated UI used bydotnet run.Update all operations (except for restore) on a project graph to ignore outer-build project nodes. Only work with instances with
TargetFrameworkset.For multi-targeted root projects only consider instances with
TargetFrameworkthat matches the framework given on command line via--frameworkoption, or manually selected.Include project display name in rude edit messages.