Skip to content

Implements target framework selection for multi-targeted projects#53466

Open
tmat wants to merge 3 commits intodotnet:release/10.0.3xxfrom
tmat:TargetSelection
Open

Implements target framework selection for multi-targeted projects#53466
tmat wants to merge 3 commits intodotnet:release/10.0.3xxfrom
tmat:TargetSelection

Conversation

@tmat
Copy link
Member

@tmat tmat commented Mar 15, 2026

Change command line parsing to treat --framework option as watch-specific option, not auto-forwarded to a subcommand or build. Forward the option explicitly when invoking the subcommand/build.

Refactor BuildProjectsAsync to allow for target framework detection. If --framework is 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:

  1. dotnet restore on project graph roots,
  2. load the project graph,
  3. select target framework if the project multi-targets,
  4. dotnet build --no-restore on project graph roots.

Add TargetFrameworkSelectionPrompt, which implements a simple framework selection TUI. This will be replaced in future with more sophisticated UI used by dotnet run.

Update all operations (except for restore) on a project graph to ignore outer-build project nodes. Only work with instances with TargetFramework set.

For multi-targeted root projects only consider instances with TargetFramework that matches the framework given on command line via --framework option, or manually selected.

Include project display name in rude edit messages.

@tmat tmat force-pushed the TargetSelection branch from 833633f to 8df2c4d Compare March 15, 2026 16:28
@tmat tmat marked this pull request as ready for review March 16, 2026 15:42
@tmat tmat requested a review from a team as a code owner March 16, 2026 15:42
Copilot AI review requested due to automatic review settings March 16, 2026 15:42
@tmat
Copy link
Member Author

tmat commented Mar 16, 2026

@DustinCampbell @jonathanpeppers ptal

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

@jonathanpeppers jonathanpeppers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but I wonder about the project references, where $(TargetFramework) wouldn't match exactly.

Comment on lines +964 to +965
// msbuild workspace doesn't set TFM if the project is not multi-targeted
var tfm = HotReloadService.GetTargetFramework(project);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a Roslyn bug that should be fixed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have wanted that recently too (dotnet/roslyn#82102)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. It's possible you might need to change project system.

@tmat
Copy link
Member Author

tmat commented Mar 16, 2026

Looks good, but I wonder about the project references, where $(TargetFramework) wouldn't match exactly.

See tests in 135c143

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants