Skip to content
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

Add GetArgumentListAsync to resource extentions #6646

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/Aspire.Hosting/ApplicationModel/ResourceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,49 @@ public static int GetReplicaCount(this IResource resource)
}
}

/// <summary>
/// Get the arguments from the given resource.
/// </summary>
/// <remarks>
/// This method is useful when you want to make sure the arguments are added properly to resources, mostly in test situations.
/// This method has asynchronous behavior when arguments were provided from <see cref="IValueProvider"/> otherwise it will be synchronous.
/// </remarks>
/// <param name="resource">The resource to get the arguments from.</param>
/// <returns>The arguments retrieved from the resource.</returns>
public static async ValueTask<IReadOnlyList<string>> GetArgumentListAsync(this IResourceWithArgs resource)
Copy link
Member

Choose a reason for hiding this comment

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

Are there any places in the current code that can be using this new API now? I see a bunch of places where we already have this logic. Especially in tests.

Copy link
Contributor Author

@Alirexaa Alirexaa Nov 12, 2024

Choose a reason for hiding this comment

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

Yes, there are. Do you want me to update those codes that use this new API or can I do this in another PR?

Copy link
Member

Choose a reason for hiding this comment

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

Please do it here. It adds extra validation to the API.

{
var finalArgs = new List<string>();

if (resource.TryGetAnnotationsOfType<CommandLineArgsCallbackAnnotation>(out var exeArgsCallbacks))
{
var args = new List<object>();
var commandLineContext = new CommandLineArgsCallbackContext(args, default);

foreach (var exeArgsCallback in exeArgsCallbacks)
{
await exeArgsCallback.Callback(commandLineContext).ConfigureAwait(false);
}

foreach (var arg in args)
{
var value = arg switch
{
string s => s,
IValueProvider valueProvider => await valueProvider.GetValueAsync().ConfigureAwait(false),
null => null,
_ => throw new InvalidOperationException($"Unexpected value for {arg}")
};

if (value is not null)
{
finalArgs.Add(value);
}
}
}

return finalArgs;
}

/// <summary>
/// Gets the lifetime type of the container for the specified resource.
/// Defaults to <see cref="ContainerLifetime.Session"/> if no <see cref="ContainerLifetimeAnnotation"/> is found.
Expand Down
1 change: 1 addition & 0 deletions src/Aspire.Hosting/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ Aspire.Hosting.LaunchSettings.Profiles.get -> System.Collections.Generic.Diction
Aspire.Hosting.LaunchSettings.Profiles.set -> void
Aspire.Hosting.Utils.VolumeNameGenerator
static Aspire.Hosting.ApplicationModel.CommandResults.Success() -> Aspire.Hosting.ApplicationModel.ExecuteCommandResult!
static Aspire.Hosting.ApplicationModel.ResourceExtensions.GetArgumentListAsync(this Aspire.Hosting.ApplicationModel.IResourceWithArgs! resource) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.IReadOnlyList<string!>!>
static Aspire.Hosting.ApplicationModel.ResourceExtensions.GetEnvironmentVariableValuesAsync(this Aspire.Hosting.ApplicationModel.IResourceWithEnvironment! resource, Aspire.Hosting.DistributedApplicationOperation applicationOperation = Aspire.Hosting.DistributedApplicationOperation.Run) -> System.Threading.Tasks.ValueTask<System.Collections.Generic.Dictionary<string!, string!>!>
Aspire.Hosting.ApplicationModel.ResourceNotificationService.WaitForResourceAsync(string! resourceName, string? targetState = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
Aspire.Hosting.ApplicationModel.ResourceNotificationService.WaitForResourceAsync(string! resourceName, System.Collections.Generic.IEnumerable<string!>! targetStates, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<string!>!
Expand Down
31 changes: 31 additions & 0 deletions tests/Aspire.Hosting.Tests/ResourceExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,32 @@ public async Task GetEnvironmentVariableValuesAsyncReturnCorrectVariablesUsingMa
});
}

[Fact]
public async Task GetArgumentListAsyncReturnCorrectArguments()
{
var builder = DistributedApplication.CreateBuilder();
builder.Configuration["Parameters:DummyKey"] = "DummyValue";

var dummyParameter = builder.AddParameter("DummyKey").Resource;
var resource = new DummyResource("dummy");
var container = builder.AddResource(resource)
.WithArgs(["--arg1", "--arg2"])
.WithArgs(context =>
{
context.Args.Add("--arg3");
})
.WithArgs(dummyParameter);

var args = await container.Resource.GetArgumentListAsync().DefaultTimeout();

Assert.Collection(args,
arg => Assert.Equal("--arg1", arg),
arg => Assert.Equal("--arg2", arg),
arg => Assert.Equal("--arg3", arg),
arg => Assert.Equal("DummyValue", arg)
);
}

private sealed class ParentResource(string name) : Resource(name)
{

Expand All @@ -278,4 +304,9 @@ private sealed class AnotherDummyAnnotation : IResourceAnnotation
{

}

private sealed class DummyResource(string name) : Resource(name), IResourceWithArgs
{

}
}