diff --git a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptHostingExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptHostingExtensions.cs index a886f5ddd..46affc67e 100644 --- a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptHostingExtensions.cs +++ b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptHostingExtensions.cs @@ -83,6 +83,7 @@ public static IResourceBuilder AddApp(this IResourceBuilder "npx", "yarn" => "yarn", "pnpm" => "pnpx", + "bun" => "bunx", _ => executionAnnotation.ExecutableName }) .WithArgs(context => @@ -133,6 +134,7 @@ public static IResourceBuilder AddApp(this IResourceBuilde "npm" => "npx", "yarn" => "yarn", "pnpm" => "pnpx", + "bun" => "bunx", _ => executionAnnotation.ExecutableName }) .WithArgs(context => @@ -182,7 +184,7 @@ public static IResourceBuilder WithPackageManagerLaunch(this IResour } else { - throw new InvalidOperationException($"The Nx workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm first, or provide an explicit package manager."); + throw new InvalidOperationException($"The Nx workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm/WithBun first, or provide an explicit package manager."); } } @@ -219,7 +221,7 @@ public static IResourceBuilder WithPackageManagerLaunch(this } else { - throw new InvalidOperationException($"The Turborepo workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm first, or provide an explicit package manager."); + throw new InvalidOperationException($"The Turborepo workspace '{builder.Resource.Name}' is not configured with a package manager. Call WithNpm/WithYarn/WithPnpm/WithBun first, or provide an explicit package manager."); } } @@ -301,6 +303,21 @@ public static IResourceBuilder WithPnpm(this IResourceBuilder + /// Configures the Nx workspace to use bun as the package manager and optionally installs packages before apps start. + /// + /// The Nx workspace resource builder. + /// When true, automatically installs packages before apps start. When false (default), only sets the package manager annotation without creating an installer resource. + /// A function to configure the installer resource builder. + /// A reference to the . + public static IResourceBuilder WithBun(this IResourceBuilder builder, bool install = false, Action>? configureInstaller = null) + { + ArgumentNullException.ThrowIfNull(builder); + + AddMonorepoInstaller(builder, "bun", install, configureInstaller); + return builder; + } + /// /// Configures the Turborepo workspace to use npm as the package manager and optionally installs packages before apps start. /// @@ -346,6 +363,21 @@ public static IResourceBuilder WithPnpm(this IResourceBuilder return builder; } + /// + /// Configures the Turborepo workspace to use bun as the package manager and optionally installs packages before apps start. + /// + /// The Turborepo workspace resource builder. + /// When true, automatically installs packages before apps start. When false (default), only sets the package manager annotation without creating an installer resource. + /// A function to configure the installer resource builder. + /// A reference to the . + public static IResourceBuilder WithBun(this IResourceBuilder builder, bool install = false, Action>? configureInstaller = null) + { + ArgumentNullException.ThrowIfNull(builder); + + AddMonorepoInstaller(builder, "bun", install, configureInstaller); + return builder; + } + private static void AddMonorepoInstaller( IResourceBuilder builder, string packageManager, diff --git a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptPackageManagerConfiguredAnnotation.cs b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptPackageManagerConfiguredAnnotation.cs index 73728374d..6a296e9e8 100644 --- a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptPackageManagerConfiguredAnnotation.cs +++ b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/JavaScriptPackageManagerConfiguredAnnotation.cs @@ -3,13 +3,13 @@ namespace Aspire.Hosting; /// -/// Tracks which JavaScript package manager was configured for a monorepo workspace (via WithNpm/WithYarn/WithPnpm). +/// Tracks which JavaScript package manager was configured for a monorepo workspace (via WithNpm/WithYarn/WithPnpm/WithBun). /// -/// The name of the JavaScript package manager (e.g., "npm", "yarn", "pnpm"). +/// The name of the JavaScript package manager (e.g., "npm", "yarn", "pnpm", "bun"). public sealed class JavaScriptPackageManagerConfiguredAnnotation(string packageManager) : IResourceAnnotation { /// /// Gets the name of the JavaScript package manager that was configured. /// public string PackageManager { get; } = packageManager; -} \ No newline at end of file +} diff --git a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/MONOREPO.md b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/MONOREPO.md index 8ebeec273..b12c2b63e 100644 --- a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/MONOREPO.md +++ b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/MONOREPO.md @@ -46,10 +46,11 @@ var app3 = turbo.AddApp("app3"); ## Package Managers -Both Nx and Turborepo support yarn and pnpm package managers: +Both Nx and Turborepo support yarn, pnpm, and bun package managers: -- `.WithYarnPackageInstaller()` - uses yarn -- `.WithPnpmPackageInstaller()` - uses pnpm +- `.WithYarn(install: true)` - uses yarn +- `.WithPnpm(install: true)` - uses pnpm +- `.WithBun(install: true)` - uses bun > **Note**: npm support (`AddNpmApp`, `WithNpmPackageInstallation`) is now provided by [Aspire.Hosting.JavaScript](https://www.nuget.org/packages/Aspire.Hosting.JavaScript) starting with Aspire 13. @@ -144,4 +145,3 @@ var nx = builder.AddNxApp("nx", workingDirectory: "../frontend") // This is valid - you can install with pnpm but run apps with yarn ``` - diff --git a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/README.md b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/README.md index 992bea1db..0dbd2582a 100644 --- a/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/README.md +++ b/src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/README.md @@ -50,9 +50,15 @@ var turbo = builder.AddTurborepoApp("turbo", workingDirectory: "../frontend") .WithPnpm() .WithPackageManagerLaunch("pnpm"); // Uses 'pnpm' command +// Bun example +var bunRepo = builder.AddTurborepoApp("bun-repo", workingDirectory: "../frontend") + .WithBun() + .WithPackageManagerLaunch("bun"); // Uses 'bun' command + // Generated commands: // Nx with yarn: yarn nx serve app1 // Turborepo with pnpm: pnpm turbo run dev --filter app1 +// Turborepo with bun: bunx turbo run dev --filter app1 ``` ### Package installation with custom flags @@ -84,4 +90,3 @@ https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-nodejs-exten ## Feedback & contributing https://github.com/CommunityToolkit/Aspire - diff --git a/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/NxResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/NxResourceCreationTests.cs index 6c09787d8..fb79cbced 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/NxResourceCreationTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/NxResourceCreationTests.cs @@ -59,6 +59,7 @@ public void NxResource_IsRunningState() [InlineData("npm")] [InlineData("yarn")] [InlineData("pnpm")] + [InlineData("bun")] public async Task Nx_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided(string packageManager) { var builder = DistributedApplication.CreateBuilder(); @@ -70,6 +71,7 @@ public async Task Nx_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided "npm" => nxBuilder.WithNpm(), "yarn" => nxBuilder.WithYarn(), "pnpm" => nxBuilder.WithPnpm(), + "bun" => nxBuilder.WithBun(), _ => throw new ArgumentOutOfRangeException(nameof(packageManager), $"Unsupported package manager: {packageManager}"), }).WithPackageManagerLaunch(); @@ -93,6 +95,7 @@ public async Task Nx_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided "npm" => "npx", "yarn" => "yarn", "pnpm" => "pnpx", + "bun" => "bunx", _ => packageManager }, nxAppResource.Command); var nxAppArgs = await nxAppResource.GetArgumentListAsync(); @@ -178,6 +181,7 @@ public async Task Nx_NoWithPackageManagerLaunch_Defaults_AppCommandsIncludeNpxOr [InlineData("npm")] [InlineData("yarn")] [InlineData("pnpm")] + [InlineData("bun")] public async Task Nx_WithPackageManager_WithoutRunWith_DoesNotAffectAppExecution(string packageManager) { var builder = DistributedApplication.CreateBuilder(); @@ -189,6 +193,7 @@ public async Task Nx_WithPackageManager_WithoutRunWith_DoesNotAffectAppExecution "npm" => nxBuilder.WithNpm(), "yarn" => nxBuilder.WithYarn(), "pnpm" => nxBuilder.WithPnpm(), + "bun" => nxBuilder.WithBun(), _ => throw new ArgumentOutOfRangeException(nameof(packageManager)) }; @@ -273,6 +278,7 @@ public void Nx_WithPackageManagerLaunch_CalledTwiceWithDifferent_Throws() [InlineData("npm")] [InlineData("yarn")] [InlineData("pnpm")] + [InlineData("bun")] public async Task Nx_MultipleApps_AllInheritExecutionAnnotation(string packageManager) { var builder = DistributedApplication.CreateBuilder(); @@ -283,6 +289,7 @@ public async Task Nx_MultipleApps_AllInheritExecutionAnnotation(string packageMa "npm" => nx.WithNpm(), "yarn" => nx.WithYarn(), "pnpm" => nx.WithPnpm(), + "bun" => nx.WithBun(), _ => throw new ArgumentOutOfRangeException(nameof(packageManager)) }; nx = nx.WithPackageManagerLaunch(); @@ -304,6 +311,7 @@ public async Task Nx_MultipleApps_AllInheritExecutionAnnotation(string packageMa "npm" => "npx", "yarn" => "yarn", "pnpm" => "pnpx", + "bun" => "bunx", _ => throw new ArgumentOutOfRangeException(nameof(packageManager)) }; diff --git a/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/TurborepoResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/TurborepoResourceCreationTests.cs index 38d5111f6..ac6a86701 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/TurborepoResourceCreationTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/TurborepoResourceCreationTests.cs @@ -59,6 +59,7 @@ public void TurborepoResource_IsRunningState() [InlineData("npm")] [InlineData("yarn")] [InlineData("pnpm")] + [InlineData("bun")] public async Task Turborepo_WithPackageManagerLaunch_InfersFromInstallerWhenNotProvided(string packageManager) { var builder = DistributedApplication.CreateBuilder(); @@ -70,6 +71,7 @@ public async Task Turborepo_WithPackageManagerLaunch_InfersFromInstallerWhenNotP "npm" => turbo.WithNpm(), "yarn" => turbo.WithYarn(), "pnpm" => turbo.WithPnpm(), + "bun" => turbo.WithBun(), _ => throw new ArgumentOutOfRangeException(nameof(packageManager), $"Unsupported package manager: {packageManager}"), }).WithPackageManagerLaunch(); @@ -92,6 +94,7 @@ public async Task Turborepo_WithPackageManagerLaunch_InfersFromInstallerWhenNotP "npm" => "npx", "yarn" => "yarn", "pnpm" => "pnpx", + "bun" => "bunx", _ => packageManager }, turboApp.Command); var turboArgs = await turboApp.GetArgumentListAsync(); @@ -175,6 +178,7 @@ public async Task Turborepo_NoWithPackageManagerLaunch_Defaults_AppCommandsInclu [InlineData("npm")] [InlineData("yarn")] [InlineData("pnpm")] + [InlineData("bun")] public async Task Turborepo_WithPackageManager_WithoutRunWith_DoesNotAffectAppExecution(string packageManager) { var builder = DistributedApplication.CreateBuilder(); @@ -185,6 +189,7 @@ public async Task Turborepo_WithPackageManager_WithoutRunWith_DoesNotAffectAppEx "npm" => turboBuilder.WithNpm(), "yarn" => turboBuilder.WithYarn(), "pnpm" => turboBuilder.WithPnpm(), + "bun" => turboBuilder.WithBun(), _ => throw new ArgumentOutOfRangeException(nameof(packageManager)) }; @@ -280,6 +285,7 @@ public void Turborepo_WithPackageManagerLaunch_CalledTwiceWithSame_DoesNotThrow( [InlineData("npm")] [InlineData("yarn")] [InlineData("pnpm")] + [InlineData("bun")] public async Task Turborepo_MultipleApps_AllInheritExecutionAnnotation(string packageManager) { var builder = DistributedApplication.CreateBuilder(); @@ -290,6 +296,7 @@ public async Task Turborepo_MultipleApps_AllInheritExecutionAnnotation(string pa "npm" => turbo.WithNpm(), "yarn" => turbo.WithYarn(), "pnpm" => turbo.WithPnpm(), + "bun" => turbo.WithBun(), _ => throw new ArgumentOutOfRangeException(nameof(packageManager)) }; turbo = turbo.WithPackageManagerLaunch(); @@ -311,6 +318,7 @@ public async Task Turborepo_MultipleApps_AllInheritExecutionAnnotation(string pa "npm" => "npx", "yarn" => "yarn", "pnpm" => "pnpx", + "bun" => "bunx", _ => throw new ArgumentOutOfRangeException(nameof(packageManager)) };