diff --git a/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs b/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs index 8feaa5133b1..92dbe095f27 100644 --- a/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs +++ b/src/Aspire.Hosting/Ats/AtsCapabilityScanner.cs @@ -786,6 +786,10 @@ private static Dictionary> BuildTypeCompatibilityMap( IsInterface = false }; + // Register under its own type ID so base types with derived types + // are included when expanding capabilities that target them directly + AddToCompatibilityMap(typeToCompatibleTypes, typeInfo.AtsTypeId, concreteTypeRef); + // Register under each implemented interface foreach (var iface in typeInfo.ImplementedInterfaces) { diff --git a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go index 5205679851e..d1963bf455d 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go +++ b/tests/Aspire.Hosting.CodeGeneration.Go.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.go @@ -2580,6 +2580,207 @@ func (s *ContainerResource) WithContainerRegistry(registry *IResource) (*IResour return result.(*IResource), nil } +// WithBindMount adds a bind mount +func (s *ContainerResource) WithBindMount(source string, target string, isReadOnly bool) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["source"] = SerializeValue(source) + reqArgs["target"] = SerializeValue(target) + reqArgs["isReadOnly"] = SerializeValue(isReadOnly) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withBindMount", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithEntrypoint sets the container entrypoint +func (s *ContainerResource) WithEntrypoint(entrypoint string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["entrypoint"] = SerializeValue(entrypoint) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withEntrypoint", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithImageTag sets the container image tag +func (s *ContainerResource) WithImageTag(tag string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["tag"] = SerializeValue(tag) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withImageTag", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithImageRegistry sets the container image registry +func (s *ContainerResource) WithImageRegistry(registry string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["registry"] = SerializeValue(registry) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withImageRegistry", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithImage sets the container image +func (s *ContainerResource) WithImage(image string, tag string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["image"] = SerializeValue(image) + reqArgs["tag"] = SerializeValue(tag) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withImage", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithImageSHA256 sets the image SHA256 digest +func (s *ContainerResource) WithImageSHA256(sha256 string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["sha256"] = SerializeValue(sha256) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withImageSHA256", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithContainerRuntimeArgs adds runtime arguments for the container +func (s *ContainerResource) WithContainerRuntimeArgs(args []string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["args"] = SerializeValue(args) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withContainerRuntimeArgs", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithLifetime sets the lifetime behavior of the container resource +func (s *ContainerResource) WithLifetime(lifetime ContainerLifetime) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["lifetime"] = SerializeValue(lifetime) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withLifetime", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithImagePullPolicy sets the container image pull policy +func (s *ContainerResource) WithImagePullPolicy(pullPolicy ImagePullPolicy) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["pullPolicy"] = SerializeValue(pullPolicy) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withImagePullPolicy", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// PublishAsContainer configures the resource to be published as a container +func (s *ContainerResource) PublishAsContainer() (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/publishAsContainer", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithDockerfile configures the resource to use a Dockerfile +func (s *ContainerResource) WithDockerfile(contextPath string, dockerfilePath string, stage string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["contextPath"] = SerializeValue(contextPath) + reqArgs["dockerfilePath"] = SerializeValue(dockerfilePath) + reqArgs["stage"] = SerializeValue(stage) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withDockerfile", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithContainerName sets the container name +func (s *ContainerResource) WithContainerName(name string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["name"] = SerializeValue(name) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withContainerName", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithBuildArg adds a build argument from a parameter resource +func (s *ContainerResource) WithBuildArg(name string, value *ParameterResource) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["name"] = SerializeValue(name) + reqArgs["value"] = SerializeValue(value) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withBuildArg", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithBuildSecret adds a build secret from a parameter resource +func (s *ContainerResource) WithBuildSecret(name string, value *ParameterResource) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["name"] = SerializeValue(name) + reqArgs["value"] = SerializeValue(value) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withBuildSecret", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + +// WithEndpointProxySupport configures endpoint proxy support +func (s *ContainerResource) WithEndpointProxySupport(proxyEnabled bool) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["proxyEnabled"] = SerializeValue(proxyEnabled) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withEndpointProxySupport", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + // WithDockerfileBaseImage sets the base image for a Dockerfile build func (s *ContainerResource) WithDockerfileBaseImage(buildImage string, runtimeImage string) (*IResource, error) { reqArgs := map[string]any{ @@ -2594,6 +2795,19 @@ func (s *ContainerResource) WithDockerfileBaseImage(buildImage string, runtimeIm return result.(*IResource), nil } +// WithContainerNetworkAlias adds a network alias for the container +func (s *ContainerResource) WithContainerNetworkAlias(alias string) (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["alias"] = SerializeValue(alias) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withContainerNetworkAlias", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + // WithMcpServer configures an MCP server endpoint on the resource func (s *ContainerResource) WithMcpServer(path string, endpointName string) (*IResourceWithEndpoints, error) { reqArgs := map[string]any{ @@ -2633,6 +2847,18 @@ func (s *ContainerResource) WithOtlpExporterProtocol(protocol OtlpProtocol) (*IR return result.(*IResourceWithEnvironment), nil } +// PublishAsConnectionString publishes the resource as a connection string +func (s *ContainerResource) PublishAsConnectionString() (*ContainerResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/publishAsConnectionString", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + // WithRequiredCommand adds a required command dependency func (s *ContainerResource) WithRequiredCommand(command string, helpLink string) (*IResource, error) { reqArgs := map[string]any{ @@ -3394,6 +3620,21 @@ func (s *ContainerResource) WithPipelineConfiguration(callback func(...any) any) return result.(*IResource), nil } +// WithVolume adds a volume +func (s *ContainerResource) WithVolume(target string, name string, isReadOnly bool) (*ContainerResource, error) { + reqArgs := map[string]any{ + "resource": SerializeValue(s.Handle()), + } + reqArgs["target"] = SerializeValue(target) + reqArgs["name"] = SerializeValue(name) + reqArgs["isReadOnly"] = SerializeValue(isReadOnly) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withVolume", reqArgs) + if err != nil { + return nil, err + } + return result.(*ContainerResource), nil +} + // GetResourceName gets the resource name func (s *ContainerResource) GetResourceName() (*string, error) { reqArgs := map[string]any{ @@ -5256,6 +5497,59 @@ func (s *ExecutableResource) WithDockerfileBaseImage(buildImage string, runtimeI return result.(*IResource), nil } +// PublishAsDockerFile publishes the executable as a Docker container +func (s *ExecutableResource) PublishAsDockerFile() (*ExecutableResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/publishAsDockerFile", reqArgs) + if err != nil { + return nil, err + } + return result.(*ExecutableResource), nil +} + +// PublishAsDockerFileWithConfigure publishes an executable as a Docker file with optional container configuration +func (s *ExecutableResource) PublishAsDockerFileWithConfigure(configure func(...any) any) (*ExecutableResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + if configure != nil { + reqArgs["configure"] = RegisterCallback(configure) + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/publishAsDockerFileWithConfigure", reqArgs) + if err != nil { + return nil, err + } + return result.(*ExecutableResource), nil +} + +// WithExecutableCommand sets the executable command +func (s *ExecutableResource) WithExecutableCommand(command string) (*ExecutableResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["command"] = SerializeValue(command) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withExecutableCommand", reqArgs) + if err != nil { + return nil, err + } + return result.(*ExecutableResource), nil +} + +// WithWorkingDirectory sets the executable working directory +func (s *ExecutableResource) WithWorkingDirectory(workingDirectory string) (*ExecutableResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["workingDirectory"] = SerializeValue(workingDirectory) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withWorkingDirectory", reqArgs) + if err != nil { + return nil, err + } + return result.(*ExecutableResource), nil +} + // WithMcpServer configures an MCP server endpoint on the resource func (s *ExecutableResource) WithMcpServer(path string, endpointName string) (*IResourceWithEndpoints, error) { reqArgs := map[string]any{ @@ -8251,6 +8545,46 @@ func (s *ProjectResource) WithOtlpExporterProtocol(protocol OtlpProtocol) (*IRes return result.(*IResourceWithEnvironment), nil } +// WithReplicas sets the number of replicas +func (s *ProjectResource) WithReplicas(replicas float64) (*ProjectResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + reqArgs["replicas"] = SerializeValue(replicas) + result, err := s.Client().InvokeCapability("Aspire.Hosting/withReplicas", reqArgs) + if err != nil { + return nil, err + } + return result.(*ProjectResource), nil +} + +// DisableForwardedHeaders disables forwarded headers for the project +func (s *ProjectResource) DisableForwardedHeaders() (*ProjectResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/disableForwardedHeaders", reqArgs) + if err != nil { + return nil, err + } + return result.(*ProjectResource), nil +} + +// PublishAsDockerFile publishes a project as a Docker file with optional container configuration +func (s *ProjectResource) PublishAsDockerFile(configure func(...any) any) (*ProjectResource, error) { + reqArgs := map[string]any{ + "builder": SerializeValue(s.Handle()), + } + if configure != nil { + reqArgs["configure"] = RegisterCallback(configure) + } + result, err := s.Client().InvokeCapability("Aspire.Hosting/publishProjectAsDockerFileWithConfigure", reqArgs) + if err != nil { + return nil, err + } + return result.(*ProjectResource), nil +} + // WithRequiredCommand adds a required command dependency func (s *ProjectResource) WithRequiredCommand(command string, helpLink string) (*IResource, error) { reqArgs := map[string]any{ diff --git a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java index e9977c1d198..f3e4b6a0274 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java +++ b/tests/Aspire.Hosting.CodeGeneration.Java.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.java @@ -2156,6 +2156,140 @@ public IResource withContainerRegistry(IResource registry) { return (IResource) getClient().invokeCapability("Aspire.Hosting/withContainerRegistry", reqArgs); } + /** Adds a bind mount */ + public ContainerResource withBindMount(String source, String target, Boolean isReadOnly) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("source", AspireClient.serializeValue(source)); + reqArgs.put("target", AspireClient.serializeValue(target)); + if (isReadOnly != null) { + reqArgs.put("isReadOnly", AspireClient.serializeValue(isReadOnly)); + } + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withBindMount", reqArgs); + } + + /** Sets the container entrypoint */ + public ContainerResource withEntrypoint(String entrypoint) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("entrypoint", AspireClient.serializeValue(entrypoint)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withEntrypoint", reqArgs); + } + + /** Sets the container image tag */ + public ContainerResource withImageTag(String tag) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("tag", AspireClient.serializeValue(tag)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withImageTag", reqArgs); + } + + /** Sets the container image registry */ + public ContainerResource withImageRegistry(String registry) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("registry", AspireClient.serializeValue(registry)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withImageRegistry", reqArgs); + } + + /** Sets the container image */ + public ContainerResource withImage(String image, String tag) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("image", AspireClient.serializeValue(image)); + if (tag != null) { + reqArgs.put("tag", AspireClient.serializeValue(tag)); + } + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withImage", reqArgs); + } + + /** Sets the image SHA256 digest */ + public ContainerResource withImageSHA256(String sha256) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("sha256", AspireClient.serializeValue(sha256)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withImageSHA256", reqArgs); + } + + /** Adds runtime arguments for the container */ + public ContainerResource withContainerRuntimeArgs(String[] args) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("args", AspireClient.serializeValue(args)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withContainerRuntimeArgs", reqArgs); + } + + /** Sets the lifetime behavior of the container resource */ + public ContainerResource withLifetime(ContainerLifetime lifetime) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("lifetime", AspireClient.serializeValue(lifetime)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withLifetime", reqArgs); + } + + /** Sets the container image pull policy */ + public ContainerResource withImagePullPolicy(ImagePullPolicy pullPolicy) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("pullPolicy", AspireClient.serializeValue(pullPolicy)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withImagePullPolicy", reqArgs); + } + + /** Configures the resource to be published as a container */ + public ContainerResource publishAsContainer() { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/publishAsContainer", reqArgs); + } + + /** Configures the resource to use a Dockerfile */ + public ContainerResource withDockerfile(String contextPath, String dockerfilePath, String stage) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("contextPath", AspireClient.serializeValue(contextPath)); + if (dockerfilePath != null) { + reqArgs.put("dockerfilePath", AspireClient.serializeValue(dockerfilePath)); + } + if (stage != null) { + reqArgs.put("stage", AspireClient.serializeValue(stage)); + } + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withDockerfile", reqArgs); + } + + /** Sets the container name */ + public ContainerResource withContainerName(String name) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("name", AspireClient.serializeValue(name)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withContainerName", reqArgs); + } + + /** Adds a build argument from a parameter resource */ + public ContainerResource withBuildArg(String name, ParameterResource value) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("name", AspireClient.serializeValue(name)); + reqArgs.put("value", AspireClient.serializeValue(value)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withBuildArg", reqArgs); + } + + /** Adds a build secret from a parameter resource */ + public ContainerResource withBuildSecret(String name, ParameterResource value) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("name", AspireClient.serializeValue(name)); + reqArgs.put("value", AspireClient.serializeValue(value)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withBuildSecret", reqArgs); + } + + /** Configures endpoint proxy support */ + public ContainerResource withEndpointProxySupport(boolean proxyEnabled) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("proxyEnabled", AspireClient.serializeValue(proxyEnabled)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withEndpointProxySupport", reqArgs); + } + /** Sets the base image for a Dockerfile build */ public IResource withDockerfileBaseImage(String buildImage, String runtimeImage) { Map reqArgs = new HashMap<>(); @@ -2169,6 +2303,14 @@ public IResource withDockerfileBaseImage(String buildImage, String runtimeImage) return (IResource) getClient().invokeCapability("Aspire.Hosting/withDockerfileBaseImage", reqArgs); } + /** Adds a network alias for the container */ + public ContainerResource withContainerNetworkAlias(String alias) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("alias", AspireClient.serializeValue(alias)); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withContainerNetworkAlias", reqArgs); + } + /** Configures an MCP server endpoint on the resource */ public IResourceWithEndpoints withMcpServer(String path, String endpointName) { Map reqArgs = new HashMap<>(); @@ -2197,6 +2339,13 @@ public IResourceWithEnvironment withOtlpExporterProtocol(OtlpProtocol protocol) return (IResourceWithEnvironment) getClient().invokeCapability("Aspire.Hosting/withOtlpExporterProtocol", reqArgs); } + /** Publishes the resource as a connection string */ + public ContainerResource publishAsConnectionString() { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/publishAsConnectionString", reqArgs); + } + /** Adds a required command dependency */ public IResource withRequiredCommand(String command, String helpLink) { Map reqArgs = new HashMap<>(); @@ -2771,6 +2920,20 @@ public IResource withPipelineConfiguration(Function callback) return (IResource) getClient().invokeCapability("Aspire.Hosting/withPipelineConfiguration", reqArgs); } + /** Adds a volume */ + public ContainerResource withVolume(String target, String name, Boolean isReadOnly) { + Map reqArgs = new HashMap<>(); + reqArgs.put("resource", AspireClient.serializeValue(getHandle())); + reqArgs.put("target", AspireClient.serializeValue(target)); + if (name != null) { + reqArgs.put("name", AspireClient.serializeValue(name)); + } + if (isReadOnly != null) { + reqArgs.put("isReadOnly", AspireClient.serializeValue(isReadOnly)); + } + return (ContainerResource) getClient().invokeCapability("Aspire.Hosting/withVolume", reqArgs); + } + /** Gets the resource name */ public String getResourceName() { Map reqArgs = new HashMap<>(); @@ -4054,6 +4217,39 @@ public IResource withDockerfileBaseImage(String buildImage, String runtimeImage) return (IResource) getClient().invokeCapability("Aspire.Hosting/withDockerfileBaseImage", reqArgs); } + /** Publishes the executable as a Docker container */ + public ExecutableResource publishAsDockerFile() { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + return (ExecutableResource) getClient().invokeCapability("Aspire.Hosting/publishAsDockerFile", reqArgs); + } + + /** Publishes an executable as a Docker file with optional container configuration */ + public ExecutableResource publishAsDockerFileWithConfigure(Function configure) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + if (configure != null) { + reqArgs.put("configure", getClient().registerCallback(configure)); + } + return (ExecutableResource) getClient().invokeCapability("Aspire.Hosting/publishAsDockerFileWithConfigure", reqArgs); + } + + /** Sets the executable command */ + public ExecutableResource withExecutableCommand(String command) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("command", AspireClient.serializeValue(command)); + return (ExecutableResource) getClient().invokeCapability("Aspire.Hosting/withExecutableCommand", reqArgs); + } + + /** Sets the executable working directory */ + public ExecutableResource withWorkingDirectory(String workingDirectory) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("workingDirectory", AspireClient.serializeValue(workingDirectory)); + return (ExecutableResource) getClient().invokeCapability("Aspire.Hosting/withWorkingDirectory", reqArgs); + } + /** Configures an MCP server endpoint on the resource */ public IResourceWithEndpoints withMcpServer(String path, String endpointName) { Map reqArgs = new HashMap<>(); @@ -6154,6 +6350,31 @@ public IResourceWithEnvironment withOtlpExporterProtocol(OtlpProtocol protocol) return (IResourceWithEnvironment) getClient().invokeCapability("Aspire.Hosting/withOtlpExporterProtocol", reqArgs); } + /** Sets the number of replicas */ + public ProjectResource withReplicas(double replicas) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + reqArgs.put("replicas", AspireClient.serializeValue(replicas)); + return (ProjectResource) getClient().invokeCapability("Aspire.Hosting/withReplicas", reqArgs); + } + + /** Disables forwarded headers for the project */ + public ProjectResource disableForwardedHeaders() { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + return (ProjectResource) getClient().invokeCapability("Aspire.Hosting/disableForwardedHeaders", reqArgs); + } + + /** Publishes a project as a Docker file with optional container configuration */ + public ProjectResource publishAsDockerFile(Function configure) { + Map reqArgs = new HashMap<>(); + reqArgs.put("builder", AspireClient.serializeValue(getHandle())); + if (configure != null) { + reqArgs.put("configure", getClient().registerCallback(configure)); + } + return (ProjectResource) getClient().invokeCapability("Aspire.Hosting/publishProjectAsDockerFileWithConfigure", reqArgs); + } + /** Adds a required command dependency */ public IResource withRequiredCommand(String command, String helpLink) { Map reqArgs = new HashMap<>(); diff --git a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py index e2de69e5b7a..1ec0aae3a77 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py +++ b/tests/Aspire.Hosting.CodeGeneration.Python.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.py @@ -1434,6 +1434,105 @@ def with_container_registry(self, registry: IResource) -> IResource: args["registry"] = serialize_value(registry) return self._client.invoke_capability("Aspire.Hosting/withContainerRegistry", args) + def with_bind_mount(self, source: str, target: str, is_read_only: bool = False) -> ContainerResource: + """Adds a bind mount""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["source"] = serialize_value(source) + args["target"] = serialize_value(target) + args["isReadOnly"] = serialize_value(is_read_only) + return self._client.invoke_capability("Aspire.Hosting/withBindMount", args) + + def with_entrypoint(self, entrypoint: str) -> ContainerResource: + """Sets the container entrypoint""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["entrypoint"] = serialize_value(entrypoint) + return self._client.invoke_capability("Aspire.Hosting/withEntrypoint", args) + + def with_image_tag(self, tag: str) -> ContainerResource: + """Sets the container image tag""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["tag"] = serialize_value(tag) + return self._client.invoke_capability("Aspire.Hosting/withImageTag", args) + + def with_image_registry(self, registry: str) -> ContainerResource: + """Sets the container image registry""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["registry"] = serialize_value(registry) + return self._client.invoke_capability("Aspire.Hosting/withImageRegistry", args) + + def with_image(self, image: str, tag: str | None = None) -> ContainerResource: + """Sets the container image""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["image"] = serialize_value(image) + if tag is not None: + args["tag"] = serialize_value(tag) + return self._client.invoke_capability("Aspire.Hosting/withImage", args) + + def with_image_sha256(self, sha256: str) -> ContainerResource: + """Sets the image SHA256 digest""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["sha256"] = serialize_value(sha256) + return self._client.invoke_capability("Aspire.Hosting/withImageSHA256", args) + + def with_container_runtime_args(self, args: list[str]) -> ContainerResource: + """Adds runtime arguments for the container""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["args"] = serialize_value(args) + return self._client.invoke_capability("Aspire.Hosting/withContainerRuntimeArgs", args) + + def with_lifetime(self, lifetime: ContainerLifetime) -> ContainerResource: + """Sets the lifetime behavior of the container resource""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["lifetime"] = serialize_value(lifetime) + return self._client.invoke_capability("Aspire.Hosting/withLifetime", args) + + def with_image_pull_policy(self, pull_policy: ImagePullPolicy) -> ContainerResource: + """Sets the container image pull policy""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["pullPolicy"] = serialize_value(pull_policy) + return self._client.invoke_capability("Aspire.Hosting/withImagePullPolicy", args) + + def publish_as_container(self) -> ContainerResource: + """Configures the resource to be published as a container""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + return self._client.invoke_capability("Aspire.Hosting/publishAsContainer", args) + + def with_dockerfile(self, context_path: str, dockerfile_path: str | None = None, stage: str | None = None) -> ContainerResource: + """Configures the resource to use a Dockerfile""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["contextPath"] = serialize_value(context_path) + if dockerfile_path is not None: + args["dockerfilePath"] = serialize_value(dockerfile_path) + if stage is not None: + args["stage"] = serialize_value(stage) + return self._client.invoke_capability("Aspire.Hosting/withDockerfile", args) + + def with_container_name(self, name: str) -> ContainerResource: + """Sets the container name""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["name"] = serialize_value(name) + return self._client.invoke_capability("Aspire.Hosting/withContainerName", args) + + def with_build_arg(self, name: str, value: ParameterResource) -> ContainerResource: + """Adds a build argument from a parameter resource""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["name"] = serialize_value(name) + args["value"] = serialize_value(value) + return self._client.invoke_capability("Aspire.Hosting/withBuildArg", args) + + def with_build_secret(self, name: str, value: ParameterResource) -> ContainerResource: + """Adds a build secret from a parameter resource""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["name"] = serialize_value(name) + args["value"] = serialize_value(value) + return self._client.invoke_capability("Aspire.Hosting/withBuildSecret", args) + + def with_endpoint_proxy_support(self, proxy_enabled: bool) -> ContainerResource: + """Configures endpoint proxy support""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["proxyEnabled"] = serialize_value(proxy_enabled) + return self._client.invoke_capability("Aspire.Hosting/withEndpointProxySupport", args) + def with_dockerfile_base_image(self, build_image: str | None = None, runtime_image: str | None = None) -> IResource: """Sets the base image for a Dockerfile build""" args: Dict[str, Any] = { "builder": serialize_value(self._handle) } @@ -1443,6 +1542,12 @@ def with_dockerfile_base_image(self, build_image: str | None = None, runtime_ima args["runtimeImage"] = serialize_value(runtime_image) return self._client.invoke_capability("Aspire.Hosting/withDockerfileBaseImage", args) + def with_container_network_alias(self, alias: str) -> ContainerResource: + """Adds a network alias for the container""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["alias"] = serialize_value(alias) + return self._client.invoke_capability("Aspire.Hosting/withContainerNetworkAlias", args) + def with_mcp_server(self, path: str = "/mcp", endpoint_name: str | None = None) -> IResourceWithEndpoints: """Configures an MCP server endpoint on the resource""" args: Dict[str, Any] = { "builder": serialize_value(self._handle) } @@ -1462,6 +1567,11 @@ def with_otlp_exporter_protocol(self, protocol: OtlpProtocol) -> IResourceWithEn args["protocol"] = serialize_value(protocol) return self._client.invoke_capability("Aspire.Hosting/withOtlpExporterProtocol", args) + def publish_as_connection_string(self) -> ContainerResource: + """Publishes the resource as a connection string""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + return self._client.invoke_capability("Aspire.Hosting/publishAsConnectionString", args) + def with_required_command(self, command: str, help_link: str | None = None) -> IResource: """Adds a required command dependency""" args: Dict[str, Any] = { "builder": serialize_value(self._handle) } @@ -1883,6 +1993,15 @@ def with_pipeline_configuration(self, callback: Callable[[PipelineConfigurationC args["callback"] = callback_id return self._client.invoke_capability("Aspire.Hosting/withPipelineConfiguration", args) + def with_volume(self, target: str, name: str | None = None, is_read_only: bool = False) -> ContainerResource: + """Adds a volume""" + args: Dict[str, Any] = { "resource": serialize_value(self._handle) } + args["target"] = serialize_value(target) + if name is not None: + args["name"] = serialize_value(name) + args["isReadOnly"] = serialize_value(is_read_only) + return self._client.invoke_capability("Aspire.Hosting/withVolume", args) + def get_resource_name(self) -> str: """Gets the resource name""" args: Dict[str, Any] = { "resource": serialize_value(self._handle) } @@ -2826,6 +2945,31 @@ def with_dockerfile_base_image(self, build_image: str | None = None, runtime_ima args["runtimeImage"] = serialize_value(runtime_image) return self._client.invoke_capability("Aspire.Hosting/withDockerfileBaseImage", args) + def publish_as_docker_file(self) -> ExecutableResource: + """Publishes the executable as a Docker container""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + return self._client.invoke_capability("Aspire.Hosting/publishAsDockerFile", args) + + def publish_as_docker_file_with_configure(self, configure: Callable[[ContainerResource], None]) -> ExecutableResource: + """Publishes an executable as a Docker file with optional container configuration""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + configure_id = register_callback(configure) if configure is not None else None + if configure_id is not None: + args["configure"] = configure_id + return self._client.invoke_capability("Aspire.Hosting/publishAsDockerFileWithConfigure", args) + + def with_executable_command(self, command: str) -> ExecutableResource: + """Sets the executable command""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["command"] = serialize_value(command) + return self._client.invoke_capability("Aspire.Hosting/withExecutableCommand", args) + + def with_working_directory(self, working_directory: str) -> ExecutableResource: + """Sets the executable working directory""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["workingDirectory"] = serialize_value(working_directory) + return self._client.invoke_capability("Aspire.Hosting/withWorkingDirectory", args) + def with_mcp_server(self, path: str = "/mcp", endpoint_name: str | None = None) -> IResourceWithEndpoints: """Configures an MCP server endpoint on the resource""" args: Dict[str, Any] = { "builder": serialize_value(self._handle) } @@ -4385,6 +4529,25 @@ def with_otlp_exporter_protocol(self, protocol: OtlpProtocol) -> IResourceWithEn args["protocol"] = serialize_value(protocol) return self._client.invoke_capability("Aspire.Hosting/withOtlpExporterProtocol", args) + def with_replicas(self, replicas: float) -> ProjectResource: + """Sets the number of replicas""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + args["replicas"] = serialize_value(replicas) + return self._client.invoke_capability("Aspire.Hosting/withReplicas", args) + + def disable_forwarded_headers(self) -> ProjectResource: + """Disables forwarded headers for the project""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + return self._client.invoke_capability("Aspire.Hosting/disableForwardedHeaders", args) + + def publish_as_docker_file(self, configure: Callable[[ContainerResource], None] | None = None) -> ProjectResource: + """Publishes a project as a Docker file with optional container configuration""" + args: Dict[str, Any] = { "builder": serialize_value(self._handle) } + configure_id = register_callback(configure) if configure is not None else None + if configure_id is not None: + args["configure"] = configure_id + return self._client.invoke_capability("Aspire.Hosting/publishProjectAsDockerFileWithConfigure", args) + def with_required_command(self, command: str, help_link: str | None = None) -> IResource: """Adds a required command dependency""" args: Dict[str, Any] = { "builder": serialize_value(self._handle) } diff --git a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs index 22cba9c57d9..5ec2aeaf225 100644 --- a/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs +++ b/tests/Aspire.Hosting.CodeGeneration.Rust.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.rs @@ -2555,6 +2555,170 @@ impl ContainerResource { Ok(IResource::new(handle, self.client.clone())) } + /// Adds a bind mount + pub fn with_bind_mount(&self, source: &str, target: &str, is_read_only: Option) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("source".to_string(), serde_json::to_value(&source).unwrap_or(Value::Null)); + args.insert("target".to_string(), serde_json::to_value(&target).unwrap_or(Value::Null)); + if let Some(ref v) = is_read_only { + args.insert("isReadOnly".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + let result = self.client.invoke_capability("Aspire.Hosting/withBindMount", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the container entrypoint + pub fn with_entrypoint(&self, entrypoint: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("entrypoint".to_string(), serde_json::to_value(&entrypoint).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withEntrypoint", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the container image tag + pub fn with_image_tag(&self, tag: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("tag".to_string(), serde_json::to_value(&tag).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withImageTag", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the container image registry + pub fn with_image_registry(&self, registry: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("registry".to_string(), serde_json::to_value(®istry).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withImageRegistry", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the container image + pub fn with_image(&self, image: &str, tag: Option<&str>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("image".to_string(), serde_json::to_value(&image).unwrap_or(Value::Null)); + if let Some(ref v) = tag { + args.insert("tag".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + let result = self.client.invoke_capability("Aspire.Hosting/withImage", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the image SHA256 digest + pub fn with_image_sha256(&self, sha256: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("sha256".to_string(), serde_json::to_value(&sha256).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withImageSHA256", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Adds runtime arguments for the container + pub fn with_container_runtime_args(&self, args: Vec) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("args".to_string(), serde_json::to_value(&args).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withContainerRuntimeArgs", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the lifetime behavior of the container resource + pub fn with_lifetime(&self, lifetime: ContainerLifetime) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("lifetime".to_string(), serde_json::to_value(&lifetime).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withLifetime", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the container image pull policy + pub fn with_image_pull_policy(&self, pull_policy: ImagePullPolicy) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("pullPolicy".to_string(), serde_json::to_value(&pull_policy).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withImagePullPolicy", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Configures the resource to be published as a container + pub fn publish_as_container(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/publishAsContainer", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Configures the resource to use a Dockerfile + pub fn with_dockerfile(&self, context_path: &str, dockerfile_path: Option<&str>, stage: Option<&str>) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("contextPath".to_string(), serde_json::to_value(&context_path).unwrap_or(Value::Null)); + if let Some(ref v) = dockerfile_path { + args.insert("dockerfilePath".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = stage { + args.insert("stage".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + let result = self.client.invoke_capability("Aspire.Hosting/withDockerfile", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Sets the container name + pub fn with_container_name(&self, name: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("name".to_string(), serde_json::to_value(&name).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withContainerName", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Adds a build argument from a parameter resource + pub fn with_build_arg(&self, name: &str, value: &ParameterResource) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("name".to_string(), serde_json::to_value(&name).unwrap_or(Value::Null)); + args.insert("value".to_string(), value.handle().to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/withBuildArg", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Adds a build secret from a parameter resource + pub fn with_build_secret(&self, name: &str, value: &ParameterResource) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("name".to_string(), serde_json::to_value(&name).unwrap_or(Value::Null)); + args.insert("value".to_string(), value.handle().to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/withBuildSecret", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + + /// Configures endpoint proxy support + pub fn with_endpoint_proxy_support(&self, proxy_enabled: bool) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("proxyEnabled".to_string(), serde_json::to_value(&proxy_enabled).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withEndpointProxySupport", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + /// Sets the base image for a Dockerfile build pub fn with_dockerfile_base_image(&self, build_image: Option<&str>, runtime_image: Option<&str>) -> Result> { let mut args: HashMap = HashMap::new(); @@ -2570,6 +2734,16 @@ impl ContainerResource { Ok(IResource::new(handle, self.client.clone())) } + /// Adds a network alias for the container + pub fn with_container_network_alias(&self, alias: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("alias".to_string(), serde_json::to_value(&alias).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withContainerNetworkAlias", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + /// Configures an MCP server endpoint on the resource pub fn with_mcp_server(&self, path: Option<&str>, endpoint_name: Option<&str>) -> Result> { let mut args: HashMap = HashMap::new(); @@ -2604,6 +2778,15 @@ impl ContainerResource { Ok(IResourceWithEnvironment::new(handle, self.client.clone())) } + /// Publishes the resource as a connection string + pub fn publish_as_connection_string(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/publishAsConnectionString", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + /// Adds a required command dependency pub fn with_required_command(&self, command: &str, help_link: Option<&str>) -> Result> { let mut args: HashMap = HashMap::new(); @@ -3272,6 +3455,22 @@ impl ContainerResource { Ok(IResource::new(handle, self.client.clone())) } + /// Adds a volume + pub fn with_volume(&self, target: &str, name: Option<&str>, is_read_only: Option) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("resource".to_string(), self.handle.to_json()); + args.insert("target".to_string(), serde_json::to_value(&target).unwrap_or(Value::Null)); + if let Some(ref v) = name { + args.insert("name".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + if let Some(ref v) = is_read_only { + args.insert("isReadOnly".to_string(), serde_json::to_value(v).unwrap_or(Value::Null)); + } + let result = self.client.invoke_capability("Aspire.Hosting/withVolume", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ContainerResource::new(handle, self.client.clone())) + } + /// Gets the resource name pub fn get_resource_name(&self) -> Result> { let mut args: HashMap = HashMap::new(); @@ -4945,6 +5144,46 @@ impl ExecutableResource { Ok(IResource::new(handle, self.client.clone())) } + /// Publishes the executable as a Docker container + pub fn publish_as_docker_file(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/publishAsDockerFile", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ExecutableResource::new(handle, self.client.clone())) + } + + /// Publishes an executable as a Docker file with optional container configuration + pub fn publish_as_docker_file_with_configure(&self, configure: impl Fn(Vec) -> Value + Send + Sync + 'static) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let callback_id = register_callback(configure); + args.insert("configure".to_string(), Value::String(callback_id)); + let result = self.client.invoke_capability("Aspire.Hosting/publishAsDockerFileWithConfigure", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ExecutableResource::new(handle, self.client.clone())) + } + + /// Sets the executable command + pub fn with_executable_command(&self, command: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("command".to_string(), serde_json::to_value(&command).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withExecutableCommand", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ExecutableResource::new(handle, self.client.clone())) + } + + /// Sets the executable working directory + pub fn with_working_directory(&self, working_directory: &str) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("workingDirectory".to_string(), serde_json::to_value(&working_directory).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withWorkingDirectory", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ExecutableResource::new(handle, self.client.clone())) + } + /// Configures an MCP server endpoint on the resource pub fn with_mcp_server(&self, path: Option<&str>, endpoint_name: Option<&str>) -> Result> { let mut args: HashMap = HashMap::new(); @@ -7832,6 +8071,36 @@ impl ProjectResource { Ok(IResourceWithEnvironment::new(handle, self.client.clone())) } + /// Sets the number of replicas + pub fn with_replicas(&self, replicas: f64) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + args.insert("replicas".to_string(), serde_json::to_value(&replicas).unwrap_or(Value::Null)); + let result = self.client.invoke_capability("Aspire.Hosting/withReplicas", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ProjectResource::new(handle, self.client.clone())) + } + + /// Disables forwarded headers for the project + pub fn disable_forwarded_headers(&self) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let result = self.client.invoke_capability("Aspire.Hosting/disableForwardedHeaders", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ProjectResource::new(handle, self.client.clone())) + } + + /// Publishes a project as a Docker file with optional container configuration + pub fn publish_as_docker_file(&self, configure: impl Fn(Vec) -> Value + Send + Sync + 'static) -> Result> { + let mut args: HashMap = HashMap::new(); + args.insert("builder".to_string(), self.handle.to_json()); + let callback_id = register_callback(configure); + args.insert("configure".to_string(), Value::String(callback_id)); + let result = self.client.invoke_capability("Aspire.Hosting/publishProjectAsDockerFileWithConfigure", args)?; + let handle: Handle = serde_json::from_value(result)?; + Ok(ProjectResource::new(handle, self.client.clone())) + } + /// Adds a required command dependency pub fn with_required_command(&self, command: &str, help_link: Option<&str>) -> Result> { let mut args: HashMap = HashMap::new(); diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj index 8f8f276a0f7..6193224150a 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj @@ -7,6 +7,7 @@ + diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs index 015fa7d28f2..699c8d26459 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/AtsTypeScriptCodeGeneratorTests.cs @@ -1343,4 +1343,63 @@ private static int CountOccurrences(string text, string pattern) } return count; } + + // ===== JavaScript Assembly Expansion Tests ===== + + [Fact] + public void Scanner_WithNpm_ExpandsToAllJavaScriptResourceTypes() + { + // Verify that withNpm (constrained to JavaScriptAppResource) expands to all three + // concrete JS resource types: JavaScriptAppResource, NodeAppResource, ViteAppResource. + // This is a regression test for capability ID expansion where concrete types + // were not registered under their own type ID in the compatibility map. + var hostingAssembly = typeof(DistributedApplication).Assembly; + var jsAssembly = typeof(Aspire.Hosting.JavaScript.JavaScriptAppResource).Assembly; + + var result = AtsCapabilityScanner.ScanAssemblies([hostingAssembly, jsAssembly]); + + var withNpm = result.Capabilities + .FirstOrDefault(c => c.CapabilityId == "Aspire.Hosting.JavaScript/withNpm"); + Assert.NotNull(withNpm); + + var expandedTypeIds = withNpm.ExpandedTargetTypes.Select(t => t.TypeId).ToList(); + + // All three JS resource types should be present + var javaScriptAppTypeId = AtsTypeMapping.DeriveTypeId(typeof(Aspire.Hosting.JavaScript.JavaScriptAppResource)); + var nodeAppTypeId = AtsTypeMapping.DeriveTypeId(typeof(Aspire.Hosting.JavaScript.NodeAppResource)); + var viteAppTypeId = AtsTypeMapping.DeriveTypeId(typeof(Aspire.Hosting.JavaScript.ViteAppResource)); + + Assert.Contains(javaScriptAppTypeId, expandedTypeIds); + Assert.Contains(nodeAppTypeId, expandedTypeIds); + Assert.Contains(viteAppTypeId, expandedTypeIds); + } + + [Theory] + [InlineData("withNpm")] + [InlineData("withBun")] + [InlineData("withYarn")] + [InlineData("withPnpm")] + public void Scanner_PackageManagerMethods_ExpandToAllJavaScriptResourceTypes(string methodName) + { + // Verify all package manager methods expand to the known JS resource types. + // Assert the minimum expected set rather than an exact count so the test + // remains valid when new JavaScriptAppResource-derived types are added. + var hostingAssembly = typeof(DistributedApplication).Assembly; + var jsAssembly = typeof(Aspire.Hosting.JavaScript.JavaScriptAppResource).Assembly; + + var result = AtsCapabilityScanner.ScanAssemblies([hostingAssembly, jsAssembly]); + + var capability = result.Capabilities + .FirstOrDefault(c => c.CapabilityId == $"Aspire.Hosting.JavaScript/{methodName}"); + Assert.NotNull(capability); + + var expandedTypeIds = capability.ExpandedTargetTypes.Select(t => t.TypeId).ToList(); + Assert.True(expandedTypeIds.Count >= 3, $"Expected at least 3 expanded types but found {expandedTypeIds.Count}"); + Assert.Contains(expandedTypeIds, + id => id.Contains(nameof(JavaScript.JavaScriptAppResource), StringComparison.Ordinal) + && !id.Contains("NodeApp", StringComparison.Ordinal) + && !id.Contains("ViteApp", StringComparison.Ordinal)); + Assert.Contains(expandedTypeIds, id => id.Contains(nameof(JavaScript.NodeAppResource), StringComparison.Ordinal)); + Assert.Contains(expandedTypeIds, id => id.Contains(nameof(JavaScript.ViteAppResource), StringComparison.Ordinal)); + } } diff --git a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts index c563cdcd06a..7370a025c12 100644 --- a/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts +++ b/tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Snapshots/TwoPassScanningGeneratedAspire.verified.ts @@ -4024,6 +4024,239 @@ export class ContainerResource extends ResourceBuilderBase { + const rpcArgs: Record = { builder: this._handle, source, target }; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBindMount', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withBindMountInternal(source, target, isReadOnly)); + } + + /** @internal */ + private async _withEntrypointInternal(entrypoint: string): Promise { + const rpcArgs: Record = { builder: this._handle, entrypoint }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEntrypoint', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEntrypointInternal(entrypoint)); + } + + /** @internal */ + private async _withImageTagInternal(tag: string): Promise { + const rpcArgs: Record = { builder: this._handle, tag }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageTag', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageTagInternal(tag)); + } + + /** @internal */ + private async _withImageRegistryInternal(registry: string): Promise { + const rpcArgs: Record = { builder: this._handle, registry }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageRegistry', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageRegistryInternal(registry)); + } + + /** @internal */ + private async _withImageInternal(image: string, tag?: string): Promise { + const rpcArgs: Record = { builder: this._handle, image }; + if (tag !== undefined) rpcArgs.tag = tag; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImage', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + const tag = options?.tag; + return new ContainerResourcePromise(this._withImageInternal(image, tag)); + } + + /** @internal */ + private async _withImageSHA256Internal(sha256: string): Promise { + const rpcArgs: Record = { builder: this._handle, sha256 }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImageSHA256', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the image SHA256 digest */ + withImageSHA256(sha256: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImageSHA256Internal(sha256)); + } + + /** @internal */ + private async _withContainerRuntimeArgsInternal(args: string[]): Promise { + const rpcArgs: Record = { builder: this._handle, args }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerRuntimeArgs', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerRuntimeArgsInternal(args)); + } + + /** @internal */ + private async _withLifetimeInternal(lifetime: ContainerLifetime): Promise { + const rpcArgs: Record = { builder: this._handle, lifetime }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withLifetime', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._withLifetimeInternal(lifetime)); + } + + /** @internal */ + private async _withImagePullPolicyInternal(pullPolicy: ImagePullPolicy): Promise { + const rpcArgs: Record = { builder: this._handle, pullPolicy }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withImagePullPolicy', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._withImagePullPolicyInternal(pullPolicy)); + } + + /** @internal */ + private async _publishAsContainerInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/publishAsContainer', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures the resource to be published as a container */ + publishAsContainer(): ContainerResourcePromise { + return new ContainerResourcePromise(this._publishAsContainerInternal()); + } + + /** @internal */ + private async _withDockerfileInternal(contextPath: string, dockerfilePath?: string, stage?: string): Promise { + const rpcArgs: Record = { builder: this._handle, contextPath }; + if (dockerfilePath !== undefined) rpcArgs.dockerfilePath = dockerfilePath; + if (stage !== undefined) rpcArgs.stage = stage; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withDockerfile', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures the resource to use a Dockerfile */ + withDockerfile(contextPath: string, options?: WithDockerfileOptions): ContainerResourcePromise { + const dockerfilePath = options?.dockerfilePath; + const stage = options?.stage; + return new ContainerResourcePromise(this._withDockerfileInternal(contextPath, dockerfilePath, stage)); + } + + /** @internal */ + private async _withContainerNameInternal(name: string): Promise { + const rpcArgs: Record = { builder: this._handle, name }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerName', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNameInternal(name)); + } + + /** @internal */ + private async _withBuildArgInternal(name: string, value: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBuildArg', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a build argument from a parameter resource */ + withBuildArg(name: string, value: ParameterResource): ContainerResourcePromise { + return new ContainerResourcePromise(this._withBuildArgInternal(name, value)); + } + + /** @internal */ + private async _withBuildSecretInternal(name: string, value: ParameterResource): Promise { + const rpcArgs: Record = { builder: this._handle, name, value }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withBuildSecret', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a build secret from a parameter resource */ + withBuildSecret(name: string, value: ParameterResource): ContainerResourcePromise { + return new ContainerResourcePromise(this._withBuildSecretInternal(name, value)); + } + + /** @internal */ + private async _withEndpointProxySupportInternal(proxyEnabled: boolean): Promise { + const rpcArgs: Record = { builder: this._handle, proxyEnabled }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withEndpointProxySupport', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Configures endpoint proxy support */ + withEndpointProxySupport(proxyEnabled: boolean): ContainerResourcePromise { + return new ContainerResourcePromise(this._withEndpointProxySupportInternal(proxyEnabled)); + } + /** @internal */ private async _withDockerfileBaseImageInternal(buildImage?: string, runtimeImage?: string): Promise { const rpcArgs: Record = { builder: this._handle }; @@ -4043,6 +4276,21 @@ export class ContainerResource extends ResourceBuilderBase { + const rpcArgs: Record = { builder: this._handle, alias }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withContainerNetworkAlias', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a network alias for the container */ + withContainerNetworkAlias(alias: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._withContainerNetworkAliasInternal(alias)); + } + /** @internal */ private async _withMcpServerInternal(path?: string, endpointName?: string): Promise { const rpcArgs: Record = { builder: this._handle }; @@ -4092,6 +4340,21 @@ export class ContainerResource extends ResourceBuilderBase { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/publishAsConnectionString', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Publishes the resource as a connection string */ + publishAsConnectionString(): ContainerResourcePromise { + return new ContainerResourcePromise(this._publishAsConnectionStringInternal()); + } + /** @internal */ private async _withRequiredCommandInternal(command: string, helpLink?: string): Promise { const rpcArgs: Record = { builder: this._handle, command }; @@ -5022,6 +5285,25 @@ export class ContainerResource extends ResourceBuilderBase { + const rpcArgs: Record = { resource: this._handle, target }; + if (name !== undefined) rpcArgs.name = name; + if (isReadOnly !== undefined) rpcArgs.isReadOnly = isReadOnly; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withVolume', + rpcArgs + ); + return new ContainerResource(result, this._client); + } + + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + const name = options?.name; + const isReadOnly = options?.isReadOnly; + return new ContainerResourcePromise(this._withVolumeInternal(target, name, isReadOnly)); + } + /** Gets the resource name */ async getResourceName(): Promise { const rpcArgs: Record = { resource: this._handle }; @@ -5303,11 +5585,91 @@ export class ContainerResourcePromise implements PromiseLike return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRegistry(registry))); } + /** Adds a bind mount */ + withBindMount(source: string, target: string, options?: WithBindMountOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBindMount(source, target, options))); + } + + /** Sets the container entrypoint */ + withEntrypoint(entrypoint: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEntrypoint(entrypoint))); + } + + /** Sets the container image tag */ + withImageTag(tag: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageTag(tag))); + } + + /** Sets the container image registry */ + withImageRegistry(registry: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageRegistry(registry))); + } + + /** Sets the container image */ + withImage(image: string, options?: WithImageOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImage(image, options))); + } + + /** Sets the image SHA256 digest */ + withImageSHA256(sha256: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImageSHA256(sha256))); + } + + /** Adds runtime arguments for the container */ + withContainerRuntimeArgs(args: string[]): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerRuntimeArgs(args))); + } + + /** Sets the lifetime behavior of the container resource */ + withLifetime(lifetime: ContainerLifetime): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withLifetime(lifetime))); + } + + /** Sets the container image pull policy */ + withImagePullPolicy(pullPolicy: ImagePullPolicy): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withImagePullPolicy(pullPolicy))); + } + + /** Configures the resource to be published as a container */ + publishAsContainer(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.publishAsContainer())); + } + + /** Configures the resource to use a Dockerfile */ + withDockerfile(contextPath: string, options?: WithDockerfileOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withDockerfile(contextPath, options))); + } + + /** Sets the container name */ + withContainerName(name: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerName(name))); + } + + /** Adds a build argument from a parameter resource */ + withBuildArg(name: string, value: ParameterResource): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBuildArg(name, value))); + } + + /** Adds a build secret from a parameter resource */ + withBuildSecret(name: string, value: ParameterResource): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withBuildSecret(name, value))); + } + + /** Configures endpoint proxy support */ + withEndpointProxySupport(proxyEnabled: boolean): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withEndpointProxySupport(proxyEnabled))); + } + /** Sets the base image for a Dockerfile build */ withDockerfileBaseImage(options?: WithDockerfileBaseImageOptions): ContainerResourcePromise { return new ContainerResourcePromise(this._promise.then(obj => obj.withDockerfileBaseImage(options))); } + /** Adds a network alias for the container */ + withContainerNetworkAlias(alias: string): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withContainerNetworkAlias(alias))); + } + /** Configures an MCP server endpoint on the resource */ withMcpServer(options?: WithMcpServerOptions): ContainerResourcePromise { return new ContainerResourcePromise(this._promise.then(obj => obj.withMcpServer(options))); @@ -5323,6 +5685,11 @@ export class ContainerResourcePromise implements PromiseLike return new ContainerResourcePromise(this._promise.then(obj => obj.withOtlpExporterProtocol(protocol))); } + /** Publishes the resource as a connection string */ + publishAsConnectionString(): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.publishAsConnectionString())); + } + /** Adds a required command dependency */ withRequiredCommand(command: string, options?: WithRequiredCommandOptions): ContainerResourcePromise { return new ContainerResourcePromise(this._promise.then(obj => obj.withRequiredCommand(command, options))); @@ -5588,6 +5955,11 @@ export class ContainerResourcePromise implements PromiseLike return new ContainerResourcePromise(this._promise.then(obj => obj.withPipelineConfiguration(callback))); } + /** Adds a volume */ + withVolume(target: string, options?: WithVolumeOptions): ContainerResourcePromise { + return new ContainerResourcePromise(this._promise.then(obj => obj.withVolume(target, options))); + } + /** Gets the resource name */ getResourceName(): Promise { return this._promise.then(obj => obj.getResourceName()); @@ -9345,6 +9717,71 @@ export class ExecutableResource extends ResourceBuilderBase { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/publishAsDockerFile', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Publishes the executable as a Docker container */ + publishAsDockerFile(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._publishAsDockerFileInternal()); + } + + /** @internal */ + private async _publishAsDockerFileWithConfigureInternal(configure: (obj: ContainerResource) => Promise): Promise { + const configureId = registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ContainerResourceHandle; + const obj = new ContainerResource(objHandle, this._client); + await configure(obj); + }); + const rpcArgs: Record = { builder: this._handle, configure: configureId }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/publishAsDockerFileWithConfigure', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Publishes an executable as a Docker file with optional container configuration */ + publishAsDockerFileWithConfigure(configure: (obj: ContainerResource) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._publishAsDockerFileWithConfigureInternal(configure)); + } + + /** @internal */ + private async _withExecutableCommandInternal(command: string): Promise { + const rpcArgs: Record = { builder: this._handle, command }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withExecutableCommand', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withExecutableCommandInternal(command)); + } + + /** @internal */ + private async _withWorkingDirectoryInternal(workingDirectory: string): Promise { + const rpcArgs: Record = { builder: this._handle, workingDirectory }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withWorkingDirectory', + rpcArgs + ); + return new ExecutableResource(result, this._client); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._withWorkingDirectoryInternal(workingDirectory)); + } + /** @internal */ private async _withMcpServerInternal(path?: string, endpointName?: string): Promise { const rpcArgs: Record = { builder: this._handle }; @@ -10610,6 +11047,26 @@ export class ExecutableResourcePromise implements PromiseLike obj.withDockerfileBaseImage(options))); } + /** Publishes the executable as a Docker container */ + publishAsDockerFile(): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.publishAsDockerFile())); + } + + /** Publishes an executable as a Docker file with optional container configuration */ + publishAsDockerFileWithConfigure(configure: (obj: ContainerResource) => Promise): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.publishAsDockerFileWithConfigure(configure))); + } + + /** Sets the executable command */ + withExecutableCommand(command: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withExecutableCommand(command))); + } + + /** Sets the executable working directory */ + withWorkingDirectory(workingDirectory: string): ExecutableResourcePromise { + return new ExecutableResourcePromise(this._promise.then(obj => obj.withWorkingDirectory(workingDirectory))); + } + /** Configures an MCP server endpoint on the resource */ withMcpServer(options?: WithMcpServerOptions): ExecutableResourcePromise { return new ExecutableResourcePromise(this._promise.then(obj => obj.withMcpServer(options))); @@ -12626,6 +13083,58 @@ export class ProjectResource extends ResourceBuilderBase return new ProjectResourcePromise(this._withOtlpExporterProtocolInternal(protocol)); } + /** @internal */ + private async _withReplicasInternal(replicas: number): Promise { + const rpcArgs: Record = { builder: this._handle, replicas }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/withReplicas', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._withReplicasInternal(replicas)); + } + + /** @internal */ + private async _disableForwardedHeadersInternal(): Promise { + const rpcArgs: Record = { builder: this._handle }; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/disableForwardedHeaders', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Disables forwarded headers for the project */ + disableForwardedHeaders(): ProjectResourcePromise { + return new ProjectResourcePromise(this._disableForwardedHeadersInternal()); + } + + /** @internal */ + private async _publishAsDockerFileInternal(configure?: (obj: ContainerResource) => Promise): Promise { + const configureId = configure ? registerCallback(async (objData: unknown) => { + const objHandle = wrapIfHandle(objData) as ContainerResourceHandle; + const obj = new ContainerResource(objHandle, this._client); + await configure(obj); + }) : undefined; + const rpcArgs: Record = { builder: this._handle }; + if (configure !== undefined) rpcArgs.configure = configureId; + const result = await this._client.invokeCapability( + 'Aspire.Hosting/publishProjectAsDockerFileWithConfigure', + rpcArgs + ); + return new ProjectResource(result, this._client); + } + + /** Publishes a project as a Docker file with optional container configuration */ + publishAsDockerFile(options?: PublishAsDockerFileOptions): ProjectResourcePromise { + const configure = options?.configure; + return new ProjectResourcePromise(this._publishAsDockerFileInternal(configure)); + } + /** @internal */ private async _withRequiredCommandInternal(command: string, helpLink?: string): Promise { const rpcArgs: Record = { builder: this._handle, command }; @@ -13872,6 +14381,21 @@ export class ProjectResourcePromise implements PromiseLike { return new ProjectResourcePromise(this._promise.then(obj => obj.withOtlpExporterProtocol(protocol))); } + /** Sets the number of replicas */ + withReplicas(replicas: number): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.withReplicas(replicas))); + } + + /** Disables forwarded headers for the project */ + disableForwardedHeaders(): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.disableForwardedHeaders())); + } + + /** Publishes a project as a Docker file with optional container configuration */ + publishAsDockerFile(options?: PublishAsDockerFileOptions): ProjectResourcePromise { + return new ProjectResourcePromise(this._promise.then(obj => obj.publishAsDockerFile(options))); + } + /** Adds a required command dependency */ withRequiredCommand(command: string, options?: WithRequiredCommandOptions): ProjectResourcePromise { return new ProjectResourcePromise(this._promise.then(obj => obj.withRequiredCommand(command, options)));