From d9069c037484cc1827e6b8abf3f4b1e7eb25d09d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 4 Dec 2025 05:29:44 +0000
Subject: [PATCH 1/8] Initial plan
From d3756c973ea50437d0a72b8573d0c4159f609641 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 4 Dec 2025 05:39:05 +0000
Subject: [PATCH 2/8] Add WithGoModTidy and WithGoModDownload extension methods
for Golang integration
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
---
.../GoModInstallerResource.cs | 9 ++
.../GolangAppHostingExtension.cs | 64 +++++++++++++
.../README.md | 39 ++++++++
.../ResourceCreationTests.cs | 94 +++++++++++++++++++
4 files changed, 206 insertions(+)
create mode 100644 src/CommunityToolkit.Aspire.Hosting.Golang/GoModInstallerResource.cs
diff --git a/src/CommunityToolkit.Aspire.Hosting.Golang/GoModInstallerResource.cs b/src/CommunityToolkit.Aspire.Hosting.Golang/GoModInstallerResource.cs
new file mode 100644
index 000000000..647415617
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Golang/GoModInstallerResource.cs
@@ -0,0 +1,9 @@
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// A resource that represents a Go module installer that runs go mod tidy or go mod download.
+///
+/// The name of the resource.
+/// The working directory to use for the command.
+public class GoModInstallerResource(string name, string workingDirectory)
+ : ExecutableResource(name, "go", workingDirectory);
diff --git a/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs b/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
index 964dc135d..62d62dfe9 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
@@ -234,4 +234,68 @@ private static string GetDefaultGoBaseImage(string workingDirectory, IServicePro
logger.LogDebug("No Go version detected, will use default version");
return null;
}
+
+ ///
+ /// Ensures Go module dependencies are tidied before the application starts using go mod tidy.
+ ///
+ /// The Golang app resource builder.
+ /// Optional action to configure the installer resource.
+ /// A reference to the .
+ public static IResourceBuilder WithGoModTidy(
+ this IResourceBuilder builder,
+ Action>? configureInstaller = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder, nameof(builder));
+
+ // Only install packages during development, not in publish mode
+ if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
+ {
+ var installerName = $"{builder.Resource.Name}-go-mod-tidy";
+ var installer = new GoModInstallerResource(installerName, builder.Resource.WorkingDirectory);
+
+ var installerBuilder = builder.ApplicationBuilder.AddResource(installer)
+ .WithArgs("mod", "tidy")
+ .WithParentRelationship(builder.Resource)
+ .ExcludeFromManifest();
+
+ // Make the parent resource wait for the installer to complete
+ builder.WaitForCompletion(installerBuilder);
+
+ configureInstaller?.Invoke(installerBuilder);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Ensures Go module dependencies are downloaded before the application starts using go mod download.
+ ///
+ /// The Golang app resource builder.
+ /// Optional action to configure the installer resource.
+ /// A reference to the .
+ public static IResourceBuilder WithGoModDownload(
+ this IResourceBuilder builder,
+ Action>? configureInstaller = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder, nameof(builder));
+
+ // Only install packages during development, not in publish mode
+ if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
+ {
+ var installerName = $"{builder.Resource.Name}-go-mod-download";
+ var installer = new GoModInstallerResource(installerName, builder.Resource.WorkingDirectory);
+
+ var installerBuilder = builder.ApplicationBuilder.AddResource(installer)
+ .WithArgs("mod", "download")
+ .WithParentRelationship(builder.Resource)
+ .ExcludeFromManifest();
+
+ // Make the parent resource wait for the installer to complete
+ builder.WaitForCompletion(installerBuilder);
+
+ configureInstaller?.Invoke(installerBuilder);
+ }
+
+ return builder;
+ }
}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Aspire.Hosting.Golang/README.md b/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
index e7de82f24..434160097 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
+++ b/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
@@ -29,6 +29,45 @@ To have the Golang application listen on the correct port, you can use the follo
r.Run(":"+os.Getenv("PORT"))
```
+## Dependency Management
+
+The integration provides support for Go module dependency management using `go mod tidy` or `go mod download`.
+
+### Using `go mod tidy`
+
+To run `go mod tidy` before your application starts (to clean up and verify dependencies):
+
+```csharp
+var golang = builder.AddGolangApp("golang", "../gin-api")
+ .WithGoModTidy()
+ .WithHttpEndpoint(env: "PORT");
+```
+
+### Using `go mod download`
+
+To run `go mod download` before your application starts (to download dependencies without verification):
+
+```csharp
+var golang = builder.AddGolangApp("golang", "../gin-api")
+ .WithGoModDownload()
+ .WithHttpEndpoint(env: "PORT");
+```
+
+Both methods create an installer resource that runs before your application starts, ensuring dependencies are available. The installer resource appears as a child resource in the Aspire dashboard.
+
+You can also customize the installer resource using the optional `configureInstaller` parameter:
+
+```csharp
+var golang = builder.AddGolangApp("golang", "../gin-api")
+ .WithGoModTidy(configureInstaller: installer =>
+ {
+ installer.WithEnvironment("GOPROXY", "https://proxy.golang.org,direct");
+ })
+ .WithHttpEndpoint(env: "PORT");
+```
+
+> **Note:** The `WithGoModTidy` and `WithGoModDownload` methods only run during development. When publishing, the generated Dockerfile handles dependency management automatically.
+
## Publishing
When publishing your Aspire application, the Golang resource automatically generates a multi-stage Dockerfile for containerization. This means you don't need to manually create a Dockerfile for your Golang application.
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
index c0ed2d211..48aa310dd 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
@@ -88,4 +88,98 @@ public async Task GolangAppWithExecutableAsync()
}
);
}
+
+ [Fact]
+ public void GolangAppWithGoModTidyCreatesInstallerResource()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddGolangApp("golang", "../../examples/golang/gin-api").WithGoModTidy();
+
+ using var app = builder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var golangResource = Assert.Single(appModel.Resources.OfType());
+ var installerResource = Assert.Single(appModel.Resources.OfType());
+
+ Assert.Equal("golang-go-mod-tidy", installerResource.Name);
+ Assert.Equal("go", installerResource.Command);
+ }
+
+ [Fact]
+ public async Task GolangAppWithGoModTidyHasCorrectArgsAsync()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddGolangApp("golang", "../../examples/golang/gin-api").WithGoModTidy();
+
+ using var app = builder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var installerResource = Assert.Single(appModel.Resources.OfType());
+
+ var args = await installerResource.GetArgumentValuesAsync();
+ Assert.Collection(
+ args,
+ arg => Assert.Equal("mod", arg),
+ arg => Assert.Equal("tidy", arg)
+ );
+ }
+
+ [Fact]
+ public void GolangAppWithGoModDownloadCreatesInstallerResource()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddGolangApp("golang", "../../examples/golang/gin-api").WithGoModDownload();
+
+ using var app = builder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var golangResource = Assert.Single(appModel.Resources.OfType());
+ var installerResource = Assert.Single(appModel.Resources.OfType());
+
+ Assert.Equal("golang-go-mod-download", installerResource.Name);
+ Assert.Equal("go", installerResource.Command);
+ }
+
+ [Fact]
+ public async Task GolangAppWithGoModDownloadHasCorrectArgsAsync()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddGolangApp("golang", "../../examples/golang/gin-api").WithGoModDownload();
+
+ using var app = builder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var installerResource = Assert.Single(appModel.Resources.OfType());
+
+ var args = await installerResource.GetArgumentValuesAsync();
+ Assert.Collection(
+ args,
+ arg => Assert.Equal("mod", arg),
+ arg => Assert.Equal("download", arg)
+ );
+ }
+
+ [Fact]
+ public void WithGoModTidyNullBuilderThrows()
+ {
+ IResourceBuilder builder = null!;
+
+ Assert.Throws(() => builder.WithGoModTidy());
+ }
+
+ [Fact]
+ public void WithGoModDownloadNullBuilderThrows()
+ {
+ IResourceBuilder builder = null!;
+
+ Assert.Throws(() => builder.WithGoModDownload());
+ }
}
\ No newline at end of file
From a394e2897dd16158ef25a066ed3014d61d4cbe7d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 15 Jan 2026 08:21:42 +0000
Subject: [PATCH 3/8] Address PR feedback: add install parameter and use
IsRunMode instead of IsPublishMode
Co-authored-by: tommasodotNET <12819039+tommasodotNET@users.noreply.github.com>
---
.../GolangAppHostingExtension.cs | 12 +++++---
.../README.md | 20 +++++++++++--
.../ResourceCreationTests.cs | 30 +++++++++++++++++++
3 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs b/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
index 62d62dfe9..836496441 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
@@ -239,16 +239,18 @@ private static string GetDefaultGoBaseImage(string workingDirectory, IServicePro
/// Ensures Go module dependencies are tidied before the application starts using go mod tidy.
///
/// The Golang app resource builder.
+ /// When true (default), automatically runs go mod tidy before the application starts. When false, this method does nothing.
/// Optional action to configure the installer resource.
/// A reference to the .
public static IResourceBuilder WithGoModTidy(
this IResourceBuilder builder,
+ bool install = true,
Action>? configureInstaller = null)
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
- // Only install packages during development, not in publish mode
- if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
+ // Only install packages if in run mode and install is true
+ if (builder.ApplicationBuilder.ExecutionContext.IsRunMode && install)
{
var installerName = $"{builder.Resource.Name}-go-mod-tidy";
var installer = new GoModInstallerResource(installerName, builder.Resource.WorkingDirectory);
@@ -271,16 +273,18 @@ public static IResourceBuilder WithGoModTidy(
/// Ensures Go module dependencies are downloaded before the application starts using go mod download.
///
/// The Golang app resource builder.
+ /// When true (default), automatically runs go mod download before the application starts. When false, this method does nothing.
/// Optional action to configure the installer resource.
/// A reference to the .
public static IResourceBuilder WithGoModDownload(
this IResourceBuilder builder,
+ bool install = true,
Action>? configureInstaller = null)
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
- // Only install packages during development, not in publish mode
- if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
+ // Only install packages if in run mode and install is true
+ if (builder.ApplicationBuilder.ExecutionContext.IsRunMode && install)
{
var installerName = $"{builder.Resource.Name}-go-mod-download";
var installer = new GoModInstallerResource(installerName, builder.Resource.WorkingDirectory);
diff --git a/src/CommunityToolkit.Aspire.Hosting.Golang/README.md b/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
index 434160097..785d1ab7d 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
+++ b/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
@@ -43,6 +43,14 @@ var golang = builder.AddGolangApp("golang", "../gin-api")
.WithHttpEndpoint(env: "PORT");
```
+By default, `WithGoModTidy()` runs `go mod tidy` before the application starts (equivalent to `install: true`). You can disable this behavior by setting `install: false`:
+
+```csharp
+var golang = builder.AddGolangApp("golang", "../gin-api")
+ .WithGoModTidy(install: false) // Does not run go mod tidy
+ .WithHttpEndpoint(env: "PORT");
+```
+
### Using `go mod download`
To run `go mod download` before your application starts (to download dependencies without verification):
@@ -53,7 +61,15 @@ var golang = builder.AddGolangApp("golang", "../gin-api")
.WithHttpEndpoint(env: "PORT");
```
-Both methods create an installer resource that runs before your application starts, ensuring dependencies are available. The installer resource appears as a child resource in the Aspire dashboard.
+Similarly, you can control whether the download runs:
+
+```csharp
+var golang = builder.AddGolangApp("golang", "../gin-api")
+ .WithGoModDownload(install: false) // Does not run go mod download
+ .WithHttpEndpoint(env: "PORT");
+```
+
+Both methods create an installer resource that runs before your application starts when `install` is `true`, ensuring dependencies are available. The installer resource appears as a child resource in the Aspire dashboard.
You can also customize the installer resource using the optional `configureInstaller` parameter:
@@ -66,7 +82,7 @@ var golang = builder.AddGolangApp("golang", "../gin-api")
.WithHttpEndpoint(env: "PORT");
```
-> **Note:** The `WithGoModTidy` and `WithGoModDownload` methods only run during development. When publishing, the generated Dockerfile handles dependency management automatically.
+> **Note:** The `WithGoModTidy` and `WithGoModDownload` methods only run in run mode (when the application is started locally). They do not run when publishing, as the generated Dockerfile handles dependency management automatically.
## Publishing
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
index 48aa310dd..08568b6b1 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
@@ -182,4 +182,34 @@ public void WithGoModDownloadNullBuilderThrows()
Assert.Throws(() => builder.WithGoModDownload());
}
+
+ [Fact]
+ public void GolangAppWithGoModTidyInstallFalseDoesNotCreateInstaller()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddGolangApp("golang", "../../examples/golang/gin-api").WithGoModTidy(install: false);
+
+ using var app = builder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var golangResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Empty(appModel.Resources.OfType());
+ }
+
+ [Fact]
+ public void GolangAppWithGoModDownloadInstallFalseDoesNotCreateInstaller()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddGolangApp("golang", "../../examples/golang/gin-api").WithGoModDownload(install: false);
+
+ using var app = builder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var golangResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Empty(appModel.Resources.OfType());
+ }
}
\ No newline at end of file
From 453e8196c8e95032a5519de3d2b09f6218838913 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 15 Jan 2026 08:32:37 +0000
Subject: [PATCH 4/8] Always create installer resource in run mode, use
WithExplicitStart when install is false
Co-authored-by: tommasodotNET <12819039+tommasodotNET@users.noreply.github.com>
---
.../GolangAppHostingExtension.cs | 40 +++++++++++++------
.../README.md | 12 +++---
.../ResourceCreationTests.cs | 22 ++++++++--
3 files changed, 52 insertions(+), 22 deletions(-)
diff --git a/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs b/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
index 836496441..a356552f6 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.Golang/GolangAppHostingExtension.cs
@@ -239,7 +239,7 @@ private static string GetDefaultGoBaseImage(string workingDirectory, IServicePro
/// Ensures Go module dependencies are tidied before the application starts using go mod tidy.
///
/// The Golang app resource builder.
- /// When true (default), automatically runs go mod tidy before the application starts. When false, this method does nothing.
+ /// When true (default), automatically runs go mod tidy before the application starts. When false, the installer resource is created but requires explicit start.
/// Optional action to configure the installer resource.
/// A reference to the .
public static IResourceBuilder WithGoModTidy(
@@ -249,8 +249,8 @@ public static IResourceBuilder WithGoModTidy(
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
- // Only install packages if in run mode and install is true
- if (builder.ApplicationBuilder.ExecutionContext.IsRunMode && install)
+ // Only create installer resource if in run mode
+ if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
{
var installerName = $"{builder.Resource.Name}-go-mod-tidy";
var installer = new GoModInstallerResource(installerName, builder.Resource.WorkingDirectory);
@@ -260,10 +260,18 @@ public static IResourceBuilder WithGoModTidy(
.WithParentRelationship(builder.Resource)
.ExcludeFromManifest();
- // Make the parent resource wait for the installer to complete
- builder.WaitForCompletion(installerBuilder);
-
configureInstaller?.Invoke(installerBuilder);
+
+ if (install)
+ {
+ // Make the parent resource wait for the installer to complete
+ builder.WaitForCompletion(installerBuilder);
+ }
+ else
+ {
+ // Add WithExplicitStart when install is false
+ installerBuilder.WithExplicitStart();
+ }
}
return builder;
@@ -273,7 +281,7 @@ public static IResourceBuilder WithGoModTidy(
/// Ensures Go module dependencies are downloaded before the application starts using go mod download.
///
/// The Golang app resource builder.
- /// When true (default), automatically runs go mod download before the application starts. When false, this method does nothing.
+ /// When true (default), automatically runs go mod download before the application starts. When false, the installer resource is created but requires explicit start.
/// Optional action to configure the installer resource.
/// A reference to the .
public static IResourceBuilder WithGoModDownload(
@@ -283,8 +291,8 @@ public static IResourceBuilder WithGoModDownload(
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
- // Only install packages if in run mode and install is true
- if (builder.ApplicationBuilder.ExecutionContext.IsRunMode && install)
+ // Only create installer resource if in run mode
+ if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
{
var installerName = $"{builder.Resource.Name}-go-mod-download";
var installer = new GoModInstallerResource(installerName, builder.Resource.WorkingDirectory);
@@ -294,10 +302,18 @@ public static IResourceBuilder WithGoModDownload(
.WithParentRelationship(builder.Resource)
.ExcludeFromManifest();
- // Make the parent resource wait for the installer to complete
- builder.WaitForCompletion(installerBuilder);
-
configureInstaller?.Invoke(installerBuilder);
+
+ if (install)
+ {
+ // Make the parent resource wait for the installer to complete
+ builder.WaitForCompletion(installerBuilder);
+ }
+ else
+ {
+ // Add WithExplicitStart when install is false
+ installerBuilder.WithExplicitStart();
+ }
}
return builder;
diff --git a/src/CommunityToolkit.Aspire.Hosting.Golang/README.md b/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
index 785d1ab7d..2e43a3ae0 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
+++ b/src/CommunityToolkit.Aspire.Hosting.Golang/README.md
@@ -43,11 +43,11 @@ var golang = builder.AddGolangApp("golang", "../gin-api")
.WithHttpEndpoint(env: "PORT");
```
-By default, `WithGoModTidy()` runs `go mod tidy` before the application starts (equivalent to `install: true`). You can disable this behavior by setting `install: false`:
+By default, `WithGoModTidy()` runs `go mod tidy` before the application starts (equivalent to `install: true`). You can set `install: false` to create the installer resource but require explicit start:
```csharp
var golang = builder.AddGolangApp("golang", "../gin-api")
- .WithGoModTidy(install: false) // Does not run go mod tidy
+ .WithGoModTidy(install: false) // Installer created but requires explicit start
.WithHttpEndpoint(env: "PORT");
```
@@ -61,15 +61,15 @@ var golang = builder.AddGolangApp("golang", "../gin-api")
.WithHttpEndpoint(env: "PORT");
```
-Similarly, you can control whether the download runs:
+Similarly, you can control the installer behavior:
```csharp
var golang = builder.AddGolangApp("golang", "../gin-api")
- .WithGoModDownload(install: false) // Does not run go mod download
+ .WithGoModDownload(install: false) // Installer created but requires explicit start
.WithHttpEndpoint(env: "PORT");
```
-Both methods create an installer resource that runs before your application starts when `install` is `true`, ensuring dependencies are available. The installer resource appears as a child resource in the Aspire dashboard.
+When `install` is `true` (default), the installer resource is created and the Go application waits for it to complete before starting. When `install` is `false`, the installer resource is still created but is set to require explicit start, appearing in the Aspire dashboard but not automatically executing.
You can also customize the installer resource using the optional `configureInstaller` parameter:
@@ -82,7 +82,7 @@ var golang = builder.AddGolangApp("golang", "../gin-api")
.WithHttpEndpoint(env: "PORT");
```
-> **Note:** The `WithGoModTidy` and `WithGoModDownload` methods only run in run mode (when the application is started locally). They do not run when publishing, as the generated Dockerfile handles dependency management automatically.
+> **Note:** The `WithGoModTidy` and `WithGoModDownload` methods only create installer resources in run mode (when the application is started locally). They do not run when publishing, as the generated Dockerfile handles dependency management automatically.
## Publishing
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
index 08568b6b1..b8cbcdbc9 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
@@ -184,7 +184,7 @@ public void WithGoModDownloadNullBuilderThrows()
}
[Fact]
- public void GolangAppWithGoModTidyInstallFalseDoesNotCreateInstaller()
+ public void GolangAppWithGoModTidyInstallFalseCreatesInstallerWithExplicitStart()
{
var builder = DistributedApplication.CreateBuilder();
@@ -195,11 +195,18 @@ public void GolangAppWithGoModTidyInstallFalseDoesNotCreateInstaller()
var appModel = app.Services.GetRequiredService();
var golangResource = Assert.Single(appModel.Resources.OfType());
- Assert.Empty(appModel.Resources.OfType());
+ var installerResource = Assert.Single(appModel.Resources.OfType());
+
+ // Installer should be created even with install: false
+ Assert.Equal("golang-go-mod-tidy", installerResource.Name);
+ Assert.Equal("go", installerResource.Command);
+
+ // Verify that the installer has ExplicitStartupAnnotation
+ Assert.True(installerResource.HasAnnotationOfType());
}
[Fact]
- public void GolangAppWithGoModDownloadInstallFalseDoesNotCreateInstaller()
+ public void GolangAppWithGoModDownloadInstallFalseCreatesInstallerWithExplicitStart()
{
var builder = DistributedApplication.CreateBuilder();
@@ -210,6 +217,13 @@ public void GolangAppWithGoModDownloadInstallFalseDoesNotCreateInstaller()
var appModel = app.Services.GetRequiredService();
var golangResource = Assert.Single(appModel.Resources.OfType());
- Assert.Empty(appModel.Resources.OfType());
+ var installerResource = Assert.Single(appModel.Resources.OfType());
+
+ // Installer should be created even with install: false
+ Assert.Equal("golang-go-mod-download", installerResource.Name);
+ Assert.Equal("go", installerResource.Command);
+
+ // Verify that the installer has ExplicitStartupAnnotation
+ Assert.True(installerResource.HasAnnotationOfType());
}
}
\ No newline at end of file
From 7be3e44e84840d1c810baaed5e08e77317c99bbc Mon Sep 17 00:00:00 2001
From: Tommaso Stocchi
Date: Thu, 15 Jan 2026 10:12:34 +0100
Subject: [PATCH 5/8] Update
tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../ResourceCreationTests.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
index f1a3f1246..57d325102 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
@@ -121,7 +121,7 @@ public async Task GolangAppWithGoModTidyHasCorrectArgsAsync()
var installerResource = Assert.Single(appModel.Resources.OfType());
- var args = await installerResource.GetArgumentValuesAsync();
+ var args = await installerResource.GetArgumentsAsync();
Assert.Collection(
args,
arg => Assert.Equal("mod", arg),
From 2ae8ee1c3f71ac2db0478cc5fb36cccda6e73d70 Mon Sep 17 00:00:00 2001
From: Tommaso Stocchi
Date: Thu, 15 Jan 2026 10:12:51 +0100
Subject: [PATCH 6/8] Update
tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../ResourceCreationTests.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
index 57d325102..386788eef 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
@@ -140,7 +140,7 @@ public void GolangAppWithGoModDownloadCreatesInstallerResource()
var appModel = app.Services.GetRequiredService();
- var golangResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Single(appModel.Resources.OfType());
var installerResource = Assert.Single(appModel.Resources.OfType());
Assert.Equal("golang-go-mod-download", installerResource.Name);
From 19406fde7e264da55964397ba1a867c7eef4fb76 Mon Sep 17 00:00:00 2001
From: Tommaso Stocchi
Date: Thu, 15 Jan 2026 10:13:15 +0100
Subject: [PATCH 7/8] Update
tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../ResourceCreationTests.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
index 386788eef..d214e23b3 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
@@ -101,7 +101,7 @@ public void GolangAppWithGoModTidyCreatesInstallerResource()
var appModel = app.Services.GetRequiredService();
- var golangResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Single(appModel.Resources.OfType());
var installerResource = Assert.Single(appModel.Resources.OfType());
Assert.Equal("golang-go-mod-tidy", installerResource.Name);
From 7abca01077d1f9e6475440d6a423b1cde90a953e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 15 Jan 2026 09:15:58 +0000
Subject: [PATCH 8/8] Address PR review feedback: fix obsolete API calls, add
WaitAnnotation assertions, remove unused variables
Co-authored-by: tommasodotNET <12819039+tommasodotNET@users.noreply.github.com>
---
.../ResourceCreationTests.cs | 20 +++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
index d214e23b3..4c26908f7 100644
--- a/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
+++ b/tests/CommunityToolkit.Aspire.Hosting.Golang.Tests/ResourceCreationTests.cs
@@ -101,11 +101,15 @@ public void GolangAppWithGoModTidyCreatesInstallerResource()
var appModel = app.Services.GetRequiredService();
- Assert.Single(appModel.Resources.OfType());
+ var golangResource = Assert.Single(appModel.Resources.OfType());
var installerResource = Assert.Single(appModel.Resources.OfType());
Assert.Equal("golang-go-mod-tidy", installerResource.Name);
Assert.Equal("go", installerResource.Command);
+
+ // Verify that the Golang app waits for the installer to complete
+ Assert.True(golangResource.TryGetAnnotationsOfType(out var waitAnnotations));
+ Assert.Contains(waitAnnotations, w => w.Resource == installerResource);
}
[Fact]
@@ -121,7 +125,7 @@ public async Task GolangAppWithGoModTidyHasCorrectArgsAsync()
var installerResource = Assert.Single(appModel.Resources.OfType());
- var args = await installerResource.GetArgumentsAsync();
+ var args = await installerResource.GetArgumentListAsync();
Assert.Collection(
args,
arg => Assert.Equal("mod", arg),
@@ -140,11 +144,15 @@ public void GolangAppWithGoModDownloadCreatesInstallerResource()
var appModel = app.Services.GetRequiredService();
- Assert.Single(appModel.Resources.OfType());
+ var golangResource = Assert.Single(appModel.Resources.OfType());
var installerResource = Assert.Single(appModel.Resources.OfType());
Assert.Equal("golang-go-mod-download", installerResource.Name);
Assert.Equal("go", installerResource.Command);
+
+ // Verify that the Golang app waits for the installer to complete
+ Assert.True(golangResource.TryGetAnnotationsOfType(out var waitAnnotations));
+ Assert.Contains(waitAnnotations, w => w.Resource == installerResource);
}
[Fact]
@@ -160,7 +168,7 @@ public async Task GolangAppWithGoModDownloadHasCorrectArgsAsync()
var installerResource = Assert.Single(appModel.Resources.OfType());
- var args = await installerResource.GetArgumentValuesAsync();
+ var args = await installerResource.GetArgumentListAsync();
Assert.Collection(
args,
arg => Assert.Equal("mod", arg),
@@ -195,7 +203,7 @@ public void GolangAppWithGoModTidyInstallFalseCreatesInstallerWithExplicitStart(
var appModel = app.Services.GetRequiredService();
- var golangResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Single(appModel.Resources.OfType());
var installerResource = Assert.Single(appModel.Resources.OfType());
// Installer should be created even with install: false
@@ -217,7 +225,7 @@ public void GolangAppWithGoModDownloadInstallFalseCreatesInstallerWithExplicitSt
var appModel = app.Services.GetRequiredService();
- var golangResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Single(appModel.Resources.OfType());
var installerResource = Assert.Single(appModel.Resources.OfType());
// Installer should be created even with install: false