-
Notifications
You must be signed in to change notification settings - Fork 816
Dotnet Tool Integration #13168
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
Dotnet Tool Integration #13168
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
5ec4c5d
Initial plan
Copilot 257a01e
Initial playground using `dotnet tool isntall` and then running the t…
afscrome 2c67f06
Rework to use `dotnet tool exec`
afscrome f60451b
Port .NET Tool Integration from PR #13168 and fix package reference
Copilot d2a0efe
Update DotnetTool launchSettings.json to align with PR #13155 port al…
Copilot dbcb13e
Remove DotnetToolInstaller and add comprehensive tests
Copilot 926c38c
Give tools their own resource type.
afscrome 434d1d7
Format dotnet tools nicely in dashboard "source" column
afscrome 52a95ba
Remove verbosity argument.
afscrome 5673ec9
Move dotnet tool implementation to `Aspire.Hosting`
afscrome 79ff8f8
Make dotnet tool apis experimental.
afscrome e2e7a1d
Mark dotnet tool apis experimental.
afscrome fb569c9
Make secret tool example not fail.
afscrome 6efa250
Refactor to local functions to make slightly cleaner.
afscrome 6247973
Add properties to tool resources.
afscrome ebc8846
Add missing experimental supression in tests.
afscrome cedafb2
Fix formatting in tests
afscrome 0f3b1fb
Missing docs.
afscrome ca77ba1
Fix typos.
afscrome 6dab8e6
Add functional tests.
afscrome 82559b5
Refactored `StartSourceFixer` to minimise risk of calling `PublishUpd…
afscrome 7834d5e
Consistently use `ArgumentSeperator`
afscrome a58e9ac
Renamed `WithPackage*` to `WithTool*`
afscrome dde6f90
Tweaks.
afscrome d7a30ec
Remove unused package.
afscrome 96dd4ec
Small tweaks to tools
afscrome f657a5a
Merge remote-tracking branch 'upstream/main' into dotnettool
afscrome b0119ec
Back to `.` as the initial working directory.
afscrome 67e6dd5
Merge remote-tracking branch 'upstream/main' into dotnettool
afscrome c14ab62
Merge remote-tracking branch 'upstream/main' into dotnettool
afscrome c626bf5
Add first-class support for .NET tool resources
afscrome 9fb3bc5
Apply suggestions from code review
afscrome 585f3a6
More PR feedback.
afscrome 5329838
Fix rogue newline.
afscrome 6e7f288
Self review
afscrome 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
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,122 @@ | ||
| // 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.DependencyInjection; | ||
| #pragma warning disable ASPIREDOTNETTOOL // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. | ||
|
|
||
| var builder = DistributedApplication.CreateBuilder(args); | ||
|
|
||
| var simpleUsage = builder.AddDotnetTool("simpleUsage", "dotnet-ef"); | ||
|
|
||
| var wildcardVersion = builder.AddDotnetTool("wildcard", "dotnet-ef") | ||
| .WithToolVersion("10.0.*") | ||
| .WithParentRelationship(simpleUsage); | ||
|
|
||
| var preRelease = builder.AddDotnetTool("prerelease", "dotnet-ef") | ||
| .WithToolPrerelease() | ||
| .WithParentRelationship(simpleUsage); | ||
|
|
||
| // Multiple versions | ||
| var differentVersion = builder.AddDotnetTool("sameToolDifferentVersion1", "dotnet-dump") | ||
| .WithArgs("--version") | ||
| .WithToolVersion("9.0.652701"); | ||
| builder.AddDotnetTool("sameToolDifferentVersion2", "dotnet-dump") | ||
| .WithToolVersion("9.0.621003") | ||
| .WithArgs("--version") | ||
| .WithParentRelationship(differentVersion); | ||
|
|
||
| // Concurrency | ||
| IResourceBuilder<DotnetToolResource>? concurrencyParent = null; | ||
| for (int i = 0; i < 5; i++) | ||
| { | ||
| var concurrency = builder.AddDotnetTool($"sametoolconcurrency-{i}", "dotnet-trace") | ||
| .WithArgs("--version"); | ||
|
|
||
| if (concurrencyParent == null) | ||
| { | ||
| concurrencyParent = concurrency; | ||
| } | ||
| else | ||
| { | ||
| concurrency.WithParentRelationship(concurrencyParent); | ||
| } | ||
| } | ||
|
|
||
| // Substitution | ||
| var substituted = builder.AddDotnetTool("substituted", "dotnet-ef") | ||
| .WithCommand("calc") | ||
| .WithIconName("Calculator") | ||
| .WithExplicitStart(); | ||
| foreach(var toolAnnotation in substituted.Resource.Annotations.OfType<DotnetToolAnnotation>().ToList()) | ||
| { | ||
| substituted.Resource.Annotations.Remove(toolAnnotation); | ||
| } | ||
|
|
||
| // Fake Offline by using "empty" package feeds | ||
| var fakeSourcesPath = Path.Combine(Path.GetTempPath(), "does-not-exist", Guid.NewGuid().ToString()); | ||
| var offline = builder.AddDotnetTool("offlineSimpleUsage", "dotnet-ef") | ||
| .WithToolSource(fakeSourcesPath) | ||
| .WithToolIgnoreExistingFeeds() | ||
| .WithToolIgnoreFailedSources() | ||
| ; | ||
|
|
||
| builder.AddDotnetTool("offlineWildcard", "dotnet-ef") | ||
| .WithToolVersion("10.0.*") | ||
| .WithParentRelationship(offline) | ||
| .WithToolSource(fakeSourcesPath) | ||
| .WithToolIgnoreExistingFeeds() | ||
| .WithToolIgnoreFailedSources(); | ||
|
|
||
| builder.AddDotnetTool("offlinePrerelease", "dotnet-ef") | ||
| .WithToolPrerelease() | ||
| .WithParentRelationship(offline) | ||
| .WithToolSource(fakeSourcesPath) | ||
| .WithToolIgnoreExistingFeeds() | ||
| .WithToolIgnoreFailedSources(); | ||
|
|
||
| var secret = builder.AddParameter("secret", "Shhhhhhh", secret: true); | ||
|
|
||
| // Secrets | ||
| builder.AddDotnetTool("secretArg", "dotnet-ef") | ||
| .WithArgs("--version") | ||
| .WithArgs(secret); | ||
|
|
||
| // Some issues only show up when installing for first time, rather than using existing downloaded versions | ||
| // Use a specific NUGET_PACKAGES path for these playground tools, so we can easily reset them | ||
| builder.Eventing.Subscribe<BeforeStartEvent>(async (evt, _) => | ||
| { | ||
| var nugetPackagesPath = Path.Join(evt.Services.GetRequiredService<IAspireStore>().BasePath, "nuget"); | ||
|
|
||
| foreach (var resource in builder.Resources.OfType<DotnetToolResource>()) | ||
| { | ||
| builder.CreateResourceBuilder(resource) | ||
| .WithEnvironment("NUGET_PACKAGES", nugetPackagesPath) | ||
| .WithCommand("reset", "Reset Packages", ctx => | ||
| { | ||
| try | ||
| { | ||
| Directory.Delete(nugetPackagesPath, true); | ||
| return Task.FromResult(CommandResults.Success()); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| return Task.FromResult(CommandResults.Failure(ex)); | ||
| } | ||
| }, new CommandOptions | ||
| { | ||
| IconName = "Delete" | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| #if !SKIP_DASHBOARD_REFERENCE | ||
| // This project is only added in playground projects to support development/debugging | ||
| // of the dashboard. It is not required in end developer code. Comment out this code | ||
| // or build with `/p:SkipDashboardReference=true`, to test end developer | ||
| // dashboard launch experience, Refer to Directory.Build.props for the path to | ||
| // the dashboard binary (defaults to the Aspire.Dashboard bin output in the | ||
| // artifacts dir). | ||
| builder.AddProject<Projects.Aspire_Dashboard>(KnownResourceNames.AspireDashboard); | ||
| #endif | ||
|
|
||
| builder.Build().Run(); | ||
|
|
19 changes: 19 additions & 0 deletions
19
playground/DotnetTool/DotnetTool.AppHost/DotnetTool.AppHost.csproj
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,19 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>$(DefaultTargetFramework)</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| <IsAspireHost>true</IsAspireHost> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <Compile Include="$(SharedDir)KnownResourceNames.cs" Link="Utils\KnownResourceNames.cs" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <AspireProjectOrPackageReference Include="Aspire.Hosting.AppHost" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
45 changes: 45 additions & 0 deletions
45
playground/DotnetTool/DotnetTool.AppHost/Properties/launchSettings.json
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,45 @@ | ||
| { | ||
| "$schema": "http://json.schemastore.org/launchsettings.json", | ||
| "profiles": { | ||
| "https": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "https://localhost:16179;http://localhost:16180", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development", | ||
| "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:17119", | ||
| "ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "https://localhost:18036", | ||
| "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:17119", | ||
| "ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" | ||
| } | ||
| }, | ||
| "http": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "launchBrowser": true, | ||
| "applicationUrl": "http://localhost:16180", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development", | ||
| "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:17120", | ||
| "ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18037", | ||
| "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:17120", | ||
| "ASPIRE_SHOW_DASHBOARD_RESOURCES": "true", | ||
| "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true" | ||
| } | ||
| }, | ||
| "generate-manifest": { | ||
| "commandName": "Project", | ||
| "dotnetRunMessages": true, | ||
| "commandLineArgs": "--publisher manifest --output-path aspire-manifest.json", | ||
| "applicationUrl": "http://localhost:16180", | ||
| "environmentVariables": { | ||
| "ASPNETCORE_ENVIRONMENT": "Development", | ||
| "DOTNET_ENVIRONMENT": "Development", | ||
| "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:17120" | ||
| } | ||
| } | ||
| } | ||
| } | ||
8 changes: 8 additions & 0 deletions
8
playground/DotnetTool/DotnetTool.AppHost/appsettings.Development.json
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,8 @@ | ||
| { | ||
| "Logging": { | ||
| "LogLevel": { | ||
| "Default": "Information", | ||
| "Microsoft.AspNetCore": "Warning" | ||
| } | ||
| } | ||
| } |
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,9 @@ | ||
| { | ||
| "Logging": { | ||
| "LogLevel": { | ||
| "Default": "Information", | ||
| "Microsoft.AspNetCore": "Warning", | ||
| "Aspire.Hosting.Dcp": "Warning" | ||
| } | ||
| } | ||
| } |
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
45 changes: 45 additions & 0 deletions
45
src/Aspire.Hosting/ApplicationModel/DotnetToolAnnotation.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,45 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Diagnostics.CodeAnalysis; | ||
|
|
||
| namespace Aspire.Hosting.ApplicationModel; | ||
| /// <summary> | ||
| /// Represents an annotation for dotnet tool resources. | ||
| /// </summary> | ||
| [Experimental("ASPIREDOTNETTOOL", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] | ||
| public class DotnetToolAnnotation : IResourceAnnotation | ||
| { | ||
| /// <summary> | ||
| /// The NuGet package ID of the .NET tool to execute. You can optionally specify a version using the <c>@</c> syntax, for example <c>dotnetsay@2.1</c>. | ||
| /// </summary> | ||
| public required string PackageId { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The version of the tool package to install. | ||
| /// </summary> | ||
| public string? Version { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Allows prerelease packages to be selected when resolving the version to install. | ||
| /// </summary> | ||
| public bool Prerelease { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// NuGet package sources to use during installation | ||
| /// </summary> | ||
| public List<string> Sources { get; } = []; | ||
|
|
||
| /// <summary> | ||
| /// Are custom sources used in addition or instead of existing feeds. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// This value has no impact if <see cref="Sources"/> is empty. | ||
| /// </remarks> | ||
| public bool IgnoreExistingFeeds { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Treats package source failures as warnings. | ||
| /// </summary> | ||
| public bool IgnoreFailedSources { get; set; } | ||
| } |
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,40 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Diagnostics; | ||
| using System.Diagnostics.CodeAnalysis; | ||
|
|
||
| namespace Aspire.Hosting.ApplicationModel; | ||
|
|
||
| /// <summary> | ||
| /// A resource that represents a specified dotnet tool. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// This class is used to define and manage resources for .NET CLI tools. It associates a tool's name and | ||
| /// command with its package ID, and ensures that the required metadata is properly annotated. | ||
| /// </remarks> | ||
| [Experimental("ASPIREDOTNETTOOL", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] | ||
| [DebuggerDisplay("Type = {GetType().Name,nq}, Name = {Name}, Tool = {ToolConfiguration?.PackageId}")] | ||
| public class DotnetToolResource : ExecutableResource | ||
| { | ||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DotnetToolResource"/> class. | ||
| /// </summary> | ||
| /// <param name="name">The name of the resource.</param> | ||
| /// <param name="packageId">The package id of the tool.</param> | ||
| public DotnetToolResource(string name, string packageId) | ||
| : base(name, "dotnet", ".") | ||
| { | ||
| ArgumentException.ThrowIfNullOrWhiteSpace(packageId, nameof(packageId)); | ||
| Annotations.Add(new DotnetToolAnnotation { PackageId = packageId }); | ||
| } | ||
|
|
||
| internal DotnetToolAnnotation? ToolConfiguration | ||
| { | ||
| get | ||
| { | ||
| this.TryGetLastAnnotation<DotnetToolAnnotation>(out var toolConfig); | ||
| return toolConfig; | ||
| } | ||
| } | ||
| } |
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.