Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ src/Components/**/ConfigurationSchema.json text eol=lf
# gofmt rewrites CRLF, and the go-starter files are scaffolded exactly as they are checked out.
*.go text eol=lf
src/Aspire.Cli/Templating/Templates/go-starter/** text eol=lf
src/Aspire.Cli/Templating/Templates/go-starter/**/*.png -text
2 changes: 1 addition & 1 deletion .github/workflows/polyglot-validation/test-go.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ if grep -q "builder.Build()" apphost.go; then
print "\t}"
print ""
print "\t// Add Redis cache resource"
print "\tredis := builder.AddRedis(\"cache\", &aspire.AddRedisOptions{Port: aspire.Float64Ptr(0)}).WithImageRegistry(\"netaspireci.azurecr.io\")"
print "\tredis := builder.AddRedis(\"cache\", &aspire.AddRedisOptions{Port: aspire.IntPtr(0)}).WithImageRegistry(\"netaspireci.azurecr.io\")"
print "\tif err := redis.Err(); err != nil {"
print "\t\tlog.Fatalf(\"Failed to set up Redis: %v\", err)"
print "\t}"
Expand Down
16 changes: 16 additions & 0 deletions docs/specs/cli-output-formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -829,3 +829,19 @@ Each entry in `capabilities` includes an `isExperimental` boolean indicating whe
The top-level fields are `schemaVersion`, `language`, `generator`, `package`, `modules`, and `declarations`. The language exporter owns the schema; the CLI passes it through without reshaping it.

TypeScript (`--language typescript`) and Go (`--language go`) ship exporters. The Go exporter projects through the same code paths as the Go SDK generator, so every `declaration` is the Go the generator emits, including the surface that is written by hand rather than discovered from capabilities: `Build()` on the builder, the `Get`, `Required`, `Value`, and `RequiredValue` helpers on interaction input collections, `Err()` on every handle, `ToMap()` on options and DTO structs, and the runtime types. Go `modules[].items[]` have kind `function`, `interface`, `augmentation`, `dto`, `options`, `enum`, `variable`, or `type`; an `augmentation` lists the members a package adds to a type that another package declares. Capability-backed members carry `capabilityId`, and members that the generator writes itself are marked `synthesized`. The top-level `declarations` hold the Go fragments that signatures refer to. Go names are resolved over the exported package and the types it references, not over a whole app host. When an app host combines integrations whose names collide, the generated SDK can qualify a name that this reference gives bare, and an `options` struct that several packages could share is documented by each package under its own `typeId`. The `Any<Type>` interfaces, which accept a handle type or any type derived from it, follow the same rule: one exists only when the set holds a type derived from its base, so a signature here can name a handle interface where an app host that includes the derived type's integration accepts `Any<Type>`.

Go field and constant members include `type` (the declared Go type) and `optional` (a boolean), additive to schema version 1. This includes DTO fields, options fields, runtime fields, enum constants, and exported value leaves. DTO optionality comes from ATS property metadata: neither a pointer type nor the generated `omitempty` tag alone means the property can be omitted. Options fields are optional; constants and exported value leaves are not. Consumers do not need to parse `declaration` to recover these values.

For example, an options field is exported as:

