Skip to content

[release/17.0] Fix Radius container image exports for TypeScript - #22014

Closed
Mitch Denny (mitchdenny) wants to merge 1 commit into
mitchdenny-backport-17-0-16-pr21881from
mitchdenny-backport-17-0-17-pr21830
Closed

Mitch Denny (mitchdenny) wants to merge 1 commit into
mitchdenny-backport-17-0-16-pr21881from
mitchdenny-backport-17-0-17-pr21830

Conversation

@mitchdenny

Copy link
Copy Markdown
Member

Description

Backport of #21830 to release/17.0 (cherry-picked from 399e3e6 with no modifications). Layer 17 of 55 in the release/17.0 backport stack; stacked on #22013.

Backport recommendation: Yes — Restores missing withContainerImage in TypeScript AppHosts.

Backport of #21830

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

## Description

Restores Radius's `withContainerImage(image)` method on
`DotnetProjectResource` in generated TypeScript AppHosts. Overlapping
legacy and generic exports previously caused a collision on
`CSharpAppResource` that removed the generic capability for every
target, including modern .NET projects.

Export the generic overload once using the existing
`Aspire.Hosting.Radius/withContainerImage` capability ID, and exclude
the legacy overload from ATS discovery. Both public C# overloads and
scanner collision policy remain unchanged. Add real-assembly
generation/scanning and runtime-dispatch regressions for legacy
projects, file-based apps, and modern .NET projects. No new external
package dependencies are required.

Fixes #21803

### User-facing usage

With the Radius and Dotnet integrations referenced, TypeScript AppHosts
can again use:

```typescript
await builder.addDotnetProject("api", "../Api/Api.csproj")
    .withContainerImage("ghcr.io/myorg/api:v1");
```

The corresponding C# API is unchanged:

```csharp
builder.AddDotnetProject("api", "../Api/Api.csproj")
       .WithContainerImage("ghcr.io/myorg/api:v1");
```

### Compatibility

The retained capability now targets and returns `IDotnetProgramResource`
in ATS metadata, while generated methods preserve each resource's
concrete fluent return type. A scoped compatibility suppression records
that intentional metadata generalization; generated release baselines
are untouched.

The separate earlier-preview
`Aspire.Hosting.Radius/withDotnetProgramContainerImage` capability ID is
retired. SDKs generated against that preview ID must be regenerated.

### Validation

Reproduced the missing method with Aspire CLI/SDK 13.6.4 and the
integration versions from the issue. Strict TypeScript compilation
failed for the modern resource before the fix and passed against the
patched generated SDK.

The following commands passed on macOS ARM64 with Podman selected.
Quarantined and outerloop tests were excluded. No live Radius deployment
was run.

```bash
export ASPIRE_CONTAINER_RUNTIME=podman MSBUILDTERMINALLOGGER=false

# Passed: 4 tests.
./dotnet.sh test --project tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests.csproj --no-launch-profile -- --filter-method '*.Generate_RadiusWithContainerImage_*' --filter-method '*.Generate_LegacyAddProject_RetainsDeprecatedBuilderMethod' --filter-method '*.Generate_DotnetProjectOptions_UsesDtoWithoutChangingLegacyOptions' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true'

# Passed: 4 tests.
./dotnet.sh test --project tests/Aspire.Hosting.RemoteHost.Tests/Aspire.Hosting.RemoteHost.Tests.csproj --no-launch-profile -- --filter-method '*.Invoke_RadiusWithContainerImage_*' --filter-method '*.ScanAssembly_TargetSpecificMethodShadowsGenericExpandedMethodOnlyForThatTarget' --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true'

# Passed: 665 tests.
./dotnet.sh test --project tests/Aspire.Hosting.Radius.Tests/Aspire.Hosting.Radius.Tests.csproj --no-launch-profile -- --filter-not-trait 'quarantined=true' --filter-not-trait 'outerloop=true'
```

The patched generated SDK also passed the following command from an
isolated TypeScript AppHost containing concrete and promise-chain calls
for all three resource types:

```bash
node node_modules/typescript/bin/tsc --noEmit --module nodenext --target es2022 --strict --types node smoke.mts
```

Fresh ATS compatibility validation passed with exactly one declared
return-type-change suppression and no undeclared breaks. Evaluated
test-selection traces reach both new regression consumers from Radius
production changes and select the compatibility job for the suppression
file.

## Checklist

- Is this feature complete?
  - [x] Yes. Ready to ship.
  - [ ] No. Follow-up changes expected.
- Are you including unit tests for the changes and scenario tests if
relevant?
  - [x] Yes
  - [ ] No
- Did you add public API?
  - [ ] Yes
    - If yes, did you have an API Review for it?
      - [ ] Yes
      - [ ] No
- Did you add `<remarks />` and `<code />` elements on your triple slash
comments?
      - [ ] Yes
      - [ ] No
  - [x] No
- Does the change make any security assumptions or guarantees?
  - [ ] Yes
    - If yes, have you done a threat model and had a security review?
      - [ ] Yes
      - [ ] No
  - [x] No

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
(cherry picked from commit 399e3e6)
@github-actions

This comment has been minimized.

@mitchdenny
Mitch Denny (mitchdenny) marked this pull request as ready for review November 10, 2026 04:31
@mitchdenny

Copy link
Copy Markdown
Member Author

Approved for inclusion in release/17.0. Do not merge yet.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 22014

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 22014"

@github-actions

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants