From 23d99143fbf8d44ac0ebdb735abe5810c41f7578 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 25 Jun 2025 05:40:39 +0000 Subject: [PATCH] Proving a callback rather than an args array This allows for more flexibility on how you configure the installer resource --- .../NodeJSHostingExtensions.cs | 27 ++++++++++--------- .../PackageInstallationTests.cs | 20 +++++++++++--- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions/NodeJSHostingExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions/NodeJSHostingExtensions.cs index 91d503598..9e315c7df 100644 --- a/src/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions/NodeJSHostingExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions/NodeJSHostingExtensions.cs @@ -110,9 +110,9 @@ public static IResourceBuilder AddPnpmApp(this IDistributedAppl /// /// The Node.js app resource. /// When true use npm ci otherwise use npm install when installing packages. - /// Additional arguments to pass to the npm command. + /// Configure the npm installer resource. /// A reference to the . - public static IResourceBuilder WithNpmPackageInstallation(this IResourceBuilder resource, bool useCI = false, string[]? args = null) + public static IResourceBuilder WithNpmPackageInstallation(this IResourceBuilder resource, bool useCI = false, Action>? configureInstaller = null) { // Only install packages during development, not in publish mode if (!resource.ApplicationBuilder.ExecutionContext.IsPublishMode) @@ -120,12 +120,13 @@ public static IResourceBuilder WithNpmPackageInstallation(this var installerName = $"{resource.Resource.Name}-npm-install"; var installer = new NpmInstallerResource(installerName, resource.Resource.WorkingDirectory); - args ??= []; var installerBuilder = resource.ApplicationBuilder.AddResource(installer) - .WithArgs([useCI ? "ci" : "install", .. args]) + .WithArgs([useCI ? "ci" : "install"]) .WithParentRelationship(resource.Resource) .ExcludeFromManifest(); + configureInstaller?.Invoke(installerBuilder); + // Make the parent resource wait for the installer to complete resource.WaitForCompletion(installerBuilder); } @@ -137,9 +138,9 @@ public static IResourceBuilder WithNpmPackageInstallation(this /// Ensures the Node.js packages are installed before the application starts using yarn as the package manager. /// /// The Node.js app resource. - /// Additional arguments to pass to the yarn command. + /// Configure the yarn installer resource. /// A reference to the . - public static IResourceBuilder WithYarnPackageInstallation(this IResourceBuilder resource, string[]? args = null) + public static IResourceBuilder WithYarnPackageInstallation(this IResourceBuilder resource, Action>? configureInstaller = null) { // Only install packages during development, not in publish mode if (!resource.ApplicationBuilder.ExecutionContext.IsPublishMode) @@ -147,12 +148,13 @@ public static IResourceBuilder WithYarnPackageInstallation(this var installerName = $"{resource.Resource.Name}-yarn-install"; var installer = new YarnInstallerResource(installerName, resource.Resource.WorkingDirectory); - args ??= []; var installerBuilder = resource.ApplicationBuilder.AddResource(installer) - .WithArgs(["install", .. args]) + .WithArgs("install") .WithParentRelationship(resource.Resource) .ExcludeFromManifest(); + configureInstaller?.Invoke(installerBuilder); + // Make the parent resource wait for the installer to complete resource.WaitForCompletion(installerBuilder); } @@ -164,9 +166,9 @@ public static IResourceBuilder WithYarnPackageInstallation(this /// Ensures the Node.js packages are installed before the application starts using pnpm as the package manager. /// /// The Node.js app resource. - /// Additional arguments to pass to the pnpm command. + /// Configure the pnpm installer resource. /// A reference to the . - public static IResourceBuilder WithPnpmPackageInstallation(this IResourceBuilder resource, string[]? args = null) + public static IResourceBuilder WithPnpmPackageInstallation(this IResourceBuilder resource, Action>? configureInstaller = null) { // Only install packages during development, not in publish mode if (!resource.ApplicationBuilder.ExecutionContext.IsPublishMode) @@ -174,12 +176,13 @@ public static IResourceBuilder WithPnpmPackageInstallation(this var installerName = $"{resource.Resource.Name}-pnpm-install"; var installer = new PnpmInstallerResource(installerName, resource.Resource.WorkingDirectory); - args ??= []; var installerBuilder = resource.ApplicationBuilder.AddResource(installer) - .WithArgs(["install", .. args]) + .WithArgs("install") .WithParentRelationship(resource.Resource) .ExcludeFromManifest(); + configureInstaller?.Invoke(installerBuilder); + // Make the parent resource wait for the installer to complete resource.WaitForCompletion(installerBuilder); } diff --git a/tests/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions.Tests/PackageInstallationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions.Tests/PackageInstallationTests.cs index 2c7f4eb58..6c5ab326b 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions.Tests/PackageInstallationTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.NodeJS.Extensions.Tests/PackageInstallationTests.cs @@ -78,8 +78,14 @@ public async Task WithNpmPackageInstallation_CanAcceptAdditionalArgs() var nodeAppWithArgs = builder.AddNpmApp("test-app-args", "./test-app-args"); // Test npm install with additional args - nodeApp.WithNpmPackageInstallation(useCI: false, args: ["--legacy-peer-deps"]); - nodeAppWithArgs.WithNpmPackageInstallation(useCI: true, args: ["--verbose", "--no-optional"]); + nodeApp.WithNpmPackageInstallation(useCI: false, configureInstaller: installerBuilder => + { + installerBuilder.WithArgs("--legacy-peer-deps"); + }); + nodeAppWithArgs.WithNpmPackageInstallation(useCI: true, configureInstaller: installerBuilder => + { + installerBuilder.WithArgs("--verbose", "--no-optional"); + }); using var app = builder.Build(); @@ -115,7 +121,10 @@ public async Task WithYarnPackageInstallation_CanAcceptAdditionalArgs() var builder = DistributedApplication.CreateBuilder(); var nodeApp = builder.AddYarnApp("test-yarn-app", "./test-yarn-app"); - nodeApp.WithYarnPackageInstallation(args: ["--frozen-lockfile", "--verbose"]); + nodeApp.WithYarnPackageInstallation(configureInstaller: installerBuilder => + { + installerBuilder.WithArgs("--frozen-lockfile", "--verbose"); + }); using var app = builder.Build(); @@ -140,7 +149,10 @@ public async Task WithPnpmPackageInstallation_CanAcceptAdditionalArgs() var builder = DistributedApplication.CreateBuilder(); var nodeApp = builder.AddPnpmApp("test-pnpm-app", "./test-pnpm-app"); - nodeApp.WithPnpmPackageInstallation(args: ["--frozen-lockfile"]); + nodeApp.WithPnpmPackageInstallation(configureInstaller: installerBuilder => + { + installerBuilder.WithArgs("--frozen-lockfile"); + }); using var app = builder.Build();