Skip to content

Watch aspire#53192

Open
tmat wants to merge 9 commits intodotnet:release/10.0.3xxfrom
tmat:WatchAspire
Open

Watch aspire#53192
tmat wants to merge 9 commits intodotnet:release/10.0.3xxfrom
tmat:WatchAspire

Conversation

@tmat
Copy link
Member

@tmat tmat commented Feb 27, 2026

Test parallelization, improved diagnostics and robustness

Refactors test utilities for watching processes to simplify the implementation and make it more robust against potential race conditions.
All dotnet watch tests now run in ~2 minutes on a 48-core machine utilizing all cores most of the time.

Fixes #50228

Adds more functionality to Aspire.Watch CLI tool to support polyglot Aspire

Aspire invokes it via CLI. 3 CLI commands are currently available: host, server and resource.

  1. host runs AppHost like an ordinary dotnet watch command:
Watch.Aspire host
 --sdk C:\Program Files\dotnet\sdk\10.0.102
  1. server runs Hot Reload server and you pass it a set of C# resource projects or .cs files for file-based apps. It also takes a unique named pipe name to listen on:
Watch.Aspire server
 --sdk C:\Program Files\dotnet\sdk\10.0.102
 --server NamedPipe_Server
 --resource AspireApp\AspireApp.ApiService\AspireApp.ApiService.csproj 
 --resource AspireApp\AspireApp.Web.cs
 --status-pipe NamedPipe_Status
 --control-pipe NamedPipe_Control

Optionally, it accepts --status-pipe and -control-pipe. The former is used to send select event messages to AppHost, the latter allows the AppHost to restart a select project (or potentially issue other commands in future). See below.

  1. resource launches a resource project:
Watch.Aspire resource 
  --server NamedPipe_Server
  --entrypoint AspireApp\AspireApp.ApiService\AspireApp.ApiService.csproj

Watch.Aspire resource 
  --server NamedPipe_Server
  --entrypoint AspireApp\AspireApp.Web.cs

This command also takes parameters like --environment, --launch-profile, etc.
It sends request to launch an app to the server.

Status events (Watch Server → AppHost):
The watch server reports lifecycle events back to the AppHost over a named pipe (--status-pipe). The AppHost uses these to update resource states in the Dashboard:

  • building / build_complete (with success/failure)
  • hot_reload_applied
  • restarting
  • process_started / process_exited (with exit code)

Control commands (AppHost → Watch Server):
The AppHost sends commands to the watch server over a named pipe (--control-pipe):

  • rebuild — triggers a forced rebuild and restart for specific projects

@tmat tmat force-pushed the WatchAspire branch 2 times, most recently from c0503a9 to 7e292e1 Compare March 3, 2026 01:35
@tmat tmat marked this pull request as ready for review March 3, 2026 01:35
@tmat tmat requested review from a team as code owners March 3, 2026 01:35
Copilot AI review requested due to automatic review settings March 3, 2026 01:35
@tmat tmat requested a review from a team as a code owner March 3, 2026 01:35
@tmat
Copy link
Member Author

tmat commented Mar 3, 2026

@DustinCampbell 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 refactors dotnet watch’s test infrastructure to enable high-parallel test execution with improved diagnostics/robustness, and extends the Watch.Aspire CLI/tooling to support Aspire’s polyglot watch scenarios via host, server, and resource commands (named-pipe based coordination + status/control channels).

Changes:

  • Reworks watch test utilities (process/output/event observation) and redistributes tests to run safely in parallel.
  • Introduces/expands Aspire watch CLI launchers and server/resource orchestration, including status/control pipe messaging.
  • Updates watch logging/environment plumbing (log prefixes, muxer path derivation from SDK directory, notification-only log events).

Reviewed changes

