-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Watch Aspire #53192
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
Merged
Merged
Watch Aspire #53192
Changes from 10 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
cd06b7f
InProcTestWatcher
tmat 00e01fa
Split tests
tmat f8ba229
Set up auto-dump collection, fixes
tmat 7d29675
Make it easier to sync code between SDK and Aspire repos
tmat 0fd7f00
Implement support for polyglot Aspire Watch
tmat 395c484
Simplify AwaitableProcess implementation and move event observing out…
tmat 1ba3c11
Fixes
tmat 3a56524
Copilot feedback
tmat 520d742
Fix
tmat 0cd3ea1
Drain channel after process exits
tmat 196615f
Feedback
tmat fe85dd0
Skip
tmat bd7e6a0
Fix tests
tmat b9018a3
Skip
tmat 28aa4d9
Skip
tmat 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # EditorConfig to suppress warnings/errors for Watch solution | ||
|
|
||
| root = false | ||
|
|
||
| [*.cs] | ||
| # CA - Code Analysis warnings | ||
| dotnet_diagnostic.CA1305.severity = none # Specify IFormatProvider | ||
| dotnet_diagnostic.CA1822.severity = none # Mark members as static | ||
| dotnet_diagnostic.CA1835.severity = none # Prefer Memory-based overloads for ReadAsync/WriteAsync | ||
| dotnet_diagnostic.CA1852.severity = none # Seal internal types | ||
| dotnet_diagnostic.CA2007.severity = none # Do not directly await a Task | ||
| dotnet_diagnostic.CA2201.severity = none # Do not raise reserved exception types | ||
| dotnet_diagnostic.CA2008.severity = none # Do not create tasks without passing a TaskScheduler | ||
|
|
||
| # CS - C# compiler warnings/errors | ||
| dotnet_diagnostic.CS1591.severity = none # Missing XML comment for publicly visible type or member | ||
| dotnet_diagnostic.CS1573.severity = none # Parameter 'sourceFile' has no matching param tag in the XML comment | ||
|
|
||
| # IDE - IDE/Style warnings | ||
| dotnet_diagnostic.IDE0005.severity = none # Using directive is unnecessary | ||
| dotnet_diagnostic.IDE0011.severity = none # Add braces | ||
| dotnet_diagnostic.IDE0036.severity = none # Order modifiers | ||
| dotnet_diagnostic.IDE0060.severity = none # Remove unused parameter | ||
| dotnet_diagnostic.IDE0073.severity = none # File header does not match required text | ||
| dotnet_diagnostic.IDE0161.severity = none # Convert to file-scoped namespace | ||
| dotnet_diagnostic.IDE1006.severity = none # Naming rule violation |
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,6 @@ | ||
| <Project> | ||
| <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" /> | ||
| <PropertyGroup> | ||
| <ProjectToolsProjectDir>$(RepoRoot)src\Microsoft.DotNet.ProjectTools\</ProjectToolsProjectDir> | ||
| </PropertyGroup> | ||
| </Project> |
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,52 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Microsoft.DotNet.Watch; | ||
|
|
||
| internal abstract class AspireLauncher | ||
| { | ||
| public EnvironmentOptions EnvironmentOptions { get; } | ||
| public GlobalOptions GlobalOptions { get; } | ||
| public PhysicalConsole Console { get; } | ||
| public ConsoleReporter Reporter { get; } | ||
| public LoggerFactory LoggerFactory { get; } | ||
| public ILogger Logger { get; } | ||
|
|
||
| public AspireLauncher(GlobalOptions globalOptions, EnvironmentOptions environmentOptions) | ||
| { | ||
| GlobalOptions = globalOptions; | ||
| EnvironmentOptions = environmentOptions; | ||
| Console = new PhysicalConsole(environmentOptions.TestFlags); | ||
| Reporter = new ConsoleReporter(Console, environmentOptions.LogMessagePrefix, environmentOptions.SuppressEmojis); | ||
| LoggerFactory = new LoggerFactory(Reporter, environmentOptions.CliLogLevel ?? globalOptions.LogLevel); | ||
| Logger = LoggerFactory.CreateLogger(DotNetWatchContext.DefaultLogComponentName); | ||
| } | ||
|
|
||
| public static AspireLauncher? TryCreate(string[] args) | ||
| { | ||
| var rootCommand = new AspireRootCommand(); | ||
|
|
||
| var parseResult = rootCommand.Parse(args); | ||
| if (parseResult.Errors.Count > 0) | ||
| { | ||
| foreach (var error in parseResult.Errors) | ||
| { | ||
| System.Console.Error.WriteLine(error); | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| return parseResult.CommandResult.Command switch | ||
| { | ||
| AspireServerCommandDefinition serverCommand => AspireServerLauncher.TryCreate(parseResult, serverCommand), | ||
| AspireResourceCommandDefinition resourceCommand => AspireResourceLauncher.TryCreate(parseResult, resourceCommand), | ||
| AspireHostCommandDefinition hostCommand => AspireHostLauncher.TryCreate(parseResult, hostCommand), | ||
| _ => throw new InvalidOperationException(), | ||
| }; | ||
| } | ||
|
|
||
| public abstract Task<int> LaunchAsync(CancellationToken cancellationToken); | ||
| } |
31 changes: 31 additions & 0 deletions
31
src/Dotnet.Watch/Watch.Aspire/Commands/AspireCommandDefinition.cs
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,31 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.CommandLine; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Microsoft.DotNet.Watch; | ||
|
|
||
| internal abstract class AspireCommandDefinition : Command | ||
| { | ||
| public readonly Option<bool> QuietOption = new("--quiet") { Arity = ArgumentArity.Zero }; | ||
| public readonly Option<bool> VerboseOption = new("--verbose") { Arity = ArgumentArity.Zero }; | ||
|
|
||
| public AspireCommandDefinition(string name, string description) | ||
| : base(name, description) | ||
| { | ||
| Options.Add(VerboseOption); | ||
| Options.Add(QuietOption); | ||
|
|
||
| VerboseOption.Validators.Add(v => | ||
| { | ||
| if (v.HasOption(QuietOption) && v.HasOption(VerboseOption)) | ||
| { | ||
| v.AddError("Cannot specify both '--quiet' and '--verbose' options."); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| public LogLevel GetLogLevel(ParseResult parseResult) | ||
| => parseResult.GetValue(QuietOption) ? LogLevel.Warning : parseResult.GetValue(VerboseOption) ? LogLevel.Debug : LogLevel.Information; | ||
| } | ||
31 changes: 31 additions & 0 deletions
31
src/Dotnet.Watch/Watch.Aspire/Commands/AspireHostCommandDefinition.cs
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,31 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.CommandLine; | ||
|
|
||
| namespace Microsoft.DotNet.Watch; | ||
|
|
||
| internal sealed class AspireHostCommandDefinition : AspireCommandDefinition | ||
| { | ||
| public readonly Option<string> SdkOption = new("--sdk") { Arity = ArgumentArity.ExactlyOne, Required = true, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| /// <summary> | ||
| /// Project or file. | ||
| /// </summary> | ||
| public readonly Option<string> EntryPointOption = new("--entrypoint") { Arity = ArgumentArity.ExactlyOne, Required = true, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| public readonly Argument<string[]> ApplicationArguments = new("arguments") { Arity = ArgumentArity.ZeroOrMore }; | ||
| public readonly Option<bool> NoLaunchProfileOption = new("--no-launch-profile") { Arity = ArgumentArity.Zero }; | ||
| public readonly Option<string> LaunchProfileOption = new("--launch-profile", "-lp") { Arity = ArgumentArity.ExactlyOne }; | ||
|
|
||
| public AspireHostCommandDefinition() | ||
| : base("host", "Starts AppHost project.") | ||
| { | ||
| Arguments.Add(ApplicationArguments); | ||
|
|
||
| Options.Add(SdkOption); | ||
| Options.Add(EntryPointOption); | ||
| Options.Add(NoLaunchProfileOption); | ||
| Options.Add(LaunchProfileOption); | ||
| } | ||
| } |
78 changes: 78 additions & 0 deletions
78
src/Dotnet.Watch/Watch.Aspire/Commands/AspireResourceCommandDefinition.cs
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,78 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.CommandLine; | ||
| using System.CommandLine.Parsing; | ||
|
|
||
| namespace Microsoft.DotNet.Watch; | ||
|
|
||
| internal sealed class AspireResourceCommandDefinition : AspireCommandDefinition | ||
| { | ||
| public readonly Argument<string[]> ApplicationArguments = new("arguments") { Arity = ArgumentArity.ZeroOrMore }; | ||
|
|
||
| /// <summary> | ||
| /// Server pipe name. | ||
| /// </summary> | ||
| public readonly Option<string> ServerOption = new("--server") { Arity = ArgumentArity.ExactlyOne, Required = true, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| public readonly Option<string> EntryPointOption = new("--entrypoint") { Arity = ArgumentArity.ExactlyOne, Required = true, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| public readonly Option<IReadOnlyDictionary<string, string>> EnvironmentOption = new("--environment", "-e") | ||
| { | ||
| Description = "Environment variables for the process", | ||
| CustomParser = ParseEnvironmentVariables, | ||
| AllowMultipleArgumentsPerToken = false | ||
| }; | ||
|
|
||
| public readonly Option<bool> NoLaunchProfileOption = new("--no-launch-profile") { Arity = ArgumentArity.Zero }; | ||
| public readonly Option<string> LaunchProfileOption = new("--launch-profile", "-lp") { Arity = ArgumentArity.ExactlyOne }; | ||
|
|
||
| public AspireResourceCommandDefinition() | ||
| : base("resource", "Starts resource project.") | ||
| { | ||
| Arguments.Add(ApplicationArguments); | ||
|
|
||
| Options.Add(ServerOption); | ||
| Options.Add(EntryPointOption); | ||
| Options.Add(EnvironmentOption); | ||
| Options.Add(NoLaunchProfileOption); | ||
| Options.Add(LaunchProfileOption); | ||
| } | ||
|
|
||
| private static IReadOnlyDictionary<string, string> ParseEnvironmentVariables(ArgumentResult argumentResult) | ||
| { | ||
| var result = new Dictionary<string, string>( | ||
| RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); | ||
|
tmat marked this conversation as resolved.
Outdated
|
||
|
|
||
| List<Token>? invalid = null; | ||
|
|
||
| foreach (var token in argumentResult.Tokens) | ||
| { | ||
| var separator = token.Value.IndexOf('='); | ||
| var (name, value) = (separator >= 0) | ||
| ? (token.Value[0..separator], token.Value[(separator + 1)..]) | ||
| : (token.Value, ""); | ||
|
|
||
| name = name.Trim(); | ||
|
|
||
| if (name != "") | ||
| { | ||
| result[name] = value; | ||
| } | ||
| else | ||
| { | ||
| invalid ??= []; | ||
| invalid.Add(token); | ||
| } | ||
| } | ||
|
|
||
| if (invalid != null) | ||
| { | ||
| argumentResult.AddError(string.Format( | ||
| "Incorrectly formatted environment variables {0}", | ||
| string.Join(", ", invalid.Select(x => $"'{x.Value}'")))); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
| } | ||
22 changes: 22 additions & 0 deletions
22
src/Dotnet.Watch/Watch.Aspire/Commands/AspireRootCommand.cs
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,22 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.CommandLine; | ||
|
|
||
| namespace Microsoft.DotNet.Watch; | ||
|
|
||
| internal sealed class AspireRootCommand : RootCommand | ||
| { | ||
| public readonly AspireServerCommandDefinition ServerCommand = new(); | ||
| public readonly AspireResourceCommandDefinition ResourceCommand = new(); | ||
| public readonly AspireHostCommandDefinition HostCommand = new(); | ||
|
|
||
| public AspireRootCommand() | ||
| { | ||
| Directives.Add(new EnvironmentVariablesDirective()); | ||
|
|
||
| Subcommands.Add(ServerCommand); | ||
| Subcommands.Add(ResourceCommand); | ||
| Subcommands.Add(HostCommand); | ||
| } | ||
| } |
41 changes: 41 additions & 0 deletions
41
src/Dotnet.Watch/Watch.Aspire/Commands/AspireServerCommandDefinition.cs
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,41 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.CommandLine; | ||
|
|
||
| namespace Microsoft.DotNet.Watch; | ||
|
|
||
| internal sealed class AspireServerCommandDefinition : AspireCommandDefinition | ||
| { | ||
| /// <summary> | ||
| /// Server pipe name. | ||
| /// </summary> | ||
| public readonly Option<string> ServerOption = new("--server") { Arity = ArgumentArity.ExactlyOne, Required = true, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| public readonly Option<string> SdkOption = new("--sdk") { Arity = ArgumentArity.ExactlyOne, Required = true, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| /// <summary> | ||
| /// Paths to resource projects or entry-point files. | ||
| /// </summary> | ||
| public readonly Option<string[]> ResourceOption = new("--resource") { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = true }; | ||
|
|
||
| /// <summary> | ||
| /// Status pipe name for sending watch status events back to the AppHost. | ||
| /// </summary> | ||
| public readonly Option<string?> StatusPipeOption = new("--status-pipe") { Arity = ArgumentArity.ExactlyOne, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| /// <summary> | ||
| /// Control pipe name for receiving commands from the AppHost. | ||
| /// </summary> | ||
| public readonly Option<string?> ControlPipeOption = new("--control-pipe") { Arity = ArgumentArity.ExactlyOne, AllowMultipleArgumentsPerToken = false }; | ||
|
|
||
| public AspireServerCommandDefinition() | ||
| : base("server", "Starts the dotnet watch server.") | ||
| { | ||
| Options.Add(ServerOption); | ||
| Options.Add(SdkOption); | ||
| Options.Add(ResourceOption); | ||
| Options.Add(StatusPipeOption); | ||
| Options.Add(ControlPipeOption); | ||
| } | ||
| } |
13 changes: 13 additions & 0 deletions
13
src/Dotnet.Watch/Watch.Aspire/Commands/OptionExtensions.cs
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,13 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.CommandLine; | ||
| using System.CommandLine.Parsing; | ||
|
|
||
| namespace Microsoft.DotNet.Watch; | ||
|
|
||
| internal static class OptionExtensions | ||
| { | ||
| public static bool HasOption(this SymbolResult symbolResult, Option option) | ||
| => symbolResult.GetResult(option) is OptionResult or && !or.Implicit; | ||
| } |
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.