diff --git a/.github/actions/setup-runtimes-caching/action.yml b/.github/actions/setup-runtimes-caching/action.yml index f92da160a..128f5f186 100644 --- a/.github/actions/setup-runtimes-caching/action.yml +++ b/.github/actions/setup-runtimes-caching/action.yml @@ -78,7 +78,7 @@ runs: - uses: actions/setup-go@v7 name: Set up Go with: - go-version: "^1.25.4" + go-version: "^1.26" cache-dependency-path: | ./examples/golang/gin-api/go.sum diff --git a/docs/go-apphost-parity.md b/docs/go-apphost-parity.md new file mode 100644 index 000000000..0e9e2e0ca --- /dev/null +++ b/docs/go-apphost-parity.md @@ -0,0 +1,80 @@ +# Go AppHost parity gaps + +These limitations were observed with Aspire SDK +`17.1.0-preview.1.26559.8`. The repository now pins +`17.0.0-preview.1.26555.11`; the ActiveMQ, Flare, Keycloak, and Zitadel +failures have also been confirmed with that version. The other cases have not +yet been revalidated against it: + +- **RustFs:** `AddRustFsOptions.AccessKey` and `SecretKey` are generated as + `*aspire.ParameterResource` (pointers to interfaces). Passing addresses of + the two parameter resources compiles, but the generated `serializeValue` + does not recognize those pointers as resource handles. During AppHost model + construction, `addRustFs` fails with `INVALID_ARGUMENT`: `Parameter type + 'IResourceBuilder\`1' must have [AspireDto] attribute to be deserialized from + JSON` for `accessKey`. The TypeScript example explicitly supplies both + credentials, so omitting them would not preserve its resource graph. +- **Umami:** `AddUmamiOptions.Secret` is likewise a `*aspire.ParameterResource`. + Passing the address of the explicitly configured `umami-secret` compiles, + but `aspire publish --apphost apphost.go --list-steps --non-interactive` + fails while constructing the model: `CommunityToolkit.Aspire.Hosting.Umami/addUmami` + reports `INVALID_ARGUMENT` for `secret`, with the same `IResourceBuilder\`1` + deserialization error as RustFs. Omitting the secret would not preserve the + TypeScript example. +- **Meilisearch:** `AddMeilisearchOptions.MasterKey` is also a pointer to a + parameter interface. An explicit `search-master-key` compiles but + `CommunityToolkit.Aspire.Hosting.Meilisearch/addMeilisearch` fails during + publish-model construction with `INVALID_ARGUMENT` for `masterKey` and + the same `IResourceBuilder\`1` deserialization error. The TypeScript + example explicitly supplies the key. +- **Redis extensions:** `AddRedisOptions.Password` is a pointer to a parameter + interface. Passing the explicit `redis-password` compiles, but + `Aspire.Hosting.Redis/addRedis` fails during publish-model construction with + `INVALID_ARGUMENT` for `password` and the same `IResourceBuilder\`1` + deserialization error. Generating a different password would change the + TypeScript example. +- **SQL Server extensions:** `AddSqlServerOptions.Password` has the same + pointer-to-parameter shape. The explicit `sql-password` compiles, but + `Aspire.Hosting.SqlServer/addSqlServer` reports `INVALID_ARGUMENT` for + `password` and the same `IResourceBuilder\`1` deserialization error during + publish-model construction. Omitting it changes the TypeScript example. +- **MCP Inspector:** `AddMcpInspectorOptions.ProxyToken` is a pointer to a + parameter interface. Passing the explicit `proxy-token` compiles, but + `CommunityToolkit.Aspire.Hosting.McpInspector/addMcpInspectorPolyglot` fails + during publish-model construction with `INVALID_ARGUMENT` for + `proxyToken` and the same `IResourceBuilder\`1` deserialization error. +- **Zitadel:** `AddZitadelOptions.Username`, `Password`, and `MasterKey` are + optional parameter-resource pointers. Supplying the credentials used by the + TypeScript example fails `CommunityToolkit.Aspire.Hosting.Zitadel/addZitadel` + with `INVALID_ARGUMENT` for `username` due to the same pointer-to-interface + serialization defect. Omitting them would change the example. +- **ActiveMQ:** `AddActiveMQOptions.UserName` is a pointer to a parameter + interface. `addActiveMQ` fails with `INVALID_ARGUMENT` for `userName` during + model construction when the TypeScript example's explicit credentials are + supplied. Its Go counterpart retains those credentials and is compile-tested. +- **Flare:** `WithPublicUrlsOptions.DashboardUrl` is a pointer to a parameter + interface. Passing the example's `flare-dashboard-url` causes + `CommunityToolkit.Aspire.Hosting.Flare/withPublicUrls` to fail with + `INVALID_ARGUMENT` for `dashboardUrl`; omitting it changes the configured + public URL. +- **Keycloak extensions:** The example's PostgreSQL `userName` and `password` + are parameter handles supplied to `addPostgres`. The generated Go options use + parameter-interface pointers; `Aspire.Hosting.PostgreSQL/addPostgres` fails + with `INVALID_ARGUMENT` for `userName`. Replacing the explicit credentials + changes the example. + +The Python extensions Go example runs, but its publish-mode model fails: +`AddStreamlitApp` removes the Python resource before adding its Streamlit +replacement, while the publish-mode executable container with the same name +remains in the model. The resulting duplicate `dashboard` resource causes +`AddStreamlitApp` to fail. Its Go compilation test therefore does not run the +publish-model check; fixing the integration is outside this example-only work. + +Floci's `WithServiceBus` is run-only by design and throws in publish mode, as +documented in the Floci README. Validate the example's Service Bus graph in run +mode rather than treating its publish-mode rejection as a Go SDK parity gap. + +On Windows, the SQL Database Projects Go example compiles but its model fails +when `MSBuildLocator.RegisterDefaults()` cannot load native `hostfxr`. Its +publish-model test is disabled on Windows; this is an environment/native-loading +issue, not the parameter serialization issue above. diff --git a/docs/setup.md b/docs/setup.md index f5b857532..c49608067 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -22,7 +22,7 @@ If you prefer not to use `devcontainer`, you can manually set up your developmen - You'll also need [Gradle](https://gradle.org/install/) and [Apache Maven](https://maven.apache.org/download.cgi) - [Bun](https://bun.sh) - [Deno 2](https://deno.land/) -- [Go 1.23](https://golang.org/) +- [Go 1.26 or later](https://go.dev/dl/) (required for Go AppHosts) - [Python 3](https://www.python.org/downloads/) - [Uvicorn](https://www.uvicorn.org/) - [Rust](https://www.rust-lang.org/tools/install) @@ -44,3 +44,5 @@ The repository currently targets Aspire **17.0.0-preview.1.26555.11**, an unsupp The C# AppHosts that host .NET projects now reference `Aspire.Hosting.Dotnet` and use `AddDotnetProject`; the TypeScript equivalents use `addDotnetProject`. `Aspire.Hosting.Dotnet` is centrally pinned to the same nightly version. The AppHosts still use `Aspire.AppHost.Sdk` for staged compatibility; Aspire 17 emits `ASPIRE012` for that obsolete SDK, and migrating to explicit `Aspire.Hosting.AppHost` references remains separate from this project-resource migration. Install the matching CLI with `aspire.dev`'s installer and its explicit version option (`-Version 17.0.0-preview.1.26555.11` on Windows or `--version 17.0.0-preview.1.26555.11` on Linux/macOS), rather than selecting a moving daily channel. See the [upstream daily-build guide](https://github.com/microsoft/aspire/blob/main/docs/using-latest-daily.md) for installer instructions. + +Go AppHosts are a preview feature. In a Go AppHost directory, run `aspire restore` to generate the SDK in `.aspire/modules`, then `go test ./...` to check compilation. Run the application with `aspire run`, rather than `go run`, so the CLI starts the AppHost server. diff --git a/eng/testing/select-affected-tests.cs b/eng/testing/select-affected-tests.cs index ed1defea3..87d54bb6a 100644 --- a/eng/testing/select-affected-tests.cs +++ b/eng/testing/select-affected-tests.cs @@ -57,7 +57,8 @@ public static async Task MainAsync(string[] args) var packageToTests = BuildPackageToTests(packageRefs, nodeToTests); var packageToProjects = BuildPackageToProjects(packageRefs); var testInfraPackages = LoadTestInfraPackages(repoRoot); - var typeScriptAppHostToTests = BuildTypeScriptAppHostToTests(repoRoot, projectPaths); + var typeScriptAppHostToTests = BuildAppHostToTests(repoRoot, projectPaths, "TypeScriptAppHostTests.cs"); + var goAppHostToTests = BuildAppHostToTests(repoRoot, projectPaths, "GoAppHostTests.cs"); foreach (var filePath in diffFiles) { @@ -165,13 +166,20 @@ public static async Task MainAsync(string[] args) continue; } - if (TryGetTypeScriptAppHostTests(filePath, typeScriptAppHostToTests, out impactedTypeScriptTests)) + if (TryGetAppHostTests(filePath, typeScriptAppHostToTests, out impactedTypeScriptTests)) { selected.UnionWith(impactedTypeScriptTests); reasons.Add($"Selected {impactedTypeScriptTests.Count} tests because {filePath} belongs to a TypeScript app host test fixture."); continue; } + if (TryGetAppHostTests(filePath, goAppHostToTests, out var impactedGoTests)) + { + selected.UnionWith(impactedGoTests); + reasons.Add($"Selected {impactedGoTests.Count} tests because {filePath} belongs to a Go app host test fixture."); + continue; + } + if (TryGetExampleTests(filePath, projectPaths, nodeToTests, out var exampleName, out var impactedExampleTests)) { selected.UnionWith(impactedExampleTests); @@ -521,7 +529,7 @@ private static Dictionary> BuildPackageToProjects(Dictio return appHostProjects.Count == 1 ? appHostProjects[0] : null; } - private static Dictionary> BuildTypeScriptAppHostToTests(string repoRoot, List projectPaths) + private static Dictionary> BuildAppHostToTests(string repoRoot, List projectPaths, string testFileName) { var appHostToTests = new Dictionary>(StringComparer.Ordinal); var testsRoot = Path.Combine(repoRoot, "tests"); @@ -530,7 +538,7 @@ private static Dictionary> BuildTypeScriptAppHostToTests return appHostToTests; } - foreach (var testFilePath in Directory.EnumerateFiles(testsRoot, "TypeScriptAppHostTests.cs", SearchOption.AllDirectories).OrderBy(static path => path, StringComparer.Ordinal)) + foreach (var testFilePath in Directory.EnumerateFiles(testsRoot, testFileName, SearchOption.AllDirectories).OrderBy(static path => path, StringComparer.Ordinal)) { var relativeTestFilePath = RelativePath(repoRoot, testFilePath); var testProjectPath = NearestProject(relativeTestFilePath, projectPaths); @@ -560,7 +568,7 @@ private static Dictionary> BuildTypeScriptAppHostToTests return appHostToTests; } - private static bool TryGetTypeScriptAppHostTests( + private static bool TryGetAppHostTests( string filePath, Dictionary> appHostToTests, out HashSet tests) diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/README.md b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/README.md new file mode 100644 index 000000000..25cc42178 --- /dev/null +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/README.md @@ -0,0 +1,26 @@ +# ActiveMQ Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It configures +Classic and Artemis brokers, explicit credentials, ports, volumes, bind mounts, +and exported endpoint properties. + +Use the Aspire 17 preview CLI matching `aspire.config.json` and Go 1.26 or later. +From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire start --isolated --non-interactive +``` + +Running the brokers requires Docker. + +## Preview SDK limitation + +With Aspire `17.1.0-preview.1.26559.8`, compilation succeeds but model execution +fails at `addActiveMQ` with `INVALID_ARGUMENT` for `userName`. The generated Go +options use `*ParameterResource` for optional resource parameters, but their +serializer does not unwrap the pointer to the interface into a resource handle. +The explicit credentials are retained for parity rather than removing them or +modifying generated SDK files. diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/apphost.go b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/apphost.go new file mode 100644 index 000000000..34a53be03 --- /dev/null +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/apphost.go @@ -0,0 +1,76 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + bindMountRoot, err := os.MkdirTemp("", "activemq-polyglot-") + check(err) + artemisDataPath := filepath.Join(bindMountRoot, "artemis-data") + artemisConfPath := filepath.Join(bindMountRoot, "artemis-conf") + check(os.MkdirAll(artemisDataPath, 0755)) + check(os.MkdirAll(artemisConfPath, 0755)) + + password := builder.AddParameter("mq-password", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("admin"), Secret: aspire.BoolPtr(true), + }) + user := builder.AddParameter("mq-user", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("admin"), PublishValueAsDefault: aspire.BoolPtr(true), + }) + check(password.Err()) + check(user.Err()) + + classic := builder.AddActiveMQ("classic", &aspire.AddActiveMQOptions{ + UserName: &user, Password: &password, Port: aspire.Float64Ptr(36161), + Scheme: aspire.StringPtr("activemq"), WebPort: aspire.Float64Ptr(38161), + }).WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("classic-data")}). + WithConfVolume(&aspire.WithConfVolumeOptions{Name: aspire.StringPtr("classic-conf")}) + classic2 := builder.AddActiveMQ("classic2", &aspire.AddActiveMQOptions{ + UserName: &user, Password: &password, + }) + artemis := builder.AddActiveMQArtemis("artemis", &aspire.AddActiveMQArtemisOptions{ + UserName: &user, Password: &password, Port: aspire.Float64Ptr(36162), + Scheme: aspire.StringPtr("tcp"), WebPort: aspire.Float64Ptr(38162), + }).WithDataBindMount(artemisDataPath).WithConfBindMount(artemisConfPath) + artemis2 := builder.AddActiveMQArtemis("artemis2", &aspire.AddActiveMQArtemisOptions{ + UserName: &user, Password: &password, + }).WithDataVolume().WithConfVolume() + + check(classic.Err()) + check(classic2.Err()) + check(artemis.Err()) + check(artemis2.Err()) + check(classic.PrimaryEndpoint().Err()) + check(classic.Host().Err()) + check(classic.Port().Err()) + _ = classic.UriExpression() + _ = classic.ConnectionStringExpression() + check(classic2.PrimaryEndpoint().Err()) + check(classic2.Host().Err()) + check(classic2.Port().Err()) + check(artemis.PrimaryEndpoint().Err()) + check(artemis.Host().Err()) + check(artemis.Port().Err()) + _ = artemis.UriExpression() + _ = artemis.ConnectionStringExpression() + check(artemis2.PrimaryEndpoint().Err()) + check(artemis2.Host().Err()) + check(artemis2.Port().Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/aspire.config.json b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..9d5404406 --- /dev/null +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.ActiveMQ": "../../../src/CommunityToolkit.Aspire.Hosting.ActiveMQ/CommunityToolkit.Aspire.Hosting.ActiveMQ.csproj" + } +} diff --git a/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/go.mod b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/activemq/CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/apphost.go b/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/apphost.go new file mode 100644 index 000000000..5bb14ae9b --- /dev/null +++ b/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/apphost.go @@ -0,0 +1,28 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + adminer := builder.AddAdminer("adminer", &aspire.AddAdminerOptions{ + Port: aspire.Float64Ptr(18080), + }).WithHostPort(aspire.Float64Ptr(18081)) + if err := adminer.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/aspire.config.json b/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..05bd5158e --- /dev/null +++ b/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Adminer": "../../../src/CommunityToolkit.Aspire.Hosting.Adminer/CommunityToolkit.Aspire.Hosting.Adminer.csproj" + } +} diff --git a/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/go.mod b/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/adminer/CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/README.md b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/README.md new file mode 100644 index 000000000..ae621543f --- /dev/null +++ b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/README.md @@ -0,0 +1,19 @@ +# Azure extensions Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It configures +Azurite with blob, queue, and table ports 27000-27002, a data volume, and Azure +Storage Explorer for the blob resource. + +Use the Aspire 17 preview CLI matching `aspire.config.json` and Go 1.26 or later. +From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire start --isolated --non-interactive +``` + +Running the emulator and explorer requires Docker. `aspire publish +--non-interactive` validates the publish model without provisioning Azure +resources. diff --git a/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/apphost.go b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..2e543c586 --- /dev/null +++ b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,35 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + storage := builder.AddAzureStorage("azure-storage").RunAsEmulator(&aspire.RunAsEmulatorOptions{ + ConfigureContainer: func(azurite aspire.AzureStorageEmulatorResource) { + azurite.WithArgs([]string{"--disableProductStyleUrl"}). + WithBlobPort(27000). + WithQueuePort(27001). + WithTablePort(27002). + WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("storage")}) + check(azurite.Err()) + }, + }) + check(storage.Err()) + blobs := storage.AddBlobs("blobs").WithAzureStorageExplorer() + check(blobs.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/aspire.config.json b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..f452f6a69 --- /dev/null +++ b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Azure.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.Azure.Extensions/CommunityToolkit.Aspire.Hosting.Azure.Extensions.csproj" + } +} diff --git a/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/go.mod b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/azure-ext/CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/apphost.go b/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/apphost.go new file mode 100644 index 000000000..d1842e4ec --- /dev/null +++ b/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/apphost.go @@ -0,0 +1,39 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + chroma := builder.AddChroma("chroma") + chroma.WithHostPort(aspire.Float64Ptr(18080)) + chroma.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("chroma-data")}) + check(chroma.PrimaryEndpoint().Err()) + check(chroma.Host().Err()) + check(chroma.Port().Err()) + _ = chroma.ConnectionStringExpression() + _ = chroma.UriExpression() + if err := chroma.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/aspire.config.json b/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..ebcfa99ad --- /dev/null +++ b/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Chroma": "../../../src/CommunityToolkit.Aspire.Hosting.Chroma/CommunityToolkit.Aspire.Hosting.Chroma.csproj" + } +} diff --git a/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/go.mod b/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/chromadb/CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/README.md b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/README.md new file mode 100644 index 000000000..17b127b59 --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/README.md @@ -0,0 +1,24 @@ +# Azure Dapr Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It configures an +Azure Container Apps environment with Dapr components, actor state metadata, and +three .NET services with the same component references and startup dependencies. + +Component references are configured on the sidecars through the exported +`ConfigureDaprSidecar` callback. This preserves the intended graph without using +the generic project `WithReference`, which does not accept Dapr components. + +Use the Aspire 17 preview CLI matching `aspire.config.json`, Go 1.26 or later, +the repository's .NET SDK, and the Dapr CLI. From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire publish --non-interactive +aspire start --isolated --non-interactive +``` + +Publishing generates Azure Bicep artifacts without provisioning Azure resources. +Local execution additionally requires Docker and an initialized Dapr runtime. +The Dapr CLI must be on `PATH` even when publishing the model. diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/apphost.go b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/apphost.go new file mode 100644 index 000000000..977080b0f --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/apphost.go @@ -0,0 +1,45 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + cae := builder.AddAzureContainerAppEnvironment("cae").WithDaprComponents() + check(cae.Err()) + stateStore := builder.AddDaprStateStore("statestore").WithMetadata("actorStateStore", "true") + pubSub := builder.AddDaprPubSub("pubsub") + check(stateStore.Err()) + check(pubSub.Err()) + + serviceA := builder.AddDotnetProject("servicea", "../CommunityToolkit.Aspire.Hosting.Dapr.ServiceA/CommunityToolkit.Aspire.Hosting.Dapr.ServiceA.csproj"). + PublishAsAzureContainerApp(func(context aspire.AzureResourceInfrastructure, app aspire.ContainerApp) {}). + ConfigureDaprSidecar(func(sidecar aspire.DaprSidecarResource) { + check(sidecar.WithReference(stateStore).WithReference(pubSub).Err()) + }) + check(serviceA.Err()) + serviceB := builder.AddDotnetProject("serviceb", "../CommunityToolkit.Aspire.Hosting.Dapr.ServiceB/CommunityToolkit.Aspire.Hosting.Dapr.ServiceB.csproj"). + ConfigureDaprSidecar(func(sidecar aspire.DaprSidecarResource) { + check(sidecar.WithReference(pubSub).Err()) + }).WaitFor(serviceA) + check(serviceB.Err()) + serviceC := builder.AddDotnetProject("servicec", "../CommunityToolkit.Aspire.Hosting.Dapr.ServiceC/CommunityToolkit.Aspire.Hosting.Dapr.ServiceC.csproj"). + ConfigureDaprSidecar(func(sidecar aspire.DaprSidecarResource) { + check(sidecar.WithReference(stateStore).Err()) + }).WaitFor(serviceA) + check(serviceC.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/aspire.config.json b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..70b19cc3a --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Azure.Dapr": "../../../src/CommunityToolkit.Aspire.Hosting.Azure.Dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/go.mod b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/README.md b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/README.md new file mode 100644 index 000000000..5f44775f6 --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/README.md @@ -0,0 +1,23 @@ +# Dapr Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It connects three +.NET services to Dapr state and pub/sub components and makes services B and C +wait for service A. + +Component references are configured on the sidecars through the exported +`ConfigureDaprSidecar` callback. This preserves the intended graph without using +the generic project `WithReference`, which does not accept Dapr components. + +Use the Aspire 17 preview CLI matching `aspire.config.json`, Go 1.26 or later, +the repository's .NET SDK, and the Dapr CLI. From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire publish --non-interactive +aspire start --isolated --non-interactive +``` + +Local execution additionally requires Docker and an initialized Dapr runtime. +The Dapr CLI must be on `PATH` even when publishing the model. diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/apphost.go b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/apphost.go new file mode 100644 index 000000000..b6c31894f --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/apphost.go @@ -0,0 +1,42 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + stateStore := builder.AddDaprStateStore("statestore") + pubSub := builder.AddDaprPubSub("pubsub") + check(stateStore.Err()) + check(pubSub.Err()) + + serviceA := builder.AddDotnetProject("servicea", "../CommunityToolkit.Aspire.Hosting.Dapr.ServiceA/CommunityToolkit.Aspire.Hosting.Dapr.ServiceA.csproj"). + ConfigureDaprSidecar(func(sidecar aspire.DaprSidecarResource) { + check(sidecar.WithReference(stateStore).WithReference(pubSub).Err()) + }) + check(serviceA.Err()) + serviceB := builder.AddDotnetProject("serviceb", "../CommunityToolkit.Aspire.Hosting.Dapr.ServiceB/CommunityToolkit.Aspire.Hosting.Dapr.ServiceB.csproj"). + ConfigureDaprSidecar(func(sidecar aspire.DaprSidecarResource) { + check(sidecar.WithReference(pubSub).Err()) + }).WaitFor(serviceA) + check(serviceB.Err()) + serviceC := builder.AddDotnetProject("servicec", "../CommunityToolkit.Aspire.Hosting.Dapr.ServiceC/CommunityToolkit.Aspire.Hosting.Dapr.ServiceC.csproj"). + ConfigureDaprSidecar(func(sidecar aspire.DaprSidecarResource) { + check(sidecar.WithReference(stateStore).Err()) + }).WaitFor(serviceA) + check(serviceC.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/aspire.config.json b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..eb7e1616a --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Dapr": "../../../src/CommunityToolkit.Aspire.Hosting.Dapr/CommunityToolkit.Aspire.Hosting.Dapr.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/go.mod b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/dapr/CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/README.md b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/README.md new file mode 100644 index 000000000..d665d8fed --- /dev/null +++ b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/README.md @@ -0,0 +1,22 @@ +# Data API builder Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It configures SQL +Server and the `trek` database, with two Data API builder resources referencing +the database and waiting for SQL Server. The second resource uses port 5001 and +two configuration files. + +The Go example reuses the configuration files and SQL initialization scripts +from the adjacent TypeScript AppHost rather than duplicating them. + +Use the Aspire 17 preview CLI matching `aspire.config.json` and Go 1.26 or later. +From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire publish --non-interactive +aspire start --isolated --non-interactive +``` + +Running the containers requires Docker. diff --git a/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/apphost.go b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/apphost.go new file mode 100644 index 000000000..692915a4a --- /dev/null +++ b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/apphost.go @@ -0,0 +1,51 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + configDirectory, err := filepath.Abs("../CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.TypeScript") + check(err) + primaryConfig := filepath.Join(configDirectory, "dab-config.json") + secondaryConfig := filepath.Join(configDirectory, "dab-config-2.json") + sql := builder.AddSqlServer("sql"). + WithBindMount(filepath.Join(configDirectory, "sql-server"), "/usr/config"). + WithBindMount("../database", "/docker-entrypoint-initdb.d"). + WithEntrypoint("/usr/config/entrypoint.sh") + check(sql.Err()) + db := sql.AddDatabase("trek") + check(db.Err()) + dab := builder.AddDataAPIBuilder("dab", &aspire.AddDataAPIBuilderOptions{ + ConfigFilePaths: []string{primaryConfig}, + }).WaitFor(sql).WithReference(db) + check(dab.Err()) + dabWithOptions := builder.AddDataAPIBuilder("dab-with-options", &aspire.AddDataAPIBuilderOptions{ + ConfigFilePaths: []string{primaryConfig, secondaryConfig}, HttpPort: aspire.Float64Ptr(5001), + }).WaitFor(sql).WithReference(db) + check(dabWithOptions.Err()) + + check(dab.PrimaryEndpoint().Err()) + check(dab.Host().Err()) + check(dab.Port().Err()) + _ = dab.UriExpression() + check(dabWithOptions.PrimaryEndpoint().Err()) + check(dabWithOptions.Host().Err()) + check(dabWithOptions.Port().Err()) + _ = dabWithOptions.UriExpression() + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/aspire.config.json b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..d4d6da423 --- /dev/null +++ b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder": "../../../src/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.csproj", + "Aspire.Hosting.SqlServer": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/go.mod b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/data-api-builder/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/README.md b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/README.md new file mode 100644 index 000000000..091155b87 --- /dev/null +++ b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/README.md @@ -0,0 +1,20 @@ +# DbGate Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It configures a +DbGate container on port 3310 with a temporary data bind mount and accesses its +primary endpoint. + +Use the Aspire 17 preview CLI matching `aspire.config.json` and Go 1.26 or later. +From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire publish --non-interactive +aspire start --isolated --non-interactive +``` + +Running the container requires Docker. Keep `ASPIRE_COMPILE_ONLY` unset for +execution: its optional volume call only covers the exported API, because the +volume and bind mount would otherwise overlap. diff --git a/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/apphost.go b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/apphost.go new file mode 100644 index 000000000..77f74c6ed --- /dev/null +++ b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/apphost.go @@ -0,0 +1,35 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" +) + +func main() { + bindMountPath, err := os.MkdirTemp("", "dbgate-") + check(err) + builder, err := aspire.CreateBuilder() + check(err) + + dbgate := builder.AddDbGate(&aspire.AddDbGateOptions{Name: aspire.StringPtr("dbgate")}). + WithHostPort(aspire.Float64Ptr(3310)). + WithDataBindMount(bindMountPath, &aspire.WithDataBindMountOptions{IsReadOnly: aspire.BoolPtr(false)}) + check(dbgate.Err()) + // A bind mount and volume would otherwise overlap on the same target path. + if os.Getenv("ASPIRE_COMPILE_ONLY") == "1" { + dbgate.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("dbgate-data")}) + check(dbgate.Err()) + } + check(dbgate.PrimaryEndpoint().Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/aspire.config.json b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..d0d8b6582 --- /dev/null +++ b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.DbGate": "../../../src/CommunityToolkit.Aspire.Hosting.DbGate/CommunityToolkit.Aspire.Hosting.DbGate.csproj" + } +} diff --git a/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/go.mod b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/apphost.go b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/apphost.go new file mode 100644 index 000000000..fc12efbd1 --- /dev/null +++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/apphost.go @@ -0,0 +1,30 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + dbx := builder.AddDbx(&aspire.AddDbxOptions{Name: aspire.StringPtr("dbx")}) + dbx.WithHostPort(aspire.Float64Ptr(3310)) + if err := dbx.PrimaryEndpoint().Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := dbx.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/aspire.config.json b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..46b21fa72 --- /dev/null +++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Dbx": "../../../src/CommunityToolkit.Aspire.Hosting.Dbx/CommunityToolkit.Aspire.Hosting.Dbx.csproj" + } +} diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/go.mod b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/README.md b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/README.md new file mode 100644 index 000000000..5f9f1d9a8 --- /dev/null +++ b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/README.md @@ -0,0 +1,18 @@ +# Deno Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It runs the +existing Vite and Oak examples with the same tasks, Deno permissions, HTTP +endpoints, health checks, and package installation. + +Use the Aspire 17 preview CLI matching `aspire.config.json` and Go 1.26 or later. +From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire publish --non-interactive +aspire start --isolated --non-interactive +``` + +Running the applications additionally requires Deno on `PATH`. diff --git a/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/apphost.go b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/apphost.go new file mode 100644 index 000000000..62d9f2420 --- /dev/null +++ b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/apphost.go @@ -0,0 +1,34 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + vite := builder.AddDenoTask("vite-demo", &aspire.AddDenoTaskOptions{TaskName: aspire.StringPtr("dev")}). + WithDenoPackageInstallation(). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}). + WithEndpoint(). + WithHttpHealthCheck(&aspire.WithHttpHealthCheckOptions{Path: aspire.StringPtr("/")}) + check(vite.Err()) + oak := builder.AddDenoApp("oak-demo", "main.ts", &aspire.AddDenoAppOptions{ + PermissionFlags: []string{"--allow-env", "--allow-net"}, + }).WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}). + WithEndpoint(). + WithHttpHealthCheck(&aspire.WithHttpHealthCheckOptions{Path: aspire.StringPtr("/health")}) + check(oak.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/aspire.config.json b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..dd7f25d39 --- /dev/null +++ b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Deno": "../../../src/CommunityToolkit.Aspire.Hosting.Deno/CommunityToolkit.Aspire.Hosting.Deno.csproj" + } +} diff --git a/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/go.mod b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/deno/CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/apphost.go b/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/apphost.go new file mode 100644 index 000000000..03aff6d98 --- /dev/null +++ b/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/apphost.go @@ -0,0 +1,31 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + duckdb := builder.AddDuckDB("analytics") + if err := duckdb.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + api := builder.AddDotnetProject("api", "../CommunityToolkit.Aspire.DuckDB.Api/CommunityToolkit.Aspire.DuckDB.Api.csproj") + api.WithReference(duckdb) + if err := api.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/aspire.config.json b/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..0fb9d01e7 --- /dev/null +++ b/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.DuckDB": "../../../src/CommunityToolkit.Aspire.Hosting.DuckDB/CommunityToolkit.Aspire.Hosting.DuckDB.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/go.mod b/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/duckdb/CommunityToolkit.Aspire.DuckDB.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/README.md b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/README.md new file mode 100644 index 000000000..183c7c850 --- /dev/null +++ b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/README.md @@ -0,0 +1,19 @@ +# Elasticsearch extensions Go AppHost + +This is the Go counterpart of the adjacent TypeScript AppHost. It provides +compile-time coverage of `WithElasticvue`, its configuration callback, and +`WithHostPort(9280)`. + +The Elasticsearch creation API is not exported by the preview SDK. Like the +TypeScript example, this AppHost deliberately creates no resources; the helper +functions validate the exported extension signatures without invoking them. + +Use the Aspire 17 preview CLI matching `aspire.config.json` and Go 1.26 or later. +From this directory: + +```shell +aspire restore --non-interactive +go build ./... +go vet ./... +aspire publish --non-interactive +``` diff --git a/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/apphost.go b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..175738102 --- /dev/null +++ b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,34 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func validateWithHostPort(elasticvue aspire.ElasticvueContainerResource) aspire.ElasticvueContainerResource { + return elasticvue.WithHostPort(aspire.Float64Ptr(9280)) +} + +// Keep extension coverage compile-only until the base Elasticsearch add API is exported. +func validateWithElasticvue(elasticsearch aspire.ElasticsearchResource) aspire.ElasticsearchResource { + return elasticsearch.WithElasticvue(&aspire.WithElasticvueOptions{ + ContainerName: aspire.StringPtr("elasticvue-ui"), + ConfigureContainer: func(elasticvue aspire.ElasticvueContainerResource) { + check(validateWithHostPort(elasticvue).Err()) + }, + }) +} + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/aspire.config.json b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..7c8d21b16 --- /dev/null +++ b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.csproj" + } +} diff --git a/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/go.mod b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/elasticsearch-ext/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/apphost.go b/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/apphost.go new file mode 100644 index 000000000..ef7af47bc --- /dev/null +++ b/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/apphost.go @@ -0,0 +1,57 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + flagsPath := "../CommunityToolkit.Aspire.Hosting.Flagd.AppHost.TypeScript/flags" + + flagd := builder.AddFlagd("flagd", &aspire.AddFlagdOptions{ + Port: aspire.Float64Ptr(18013), + OfrepPort: aspire.Float64Ptr(18016), + }) + flagd.WithBindFileSync(flagsPath) + check(flagd.PrimaryEndpoint().Err()) + check(flagd.Host().Err()) + check(flagd.Port().Err()) + check(flagd.GetEndpoint("health").Err()) + check(flagd.GetEndpoint("ofrep").Err()) + _ = flagd.UriExpression() + _ = flagd.ConnectionStringExpression() + if err := flagd.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + defaults := builder.AddFlagd("flagd-default") + defaults.WithBindFileSync(flagsPath, &aspire.WithBindFileSyncOptions{Filename: aspire.StringPtr("custom-flagd.json")}) + check(defaults.PrimaryEndpoint().Err()) + check(defaults.Host().Err()) + check(defaults.Port().Err()) + check(defaults.GetEndpoint("health").Err()) + check(defaults.GetEndpoint("ofrep").Err()) + _ = defaults.UriExpression() + _ = defaults.ConnectionStringExpression() + if err := defaults.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/aspire.config.json b/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..771ec572a --- /dev/null +++ b/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Flagd": "../../../src/CommunityToolkit.Aspire.Hosting.Flagd/CommunityToolkit.Aspire.Hosting.Flagd.csproj" + } +} diff --git a/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/go.mod b/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/flagd/CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/.gitignore b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/.gitignore new file mode 100644 index 000000000..d31c96078 --- /dev/null +++ b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/.gitignore @@ -0,0 +1 @@ +.aspire/ diff --git a/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/README.md b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/README.md new file mode 100644 index 000000000..cb3e321b7 --- /dev/null +++ b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/README.md @@ -0,0 +1,11 @@ +# Flare Go AppHost + +This example mirrors the adjacent TypeScript AppHost using the pinned Aspire 17 +preview Go SDK. Run `aspire restore --apphost apphost.go`, then `go test ./...` +and `go vet ./...` to validate the generated SDK and example. + +The current preview SDK does not serialize optional resource-builder handles +correctly. Model construction fails at `WithPublicUrls` when passing the dashboard +URL parameter, with `INVALID_ARGUMENT` for `dashboardUrl`. The example retains +the parameter-based configuration for parity; its integration test validates +compilation only until the upstream SDK supports this argument. diff --git a/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/apphost.go b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/apphost.go new file mode 100644 index 000000000..2aa844551 --- /dev/null +++ b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/apphost.go @@ -0,0 +1,56 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + clickhouse := builder.AddClickHouse("clickhouse") + redis := builder.AddRedis("redis") + ingestKey := builder.AddParameter("flare-ingest-key", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("local-dev-ingest-key"), Secret: aspire.BoolPtr(true), + }) + dashboardURL := builder.AddParameter("flare-dashboard-url", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("http://localhost:3000"), + }) + flare := builder.AddFlare("flare", clickhouse, redis, &aspire.AddFlareOptions{ + DashboardPort: aspire.Float64Ptr(3000), + }) + flare.WithDataVolume(). + WithIngestPorts(&aspire.WithIngestPortsOptions{GrpcPort: aspire.Float64Ptr(4317), HttpPort: aspire.Float64Ptr(4318)}). + WithFlareImageTag("0.6"). + WithPublicUrls(&aspire.WithPublicUrlsOptions{DashboardUrl: &dashboardURL}). + WithApiKey(ingestKey) + check(flare.OtlpGrpcEndpoint().Err()) + check(flare.OtlpHttpEndpoint().Err()) + protocol := aspire.OtlpProtocolHttpProtobuf + api := builder.AddDotnetProject("apiservice", "../CommunityToolkit.Aspire.Hosting.Flare.ApiService/CommunityToolkit.Aspire.Hosting.Flare.ApiService.csproj"). + WithFlareOtlpExporter(flare, &aspire.WithFlareOtlpExporterOptions{Protocol: &protocol}). + WaitFor(flare) + if err := api.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := flare.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/aspire.config.json b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..29aea3662 --- /dev/null +++ b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Flare": "../../../src/CommunityToolkit.Aspire.Hosting.Flare/CommunityToolkit.Aspire.Hosting.Flare.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/go.mod b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/flare/CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/.gitignore b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/.gitignore new file mode 100644 index 000000000..d31c96078 --- /dev/null +++ b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/.gitignore @@ -0,0 +1 @@ +.aspire/ diff --git a/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/README.md b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/README.md new file mode 100644 index 000000000..67bae564a --- /dev/null +++ b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/README.md @@ -0,0 +1,19 @@ +# Floci Go AppHost + +This example mirrors the adjacent TypeScript AppHost, including all three cloud +emulators, their shared UI, the API service, and the Service Bus AMQP probe. +It requires the pinned Aspire 17 preview CLI, Go 1.26 or later, and Docker. + +From this directory, run: + +```shell +aspire restore --apphost apphost.go +go test ./... +go vet ./... +aspire run --apphost apphost.go +``` + +The Service Bus emulator supports run mode only, so publishing this development +graph is intentionally unsupported. The integration test validates compilation +without constructing a publish-mode model. The checked-in TypeScript example +remains the source of the equivalent runtime scenario. diff --git a/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/apphost.go b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/apphost.go new file mode 100644 index 000000000..10884605c --- /dev/null +++ b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/apphost.go @@ -0,0 +1,150 @@ +package main + +import ( + "apphost/modules/aspire" + "crypto/rand" + "fmt" + "log" + "os" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + aws := builder.AddFlociAws("floci-aws") + azure := builder.AddFlociAzure("floci-az") + gcp := builder.AddFlociGcp("floci-gcp") + namespace := make([]byte, 16) + if _, err := rand.Read(namespace); err != nil { + log.Fatal(err) + } + azure.WithDockerSocket().WithEnvironment("FLOCI_AZ_DOCKER_RESOURCE_NAMESPACE", fmt.Sprintf("sample-%x", namespace)) + serviceBus := azure.WithServiceBus(&aspire.WithServiceBusOptions{Name: aspire.StringPtr("servicebus")}) + check(serviceBus.AmqpEndpoint().Err()) + check(serviceBus.AmqpTlsEndpoint().Err()) + _ = serviceBus.ConnectionStringExpression() + storage := azure.WithStorage(&aspire.WithStorageOptions{Name: aspire.StringPtr("storage")}) + if _, err := storage.AccountName(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + _ = storage.ServiceEndpoint() + _ = storage.ConnectionStringExpression() + aws.WithFlociUI(&aspire.WithFlociUIOptions{ + ConfigureContainer: func(ui aspire.FlociUIContainerResource) { + ui.WithAzureReference(azure).WithGcpReference(gcp) + if err := ui.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + }, + }) + api := builder.AddDotnetProject("floci-api", "../CommunityToolkit.Aspire.Hosting.Floci.ApiService/CommunityToolkit.Aspire.Hosting.Floci.ApiService.csproj"). + WithExternalHttpEndpoints(). + WithHttpHealthCheck(&aspire.WithHttpHealthCheckOptions{Path: aspire.StringPtr("/health")}). + WithFlociAwsReference(aws).WithFlociAzureReference(azure).WithFlociGcpReference(gcp). + WithFlociAzureServiceBusReference(serviceBus).WithReference(storage). + WaitFor(aws).WaitFor(azure).WaitFor(gcp).WaitFor(storage) + probe := builder.AddContainer("servicebus-probe", "node:22-alpine"). + WithFlociAzureServiceBusReference(serviceBus). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{TargetPort: aspire.Float64Ptr(8080)}). + WithHttpHealthCheck(&aspire.WithHttpHealthCheckOptions{Path: aspire.StringPtr("/")}). + WaitFor(azure).WithArgs([]string{"-e", ` + const net = require('node:net'); + const http = require('node:http'); + const assert = require('node:assert/strict'); + const connectionString = process.env.ConnectionStrings__servicebus; + const endpoint = new URL(connectionString.split(';')[0].slice('Endpoint='.length)); + const header = Buffer.from([65, 77, 81, 80, 0, 1, 0, 0]); + let ready = false; + const socket = net.connect({ host: endpoint.hostname, port: Number(endpoint.port) }, () => socket.write(header)); + socket.setTimeout(20000, () => { throw new Error('AMQP handshake timed out'); }); + let response = Buffer.alloc(0); + socket.on('data', data => { + response = Buffer.concat([response, data]); + if (response.length >= header.length) { + assert.deepEqual(response.subarray(0, header.length), header); + ready = true; + socket.destroy(); + } + }); + http.createServer((request, response) => { + response.writeHead(ready ? 200 : 503); + response.end(); + }).listen(8080, '0.0.0.0'); + `}) + custom := builder.AddFlociAws("floci-custom", &aspire.AddFlociAwsOptions{ + Port: aspire.Float64Ptr(14566), DefaultRegion: aspire.StringPtr("eu-west-1"), DefaultAccountId: aspire.StringPtr("123456789012"), + }) + gcpCustom := builder.AddFlociGcp("floci-gcp-custom", &aspire.AddFlociGcpOptions{DefaultProjectId: aspire.StringPtr("my-project")}) + persistent := builder.AddFlociAws("floci-persistent").WithDataVolume("floci-data") + dataPath, err := filepath.Abs(filepath.Join(".aspire", "floci-data")) + if err != nil { + log.Fatal(err) + } + if err := os.MkdirAll(dataPath, 0755); err != nil { + log.Fatal(err) + } + mount := builder.AddFlociAws("floci-mount").WithDataBindMount(dataPath) + + const includeCompileOnlyScenarios = false + if includeCompileOnlyScenarios { + builder.AddFlociAws("floci-with-ui").WithFlociUI(&aspire.WithFlociUIOptions{ + ContainerName: aspire.StringPtr("my-floci-ui"), + ConfigureContainer: func(ui aspire.FlociUIContainerResource) { + ui.WithHostPort(aspire.Float64Ptr(14500)) + if err := ui.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + }, + }) + socketOptions := &aspire.WithDockerSocketOptions{SocketPath: aspire.StringPtr("/run/user/1000/podman/podman.sock")} + builder.AddFlociAws("floci-podman").WithDockerSocket(socketOptions) + builder.AddFlociAzure("floci-az-podman").WithDockerSocket(socketOptions). + WithServiceBus(&aspire.WithServiceBusOptions{Name: aspire.StringPtr("podman-servicebus"), AmqpPort: aspire.Float64Ptr(15673), AmqpTlsPort: aspire.Float64Ptr(15674)}) + builder.AddFlociGcp("floci-gcp-podman").WithDockerSocket(socketOptions) + builder.AddFlociAzure("floci-az-persistent").WithDataVolume("floci-az-data") + builder.AddFlociAzure("floci-az-mount").WithDataBindMount("/tmp/floci-az-data") + builder.AddFlociGcp("floci-gcp-persistent").WithDataVolume("floci-gcp-data") + builder.AddFlociGcp("floci-gcp-mount").WithDataBindMount("/tmp/floci-gcp-data") + builder.AddFlociAws("floci-tls").WithHttpsDeveloperCertificate() + builder.AddFlociAzure("floci-az-tls").WithHttpsDeveloperCertificate() + builder.AddFlociAws("floci-configured").WithConfigFile("./floci.yml") + check(aws.PrimaryEndpoint().Err()) + check(aws.Host().Err()) + check(aws.Port().Err()) + _ = aws.ConnectionStringExpression() + check(azure.PrimaryEndpoint().Err()) + check(azure.Host().Err()) + check(azure.Port().Err()) + _ = azure.ConnectionStringExpression() + check(gcp.PrimaryEndpoint().Err()) + check(gcp.Host().Err()) + check(gcp.Port().Err()) + _ = gcp.ConnectionStringExpression() + builder.AddDotnetProject("api", "../FlociApi/FlociApi.csproj"). + WithFlociAwsReference(aws).WithFlociAzureReference(azure).WithFlociGcpReference(gcp) + builder.AddContainer("worker", "myorg/worker"). + WithFlociAwsReference(aws).WithFlociAzureReference(azure).WithFlociGcpReference(gcp) + } + for _, resource := range []interface{ Err() error }{aws, azure, gcp, serviceBus, storage, api, probe, custom, gcpCustom, persistent, mount} { + if err := resource.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + } + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/aspire.config.json b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..550e8eaa8 --- /dev/null +++ b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Floci": "../../../src/CommunityToolkit.Aspire.Hosting.Floci/CommunityToolkit.Aspire.Hosting.Floci.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/go.mod b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/apphost.go b/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/apphost.go new file mode 100644 index 000000000..59be212d1 --- /dev/null +++ b/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/apphost.go @@ -0,0 +1,33 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + flyway := builder.AddFlyway("flyway", "../CommunityToolkit.Aspire.Hosting.Flyway.AppHost.TypeScript/migrations") + flyway.WithArgs([]string{"-v"}) + if err := flyway.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + telemetry := builder.AddFlyway("flyway-telemetry", "../CommunityToolkit.Aspire.Hosting.Flyway.AppHost.TypeScript/migrations") + telemetry.WithTelemetryOptIn().WithArgs([]string{"-v"}) + if err := telemetry.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/aspire.config.json b/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..1905ec1c7 --- /dev/null +++ b/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Flyway": "../../../src/CommunityToolkit.Aspire.Hosting.Flyway/CommunityToolkit.Aspire.Hosting.Flyway.csproj" + } +} diff --git a/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/go.mod b/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/flyway/CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/apphost.go b/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/apphost.go new file mode 100644 index 000000000..218619038 --- /dev/null +++ b/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/apphost.go @@ -0,0 +1,45 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + directory, err := builder.AppHostDirectory() + check(err) + config := filepath.Join(directory, "..", "CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.TypeScript", "goff") + + goff := builder.AddGoFeatureFlag("goff", &aspire.AddGoFeatureFlagOptions{ + PathToConfigFile: aspire.StringPtr("/goff/goff-proxy.yaml"), + Port: aspire.Float64Ptr(11031), + }) + goff.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("goff-data")}) + goff.WithGoffBindMount(config) + goff.WithLogLevel(aspire.GoFeatureFlagLogLevelDebug) + + goff2 := builder.AddGoFeatureFlag("goff2") + goff2.WithGoffBindMount(config) + + for _, resource := range []aspire.GoFeatureFlagResource{goff, goff2} { + check(resource.PrimaryEndpoint().Err()) + check(resource.Host().Err()) + check(resource.Port().Err()) + _ = resource.UriExpression() + _ = resource.ConnectionStringExpression() + check(resource.Err()) + } + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/aspire.config.json b/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..ab013100c --- /dev/null +++ b/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.GoFeatureFlag": "../../../src/CommunityToolkit.Aspire.Hosting.GoFeatureFlag/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.csproj" + } +} diff --git a/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/go.mod b/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/goff/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/apphost.go b/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/apphost.go new file mode 100644 index 000000000..81a0870ef --- /dev/null +++ b/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/apphost.go @@ -0,0 +1,108 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "path/filepath" + "runtime" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + projectDirectory, err := filepath.Abs("../CommunityToolkit.Aspire.Hosting.Java.Spring.Maven") + if err != nil { + log.Fatal(err) + } + jarPath := filepath.Join("target", "spring-maven-0.0.1-SNAPSHOT.jar") + mavenWrapper, gradleWrapper := "mvnw", "gradlew" + if runtime.GOOS == "windows" { + mavenWrapper, gradleWrapper = "mvnw.cmd", "gradlew.bat" + } + + container := builder.AddJavaContainerApp("java-container", "docker.io/aliencube/aspire-spring-maven-sample", + &aspire.AddJavaContainerAppOptions{ImageTag: aspire.StringPtr("latest")}). + WithJvmArgs([]string{"-Djava.awt.headless=true"}). + WithOtelAgent(). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{TargetPort: aspire.Float64Ptr(8080), Env: aspire.StringPtr("SERVER_PORT")}). + WithHttpHealthCheck(&aspire.WithHttpHealthCheckOptions{Path: aspire.StringPtr("/")}). + WithExplicitStart() + container.SetEntrypoint(aspire.StringPtr("java")) + _, err = container.Entrypoint() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + container.SetShellExecution(aspire.BoolPtr(false)) + if _, err := container.ShellExecution(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := container.Name(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + jar := builder.AddJavaAppWithJar("java-jar", projectDirectory, jarPath, + &aspire.AddJavaAppWithJarOptions{Args: []string{"--spring.main.banner-mode=off"}}). + WithWrapperPath(mavenWrapper). + WithMavenBuild([]string{}). + WithJvmArgs([]string{"-Duser.timezone=UTC"}). + WithOtelAgent(). + WithExplicitStart() + if _, err := jar.Command(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := jar.WorkingDirectory(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := jar.Name(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := jar.JarPath(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + jar.SetJarPath(aspire.StringPtr(jarPath)) + if _, err := jar.JarPath(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + mavenGoal := builder.AddJavaApp("java-maven-goal", projectDirectory). + WithWrapperPath(mavenWrapper). + WithMavenGoal("spring-boot:run", []string{}). + WithJvmArgs([]string{"-Dfile.encoding=UTF-8"}). + WithOtelAgent(). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{TargetPort: aspire.Float64Ptr(8080), Env: aspire.StringPtr("SERVER_PORT")}). + WithHttpHealthCheck(&aspire.WithHttpHealthCheckOptions{Path: aspire.StringPtr("/health")}). + WithExplicitStart() + if _, err := mavenGoal.Command(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := mavenGoal.WorkingDirectory(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := mavenGoal.Name(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + gradleBuild := builder.AddJavaApp("java-gradle-build", projectDirectory). + WithWrapperPath(gradleWrapper). + WithGradleBuild([]string{"--parallel"}). + WithExplicitStart() + gradleTask := builder.AddJavaApp("java-gradle-task", projectDirectory). + WithWrapperPath(gradleWrapper). + WithGradleTask("bootRun", []string{"--args=--spring.main.banner-mode=off"}). + WithExplicitStart() + + for _, resource := range []interface{ Err() error }{container, jar, mavenGoal, gradleBuild, gradleTask} { + if err := resource.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + } + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/aspire.config.json b/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..c8bf0b60a --- /dev/null +++ b/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Java": "../../../src/CommunityToolkit.Aspire.Hosting.Java/CommunityToolkit.Aspire.Hosting.Java.csproj" + } +} diff --git a/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/go.mod b/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/java/CommunityToolkit.Aspire.Hosting.Java.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/apphost.go b/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..de1076479 --- /dev/null +++ b/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,67 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + nxRoot, err := filepath.Abs("../nx-demo") + if err != nil { + log.Fatal(err) + } + turboRoot, err := filepath.Abs("../turborepo-demo") + if err != nil { + log.Fatal(err) + } + + nx := builder.AddNxApp("nx-demo", &aspire.AddNxAppOptions{WorkingDirectory: aspire.StringPtr(nxRoot)}). + WithNpm().WithPackageManagerLaunch().WithExplicitStart() + nxBlog := nx.AddApp("blog-monorepo"). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}). + WithMappedEndpointPort().WithHttpHealthCheck().WithExplicitStart() + nxYarn := builder.AddNxApp("nx-yarn", &aspire.AddNxAppOptions{WorkingDirectory: aspire.StringPtr(nxRoot)}). + WithYarn().WithPackageManagerLaunch(&aspire.WithPackageManagerLaunchOptions{PackageManager: aspire.StringPtr("yarn")}). + WithExplicitStart() + nxYarnBlog := nxYarn.AddApp("blog-monorepo-yarn", &aspire.AddAppOptions{AppName: aspire.StringPtr("blog-monorepo")}). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}). + WithMappedEndpointPort(&aspire.WithMappedEndpointPortOptions{EndpointName: aspire.StringPtr("http")}). + WithExplicitStart() + nxPnpm := builder.AddNxApp("nx-pnpm", &aspire.AddNxAppOptions{WorkingDirectory: aspire.StringPtr(nxRoot)}). + WithPnpm().WithPackageManagerLaunch(&aspire.WithPackageManagerLaunchOptions{PackageManager: aspire.StringPtr("pnpm")}). + WithExplicitStart() + + turbo := builder.AddTurborepoApp("turborepo-demo", &aspire.AddTurborepoAppOptions{WorkingDirectory: aspire.StringPtr(turboRoot)}). + WithNpm(&aspire.WithNpmOptions{Install: aspire.BoolPtr(true)}).WithPackageManagerLaunch() + turboWeb := turbo.AddApp("turbo-web", &aspire.TurborepoResourceAddAppOptions{Filter: aspire.StringPtr("web")}). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}). + WithMappedEndpointPort().WithHttpHealthCheck() + turboYarn := builder.AddTurborepoApp("turborepo-yarn", &aspire.AddTurborepoAppOptions{WorkingDirectory: aspire.StringPtr(turboRoot)}). + WithYarn().WithPackageManagerLaunch(&aspire.WithPackageManagerLaunchOptions{PackageManager: aspire.StringPtr("yarn")}). + WithExplicitStart() + turboDocs := turboYarn.AddApp("docs"). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}). + WithMappedEndpointPort(&aspire.WithMappedEndpointPortOptions{EndpointName: aspire.StringPtr("http")}). + WithExplicitStart() + turboPnpm := builder.AddTurborepoApp("turborepo-pnpm", &aspire.AddTurborepoAppOptions{WorkingDirectory: aspire.StringPtr(turboRoot)}). + WithPnpm().WithPackageManagerLaunch(&aspire.WithPackageManagerLaunchOptions{PackageManager: aspire.StringPtr("pnpm")}). + WithExplicitStart() + + for _, resource := range []interface{ Err() error }{nx, nxBlog, nxYarn, nxYarnBlog, nxPnpm, turbo, turboWeb, turboYarn, turboDocs, turboPnpm} { + if err := resource.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + } + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/aspire.config.json b/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..1cebfa4a8 --- /dev/null +++ b/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.JavaScript.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.csproj" + } +} diff --git a/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/go.mod b/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/javascript-ext/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/apphost.go b/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/apphost.go index afb0046ae..91e4755c9 100644 --- a/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/apphost.go +++ b/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/apphost.go @@ -21,39 +21,42 @@ func main() { // by the compile-time section below. cluster := builder.AddK3sCluster("k8s") - _ = cluster.ApiEndpoint() + check(cluster.ApiEndpoint().Err()) + check(cluster.Err()) setupPodinfo := cluster.AddHelmRelease("podinfo", "podinfo", &aspire.AddHelmReleaseOptions{ Repo: aspire.StringPtr("https://stefanprodan.github.io/podinfo"), Version: aspire.StringPtr("6.7.1"), Namespace: aspire.StringPtr("podinfo"), }) + check(setupPodinfo.Err()) - cluster.AddServiceEndpoint("podinfo-web", "podinfo", 9898, &aspire.AddServiceEndpointOptions{ + endpoint := cluster.AddServiceEndpoint("podinfo-web", "podinfo", 9898, &aspire.AddServiceEndpointOptions{ Namespace: aspire.StringPtr("podinfo"), }).WaitForCompletion(setupPodinfo) + check(endpoint.Err()) // ── Compile-time coverage ───────────────────────────────────────────────────── // Guards with false so these are type-checked but never executed. // Covers the full exported API surface without requiring Docker/k3s in CI. const includeCompileOnlyScenarios = false - if (includeCompileOnlyScenarios) { + if includeCompileOnlyScenarios { // ── Cluster configuration ──────────────────────────────────────────────── // All K3sClusterOptions are now available as fluent builder methods. - configuredCluster := builder.AddK3sCluster("k8s-configured", + configuredCluster := builder.AddK3sCluster("k8s-configured", &aspire.AddK3sClusterOptions{ ApiServerPort: aspire.Float64Ptr(6443), - AgentCount: aspire.Float64Ptr(2), + AgentCount: aspire.Float64Ptr(2), }). WithK3sVersion("v1.32.3-k3s1"). WithPodSubnet("10.42.0.0/16"). WithServiceSubnet("10.43.0.0/16"). WithDisabledComponent("traefik"). WithExtraArg("--write-kubeconfig-mode=644"). - WithDataVolume(&aspire.WithDataVolumeOptions{ Name: aspire.StringPtr("k8s-data") }). - WithHelmImage(&aspire.WithHelmImageOptions{ Tag: aspire.StringPtr("3.18.0") }). - WithKubectlImage(&aspire.WithKubectlImageOptions{ Tag: aspire.StringPtr("1.37.0") }). + WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("k8s-data")}). + WithHelmImage(&aspire.WithHelmImageOptions{Tag: aspire.StringPtr("3.18.0")}). + WithKubectlImage(&aspire.WithKubectlImageOptions{Tag: aspire.StringPtr("1.37.0")}). WithLifetime(aspire.ContainerLifetimePersistent) _ = configuredCluster.ApiEndpoint() @@ -66,7 +69,7 @@ func main() { }) _ = podinfo.Parent() - + _, _ = podinfo.ReleaseName() _, _ = podinfo.Namespace() @@ -107,7 +110,7 @@ func main() { // • Project/executable: KUBECONFIG=/.k3s/k8s/local/kubeconfig.yaml // • Container: KUBECONFIG=/tmp/k3s-kubeconfig.yaml + bind-mount _ = builder. - AddProject("operator", "../WidgetOperator/WidgetOperator.csproj"). + AddDotnetProject("operator", "../WidgetOperator/WidgetOperator.csproj"). WithReference(configuredCluster) _ = builder. @@ -115,9 +118,9 @@ func main() { WithReference(configuredCluster) // ── WithReference — service endpoint URL injection ──────────────────────── - + _ = builder. - AddProject("api", "../WidgetApi/WidgetApi.csproj"). + AddDotnetProject("api", "../WidgetApi/WidgetApi.csproj"). WithReference(podinfoWeb) } @@ -128,4 +131,10 @@ func main() { if err := app.Run(); err != nil { log.Fatal(aspire.FormatError(err)) } -} \ No newline at end of file +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/aspire.config.json b/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/aspire.config.json index f2b46ab14..29e69c2ff 100644 --- a/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/aspire.config.json +++ b/examples/k3s/CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go/aspire.config.json @@ -3,13 +3,11 @@ "path": "apphost.go", "language": "go" }, - "features.experimentalPolyglot": { - "go": "true" - }, "sdk": { "version": "17.0.0-preview.1.26555.11" }, "packages": { - "CommunityToolkit.Aspire.Hosting.K3s": "../../../src/CommunityToolkit.Aspire.Hosting.K3s/CommunityToolkit.Aspire.Hosting.K3s.csproj" + "CommunityToolkit.Aspire.Hosting.K3s": "../../../src/CommunityToolkit.Aspire.Hosting.K3s/CommunityToolkit.Aspire.Hosting.K3s.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" } } diff --git a/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/apphost.go b/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/apphost.go new file mode 100644 index 000000000..a621c08a8 --- /dev/null +++ b/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/apphost.go @@ -0,0 +1,41 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + defaultK6 := builder.AddK6("k6-default") + browserK6 := builder.AddK6("k6-browser", &aspire.AddK6Options{ + EnableBrowserExtensions: aspire.BoolPtr(true), Port: aspire.Float64Ptr(6566), + }) + for _, resource := range []aspire.K6Resource{defaultK6, browserK6} { + resource.WithBindMount("../CommunityToolkit.Aspire.Hosting.k6.AppHost.TypeScript/scripts", "/scripts", &aspire.WithBindMountOptions{IsReadOnly: aspire.BoolPtr(true)}) + } + defaultK6.WithScript("/scripts/main.js").WithK6OtlpEnvironment() + browserK6.WithScript("/scripts/main.js", &aspire.WithScriptOptions{ + VirtualUsers: aspire.Float64Ptr(5), Duration: aspire.StringPtr("45s"), + }).WithK6OtlpEnvironment() + for _, resource := range []aspire.K6Resource{defaultK6, browserK6} { + if err := resource.PrimaryEndpoint().Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := resource.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/aspire.config.json b/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..02485ceac --- /dev/null +++ b/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.k6": "../../../src/CommunityToolkit.Aspire.Hosting.k6/CommunityToolkit.Aspire.Hosting.k6.csproj" + } +} diff --git a/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/go.mod b/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/k6/CommunityToolkit.Aspire.Hosting.k6.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/README.md b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/README.md new file mode 100644 index 000000000..51311cecd --- /dev/null +++ b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/README.md @@ -0,0 +1,15 @@ +# Keycloak PostgreSQL Go AppHost + +This example mirrors the adjacent TypeScript AppHost using the pinned Aspire 17 +preview Go SDK. Run `aspire restore --apphost apphost.go`, then `go test ./...` +and `go vet ./...` to validate the generated SDK and example. + +`AddKeycloak` is not exported by the underlying hosting package. As in the +TypeScript example, `WithPostgres` receives compile-only coverage and the runtime +graph contains PostgreSQL and its database. + +The current preview SDK also fails to serialize the optional PostgreSQL username +and password resource-builder handles. Model construction reports +`INVALID_ARGUMENT` for `userName`. The example preserves these parameters rather +than substituting plain-text credentials; its integration test validates +compilation only until the upstream SDK supports these arguments. diff --git a/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/apphost.go b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..031960439 --- /dev/null +++ b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,40 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +// AddKeycloak is not exported by Aspire.Hosting.Keycloak yet. Match the TypeScript +// example's compile-only coverage of the generated WithPostgres signatures. +func configureKeycloak(keycloak aspire.KeycloakResource, db aspire.PostgresDatabaseResource, username, password aspire.ParameterResource) { + keycloak.WithPostgres(db) + keycloak.WithPostgres(db, &aspire.WithPostgresOptions{ + Username: &username, Password: &password, XaEnabled: aspire.BoolPtr(true), + }) +} + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + username := builder.AddParameter("db-username", &aspire.AddParameterOptions{Value: aspire.StringPtr("postgres")}) + password := builder.AddParameter("db-password", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("Postgres!123"), Secret: aspire.BoolPtr(true), + }) + postgres := builder.AddPostgres("keycloak-postgres", &aspire.AddPostgresOptions{UserName: &username, Password: &password}) + db := postgres.AddDatabase("keycloak") + if err := db.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/aspire.config.json b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..fd5904a74 --- /dev/null +++ b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Keycloak.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.csproj" + } +} diff --git a/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/go.mod b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/keycloak-postgres/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/apphost.go b/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/apphost.go new file mode 100644 index 000000000..bf500a296 --- /dev/null +++ b/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/apphost.go @@ -0,0 +1,99 @@ +package main + +import ( + "apphost/modules/aspire" + "fmt" + "log" + "path/filepath" +) + +func configureWait(options aspire.CrdWaitOptions, timeout float64) error { + options.SetTimeout(timeout).SetFailureBehavior(aspire.CrdWaitBehaviorBestEffort) + if err := options.Err(); err != nil { + return err + } + actualTimeout, err := options.Timeout() + if err != nil { + return err + } + behavior, err := options.FailureBehavior() + if err != nil { + return err + } + if actualTimeout != timeout || behavior != aspire.CrdWaitBehaviorBestEffort { + return fmt.Errorf("CRD-wait options did not round-trip through the generated SDK") + } + return nil +} + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + cluster := builder.AddKindCluster("ts-kind") + manifestConfigured, chartConfigured := false, false + manifest := cluster.AddManifestFromContent("ts-manifest", ` +apiVersion: v1 +kind: Namespace +metadata: + name: ts-crd-wait +`) + manifest.WithCrdWait(func(options aspire.CrdWaitOptions) { + if err := configureWait(options, 120_000); err != nil { + log.Fatal(aspire.FormatError(err)) + } + manifestConfigured = true + }) + chartPath, err := filepath.Abs("../CommunityToolkit.Aspire.Hosting.Kind.AppHost.TypeScript/chart") + if err != nil { + log.Fatal(err) + } + chart := cluster.AddHelmChart("ts-chart", chartPath) + chart.WithCrdWait(func(options aspire.CrdWaitOptions) { + if err := configureWait(options, 180_000); err != nil { + log.Fatal(aspire.FormatError(err)) + } + chartConfigured = true + }) + if !manifestConfigured || !chartConfigured { + log.Fatal("CRD-wait callbacks were not invoked for both Kind builders") + } + timeout, err := manifest.CrdWaitTimeout() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + behavior, err := manifest.CrdWaitBehavior() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if timeout != 120_000 || behavior != aspire.CrdWaitBehaviorBestEffort { + log.Fatal("Manifest CRD-wait policy did not retain the configured options") + } + manifest.WithCrdWaitTimeout(90_000).WithCrdWaitBehavior(aspire.CrdWaitBehaviorFail) + timeout, err = manifest.CrdWaitTimeout() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + behavior, err = manifest.CrdWaitBehavior() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if timeout != 90_000 || behavior != aspire.CrdWaitBehaviorFail { + log.Fatal("Legacy manifest CRD-wait methods did not update the configured options") + } + if err := chart.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := manifest.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/aspire.config.json b/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..c79397d82 --- /dev/null +++ b/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Kind": "../../../src/CommunityToolkit.Aspire.Hosting.Kind/CommunityToolkit.Aspire.Hosting.Kind.csproj" + } +} diff --git a/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/go.mod b/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/kind/CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/apphost.go b/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/apphost.go new file mode 100644 index 000000000..30df78a98 --- /dev/null +++ b/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/apphost.go @@ -0,0 +1,43 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + directory, err := builder.AppHostDirectory() + check(err) + mount := filepath.Join(directory, "..", "CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.TypeScript", "data", "kurrentdb") + check(os.MkdirAll(mount, 0755)) + + volume := builder.AddKurrentDB("kurrentdb", &aspire.AddKurrentDBOptions{Port: aspire.Float64Ptr(22113)}) + volume.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("kurrentdb-data")}) + mounted := builder.AddKurrentDB("kurrentdb2") + mounted.WithDataBindMount(mount) + defaultVolume := builder.AddKurrentDB("kurrentdb3") + defaultVolume.WithDataVolume() + + for _, resource := range []aspire.KurrentDBResource{volume, mounted, defaultVolume} { + check(resource.PrimaryEndpoint().Err()) + check(resource.Host().Err()) + check(resource.Port().Err()) + _ = resource.UriExpression() + _ = resource.ConnectionStringExpression() + check(resource.Err()) + } + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/aspire.config.json b/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..d03c7649d --- /dev/null +++ b/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.KurrentDB": "../../../src/CommunityToolkit.Aspire.Hosting.KurrentDB/CommunityToolkit.Aspire.Hosting.KurrentDB.csproj" + } +} diff --git a/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/go.mod b/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/kurrentdb/CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/apphost.go b/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/apphost.go new file mode 100644 index 000000000..8d1593c0c --- /dev/null +++ b/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/apphost.go @@ -0,0 +1,55 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" +) + +func main() { + bindMountPath, err := os.MkdirTemp("", "lavinmq-") + if err != nil { + log.Fatal(err) + } + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + volume := builder.AddLavinMQ("volume-broker", &aspire.AddLavinMQOptions{ + AmqpPort: aspire.Float64Ptr(35672), + ManagementPort: aspire.Float64Ptr(35673), + }) + volume.WithDataVolume("lavinmq-volume") + check(volume.PrimaryEndpoint().Err()) + check(volume.Host().Err()) + check(volume.Port().Err()) + _ = volume.UriExpression() + _ = volume.ConnectionStringExpression() + if err := volume.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + mounted := builder.AddLavinMQ("bind-broker", &aspire.AddLavinMQOptions{ + AmqpPort: aspire.Float64Ptr(35674), + ManagementPort: aspire.Float64Ptr(35675), + }) + mounted.WithDataBindMount(bindMountPath) + if err := mounted.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/aspire.config.json b/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..afbf3c900 --- /dev/null +++ b/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.LavinMQ": "../../../src/CommunityToolkit.Aspire.Hosting.LavinMQ/CommunityToolkit.Aspire.Hosting.LavinMQ.csproj" + } +} diff --git a/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/go.mod b/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/lavinmq/CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/apphost.go b/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/apphost.go new file mode 100644 index 000000000..e0210a015 --- /dev/null +++ b/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/apphost.go @@ -0,0 +1,55 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + password := builder.AddParameter("admin-password", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("SuperSecret123!"), + Secret: aspire.BoolPtr(true), + }) + check(password.Err()) + postgres := builder.AddPostgres("postgres") + database := postgres.AddDatabase("listmonkdb") + defaultPostgres := builder.AddPostgres("listmonk-default-postgres") + defaultDatabase := defaultPostgres.AddDatabase("listmonk-default-db") + check(postgres.Err()) + check(database.Err()) + check(defaultPostgres.Err()) + check(defaultDatabase.Err()) + + listmonk := builder.AddListmonk("listmonk", &aspire.AddListmonkOptions{Port: aspire.Float64Ptr(31900)}) + defaults := builder.AddListmonk("listmonk-default") + listmonk.WithReference(database) + listmonk.WithAdminCredentials("admin", password) + listmonk.WithDatabaseMaxOpenConnections(25) + listmonk.WithDatabaseMaxIdleConnections(25) + listmonk.WithDatabaseMaxLifetime("300s") + listmonk.WithTimeZone("Etc/UTC") + listmonk.WithUserId(0) + listmonk.WithGroupId(0) + listmonk.WithUploadsVolume() + defaults.WithReference(defaultDatabase) + defaults.WithDatabaseSslMode("disable") + check(listmonk.PrimaryEndpoint().Err()) + check(listmonk.Host().Err()) + check(listmonk.Port().Err()) + _ = listmonk.UriExpression() + _ = listmonk.ConnectionStringExpression() + check(listmonk.Err()) + check(defaults.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/aspire.config.json b/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..1ee5eeeac --- /dev/null +++ b/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Listmonk": "../../../src/CommunityToolkit.Aspire.Hosting.Listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.csproj" + } +} diff --git a/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/go.mod b/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/listmonk/CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/apphost.go b/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/apphost.go new file mode 100644 index 000000000..d803fe414 --- /dev/null +++ b/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/apphost.go @@ -0,0 +1,38 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + postgres := builder.AddPostgres("postgres") + redis := builder.AddRedis("redis") + check(postgres.Err()) + check(redis.Err()) + + logto := builder.AddLogto("logto", postgres) + logto.WithRedis(redis) + logto.WithDatabaseSeeding() + check(logto.Err()) + + oidc := builder.AddDotnetProject("clientOIDC", "../CommunityToolkit.Aspire.Logto.ClientOIDC/CommunityToolkit.Aspire.Logto.ClientOIDC.csproj") + oidc.WithReference(logto).WaitFor(logto) + check(oidc.Err()) + jwt := builder.AddDotnetProject("clientJWT", "../CommunityToolkit.Aspire.Logto.ClientJWT/CommunityToolkit.Aspire.Logto.ClientJWT.csproj") + jwt.WithReference(logto).WaitFor(logto) + check(jwt.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/aspire.config.json b/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..486ddbb5e --- /dev/null +++ b/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Logto": "../../../src/CommunityToolkit.Aspire.Hosting.Logto/CommunityToolkit.Aspire.Hosting.Logto.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/go.mod b/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/logto/CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/apphost.go b/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/apphost.go new file mode 100644 index 000000000..85780b2a9 --- /dev/null +++ b/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/apphost.go @@ -0,0 +1,44 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" + "path/filepath" + "runtime" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + directory, err := builder.AppHostDirectory() + check(err) + + loki := builder.AddLoki("loki") + loki.WithHttpHostPort(nil) + loki.WithGrpcHostPort(nil) + loki.WithDataVolume() + check(loki.HttpEndpoint().Err()) + check(loki.GrpcEndpoint().Err()) + check(loki.Err()) + + mount, err := os.MkdirTemp("", "loki-") + check(err) + if runtime.GOOS != "windows" { + check(os.Chmod(mount, 0777)) + } + mounted := builder.AddLoki("loki-mounted") + mounted.WithDataBindMount(mount) + mounted.WithConfigFile(filepath.Join(directory, "..", "CommunityToolkit.Aspire.Hosting.Loki.AppHost.TypeScript", "loki.yaml")) + check(mounted.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/aspire.config.json b/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..ed476c93a --- /dev/null +++ b/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Loki": "../../../src/CommunityToolkit.Aspire.Hosting.Loki/CommunityToolkit.Aspire.Hosting.Loki.csproj" + } +} diff --git a/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/go.mod b/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/loki/CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/apphost.go b/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/apphost.go new file mode 100644 index 000000000..ac2ed80cd --- /dev/null +++ b/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/apphost.go @@ -0,0 +1,57 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" +) + +func main() { + bindMountPath, err := os.MkdirTemp("", "mailpit-") + if err != nil { + log.Fatal(err) + } + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + mailpit := builder.AddMailPit("mailpit", &aspire.AddMailPitOptions{ + HttpPort: aspire.Float64Ptr(18025), + SmtpPort: aspire.Float64Ptr(11025), + }) + mailpit.WithDataVolume("mailpit-data") + check(mailpit.PrimaryEndpoint().Err()) + check(mailpit.Host().Err()) + check(mailpit.Port().Err()) + _ = mailpit.UriExpression() + _ = mailpit.ConnectionStringExpression() + if err := mailpit.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + defaults := builder.AddMailPit("mailpit-default") + defaults.WithDataBindMount(bindMountPath) + check(defaults.PrimaryEndpoint().Err()) + check(defaults.Host().Err()) + check(defaults.Port().Err()) + _ = defaults.UriExpression() + _ = defaults.ConnectionStringExpression() + if err := defaults.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/aspire.config.json b/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..0e70907b8 --- /dev/null +++ b/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.MailPit": "../../../src/CommunityToolkit.Aspire.Hosting.MailPit/CommunityToolkit.Aspire.Hosting.MailPit.csproj" + } +} diff --git a/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/go.mod b/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/mailpit/CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/apphost.go b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..3f2a8b8b5 --- /dev/null +++ b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,42 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + mongo := builder.AddMongoDB("mongo") + mongo.WithDbGate() + catalog := mongo.AddDatabase("catalog") + mongo.WithDataVolume() + if err := mongo.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := catalog.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + named := builder.AddMongoDB("mongo-named") + named.WithDbGate(&aspire.WithDbGateOptions{ContainerName: aspire.StringPtr("mongo-ui")}) + orders := named.AddDatabase("orders", &aspire.AddDatabaseOptions{DatabaseName: aspire.StringPtr("orders-db")}) + if err := named.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := orders.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/aspire.config.json b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..e4b2f8da1 --- /dev/null +++ b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.MongoDB.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.csproj" + } +} diff --git a/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/go.mod b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/apphost.go b/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/apphost.go new file mode 100644 index 000000000..7ac3b602a --- /dev/null +++ b/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/apphost.go @@ -0,0 +1,38 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + mqtt := builder.AddMosquitto("mqtt") + mqtt.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("mosquitto-data")}) + check(mqtt.PrimaryEndpoint().Err()) + check(mqtt.Host().Err()) + check(mqtt.Port().Err()) + _ = mqtt.ConnectionStringExpression() + _ = mqtt.UriExpression() + if err := mqtt.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/aspire.config.json b/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..e9ee7ea6e --- /dev/null +++ b/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Mosquitto": "../../../src/CommunityToolkit.Aspire.Hosting.Mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.csproj" + } +} diff --git a/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/go.mod b/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/mosquitto/CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/apphost.go b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..b1a068796 --- /dev/null +++ b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,36 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + mysql := builder.AddMySql("mysql") + mysql.WithAdminer(&aspire.WithAdminerOptions{ + ConfigureContainer: func(adminer aspire.AdminerContainerResource) {}, + ContainerName: aspire.StringPtr("mysql-adminer"), + }) + mysql.WithDbGate(&aspire.WithDbGateOptions{ + ConfigureContainer: func(dbgate aspire.DbGateContainerResource) {}, + ContainerName: aspire.StringPtr("mysql-dbgate"), + }) + check(mysql.PrimaryEndpoint().Err()) + check(mysql.Host().Err()) + check(mysql.Port().Err()) + _ = mysql.ConnectionStringExpression() + check(mysql.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/aspire.config.json b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..c1759b8bf --- /dev/null +++ b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "Aspire.Hosting.MySql": "", + "CommunityToolkit.Aspire.Hosting.MySql.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/CommunityToolkit.Aspire.Hosting.MySql.Extensions.csproj" + } +} diff --git a/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/go.mod b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/apphost.go b/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/apphost.go new file mode 100644 index 000000000..f3a67f52d --- /dev/null +++ b/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/apphost.go @@ -0,0 +1,41 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + authToken := builder.AddParameter("ngrok-auth-token", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("ngrok-token-value"), Secret: aspire.BoolPtr(true), + }) + upstream := builder.AddContainer("upstream", "nginx:alpine"). + WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Name: aspire.StringPtr("http"), TargetPort: aspire.Float64Ptr(80)}) + parameter := builder.AddNgrok("ngrok-parameter", &aspire.AddNgrokOptions{ + ConfigurationFolder: aspire.StringPtr(".ngrok-parameter"), EndpointPort: aspire.Float64Ptr(59600), + EndpointName: aspire.StringPtr("http"), ConfigurationVersion: aspire.Float64Ptr(3), + }).WithAuthToken(authToken).WithTunnelEndpoint(upstream, "http", &aspire.WithTunnelEndpointOptions{ + NgrokUrl: aspire.StringPtr("https://parameter.ngrok.test"), + Labels: map[string]string{"environment": "dev", "service": "upstream"}, + }) + value := builder.AddNgrok("ngrok-value").WithAuthTokenValue("plain-text-token").WithTunnelEndpoint(upstream, "http") + if err := parameter.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := value.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/aspire.config.json b/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..6cec2e598 --- /dev/null +++ b/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Ngrok": "../../../src/CommunityToolkit.Aspire.Hosting.Ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.csproj" + } +} diff --git a/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/go.mod b/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/ngrok/CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/apphost.go b/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/apphost.go new file mode 100644 index 000000000..bcd700180 --- /dev/null +++ b/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/apphost.go @@ -0,0 +1,49 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + ollama := builder.AddOllama("ollama") + ollama.WithOpenWebUI() + phi3 := ollama.AddNamedModel("phi3", "phi3") + llama := ollama.AddHuggingFaceModel("llama", "bartowski/Llama-3.2-1B-Instruct-GGUF:IQ4_XS") + if err := ollama.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + _ = phi3.ConnectionStringExpression() + if err := phi3.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + _ = llama.ConnectionStringExpression() + if err := llama.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + ollama2 := builder.AddOllama("ollama2") + ollama2.WithDataVolume() + ollama2.WithOpenWebUI() + tinyllama := ollama2.AddNamedModel("tinyllama", "tinyllama") + if err := ollama2.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + _ = tinyllama.ConnectionStringExpression() + if err := tinyllama.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/aspire.config.json b/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..553cc83eb --- /dev/null +++ b/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Ollama": "../../../src/CommunityToolkit.Aspire.Hosting.Ollama/CommunityToolkit.Aspire.Hosting.Ollama.csproj" + } +} diff --git a/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/go.mod b/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/ollama/CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/apphost.go b/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/apphost.go new file mode 100644 index 000000000..a908bca44 --- /dev/null +++ b/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/apphost.go @@ -0,0 +1,36 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + collector := builder.AddOpenTelemetryCollector("collector") + collector.WithConfig("../CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.TypeScript/otel-config.yaml") + collector.WithAppForwarding() + grpc := collector.GrpcEndpoint() + http := collector.HttpEndpoint() + if err := collector.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := grpc.EndpointName(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if _, err := http.EndpointName(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/aspire.config.json b/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..382c40070 --- /dev/null +++ b/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector": "../../../src/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.csproj" + } +} diff --git a/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/go.mod b/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/opentelemetry-collector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/apphost.go b/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/apphost.go new file mode 100644 index 000000000..4409c4424 --- /dev/null +++ b/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/apphost.go @@ -0,0 +1,48 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + papercut := builder.AddPapercutSmtp("papercut", &aspire.AddPapercutSmtpOptions{ + HttpPort: aspire.Float64Ptr(8080), + SmtpPort: aspire.Float64Ptr(2525), + }) + check(papercut.Host().Err()) + check(papercut.Port().Err()) + _ = papercut.UriExpression() + _ = papercut.ConnectionStringExpression() + if err := papercut.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + defaults := builder.AddPapercutSmtp("papercut-default") + check(defaults.Host().Err()) + check(defaults.Port().Err()) + _ = defaults.UriExpression() + _ = defaults.ConnectionStringExpression() + if err := defaults.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/aspire.config.json b/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..844afb492 --- /dev/null +++ b/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.PapercutSmtp": "../../../src/CommunityToolkit.Aspire.Hosting.PapercutSmtp/CommunityToolkit.Aspire.Hosting.PapercutSmtp.csproj" + } +} diff --git a/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/go.mod b/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/perl/CpanmApiIntegration.AppHost.Go/apphost.go b/examples/perl/CpanmApiIntegration.AppHost.Go/apphost.go new file mode 100644 index 000000000..bb37d2fa5 --- /dev/null +++ b/examples/perl/CpanmApiIntegration.AppHost.Go/apphost.go @@ -0,0 +1,37 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + perlAPI := builder.AddPerlApi("perl-api", ".", "../scripts/API.pl") + perlAPI.WithCpanMinus() + perlAPI.WithPackage("Mojolicious::Lite", &aspire.WithPackageOptions{ + Force: aspire.BoolPtr(true), SkipTest: aspire.BoolPtr(true), + }) + perlAPI.WithLocalLib(&aspire.WithLocalLibOptions{Path: aspire.StringPtr("local")}) + perlAPI.WithHttpEndpoint(&aspire.WithHttpEndpointOptions{ + Name: aspire.StringPtr("http"), Env: aspire.StringPtr("PORT"), + }) + check(perlAPI.Err()) + + driver := builder.AddPerlScript("perl-driver", "../scripts", "driver.pl") + driver.WithEnvironment("API_URL", perlAPI.GetEndpoint("http")) + driver.WithReference(perlAPI).WaitFor(perlAPI) + check(driver.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/perl/CpanmApiIntegration.AppHost.Go/aspire.config.json b/examples/perl/CpanmApiIntegration.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..2f5b3e0ca --- /dev/null +++ b/examples/perl/CpanmApiIntegration.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Perl": "../../../src/CommunityToolkit.Aspire.Hosting.Perl/CommunityToolkit.Aspire.Hosting.Perl.csproj" + } +} diff --git a/examples/perl/CpanmApiIntegration.AppHost.Go/go.mod b/examples/perl/CpanmApiIntegration.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/perl/CpanmApiIntegration.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/apphost.go b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..beec35265 --- /dev/null +++ b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,52 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + postgres := builder.AddPostgres("postgres") + postgres.WithDbGate(&aspire.WithDbGateOptions{ContainerName: aspire.StringPtr("postgres-dbgate")}) + postgres.WithAdminer(&aspire.WithAdminerOptions{ContainerName: aspire.StringPtr("postgres-adminer")}) + database := postgres.AddDatabase("appdb") + check(postgres.PrimaryEndpoint().Err()) + check(postgres.Host().Err()) + check(postgres.Port().Err()) + _ = postgres.UriExpression() + _ = postgres.JdbcConnectionString() + if err := postgres.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + migrations := "../CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.TypeScript/migrations" + database.WithFlywayMigration("flyway-migration", migrations) + database.WithFlywayRepair("flyway-repair", migrations) + if _, err := database.DatabaseName(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + _ = database.UriExpression() + _ = database.JdbcConnectionString() + if err := database.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/aspire.config.json b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..6665b45ee --- /dev/null +++ b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj" + } +} diff --git a/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/go.mod b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/apphost.go b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/apphost.go new file mode 100644 index 000000000..7b6addff5 --- /dev/null +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/apphost.go @@ -0,0 +1,40 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + blob := builder.AddConnectionString("myblob") + check(blob.Err()) + powershell := builder.AddPowerShell("ps").WaitFor(blob) + check(powershell.Err()) + + script1 := powershell.AddScript("script1", + "\nparam($name)\n"+ + "write-information \"Hello, $name\"\n"+ + "write-information \"`$myblob is $myblob\"\n") + script1.WithReference(blob).WithArgs([]string{"world"}) + check(script1.Err()) + + script2 := powershell.AddScript("script2", ` +write-information "Getting there..." +write-information "the sum of 2 and 3 is $([int]$args[0] + [int]$args[1])" +`) + script2.WithArgs([]string{"2", "3"}).WaitForCompletion(script1) + check(script2.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/aspire.config.json b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..12f87992e --- /dev/null +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.PowerShell": "../../../src/CommunityToolkit.Aspire.Hosting.PowerShell/CommunityToolkit.Aspire.Hosting.PowerShell.csproj" + } +} diff --git a/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/go.mod b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/powershell/CommunityToolkit.Aspire.PowerShell.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/apphost.go b/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/apphost.go new file mode 100644 index 000000000..d2b336f41 --- /dev/null +++ b/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/apphost.go @@ -0,0 +1,27 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + dashboard := builder.AddStreamlitApp("dashboard", "../CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.TypeScript/streamlit-app", "app.py") + dashboard.WithExplicitStart() + if err := dashboard.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/aspire.config.json b/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..884e665ab --- /dev/null +++ b/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Python.Extensions": "../../../src/CommunityToolkit.Aspire.Hosting.Python.Extensions/CommunityToolkit.Aspire.Hosting.Python.Extensions.csproj" + } +} diff --git a/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/go.mod b/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/python/CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/apphost.go b/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/apphost.go new file mode 100644 index 000000000..f1be307ec --- /dev/null +++ b/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/apphost.go @@ -0,0 +1,35 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + ravendb := builder.AddRavenDB("ravendb") + database := ravendb.AddDatabase("ravenDatabase") + if err := ravendb.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := database.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + api := builder.AddDotnetProject("apiservice", "../CommunityToolkit.Aspire.Hosting.RavenDB.ApiService/CommunityToolkit.Aspire.Hosting.RavenDB.ApiService.csproj") + api.WithReference(ravendb).WaitFor(ravendb) + if err := api.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/aspire.config.json b/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..b6d9c40e4 --- /dev/null +++ b/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.RavenDB": "../../../src/CommunityToolkit.Aspire.Hosting.RavenDB/CommunityToolkit.Aspire.Hosting.RavenDB.csproj", + "Aspire.Hosting.Dotnet": "17.0.0-preview.1.26555.11" + } +} diff --git a/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/go.mod b/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/ravendb/CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/apphost.go b/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/apphost.go new file mode 100644 index 000000000..6ba9ccb0b --- /dev/null +++ b/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/apphost.go @@ -0,0 +1,42 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + redpanda := builder.AddRedPanda("redpanda") + redpanda.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("redpanda-data")}) + check(redpanda.PrimaryEndpoint().Err()) + check(redpanda.Host().Err()) + check(redpanda.Port().Err()) + _ = redpanda.ConnectionStringExpression() + if err := redpanda.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + pinned := builder.AddRedPanda("redpanda-pinned", &aspire.AddRedPandaOptions{Port: aspire.Float64Ptr(9092)}) + if err := pinned.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/aspire.config.json b/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..2a7a94608 --- /dev/null +++ b/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.RedPanda": "../../../src/CommunityToolkit.Aspire.Hosting.RedPanda/CommunityToolkit.Aspire.Hosting.RedPanda.csproj" + } +} diff --git a/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/go.mod b/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/redpanda/CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/apphost.go b/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/apphost.go new file mode 100644 index 000000000..25d4079aa --- /dev/null +++ b/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/apphost.go @@ -0,0 +1,36 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + rust := builder.AddRustApp("rust-app", "../actix_api") + rust.WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}) + rust.WithExternalHttpEndpoints() + rust.WithHttpHealthCheck(&aspire.WithHttpHealthCheckOptions{Path: aspire.StringPtr("/")}) + check(rust.Err()) + + if os.Getenv("RUST_ARGS_VALIDATION") == "1" { + withArgs := builder.AddRustApp("rust-app-with-args", "../actix_api", &aspire.AddRustAppOptions{ + Args: []string{"--", "--help"}, + }) + withArgs.WithHttpEndpoint(&aspire.WithHttpEndpointOptions{Env: aspire.StringPtr("PORT")}) + check(withArgs.Err()) + } + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/aspire.config.json b/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..bf264242b --- /dev/null +++ b/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Rust": "../../../src/CommunityToolkit.Aspire.Hosting.Rust/CommunityToolkit.Aspire.Hosting.Rust.csproj" + } +} diff --git a/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/go.mod b/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/rust/CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/seaweedfs/SeaweedFS.AppHost.Go/apphost.go b/examples/seaweedfs/SeaweedFS.AppHost.Go/apphost.go new file mode 100644 index 000000000..7de8eabee --- /dev/null +++ b/examples/seaweedfs/SeaweedFS.AppHost.Go/apphost.go @@ -0,0 +1,34 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + s3 := builder.AddSeaweedFS("typescript-seaweedfs-s3") + s3.WithS3() + s3.WithDataVolume() + if err := s3.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + filer := builder.AddSeaweedFS("typescript-seaweedfs-filer") + filer.WithFiler() + if err := filer.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/seaweedfs/SeaweedFS.AppHost.Go/aspire.config.json b/examples/seaweedfs/SeaweedFS.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..7be90f28a --- /dev/null +++ b/examples/seaweedfs/SeaweedFS.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.SeaweedFS": "../../../src/CommunityToolkit.Aspire.Hosting.SeaweedFS/CommunityToolkit.Aspire.Hosting.SeaweedFS.csproj" + } +} diff --git a/examples/seaweedfs/SeaweedFS.AppHost.Go/go.mod b/examples/seaweedfs/SeaweedFS.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/seaweedfs/SeaweedFS.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/apphost.go b/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/apphost.go new file mode 100644 index 000000000..a9ed757a0 --- /dev/null +++ b/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/apphost.go @@ -0,0 +1,45 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + directory, err := builder.AppHostDirectory() + check(err) + fixtures := filepath.Join(directory, "..", "CommunityToolkit.Aspire.Hosting.Sftp.AppHost") + + sftp := builder.AddSftp("sftp", &aspire.AddSftpOptions{Port: aspire.Float64Ptr(2222)}) + if os.Getenv("ASPIRE_RUNTIME_SMOKE") == "1" { + sftp.WithEnvironment("SFTP_USERS", "foo:pass:::upload") + } else { + sftp.WithUsersFile(filepath.Join(fixtures, "etc", "sftp", "users.conf")) + sftp.WithHostKeyFile(filepath.Join(fixtures, "etc", "ssh", "ssh_host_ed25519_key"), aspire.KeyTypeEd25519) + sftp.WithUserKeyFile("foo", filepath.Join(fixtures, "home", "foo", ".ssh", "keys", "id_ed25519.pub"), aspire.KeyTypeEd25519) + } + defaults := builder.AddSftp("sftp-defaults") + defaults.WithEnvironment("SFTP_USERS", "bar:pass:::upload") + + for _, resource := range []aspire.SftpContainerResource{sftp, defaults} { + check(resource.Host().Err()) + check(resource.Port().Err()) + _ = resource.UriExpression() + _ = resource.ConnectionStringExpression() + check(resource.Err()) + } + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/aspire.config.json b/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..ca06ce7c5 --- /dev/null +++ b/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Sftp": "../../../src/CommunityToolkit.Aspire.Hosting.Sftp/CommunityToolkit.Aspire.Hosting.Sftp.csproj" + } +} diff --git a/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/go.mod b/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/sftp/CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/apphost.go b/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/apphost.go new file mode 100644 index 000000000..0941ef3cc --- /dev/null +++ b/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/apphost.go @@ -0,0 +1,58 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + directory, err := builder.AppHostDirectory() + check(err) + data := filepath.Join(directory, "..", "CommunityToolkit.Aspire.Hosting.Solr.AppHost.TypeScript", "solr-data") + check(os.MkdirAll(data, 0777)) + check(os.Chmod(data, 0777)) + + solr := builder.AddSolr("solr") + core, err := solr.CoreName() + check(err) + solr.SetCoreName(core) + solr.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("solr-data")}) + check(solr.PrimaryEndpoint().Err()) + check(solr.Host().Err()) + check(solr.Port().Err()) + _, err = solr.CoreName() + check(err) + _ = solr.ConnectionStringExpression() + _ = solr.UriExpression() + check(solr.Err()) + + mounted := builder.AddSolr("solr-bind", &aspire.AddSolrOptions{ + Port: aspire.Float64Ptr(8984), + CoreName: aspire.StringPtr("bindcore"), + }) + mountedCore, err := mounted.CoreName() + check(err) + mounted.SetCoreName(mountedCore) + mounted.WithDataBindMount(data) + check(mounted.Err()) + + if false { + configset := builder.AddSolr("solr-configset", &aspire.AddSolrOptions{CoreName: aspire.StringPtr("configset-core")}) + configset.WithConfigset("sample-configset", filepath.Join(directory, "..", "CommunityToolkit.Aspire.Hosting.Solr.AppHost.TypeScript", "configsets", "sample-configset")) + check(configset.Err()) + } + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/aspire.config.json b/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..460c889ef --- /dev/null +++ b/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Solr": "../../../src/CommunityToolkit.Aspire.Hosting.Solr/CommunityToolkit.Aspire.Hosting.Solr.csproj" + } +} diff --git a/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/go.mod b/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/solr/CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/README.md b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/README.md new file mode 100644 index 000000000..589aafe20 --- /dev/null +++ b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/README.md @@ -0,0 +1,18 @@ +# SQL Database Projects Go AppHost + +This example mirrors the adjacent TypeScript AppHost, including both a managed SQL database and an existing connection string. + +With Go 1.26 or later and the Aspire CLI version pinned in `aspire.config.json`, run: + +```shell +aspire restore --non-interactive +go test ./... +go vet ./... +aspire publish --list-steps --non-interactive +``` + +Run the application with `aspire run`. Configure `ConnectionStrings:Aspire` for the existing database before running. + +## Preview limitation + +SDK generation and Go compilation succeed with `17.1.0-preview.1.26559.8`. On the Windows prebuilt AppHost server, model construction currently fails in `SqlProjectBuilderExtensions` when `MSBuildLocator.RegisterDefaults()` cannot load the native `hostfxr` library. Adding the installed `hostfxr.dll` directory to `PATH` did not resolve this failure. The example retains both SQL project resources rather than omitting them to bypass the prerequisite failure. diff --git a/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/apphost.go b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/apphost.go new file mode 100644 index 000000000..c704b7002 --- /dev/null +++ b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/apphost.go @@ -0,0 +1,55 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + appHostDirectory, err := builder.AppHostDirectory() + check(err) + projectPath := filepath.Join(appHostDirectory, "..", "SdkProject", "SdkProject.csproj") + profilePath := filepath.Join(appHostDirectory, "..", "SdkProject", "Database.publish.xml") + + sql := builder.AddSqlServer("sql") + database := sql.AddDatabase("TargetDatabase") + existingConnection := builder.AddConnectionString("Aspire") + check(sql.Err()) + check(database.Err()) + check(existingConnection.Err()) + + project := builder.AddSqlProject("database-project") + project.WithDacpac(projectPath) + project.WithDacDeployOptions(profilePath) + project.WithSkipWhenDeployed() + project.WithReference(database) + check(project.Err()) + + connectionProject := builder.AddSqlProject("connection-project") + connectionProject.WithDacpac(projectPath) + connectionProject.WithConnectionReference(existingConnection) + check(connectionProject.Err()) + + _, err = project.DacpacPath() + check(err) + _, err = project.DacDeployOptionsPath() + check(err) + _, err = project.SkipWhenDeployed() + check(err) + _, err = connectionProject.DacpacPath() + check(err) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/aspire.config.json b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..be2117644 --- /dev/null +++ b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "Aspire.Hosting.SqlServer": "", + "CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects": "../../../src/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.csproj" + } +} diff --git a/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/go.mod b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/sql-database-projects/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/apphost.go b/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/apphost.go new file mode 100644 index 000000000..1d7b56811 --- /dev/null +++ b/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/apphost.go @@ -0,0 +1,37 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + + sqlite := builder.AddSqlite("sqlite", &aspire.AddSqliteOptions{ + DatabasePath: aspire.StringPtr(".data/sqlite"), + DatabaseFileName: aspire.StringPtr("app.db"), + }) + sqlite.WithSqliteWeb(&aspire.WithSqliteWebOptions{ContainerName: aspire.StringPtr("sqlite-browser")}) + _ = sqlite.ConnectionStringExpression() + if err := sqlite.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + sqliteDefault := builder.AddSqlite("sqlite-default") + sqliteDefault.WithSqliteWeb() + if err := sqliteDefault.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/aspire.config.json b/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..ca55d87ed --- /dev/null +++ b/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Sqlite": "../../../src/CommunityToolkit.Aspire.Hosting.Sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.csproj" + } +} diff --git a/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/go.mod b/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/sqlite/CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/apphost.go b/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/apphost.go new file mode 100644 index 000000000..193d4cfbe --- /dev/null +++ b/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/apphost.go @@ -0,0 +1,40 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "path/filepath" +) + +func main() { + builder, err := aspire.CreateBuilder() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + appHostDirectory, err := builder.AppHostDirectory() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + csharpAppHost := filepath.Join(appHostDirectory, "..", "CommunityToolkit.Aspire.Hosting.Squad.AppHost") + + research := builder.AddSquad("research-squad", &aspire.AddSquadOptions{ + TeamRoot: aspire.StringPtr(filepath.Join(csharpAppHost, "research-squad")), + }) + if err := research.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + development := builder.AddSquad("dev-squad", &aspire.AddSquadOptions{ + TeamRoot: aspire.StringPtr(filepath.Join(csharpAppHost, "dev-squad")), + }) + if err := development.Err(); err != nil { + log.Fatal(aspire.FormatError(err)) + } + + app, err := builder.Build() + if err != nil { + log.Fatal(aspire.FormatError(err)) + } + if err := app.Run(); err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/aspire.config.json b/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..0597dc640 --- /dev/null +++ b/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Squad": "../../../src/CommunityToolkit.Aspire.Hosting.Squad/CommunityToolkit.Aspire.Hosting.Squad.csproj" + } +} diff --git a/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/go.mod b/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/squad/CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/apphost.go b/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/apphost.go new file mode 100644 index 000000000..28ae5c1e4 --- /dev/null +++ b/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/apphost.go @@ -0,0 +1,59 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + apiKey := builder.AddParameter("stripe-api-key", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("sk_test_123"), Secret: aspire.BoolPtr(true), + }) + override := builder.AddParameter("stripe-api-key-override", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("sk_test_override"), Secret: aspire.BoolPtr(true), + }) + target := builder.AddContainer("webhook-target", "nginx:alpine") + target.WithHttpEndpoint(&aspire.WithHttpEndpointOptions{ + TargetPort: aspire.Float64Ptr(80), Name: aspire.StringPtr("http"), + }) + external := builder.AddExternalService("external-target", "http://localhost:5082") + consumer := builder.AddContainer("consumer", "nginx:alpine") + check(apiKey.Err()) + check(override.Err()) + check(target.Err()) + check(external.Err()) + check(consumer.Err()) + + stripe := builder.AddStripe("stripe", apiKey) + stripe.WithListen(target, &aspire.WithListenOptions{ + WebhookPath: aspire.StringPtr("/webhooks/stripe"), Events: []string{"payment_intent.created"}, + }) + stripe.WithApiKey(override) + check(stripe.Err()) + + stripeExternal := builder.AddStripe("stripe-external", apiKey) + stripeExternal.WithListenExternalService(external, &aspire.WithListenExternalServiceOptions{ + WebhookPath: aspire.StringPtr("/webhooks/external"), Events: []string{"payment_intent.created", "charge.succeeded"}, + }) + check(stripeExternal.Err()) + + consumer.WithStripeReference(stripe, &aspire.WithStripeReferenceOptions{ + WebhookSigningSecretEnvVarName: aspire.StringPtr("CUSTOM_STRIPE_SECRET"), + }) + check(consumer.Err()) + _, err = stripe.WebhookSigningSecret() + check(err) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/aspire.config.json b/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..d88915982 --- /dev/null +++ b/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Stripe": "../../../src/CommunityToolkit.Aspire.Hosting.Stripe/CommunityToolkit.Aspire.Hosting.Stripe.csproj" + } +} diff --git a/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/go.mod b/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/stripe/CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/apphost.go b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/apphost.go new file mode 100644 index 000000000..d3cabd9b0 --- /dev/null +++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/apphost.go @@ -0,0 +1,77 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + primary := builder.AddSurrealServer("primary", &aspire.AddSurrealServerOptions{ + Port: aspire.Float64Ptr(18000), Path: aspire.StringPtr("memory"), + }) + primary.WithDataVolume(&aspire.WithDataVolumeOptions{Name: aspire.StringPtr("surreal-primary-data")}) + primary.WithLogLevel("Information") + primary.WithSurrealist(&aspire.WithSurrealistOptions{ContainerName: aspire.StringPtr("surrealist-primary")}) + primary.WithSurrealDbOtlpExporter() + check(primary.Err()) + + namespace := primary.AddNamespace("appns", &aspire.AddNamespaceOptions{NamespaceName: aspire.StringPtr("polyglotNs")}) + namespace.WithCreationScript("DEFINE NAMESPACE IF NOT EXISTS `polyglotNs`;") + check(namespace.Err()) + database := namespace.AddDatabase("appdb", &aspire.AddDatabaseOptions{DatabaseName: aspire.StringPtr("polyglotDb")}) + database.WithCreationScript("DEFINE DATABASE IF NOT EXISTS `polyglotDb`;") + check(database.Err()) + + mounted := builder.AddSurrealServer("mounted", &aspire.AddSurrealServerOptions{ + Port: aspire.Float64Ptr(18001), Path: aspire.StringPtr("memory"), + }) + mounted.WithDataBindMount("./data") + mounted.WithInitFiles("./seed.surql") + check(mounted.Err()) + + check(primary.PrimaryEndpoint().Err()) + check(primary.Host().Err()) + check(primary.Port().Err()) + check(primary.PasswordParameter().Err()) + _ = primary.UriExpression() + _ = primary.ConnectionStringExpression() + + namespaceParent := namespace.Parent() + check(namespaceParent.Err()) + _ = namespace.ConnectionStringExpression() + _, err = namespace.NamespaceName() + check(err) + _, err = namespaceParent.Name() + check(err) + + databaseParent := database.Parent() + check(databaseParent.Err()) + _ = database.ConnectionStringExpression() + _, err = database.DatabaseName() + check(err) + _, err = databaseParent.Name() + check(err) + server := databaseParent.Parent() + check(server.Err()) + _, err = server.Name() + check(err) + + check(mounted.PrimaryEndpoint().Err()) + check(mounted.Host().Err()) + check(mounted.Port().Err()) + _ = mounted.UriExpression() + _ = mounted.ConnectionStringExpression() + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/aspire.config.json b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..977574745 --- /dev/null +++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.SurrealDb": "../../../src/CommunityToolkit.Aspire.Hosting.SurrealDb/CommunityToolkit.Aspire.Hosting.SurrealDb.csproj" + } +} diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/data/.gitkeep b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/data/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/go.mod b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/seed.surql b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/seed.surql new file mode 100644 index 000000000..851797071 --- /dev/null +++ b/examples/surrealdb/CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go/seed.surql @@ -0,0 +1 @@ +DEFINE TABLE IF NOT EXISTS polyglot SCHEMALESS; diff --git a/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/apphost.go b/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/apphost.go new file mode 100644 index 000000000..ec0247f23 --- /dev/null +++ b/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/apphost.go @@ -0,0 +1,48 @@ +package main + +import ( + "apphost/modules/aspire" + "log" + "os" + "path/filepath" + "runtime" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + directory, err := builder.AppHostDirectory() + check(err) + + tempo := builder.AddTempo("tempo") + tempo.WithHttpHostPort(nil) + tempo.WithGrpcHostPort(nil) + tempo.WithOtlpGrpcHostPort(nil) + tempo.WithOtlpHttpHostPort(nil) + tempo.WithDataVolume() + check(tempo.HttpEndpoint().Err()) + check(tempo.GrpcEndpoint().Err()) + check(tempo.OtlpGrpcEndpoint().Err()) + check(tempo.OtlpHttpEndpoint().Err()) + check(tempo.Err()) + + mount, err := os.MkdirTemp("", "tempo-") + check(err) + if runtime.GOOS != "windows" { + check(os.Chmod(mount, 0777)) + } + mounted := builder.AddTempo("tempo-mounted") + mounted.WithDataBindMount(mount) + mounted.WithConfigFile(filepath.Join(directory, "..", "CommunityToolkit.Aspire.Hosting.Tempo.AppHost.TypeScript", "tempo.yaml")) + check(mounted.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/aspire.config.json b/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..ba138a9cb --- /dev/null +++ b/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/aspire.config.json @@ -0,0 +1,12 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Tempo": "../../../src/CommunityToolkit.Aspire.Hosting.Tempo/CommunityToolkit.Aspire.Hosting.Tempo.csproj" + } +} diff --git a/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/go.mod b/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/tempo/CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/README.md b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/README.md new file mode 100644 index 000000000..a374c5347 --- /dev/null +++ b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/README.md @@ -0,0 +1,20 @@ +# Zitadel Go AppHost + +This example mirrors the adjacent TypeScript AppHost, including explicit admin parameters, a managed database, and a second Zitadel instance using an existing database. + +With Go 1.26 or later and the Aspire CLI version pinned in `aspire.config.json`, run: + +```shell +aspire restore --non-interactive +go test ./... +go vet ./... +aspire publish --list-steps --non-interactive +``` + +Run the application with `aspire run` once the preview limitation below is resolved. The fixed credentials match the TypeScript example and are for local demonstration only. + +## Preview limitation + +SDK generation and Go compilation succeed with `17.1.0-preview.1.26559.8`, but model construction fails at `AddZitadel`. The generated options expose optional resource arguments as pointers to interfaces (`*ParameterResource`), then serialize those pointers without unwrapping their resource handles. The AppHost server rejects `username` with `INVALID_ARGUMENT`, reporting that `IResourceBuilder` requires an `AspireDto` attribute. + +This example preserves the explicit username, password, and master-key parameters. Resolving the failure requires an Aspire Go SDK serialization fix; do not edit the generated `.aspire/modules` files or drop the parameters to hide it. diff --git a/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/apphost.go b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/apphost.go new file mode 100644 index 000000000..947c41c68 --- /dev/null +++ b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/apphost.go @@ -0,0 +1,49 @@ +package main + +import ( + "apphost/modules/aspire" + "log" +) + +func main() { + builder, err := aspire.CreateBuilder() + check(err) + + username := builder.AddParameter("zitadel-username", &aspire.AddParameterOptions{Value: aspire.StringPtr("admin")}) + password := builder.AddParameter("zitadel-password", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("AspireZitadelPassword!1"), Secret: aspire.BoolPtr(true), + }) + masterKey := builder.AddParameter("zitadel-master-key", &aspire.AddParameterOptions{ + Value: aspire.StringPtr("Aa1!Aa1!Aa1!Aa1!Aa1!Aa1!Aa1!Aa1!"), Secret: aspire.BoolPtr(true), + }) + check(username.Err()) + check(password.Err()) + check(masterKey.Err()) + + postgres := builder.AddPostgres("postgres") + existingDatabase := postgres.AddDatabase("zitadel-existing-db") + check(postgres.Err()) + check(existingDatabase.Err()) + + zitadel := builder.AddZitadel("zitadel", &aspire.AddZitadelOptions{ + Port: aspire.Float64Ptr(8080), Username: &username, Password: &password, MasterKey: &masterKey, + }) + zitadel.WithExternalDomain("auth.example.com") + zitadel.WithDatabase(postgres, &aspire.WithDatabaseOptions{DatabaseName: aspire.StringPtr("zitadel-db")}) + check(zitadel.Err()) + + minimal := builder.AddZitadel("zitadel-minimal") + minimal.WithExistingDatabase(existingDatabase) + minimal.WithExternalDomain("login.example.com") + check(minimal.Err()) + + app, err := builder.Build() + check(err) + check(app.Run()) +} + +func check(err error) { + if err != nil { + log.Fatal(aspire.FormatError(err)) + } +} diff --git a/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/aspire.config.json b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/aspire.config.json new file mode 100644 index 000000000..7d1c3a745 --- /dev/null +++ b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/aspire.config.json @@ -0,0 +1,13 @@ +{ + "appHost": { + "path": "apphost.go", + "language": "go" + }, + "sdk": { + "version": "17.0.0-preview.1.26555.11" + }, + "packages": { + "CommunityToolkit.Aspire.Hosting.Zitadel": "../../../src/CommunityToolkit.Aspire.Hosting.Zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.csproj", + "Aspire.Hosting.PostgreSQL": "" + } +} diff --git a/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/go.mod b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/go.mod new file mode 100644 index 000000000..b152cea77 --- /dev/null +++ b/examples/zitadel/CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go/go.mod @@ -0,0 +1,7 @@ +module apphost + +go 1.26 + +require apphost/modules/aspire v0.0.0 + +replace apphost/modules/aspire => ./.aspire/modules diff --git a/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..75c8dec08 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests/GoAppHostTests.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.ActiveMQ.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.ActiveMQ.AppHost.Go", + exampleName: "activemq", + // The preview SDK cannot serialize the optional credential handles. + validatePublish: false, + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..0b9cbef0e --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Adminer.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Adminer.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Adminer.AppHost.Go", + exampleName: "adminer", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..27c7fd061 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Azure.Dapr.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Azure.Dapr.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Azure.Dapr.AppHost.Go", + exampleName: "dapr", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..2cec5734b --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Azure.DataApiBuilder.AppHost.Go", + exampleName: "data-api-builder", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Azure.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Azure.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..6b07feb8c --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Azure.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Azure.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Azure.Extensions.AppHost.Go", + exampleName: "azure-ext", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Chroma.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Chroma.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..08425ef5d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Chroma.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Chroma.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Chroma.AppHost.Go", + exampleName: "chromadb", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..c773a1fd1 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Dapr.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Dapr.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Dapr.AppHost.Go", + exampleName: "dapr", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..71148e919 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.DbGate.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.DbGate.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.DbGate.AppHost.Go", + exampleName: "dbgate", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AffectedGoAppHostSelectionTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AffectedGoAppHostSelectionTests.cs new file mode 100644 index 000000000..21b11bd9f --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AffectedGoAppHostSelectionTests.cs @@ -0,0 +1,90 @@ +using System.Diagnostics; +using System.Text.Json; + +namespace CommunityToolkit.Aspire.Hosting.Dbx.Tests; + +public class AffectedGoAppHostSelectionTests +{ + [Theory] + [InlineData("one", "One.AppHost.Go", "apphost.go", "Hosting.One.Tests")] + [InlineData("one", "One.AppHost.Go", "assets/config.json", "Hosting.One.Tests")] + [InlineData("two", "Two.AppHost.Go", "apphost.go", "Hosting.Two.Tests")] + public async Task GoAppHostChangesSelectTheirTestProject(string example, string appHost, string changedFile, string expectedTest) + { + var cancellationToken = TestContext.Current.CancellationToken; + var repositoryRoot = Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..")); + var selector = Path.Combine(repositoryRoot, "eng", "testing", "select-affected-tests.cs"); + var fixture = Path.Combine(Path.GetTempPath(), $"go-selection-{Guid.NewGuid():N}"); + Directory.CreateDirectory(fixture); + + try + { + WriteFile(fixture, "tests/Directory.Build.props", ""); + WriteFile(fixture, "tests/CommunityToolkit.Aspire.Hosting.One.Tests/CommunityToolkit.Aspire.Hosting.One.Tests.csproj", ""); + WriteFile(fixture, "tests/CommunityToolkit.Aspire.Hosting.One.Tests/GoAppHostTests.cs", + """GoAppHostTest.Run(appHostProject: "One.AppHost.Go", exampleName: "one");"""); + WriteFile(fixture, "tests/CommunityToolkit.Aspire.Hosting.Two.Tests/CommunityToolkit.Aspire.Hosting.Two.Tests.csproj", ""); + WriteFile(fixture, "tests/CommunityToolkit.Aspire.Hosting.Two.Tests/GoAppHostTests.cs", + """const string Project = "Two.AppHost.Go"; const string Example = "two"; GoAppHostTest.Run(appHostProject: Project, exampleName: Example);"""); + WriteFile(fixture, "examples/one/One.AppHost.Go/apphost.go", "before"); + WriteFile(fixture, "examples/two/Two.AppHost.Go/apphost.go", "before"); + WriteFile(fixture, $"examples/{example}/{appHost}/{changedFile}", "before"); + + await RunAsync("git", ["init", "--quiet"], fixture, cancellationToken); + await RunAsync("git", ["add", "."], fixture, cancellationToken); + await RunAsync("git", ["-c", "user.name=Test", "-c", "user.email=test@example.invalid", "-c", "commit.gpgsign=false", "commit", "--quiet", "-m", "base"], fixture, cancellationToken); + WriteFile(fixture, $"examples/{example}/{appHost}/{changedFile}", "after"); + await RunAsync("git", ["add", "."], fixture, cancellationToken); + await RunAsync("git", ["-c", "user.name=Test", "-c", "user.email=test@example.invalid", "-c", "commit.gpgsign=false", "commit", "--quiet", "-m", "change"], fixture, cancellationToken); + + var outputDirectory = Path.Combine(fixture, "output"); + var fixtureSelector = Path.Combine(fixture, "select-affected-tests.cs"); + File.Copy(selector, fixtureSelector); + await RunAsync("dotnet", ["run", fixtureSelector, "--", "--repo-root", fixture, "--base-sha", "HEAD~1", "--head-sha", "HEAD", "--output-dir", outputDirectory], fixture, cancellationToken); + using var selection = JsonDocument.Parse(await File.ReadAllTextAsync(Path.Combine(outputDirectory, "selection.json"), cancellationToken)); + Assert.False(selection.RootElement.GetProperty("runAll").GetBoolean()); + var selected = selection.RootElement.GetProperty("selectedTests").EnumerateArray().Select(static item => item.GetString()!).ToArray(); + Assert.Equal([expectedTest], selected); + Assert.Contains(selection.RootElement.GetProperty("reasons").EnumerateArray(), static reason => + reason.GetString()!.Contains("Go app host test fixture", StringComparison.Ordinal)); + } + finally + { + foreach (var file in Directory.EnumerateFiles(fixture, "*", SearchOption.AllDirectories)) + { + File.SetAttributes(file, FileAttributes.Normal); + } + Directory.Delete(fixture, recursive: true); + } + } + + private static void WriteFile(string root, string path, string content) + { + var fullPath = Path.Combine(root, path); + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!); + File.WriteAllText(fullPath, content); + } + + private static async Task RunAsync(string executable, string[] arguments, string directory, CancellationToken cancellationToken) + { + var startInfo = new ProcessStartInfo(executable) + { + WorkingDirectory = directory, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + }; + foreach (var argument in arguments) + { + startInfo.ArgumentList.Add(argument); + } + startInfo.Environment.Remove("GITHUB_OUTPUT"); + startInfo.Environment.Remove("GITHUB_STEP_SUMMARY"); + + using var process = Process.Start(startInfo) ?? throw new InvalidOperationException($"Could not start {executable}."); + var output = process.StandardOutput.ReadToEndAsync(cancellationToken); + var error = process.StandardError.ReadToEndAsync(cancellationToken); + await process.WaitForExitAsync(cancellationToken); + Assert.True(process.ExitCode == 0, $"{executable} exited with {process.ExitCode}: {await output}\n{await error}"); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..344f18d3d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Dbx.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Dbx.AppHost.Go", + exampleName: "dbx", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Deno.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Deno.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..ccaaa9214 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Deno.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Deno.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Deno.AppHost.Go", + exampleName: "deno", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.DuckDB.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.DuckDB.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..ce68e53cc --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.DuckDB.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.DuckDB.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.DuckDB.AppHost.Go", + exampleName: "duckdb", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..19536ef72 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions.AppHost.Go", + exampleName: "elasticsearch-ext", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Flagd.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Flagd.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..b6cd6c81d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Flagd.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Flagd.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Flagd.AppHost.Go", + exampleName: "flagd", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Flare.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Flare.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..b4f1a2396 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Flare.Tests/GoAppHostTests.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Flare.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Flare.AppHost.Go", + exampleName: "flare", + // The preview Go SDK cannot serialize the optional dashboard URL parameter handle. + validatePublish: false, + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..0433bbad3 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/GoAppHostTests.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Floci.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Floci.AppHost.Go", + exampleName: "floci", + // The Service Bus emulator is run-only and rejects publish-mode model construction. + validatePublish: false, + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Flyway.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Flyway.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..573e4ff4d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Flyway.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Flyway.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Flyway.AppHost.Go", + exampleName: "flyway", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..948cc6885 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.GoFeatureFlag.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.GoFeatureFlag.AppHost.Go", + exampleName: "goff", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Java.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Java.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..7815ee65f --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Java.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Java.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Java.AppHost.Go", + exampleName: "java", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..dac432dd3 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.JavaScript.Extensions.AppHost.Go", + exampleName: "javascript-ext", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.K3s.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.K3s.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..21980e2bb --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.K3s.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.K3s.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.K3s.AppHost.Go", + exampleName: "k3s", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..b3422407d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Keycloak.Extensions.AppHost.Go", + exampleName: "keycloak-postgres", + // The preview Go SDK cannot serialize optional PostgreSQL credential parameter handles. + validatePublish: false, + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Kind.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Kind.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..bb39e823e --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Kind.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Kind.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task CrdWaitApisWorkFromGeneratedGoSdk() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Kind.AppHost.Go", + exampleName: "kind", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.KurrentDB.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.KurrentDB.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..ca89021f5 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.KurrentDB.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.KurrentDB.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.KurrentDB.AppHost.Go", + exampleName: "kurrentdb", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.LavinMQ.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.LavinMQ.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..9ad8c30dd --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.LavinMQ.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.LavinMQ.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.LavinMQ.AppHost.Go", + exampleName: "lavinmq", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Listmonk.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Listmonk.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..45b089a4d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Listmonk.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Listmonk.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Listmonk.AppHost.Go", + exampleName: "listmonk", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Logto.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Logto.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..cd92d9816 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Logto.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Logto.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Logto.AppHost.Go", + exampleName: "logto", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Loki.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Loki.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..5492d3adb --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Loki.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Loki.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Loki.AppHost.Go", + exampleName: "loki", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.MailPit.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.MailPit.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..e3a8a8425 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.MailPit.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.MailPit.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.MailPit.AppHost.Go", + exampleName: "mailpit", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..c17608beb --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost.Go", + exampleName: "mongodb-ext", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Mosquitto.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Mosquitto.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..4f886b854 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Mosquitto.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Mosquitto.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Mosquitto.AppHost.Go", + exampleName: "mosquitto", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.MySql.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.MySql.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..3193aa663 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.MySql.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.MySql.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost.Go", + exampleName: "mysql-ext", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Ngrok.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Ngrok.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..9ef05acad --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Ngrok.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Ngrok.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Ngrok.AppHost.Go", + exampleName: "ngrok", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Ollama.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Ollama.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..33b8c65ad --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Ollama.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Ollama.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Ollama.AppHost.Go", + exampleName: "ollama", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..53022829f --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.AppHost.Go", + exampleName: "opentelemetry-collector", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..e49a8f082 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.PapercutSmtp.AppHost.Go", + exampleName: "papercut", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..c74820db2 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Perl.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Perl.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CpanmApiIntegration.AppHost.Go", + exampleName: "perl", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..e653321ea --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.Go", + exampleName: "postgres-ext", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..6964b8bbb --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.PowerShell.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.PowerShell.AppHost.Go", + exampleName: "powershell", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Python.Extensions.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Python.Extensions.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..87157412d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Python.Extensions.Tests/GoAppHostTests.cs @@ -0,0 +1,16 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Python.Extensions.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Python.Extensions.AppHost.Go", + exampleName: "python", + validatePublish: false, + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..f6c1ac721 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.RavenDB.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.RavenDB.AppHost.Go", + exampleName: "ravendb", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.RedPanda.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.RedPanda.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..b08f0111d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.RedPanda.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.RedPanda.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.RedPanda.AppHost.Go", + exampleName: "redpanda", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..8a79381b6 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Rust.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Rust.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Rust.AppHost.Go", + exampleName: "rust", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.SeaweedFS.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SeaweedFS.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..a8ed9cd02 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.SeaweedFS.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.SeaweedFS.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "SeaweedFS.AppHost.Go", + exampleName: "seaweedfs", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..88da7e98d --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Sftp.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Sftp.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Sftp.AppHost.Go", + exampleName: "sftp", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Solr.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Solr.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..1c6900de0 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Solr.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Solr.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Solr.AppHost.Go", + exampleName: "solr", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..1dd58489c --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/GoAppHostTests.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await SqlPolyglotAppHostTest.Run(() => GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.Go", + exampleName: "sql-database-projects", + // The prebuilt Windows AppHost server fails to load hostfxr for MSBuildLocator. + validatePublish: !OperatingSystem.IsWindows(), + cancellationToken: TestContext.Current.CancellationToken)); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlPolyglotAppHostTest.cs b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlPolyglotAppHostTest.cs new file mode 100644 index 000000000..e74659b20 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlPolyglotAppHostTest.cs @@ -0,0 +1,35 @@ +namespace CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests; + +internal static class SqlPolyglotAppHostTest +{ + private static readonly string[] s_msbuildEnvironmentVariables = + [ + "MSBUILD_EXE_PATH", + "MSBuildExtensionsPath", + "MSBuildSDKsPath" + ]; + + public static async Task Run(Func test) + { + // MSBuildLocator in other SQL tests configures in-process MSBuild; child dotnet builds + // must select their own SDK instead of inheriting those paths. + Dictionary originalValues = s_msbuildEnvironmentVariables.ToDictionary( + name => name, Environment.GetEnvironmentVariable); + try + { + foreach (string name in s_msbuildEnvironmentVariables) + { + Environment.SetEnvironmentVariable(name, null); + } + + await test(); + } + finally + { + foreach ((string name, string? value) in originalValues) + { + Environment.SetEnvironmentVariable(name, value); + } + } + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlPolyglotAppHostTestTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlPolyglotAppHostTestTests.cs new file mode 100644 index 000000000..5d0eb94af --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/SqlPolyglotAppHostTestTests.cs @@ -0,0 +1,40 @@ +namespace CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests; + +public class SqlPolyglotAppHostTestTests +{ + [Fact] + public async Task RestoresMSBuildEnvironmentAfterFailure() + { + string[] variables = ["MSBUILD_EXE_PATH", "MSBuildExtensionsPath", "MSBuildSDKsPath"]; + Dictionary originalValues = variables.ToDictionary(name => name, Environment.GetEnvironmentVariable); + try + { + foreach (string variable in variables) + { + Environment.SetEnvironmentVariable(variable, "test-sdk-path"); + } + + await Assert.ThrowsAsync(() => SqlPolyglotAppHostTest.Run(() => + { + foreach (string variable in variables) + { + Assert.Null(Environment.GetEnvironmentVariable(variable)); + } + + throw new InvalidOperationException(); + })); + + foreach (string variable in variables) + { + Assert.Equal("test-sdk-path", Environment.GetEnvironmentVariable(variable)); + } + } + finally + { + foreach ((string variable, string? value) in originalValues) + { + Environment.SetEnvironmentVariable(variable, value); + } + } + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/TypeScriptAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/TypeScriptAppHostTests.cs index 27163b8c9..fb689b2fc 100644 --- a/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/TypeScriptAppHostTests.cs +++ b/tests/CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.Tests/TypeScriptAppHostTests.cs @@ -9,11 +9,11 @@ public class TypeScriptAppHostTests [Fact] public async Task TypeScriptAppHostCompilesAndStarts() { - await TypeScriptAppHostTest.Run( + await SqlPolyglotAppHostTest.Run(() => TypeScriptAppHostTest.Run( appHostProject: "CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects.AppHost.TypeScript", packageName: "CommunityToolkit.Aspire.Hosting.SqlDatabaseProjects", exampleName: "sql-database-projects", waitForResources: [], - cancellationToken: TestContext.Current.CancellationToken); + cancellationToken: TestContext.Current.CancellationToken)); } } \ No newline at end of file diff --git a/tests/CommunityToolkit.Aspire.Hosting.Sqlite.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Sqlite.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..0432d3557 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Sqlite.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Sqlite.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Sqlite.AppHost.Go", + exampleName: "sqlite", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Squad.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Squad.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..c72003ff5 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Squad.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Squad.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Squad.AppHost.Go", + exampleName: "squad", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Stripe.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Stripe.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..5c1db8cf1 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Stripe.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Stripe.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Stripe.AppHost.Go", + exampleName: "stripe", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..456b6827b --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.SurrealDb.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.SurrealDb.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.SurrealDb.AppHost.Go", + exampleName: "surrealdb", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Tempo.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Tempo.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..dca151472 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Tempo.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Tempo.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Tempo.AppHost.Go", + exampleName: "tempo", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.Zitadel.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Zitadel.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..342a1df51 --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.Zitadel.Tests/GoAppHostTests.cs @@ -0,0 +1,17 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.Zitadel.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.Zitadel.AppHost.Go", + exampleName: "zitadel", + // The preview SDK cannot serialize the optional credential handles. + validatePublish: false, + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Hosting.k6.Tests/GoAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.k6.Tests/GoAppHostTests.cs new file mode 100644 index 000000000..7c1b041ed --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Hosting.k6.Tests/GoAppHostTests.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Aspire.Testing; + +namespace CommunityToolkit.Aspire.Hosting.k6.Tests; + +public class GoAppHostTests +{ + [Fact] + public async Task GoAppHostCompiles() + { + await GoAppHostTest.Run( + appHostProject: "CommunityToolkit.Aspire.Hosting.k6.AppHost.Go", + exampleName: "k6", + cancellationToken: TestContext.Current.CancellationToken); + } +} diff --git a/tests/CommunityToolkit.Aspire.Testing/GoAppHostTest.cs b/tests/CommunityToolkit.Aspire.Testing/GoAppHostTest.cs new file mode 100644 index 000000000..5e826b9dd --- /dev/null +++ b/tests/CommunityToolkit.Aspire.Testing/GoAppHostTest.cs @@ -0,0 +1,31 @@ +namespace CommunityToolkit.Aspire.Testing; + +/// +/// Runs the Go AppHost SDK generation, compilation, and model checks. +/// +public static class GoAppHostTest +{ + /// + /// Restores, compiles, and builds the model for an example Go AppHost. + /// + /// The AppHost directory name under the example folder. + /// The example folder name. + /// Whether to validate the publish-mode model. + /// The cancellation token. + public static async Task Run(string appHostProject, string exampleName, bool validatePublish = true, CancellationToken cancellationToken = default) + { + ArgumentException.ThrowIfNullOrWhiteSpace(appHostProject); + ArgumentException.ThrowIfNullOrWhiteSpace(exampleName); + + string repoRoot = Path.GetFullPath(Path.Combine("..", "..", "..", "..", "..")); + string appHostDirectory = Path.Combine(repoRoot, "examples", exampleName, appHostProject); + string aspire = OperatingSystem.IsWindows() ? "cmd.exe" : "aspire"; + string[] aspirePrefix = OperatingSystem.IsWindows() ? ["/d", "/c", "aspire"] : []; + await ProcessTestUtilities.RunProcessAsync(aspire, [.. aspirePrefix, "restore", "--apphost", "apphost.go", "--non-interactive"], appHostDirectory, cancellationToken); + await ProcessTestUtilities.RunProcessAsync("go", ["test", "./..."], appHostDirectory, cancellationToken); + if (validatePublish) + { + await ProcessTestUtilities.RunProcessAsync(aspire, [.. aspirePrefix, "publish", "--apphost", "apphost.go", "--list-steps", "--non-interactive"], appHostDirectory, cancellationToken); + } + } +}