diff --git a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs index ab491ed4f..224234d9a 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppExecutableResource.cs @@ -5,8 +5,5 @@ /// /// The name of the resource. /// The working directory to use for the command. -public class RustAppExecutableResource(string name, string workingDirectory) - : ExecutableResource(name, "cargo", workingDirectory), IResourceWithServiceDiscovery -{ - -} +public class RustAppExecutableResource(string name, string workingDirectory, string command = "cargo") + : ExecutableResource(name, command, workingDirectory), IResourceWithServiceDiscovery; \ No newline at end of file diff --git a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs index 6e2211d94..2f39d8980 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Rust/RustAppHostingExtension.cs @@ -11,7 +11,7 @@ namespace Aspire.Hosting; public static class RustAppHostingExtension { /// - /// Adds a Rust application to the application model. Executes the executable Rust app. + /// Adds a Rust application to the application model, using the cargo cli. /// /// The to add the resource to. /// The name of the resource. @@ -19,22 +19,64 @@ public static class RustAppHostingExtension /// The optional arguments to be passed to the executable when it is started. /// A reference to the . [AspireExport("addRustApp", Description = "Adds a Rust application to the application model")] - public static IResourceBuilder AddRustApp(this IDistributedApplicationBuilder builder, [ResourceName] string name, string workingDirectory, string[]? args = null) + public static IResourceBuilder AddRustApp( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + string workingDirectory, + string[]? args = null + ) { - ArgumentNullException.ThrowIfNull(builder, nameof(builder)); - ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name)); - ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory, nameof(workingDirectory)); + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrWhiteSpace(name); + ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory); string[] allArgs = args is { Length: > 0 } ? ["run", .. args] : ["run"]; + return builder.AddRustApp(name, workingDirectory, command: "cargo", allArgs); + } + + /// + /// Adds a Rust application to the application model, using the bacon cli. + /// + /// The to add the resource to. + /// The name of the resource. + /// The working directory to use for the command. + /// The optional arguments to be passed to the executable when it is started. + /// A reference to the . + [AspireExport("addBaconApp", Description = "Adds a Rust application to the application model")] + public static IResourceBuilder AddBaconApp( + this IDistributedApplicationBuilder builder, + [ResourceName] string name, + string workingDirectory, + string[]? args = null + ) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrWhiteSpace(name); + ArgumentException.ThrowIfNullOrWhiteSpace(workingDirectory); + + string[] allArgs = args is { Length: > 0 } + ? args + : ["run"]; + + return builder.AddRustApp(name, workingDirectory, command: "bacon", allArgs); + } + + private static IResourceBuilder AddRustApp( + this IDistributedApplicationBuilder builder, + string name, + string workingDirectory, + string command, + string[] args) + { workingDirectory = Path.Combine(builder.AppHostDirectory, workingDirectory).NormalizePathForCurrentPlatform(); - var resource = new RustAppExecutableResource(name, workingDirectory); + var resource = new RustAppExecutableResource(name, workingDirectory, command); return builder.AddResource(resource) .WithRustDefaults() - .WithArgs(allArgs) + .WithArgs(args) .PublishAsDockerFile(); } diff --git a/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/AddBaconAppTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/AddBaconAppTests.cs new file mode 100644 index 000000000..c607a8341 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/AddBaconAppTests.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Hosting; +using CommunityToolkit.Aspire.Utils; +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Rust.Tests; +public class AddBaconAppTests +{ + [Fact] + public async Task AddBaconAppAddsAnnotationMetadata() + { + var appBuilder = DistributedApplication.CreateBuilder(); + + var workingDirectory = "../../examples/rust/actix_api"; + var baconApp = appBuilder.AddBaconApp("bacon-app", workingDirectory); + + await using var app = appBuilder.Build(); + + var appModel = app.Services.GetRequiredService(); + + var resource = Assert.Single(appModel.Resources.OfType()); + workingDirectory = Path.Combine(appBuilder.AppHostDirectory, workingDirectory).NormalizePathForCurrentPlatform(); + Assert.Equal("bacon-app", resource.Name); + Assert.Equal(workingDirectory, resource.WorkingDirectory); + Assert.Equal("bacon", resource.Command); + var args = await resource.GetArgumentListAsync(); + Assert.Collection(args, + arg => Assert.Equal("run", arg)); + } + + [Fact] + public async Task AddBaconAppWithArgsAddsAnnotationMetadata() + { + var appBuilder = DistributedApplication.CreateBuilder(); + + var workingDirectory = "../../examples/rust/actix_api"; + var baconApp = appBuilder.AddBaconApp("bacon-app", workingDirectory, ["check"]); + + await using var app = appBuilder.Build(); + + var appModel = app.Services.GetRequiredService(); + + var resource = Assert.Single(appModel.Resources.OfType()); + workingDirectory = Path.Combine(appBuilder.AppHostDirectory, workingDirectory).NormalizePathForCurrentPlatform(); + Assert.Equal("bacon-app", resource.Name); + Assert.Equal(workingDirectory, resource.WorkingDirectory); + Assert.Equal("bacon", resource.Command); + var args = await resource.GetArgumentListAsync(); + Assert.Collection(args, + arg => Assert.Equal("check", arg)); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/BaconAppPublicApiTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/BaconAppPublicApiTests.cs new file mode 100644 index 000000000..f1b8931b1 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/BaconAppPublicApiTests.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Hosting; + +namespace CommunityToolkit.Aspire.Hosting.Rust.Tests; + +public class BaconAppPublicApiTests +{ + [Fact] + public void AddBaconAppShouldThrowWhenBuilderIsNull() + { + IDistributedApplicationBuilder builder = null!; + const string name = "bacon-app"; + const string workingDirectory = "bacon_app"; + var action = () => builder.AddBaconApp(name, workingDirectory); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(builder), exception.ParamName); + } + + [Fact] + public void AddBaconAppShouldThrowWhenNameIsNull() + { + IDistributedApplicationBuilder builder = new DistributedApplicationBuilder([]); + const string name = null!; + const string workingDirectory = "bacon_app"; + + var action = () => builder.AddBaconApp(name!, workingDirectory); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(name), exception.ParamName); + } + + [Fact] + public void AddBaconAppShouldThrowWhenWorkingDirectoryIsNull() + { + IDistributedApplicationBuilder builder = new DistributedApplicationBuilder([]); + const string name = "bacon-app"; + const string workingDirectory = null!; + + var action = () => builder.AddBaconApp(name, workingDirectory!); + + var exception = Assert.Throws(action); + Assert.Equal(nameof(workingDirectory), exception.ParamName); + } +}