```json
{
"id": "WithPersistenceOptions.Mode",
"kind": "field",
"name": "Mode",
"declaration": "Mode *TestPersistenceMode `json:\"mode,omitempty\"`",
"jsonName": "mode",
"type": "*TestPersistenceMode",
"optional": true
}
```
15 changes: 12 additions & 3 deletions eng/scripts/cli-starter-validation.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ $templates = @(
ProjectName = 'AspireCliGoStarterSmoke'
# Hosted macOS/Windows runners have no Linux container runtime. Keep full Redis
# readiness on Linux; the other runners exercise the supported cache-free starter.
ExpectedResources = $(if ($IsLinux) { @('api', 'cache') } else { @('api') })
ExpectedResources = $(if ($IsLinux) { @('app', 'cache') } else { @('app') })
}
)

Expand Down Expand Up @@ -287,9 +287,9 @@ foreach ($template in $templates)
$newStartedAt = Get-Date
Write-DiagnosticMessage "${templateId}: invoking aspire new."
$templateArguments = @()
if ($templateId -eq 'aspire-go-starter' -and -not $IsLinux)
if ($templateId -eq 'aspire-go-starter')
{
$templateArguments = @('--use-redis-cache', 'false')
$templateArguments = @('--use-redis-cache', $(if ($IsLinux) { 'true' } else { 'false' }))
}
aspire new $templateId --name $projectName --output $projectRoot --channel "pr-$PRNumber" --non-interactive --nologo --suppress-agent-init @templateArguments
Write-DiagnosticMessage "${templateId}: aspire new returned after $([math]::Round(((Get-Date) - $newStartedAt).TotalSeconds, 1)) seconds."
Expand Down Expand Up @@ -431,6 +431,15 @@ foreach ($template in $templates)
{
Pop-Location
}

# The diagnostics artifact preserves the generated project but does not need installed
# dependencies. Remove them after all Aspire processes stop so upload-artifact cannot race
# a package installer cleanup and fail while stat-ing a disappearing node_modules directory.
foreach ($relativeDependencyPath in @('node_modules', 'frontend/node_modules'))
{
$dependencyPath = Join-Path $projectRoot $relativeDependencyPath
Remove-Item -Recurse -Force $dependencyPath -ErrorAction SilentlyContinue
}
}

Pop-Location
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ private async Task<TemplateResult> ApplyGoStarterTemplateAsync(CallbackTemplate
_logger.LogDebug("Applying Go starter template. ProjectName: {ProjectName}, OutputPath: {OutputPath}, AspireVersion: {AspireVersion}.", projectName, outputPath, aspireVersion);

var useLocalhostTld = await ResolveUseLocalhostTldAsync(parseResult, cancellationToken);
// Keep the existing Redis-enabled default, including non-interactive scaffolding.
var useRedisCache = parseResult.GetValue(_useRedisCacheOption) ?? true;
var useRedisCache = await ResolveUseRedisCacheAsync(parseResult, cancellationToken);

TemplateResult templateResult;
try
Expand All @@ -54,7 +53,11 @@ private async Task<TemplateResult> ApplyGoStarterTemplateAsync(CallbackTemplate
var projectNameLower = projectName.ToLowerInvariant();
var ports = GenerateRandomPorts();
var hostName = useLocalhostTld ? $"{projectNameLower}.dev.localhost" : "localhost";
var conditions = new Dictionary<string, bool> { ["redis"] = useRedisCache };
var conditions = new Dictionary<string, bool>
{
["redis"] = useRedisCache,
["no-redis"] = !useRedisCache,
};
string ApplyAllTokens(string content) => ConditionalBlockProcessor.Process(
ApplyTokens(content, projectName, projectNameLower, aspireVersion, ports, hostName),
conditions);
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Cli/Templating/CliTemplateFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ private IEnumerable<ITemplate> GetTemplateDefinitions()

new CallbackTemplate(
KnownTemplateId.GoStarter,
"Starter App (Go API + Redis, Go AppHost)",
"Starter App (Go API/React, Go AppHost)",
(ctx, projectName) => OutputPathHelper.GetUniqueDefaultOutputPath(projectName, ctx.WorkingDirectory.FullName),
cmd =>
{
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Cli/Templating/KnownTemplateId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ internal static class KnownTemplateId
public const string RustEmptyAppHost = "aspire-rust-empty";

/// <summary>
/// The template ID for the Go starter template (Redis + Go HTTP API).
/// The template ID for the Go starter template (Go HTTP API + React frontend + optional Redis).
/// </summary>
public const string GoStarter = "aspire-go-starter";

Expand Down
2 changes: 2 additions & 0 deletions src/Aspire.Cli/Templating/Templates/go-starter/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.aspire/
node_modules/
dist/
12 changes: 10 additions & 2 deletions src/Aspire.Cli/Templating/Templates/go-starter/api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ module {{projectNameLower}}/api
go 1.26

require (
// {{#redis}}
github.com/redis/go-redis/extra/redisotel/v9 v9.19.0
github.com/redis/go-redis/v9 v9.19.0
// {{/redis}}
go.opentelemetry.io/contrib/bridges/otelslog v0.18.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0
go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0
go.opentelemetry.io/otel v1.43.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0
go.opentelemetry.io/otel/log v0.19.0
go.opentelemetry.io/otel/metric v1.43.0
go.opentelemetry.io/otel/sdk v1.43.0
go.opentelemetry.io/otel/sdk/log v0.19.0
go.opentelemetry.io/otel/sdk/metric v1.43.0
Expand All @@ -25,11 +27,17 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
// {{#redis}}
github.com/redis/go-redis/extra/rediscmd/v9 v9.19.0 // indirect
// {{/redis}}
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
// {{#redis}}
go.uber.org/atomic v1.11.0 // indirect
// {{/redis}}
golang.org/x/net v0.52.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.35.0 // indirect
Expand Down
18 changes: 16 additions & 2 deletions src/Aspire.Cli/Templating/Templates/go-starter/api/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// {{#redis}}
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
// {{/redis}}
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
Expand All @@ -23,22 +25,32 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
// {{#redis}}
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
// {{/redis}}
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
// {{#redis}}
github.com/redis/go-redis/extra/rediscmd/v9 v9.19.0 h1:QL3vQTj64ZQpxiDZx6bFYS7oN37EdHHqiYGz3grgTRI=
github.com/redis/go-redis/extra/rediscmd/v9 v9.19.0/go.mod h1:kGroOkFJzE2Si+mojCi3PCvuAnGnzEh1FAzy1Oh9mI8=
github.com/redis/go-redis/extra/redisotel/v9 v9.19.0 h1:yXeFe+EFMUirnzzy8MI5iazoqlpBdzVC6pk+K2Mu7do=
github.com/redis/go-redis/extra/redisotel/v9 v9.19.0/go.mod h1:GgAFS1Cg26tQEiHzDd8cHXPKUzzTineQ91Ei9glAxQs=
github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k=
github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA=
// {{/redis}}
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
// {{#redis}}
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
// {{/redis}}
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/bridges/otelslog v0.18.0 h1:hhPGP3zvvy1xWT9RTy970wlniSxFttBIsAK1gvMguJM=
go.opentelemetry.io/contrib/bridges/otelslog v0.18.0/go.mod h1:twJF7inoMza6kxMcF8JOdL3mPmtOZu7GEr34CUNE6Dg=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 h1:CqXxU8VOmDefoh0+ztfGaymYbhdB/tT3zs79QaZTNGY=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0/go.mod h1:BuhAPThV8PBHBvg8ZzZ/Ok3idOdhWIodywz2xEcRbJo=
go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0 h1:jhVIQEprwUTV+KfzzliLidclhoTOoHTgdz96kAyR8mU=
go.opentelemetry.io/contrib/instrumentation/runtime v0.68.0/go.mod h1:4HsdbLUbernaTnA8CNaNE+1g026SciXb3juRYe3l8EY=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y=
Expand All @@ -65,8 +77,10 @@ go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
// {{#redis}}
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
// {{/redis}}
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
Expand Down
Loading
Loading