Copilot reviewed 92 out of 93 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
test/dotnet-watch.Tests/Watch/NoDepsAppTests.cs Removed; tests moved/rewritten under new file-update suite.
test/dotnet-watch.Tests/Watch/GlobbingAppTests.cs Adjusts output assertions to new process/output utilities.
test/dotnet-watch.Tests/Watch/FileUpdateTests.cs New file-change restart coverage using updated output waiting APIs.
test/dotnet-watch.Tests/TestUtilities/TestRuntimeProcessLauncher.cs Adds Launch helper to align with in-proc watcher and restart semantics.
test/dotnet-watch.Tests/TestUtilities/TestReporter.cs Simplifies reporter behavior; shifts event observation out of reporter.
test/dotnet-watch.Tests/TestUtilities/TestOptions.cs Environment options now derive SDK dir and log prefix; removes muxerPath param.
test/dotnet-watch.Tests/TestUtilities/TestObservableLoggerFactory.cs New: observes EventIds during logging for deterministic test signaling.
test/dotnet-watch.Tests/TestUtilities/TestEventObserver.cs New: event-to-action registry for semaphores/actions.
test/dotnet-watch.Tests/TestUtilities/MockFileSetFactory.cs Updates environment options call-site.
test/dotnet-watch.Tests/TestUtilities/InProcTestWatcher.cs New: shared in-proc watcher harness for tests.
test/dotnet-watch.Tests/TestUtilities/InProcBuildTestCollection.cs Removed; replaced by explicit build semaphore usage.
test/dotnet-watch.Tests/TestUtilities/DotNetWatchTestBase.cs Base test now uses WatchableApp factory + adds in-proc watcher creation.
test/dotnet-watch.Tests/HotReload/SourceFileUpdateTests.cs Removes scenarios moved into a dedicated file.
test/dotnet-watch.Tests/HotReload/SourceFileUpdateTests.HotReloadNotSupported.cs New split-out suite for “hot reload not supported” scenarios.
test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs Refactored to use shared in-proc watcher + observer-based signaling.
test/dotnet-watch.Tests/HotReload/ProjectUpdateInProcTests.cs New in-proc coverage for project+source updates.
test/dotnet-watch.Tests/HotReload/FileExclusionTests.cs New in-proc coverage for file exclusion/ignored changes.
test/dotnet-watch.Tests/HotReload/CtrlRTests.cs New in-proc coverage for Ctrl+R behaviors.
test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs Updates environment options call-site.
test/dotnet-watch.Tests/HotReload/AspireHotReloadTests.cs Adjusts build-message assertions and shutdown expectations.
test/dotnet-watch.Tests/ConsoleReporterTests.cs Updates ConsoleReporter ctor to accept explicit log prefix.
test/dotnet-watch.Tests/CommandLine/SubcommandTests.cs New tests for subcommand behaviors (test/build/msbuild/pack/publish/format).
test/dotnet-watch.Tests/CommandLine/ProgramTests.cs Uses observable logger factory + updated output completion waiting.
test/dotnet-watch.Tests/CommandLine/ProgramTests.HostArguments.cs New split-out suite for host-argument parsing cases.
test/dotnet-watch.Tests/CommandLine/ProgramTests.Arguments.cs New split-out suite for argument forwarding/launch settings cases.
test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs Updates arg plumbing (WatchArgs) and output wait API.
test/dotnet-watch.Tests/CommandLine/BinaryLoggerTests.cs Uses build semaphore to avoid in-proc MSBuild concurrency issues.
test/dotnet-watch.Tests/Build/EvaluationTests.cs Updates env options + improves test asset identifier uniqueness.
test/dotnet-new.IntegrationTests/TemplateEngineSamplesTest.cs Env var dictionary now allows nullable values to match framework changes.
test/dotnet-new.IntegrationTests/DotnetClassTemplateTests.cs Same nullable env var dictionary update.
test/dotnet-new.IntegrationTests/CommonTemplatesTests.cs Same nullable env var dictionary update.
test/Microsoft.NET.TestFramework/ToolsetInfo.cs AddTestEnvironmentVariables now accepts nullable values.
test/Microsoft.NET.TestFramework/TestContext.cs AddTestEnvironmentVariables now accepts nullable values.
test/Microsoft.NET.TestFramework/Commands/SdkCommandSpec.cs Environment dictionary now stores nullable values.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Utilities/PipeUtilities.cs New helper to read JSONL status events from a named pipe.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/Microsoft.DotNet.HotReload.Watch.Aspire.Tests.csproj Adds Moq dependency.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/DotNetWatchOptionsTests.cs Removed; superseded by new Aspire launcher CLI parsing tests.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/DotNetWatchLauncherTests.cs Removed; replaced by new integration-style launcher tests.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireServerLauncherCliTests.cs New: server CLI parsing tests.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireResourceLauncherCliTests.cs New: resource CLI parsing tests (env vars, launch profile, args).
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireLauncherTests.cs New: end-to-end host/server/resource orchestration tests.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherTests.cs New: host launcher option construction tests.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/AspireHostLauncherCliTests.cs New: host CLI parsing tests.
test/Microsoft.DotNet.HotReload.Test.Utilities/WatchableApp.cs Refactors process launch + output waiting; moves to async disposal.
test/Microsoft.DotNet.HotReload.Test.Utilities/WatchSdkTest.cs New shared base for SDK-backed watch tests.
test/Microsoft.DotNet.HotReload.Test.Utilities/TestLogger.cs Ignores LogLevel.None to support notification-only events.
test/Microsoft.DotNet.HotReload.Test.Utilities/DebugTestOutputLogger.cs Makes output robust against disposed test output helper.
test/Microsoft.DotNet.HotReload.Test.Utilities/AwaitableProcess.cs Refactors output capture to Channels + async disposal.
src/Microsoft.CodeAnalysis.NetAnalyzers/src/Microsoft.CodeAnalysis.NetAnalyzers.sarif Formatting/EOF adjustment.
src/Dotnet.Watch/dotnet-watch/dotnet-watch.csproj Simplifies published input file list for testhost publishing.
src/Dotnet.Watch/dotnet-watch/Watch/MsBuildFileSetFactory.cs Uses EnvironmentOptions.GetMuxerPath().
src/Dotnet.Watch/dotnet-watch/Watch/DotNetWatcher.cs Uses EnvironmentOptions.GetMuxerPath().
src/Dotnet.Watch/dotnet-watch/Program.cs Centralizes log prefix + SDK-based env options; logger factory signature generalized.
src/Dotnet.Watch/Watch/UI/IReporter.cs Adds configurable log prefix and notification-only message descriptors.
src/Dotnet.Watch/Watch/UI/ConsoleReporter.cs Accepts configurable log prefix.
src/Dotnet.Watch/Watch/Process/RunningProject.cs Moves restart behavior into RestartAsync() and adds restart logging.
src/Dotnet.Watch/Watch/Process/ProjectLauncher.cs Exposes CompilationHandler; uses log prefix for client logger env var.
src/Dotnet.Watch/Watch/Microsoft.DotNet.HotReload.Watch.csproj Switches ProjectTools reference to configurable path + conditional package ref.
src/Dotnet.Watch/Watch/HotReload/HotReloadDotNetWatcher.cs Adds build notifications; refactors multi-project build and logs.
src/Dotnet.Watch/Watch/HotReload/CompilationHandler.cs OS-specific path comparer; adds status notifications; adds restart helper.
src/Dotnet.Watch/Watch/Context/EnvironmentVariables.cs Clarifies ms-based timeout parsing + adds seconds parsing helper.
src/Dotnet.Watch/Watch/Context/EnvironmentOptions.cs Switches from muxer path to SDK directory + GetMuxerPath().
src/Dotnet.Watch/Watch/Build/ProjectRepresentation.cs Adds IsProjectFile + OS-specific equality/hash semantics.
src/Dotnet.Watch/Watch/Build/ProjectBuildManager.cs Exposes build semaphore for tests.
src/Dotnet.Watch/Watch/Aspire/AspireServiceFactory.cs Adjusts API signature for start project (no longer returns RunningProject).
src/Dotnet.Watch/Watch/AppModels/WebApplicationAppModel.cs Uses EnvironmentOptions.GetMuxerPath().
src/Dotnet.Watch/Watch.Aspire/Utilities/AspireEnvironmentVariables.cs New: reads pipe timeout (seconds) from env var.
src/Dotnet.Watch/Watch.Aspire/Server/WatchStatusWriter.cs New: sends status JSON events via named pipe.
src/Dotnet.Watch/Watch.Aspire/Server/WatchStatusEvent.cs New: status event contract.
src/Dotnet.Watch/Watch.Aspire/Server/WatchControlReader.cs New: receives control commands and triggers targeted rebuild/restart.
src/Dotnet.Watch/Watch.Aspire/Server/WatchControlCommand.cs New: control command contract.
src/Dotnet.Watch/Watch.Aspire/Server/StatusReportingLoggerFactory.cs New: maps internal log notifications to status events.
src/Dotnet.Watch/Watch.Aspire/Server/ProcessLauncherFactory.cs New: server-side resource request handling + output proxying.
src/Dotnet.Watch/Watch.Aspire/Server/AspireWatcherLauncher.cs New: common launcher base for hosting watch server/host.
src/Dotnet.Watch/Watch.Aspire/Server/AspireServerLauncher.cs New: server command launcher wiring (status/control pipe).
src/Dotnet.Watch/Watch.Aspire/Resource/LaunchResourceRequest.cs New: resource launch request contract.
src/Dotnet.Watch/Watch.Aspire/Resource/AspireResourceLauncher.cs New: resource command client (connect/send request/proxy output).
src/Dotnet.Watch/Watch.Aspire/Program.cs Switches to new AspireLauncher command model + robust exception handling.
src/Dotnet.Watch/Watch.Aspire/Microsoft.DotNet.HotReload.Watch.Aspire.csproj Adds MSBuild packages needed for registration/loading.
src/Dotnet.Watch/Watch.Aspire/Host/AspireHostLauncher.cs New: host launcher building main project options.
src/Dotnet.Watch/Watch.Aspire/DotNetWatchOptions.cs Removed legacy parsing/options type.
src/Dotnet.Watch/Watch.Aspire/DotNetWatchLauncher.cs Removed legacy launcher wrapper.
src/Dotnet.Watch/Watch.Aspire/Commands/OptionExtensions.cs New: option presence helper.
src/Dotnet.Watch/Watch.Aspire/Commands/AspireServerCommandDefinition.cs New: server command/option definitions.
src/Dotnet.Watch/Watch.Aspire/Commands/AspireRootCommand.cs New: root command composing host/server/resource.
src/Dotnet.Watch/Watch.Aspire/Commands/AspireResourceCommandDefinition.cs New: resource command/option definitions + env var parsing.
src/Dotnet.Watch/Watch.Aspire/Commands/AspireHostCommandDefinition.cs New: host command/option definitions.
src/Dotnet.Watch/Watch.Aspire/Commands/AspireCommandDefinition.cs New: shared quiet/verbose validation + log level selection.
src/Dotnet.Watch/Watch.Aspire/AspireLauncher.cs New: parsing + launcher dispatch for Aspire tool.
src/Dotnet.Watch/HotReloadClient/NamedPipeClientTransport.cs Improves log message formatting.
src/Dotnet.Watch/HotReloadClient/DefaultHotReloadClient.cs Logs full exception for response read failures.
src/Dotnet.Watch/Directory.Build.props New: sets ProjectToolsProjectDir for Watch solution builds.
src/Dotnet.Watch/.editorconfig New: suppresses analyzer/style warnings for Watch solution.

=> new Logger(writer, underlyingFactory.CreateLogger(categoryName));

public void AddProvider(ILoggerProvider provider)
=> throw new NotImplementedException();
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

ILoggerFactory.AddProvider throws NotImplementedException. If any code path adds providers to this factory (directly or via logging infrastructure), it will crash at runtime. Consider delegating to the underlying factory (or at least implementing this as a no-op if provider addition is intentionally unsupported).

Suggested change
=> throw new NotImplementedException();
{
underlyingFactory.AddProvider(provider);
}

Copilot uses AI. Check for mistakes.
@tmat tmat added Area-Watch dotnet-watch and removed Area-Infrastructure labels Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Watch dotnet-watch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants