[dotnet-watch] Add device selection support#53631
[dotnet-watch] Add device selection support#53631jonathanpeppers wants to merge 9 commits intorelease/10.0.3xxfrom
Conversation
Adds device selection to dotnet-watch for MAUI/mobile scenarios, mirroring the dotnet-run device selection flow from the spec (documentation/specs/dotnet-run-for-maui.md). Merged TargetFrameworkSelectionPrompt and the new device prompt into a single WatchSelectionPrompt (library) / SpectreWatchSelectionPrompt (console app), keeping Spectre.Console isolated to the console app project and avoiding a second constructor parameter on HotReloadDotNetWatcher. After TFM selection, HotReloadDotNetWatcher calls the ComputeAvailableDevices MSBuild target via in-process MSBuild. A single device is auto-selected; multiple devices show an interactive Spectre prompt with search. The selected device and its RuntimeIdentifier are passed to dotnet build (-p:Device, -p:RuntimeIdentifier) and to the launched dotnet run subprocess (--device). A re-restore is performed when the device provides a RuntimeIdentifier not present in the original restore. Adds --device CLI option to dotnet-watch for pre-specifying a device. Tests: - Unit tests for prompt selection, search, caching, and FormatDevice - E2e tests using DotnetRunDevices test asset: interactive device selection, single-device auto-select Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds MAUI/mobile-oriented device selection to dotnet-watch Hot Reload, aligning the watch experience with the dotnet run device-selection spec by computing devices via MSBuild and prompting (when needed) through a Spectre.Console-based UI.
Changes:
- Introduces a unified selection prompt abstraction (
WatchSelectionPrompt) for both target framework and device selection, with a Spectre.Console implementation for interactive console scenarios. - Extends
HotReloadDotNetWatcherto invokeComputeAvailableDevices, auto-select a single device, prompt when multiple devices are available, and flow device/RID into build + run. - Adds
--devicetodotnet-watch, updates resources/localization, and adds unit + E2E coverage for device selection prompting/formatting.
Reviewed changes
Copilot reviewed 32 out of 32 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/dotnet-watch.Tests/TestUtilities/NoOpWatchSelectionPrompt.cs | Adds a non-interactive prompt implementation for tests. |
| test/dotnet-watch.Tests/TestUtilities/DotNetWatchTestBase.cs | Updates watcher construction to use WatchSelectionPrompt. |
| test/dotnet-watch.Tests/HotReload/WatchSelectionPromptTests.cs | New unit tests covering framework/device selection, search, caching, and device formatting. |
| test/dotnet-watch.Tests/HotReload/TargetFrameworkSelectionPromptTests.cs | Removes old prompt-specific tests after prompt unification. |
| test/dotnet-watch.Tests/HotReload/MauiHotReloadTests.cs | Adds E2E tests for interactive device selection and single-device auto-select. |
| test/dotnet-watch.Tests/HotReload/BuildProjectsTests.cs | Updates tests for new watcher signature and new deviceSelector parameter. |
| src/Dotnet.Watch/Watch/UI/WatchSelectionPrompt.cs | New shared abstraction for framework + device selection with cached selections. |
| src/Dotnet.Watch/Watch/UI/TargetFrameworkSelectionPrompt.cs | Removes superseded framework-only prompt abstraction. |
| src/Dotnet.Watch/Watch/UI/IReporter.cs | Adds a new message descriptor related to device availability. |
| src/Dotnet.Watch/Watch/UI/DeviceInfo.cs | Adds a record representing device metadata coming from MSBuild. |
| src/Dotnet.Watch/Watch/Process/ProjectLauncher.cs | Passes selected device/RID into the launched dotnet run invocation. |
| src/Dotnet.Watch/Watch/HotReload/HotReloadDotNetWatcher.cs | Implements MSBuild-driven device discovery/selection and flows results into build pipeline. |
| src/Dotnet.Watch/Watch/Context/ProjectOptions.cs | Adds Device and DeviceRuntimeIdentifier to project launch/build options. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.zh-Hant.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.zh-Hans.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.tr.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.ru.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.pt-BR.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.pl.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.ko.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.ja.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.it.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.fr.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.es.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.de.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/xlf/Resources.cs.xlf | Localization updates for new device-related strings. |
| src/Dotnet.Watch/dotnet-watch/Watch/BuildEvaluator.cs | Ensures --device is included in the evaluated run arguments. |
| src/Dotnet.Watch/dotnet-watch/UI/SpectreWatchSelectionPrompt.cs | Implements interactive Spectre prompt for framework + device selection. |
| src/Dotnet.Watch/dotnet-watch/Resources.resx | Adds new device prompt/help strings. |
| src/Dotnet.Watch/dotnet-watch/Program.cs | Switches to the unified selection prompt for Hot Reload runs. |
| src/Dotnet.Watch/dotnet-watch/CommandLine/DotnetWatchCommandDefinition.cs | Adds the --device root option to dotnet-watch. |
| src/Dotnet.Watch/dotnet-watch/CommandLine/CommandLineOptions.cs | Parses --device into CommandLineOptions and flows into ProjectOptions. |
| var needsFrameworkSelection = targetFramework == null && frameworkSelector != null; | ||
| var needsDeviceSelection = mainProjectOptions?.Device == null && deviceSelector != null; | ||
|
|
||
| if (mainProjectOptions == null || | ||
| frameworkSelector == null || | ||
| targetFramework != null || | ||
| (!needsFrameworkSelection && !needsDeviceSelection) || | ||
| !mainProjectOptions.Representation.IsProjectFile) |
There was a problem hiding this comment.
When --device is specified on the command line, mainProjectOptions.Device is non-null so device computation/selection is skipped and selectedDevice remains null. As a result, the subsequent build/restore invocations won’t get -p:Device=... (and no RID discovery/re-restore can happen), which breaks the intended “pre-specified device” flow. Consider treating an explicitly provided device as a pre-selection: run ComputeAvailableDevices to validate/resolve the matching device (including RuntimeIdentifier), set selectedDevice, and pass it into the build/restore path (including the re-restore when the RID is new).
There was a problem hiding this comment.
That is one thing we don't do for dotnet run either. If someone passes --device, we just use it and don't compute the RuntimeIdentifier.
I think it is OK for now; we haven't found a place you would need this -- you can pass -r.
- Fix Aspire build: update HotReloadDotNetWatcher constructor call - Make WatchSelectionPrompt nullable; Aspire and tests pass null - Remove NoPromptWatchSelectionPrompt and NoOpWatchSelectionPrompt - Zero devices now propagates failure instead of silently continuing - Fix stale XML doc on TrySelectDeviceAsync Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rename WatchSelectionPrompt to BuildParametersSelectionPrompt - Use needsFrameworkSelection/needsDeviceSelection variables in selection blocks - Use LoadedProjectGraph.TryGetProjectNode + DeepCopy instead of creating a new ProjectInstance - Use ProjectBuildManager for building ComputeAvailableDevices target - Move ComputeAvailableDevices constant to TargetNames Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirror the targetFramework pattern: selectedDevice and selectedDeviceRuntimeIdentifier are now string? variables initialized from CLI options, making needsDeviceSelection consistent with needsFrameworkSelection. BuildProjectsResult carries string? fields instead of DeviceInfo?. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use the proper CLI option for passing RuntimeIdentifier to build, restore, and run subprocesses. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Inline the null checks from needsFrameworkSelection/needsDeviceSelection directly into the if conditions so the compiler can see the narrowing without needing is not null guards or ! operators. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds device selection to dotnet-watch for MAUI/mobile scenarios, mirroring the
dotnet-rundevice selection flow from the spec (documentation/specs/dotnet-run-for-maui.md).Merged
TargetFrameworkSelectionPromptand the new device prompt into a singleWatchSelectionPrompt(library) /SpectreWatchSelectionPrompt(console app), keeping Spectre.Console isolated to the console app project.After TFM selection,
HotReloadDotNetWatchercalls theComputeAvailableDevicesMSBuild target via in-process MSBuild. A single device is auto-selected; multiple devices show an interactive Spectre prompt with search. The selected device and itsRuntimeIdentifierare passed todotnet build(-p:Device,-p:RuntimeIdentifier) and to the launched dotnet run subprocess (--device). A re-restore is performed when the device provides aRuntimeIdentifiernot present in the original restore.Adds
--deviceCLI option todotnet-watchfor pre-specifying a device.Tests:
FormatDeviceDotnetRunDevicestest asset: interactive device selection, single-device auto-select