Skip to content

Remove the dotnetSdkInstallationEnabled feature flag#14811

Merged
davidfowl merged 1 commit intorelease/13.2from
copilot/remove-dotnet-sdk-feature-flag
Mar 1, 2026
Merged

Remove the dotnetSdkInstallationEnabled feature flag#14811
davidfowl merged 1 commit intorelease/13.2from
copilot/remove-dotnet-sdk-feature-flag

Conversation

Copy link
Contributor

Copilot AI commented Feb 28, 2026

Description

Users are responsible for acquiring .NET SDK. The CLI still fails fast when the required SDK version is absent, but no longer offers automatic download/installation.

Feature flag removal

  • Removed DotNetSdkInstallationEnabled from KnownFeatures.cs and both VS Code extension schemas

SDK installer simplification

  • IDotNetSdkInstaller: removed InstallAsync; CheckAsync returns (Success, HighestDetectedVersion, MinimumRequiredVersion) — dropped ForceInstall
  • DotNetSdkInstaller: removed InstallAsync, all install helpers, forceInstall/alwaysInstallSdk logic, private SDK dir check, unused constructor params (executionContext, dotNetCliRunner, logger)
  • SdkInstallHelper.EnsureSdkInstalledAsync: removed features and hostEnvironment params; now just checks and displays error on failure
  • SdkInstallResult / SdkCheckResult: pruned to AlreadyInstalled / NotInstalled

Runtime behavior

  • Removed DOTNET_ROLL_FORWARD=LatestMajor injection from DotNetCliRunner (only needed to support auto-installed SDKs)

Deleted files

  • src/Aspire.Cli/Resources/dotnet-install.sh
  • src/Aspire.Cli/Resources/dotnet-install.ps1
  • .github/workflows/update-dotnet-install-scripts.yml

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
  • Does the change require an update in our Aspire docs?

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • centralus-2.in.applicationinsights.azure.com
    • Triggering command: /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests --internal-msbuild-node /home/REDACTED/.local/share/fbbd10cf7c5c45b9a1742c769b8bd30c/.p --filter-not-trait category=failing --filter-not-trait quarantined=true --filter-not-trait outerloop=true (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.deps.json /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Microsoft.DotNet.RemoteExecutor.dll Aspire.Cli.Tests, Version=42.42.42.42, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 Aspire.Cli.Tests.CliSmokeTests&#43;&lt;&gt;c &lt;LocaleOverrideReturnsExitCode&gt;b__4_0 /tmp/bfvrwdhr.gc1 invalid-locale False ASPIRE_LOCALE_OVERRIDE (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.deps.json /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Microsoft.DotNet.RemoteExecutor.dll Aspire.Cli.Tests, Version=42.42.42.42, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 Aspire.Cli.Tests.CliSmokeTests&#43;&lt;&gt;c &lt;LocaleOverrideReturnsExitCode&gt;b__4_0 /tmp/bfvrwdhr.gc1 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Remove the dotnetSdkInstallationEnabled feature flag</issue_title>
<issue_description>We've decided that the user is responsible to acquiring .NET for C# based apphosts.</issue_description>

<agent_instructions>Users are responsible for acquiring .NET for C# apphosts. The CLI still fails fast when the required SDK version is absent, but no longer offers automatic download and installation.

Changes

Feature flag removal

  • Removed DotNetSdkInstallationEnabled from KnownFeatures.cs and both VS Code extension schemas

SDK installer simplification

  • IDotNetSdkInstaller: removed InstallAsync; CheckAsync now returns (Success, HighestDetectedVersion, MinimumRequiredVersion) (dropped ForceInstall)
  • DotNetSdkInstaller: removed InstallAsync, all install helpers, forceInstall/alwaysInstallSdk logic, private SDK dir check, and unused constructor params (executionContext, dotNetCliRunner, logger)
  • SdkInstallHelper.EnsureSdkInstalledAsync: removed features and hostEnvironment params; now just checks availability and displays an error on failure
  • SdkInstallResult / SdkCheckResult: pruned to AlreadyInstalled / NotInstalled only

Runtime behavior

  • Removed DOTNET_ROLL_FORWARD=LatestMajor injection from DotNetCliRunner (was needed only to support auto-installed SDKs)

Deleted files

  • src/Aspire.Cli/Resources/dotnet-install.sh
  • src/Aspire.Cli/Resources/dotnet-install.ps1
  • .github/workflows/update-dotnet-install-scripts.yml

Tests: updated TestDotNetSdkInstaller, SdkInstallHelperTests, DotNetSdkInstallerTests, and SdkInstallerTests to reflect the simplified interface.

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
  • Does the change require an update in our Aspire docs?

[!WARNING]

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • centralus-2.in.applicationinsights.azure.com
    • Triggering command: /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests --internal-msbuild-node /home/REDACTED/.local/share/b99a89f36da842919f541adcd0c83ae7/.p --filter-not-trait category=failing --filter-not-trait quarantined=true --filter-not-trait outerloop=true (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.deps.json /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Microsoft.DotNet.RemoteExecutor.dll Aspire.Cli.Tests, Version=42.42.42.42, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 Aspire.Cli.Tests.CliSmokeTests&#43;&lt;&gt;c &lt;LocaleOverrideReturnsExitCode&gt;b__4_0 /tmp/v5ndm0io.1e4 invalid-locale False ASPIRE_LOCALE_OVERRIDE (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Aspire.Cli.Tests.deps.json /home/REDACTED/work/aspire/aspire/artifacts/bin/Aspire.Cli.Tests/Debug/net10.0/Microsoft.DotNet.RemoteExecutor.dll Aspire.Cli.Tests, Version=42.42.42.42, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 Aspire.Cli.Tests.CliSmokeTests&#43;&lt;&gt;c &lt;LocaleOverrideReturnsExitCode&gt;b__4_0 /tmp/v5ndm0io.1e4 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

  • Configure Actions setup steps to set up my environment, which run before the firewall is enabled
  • Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent s...

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Remove the dotnetSdkInstallationEnabled feature flag Remove the dotnetSdkInstallationEnabled feature flag Feb 28, 2026
@davidfowl davidfowl marked this pull request as ready for review February 28, 2026 19:31
Copilot AI review requested due to automatic review settings February 28, 2026 19:31
@github-actions
Copy link
Contributor

github-actions bot commented Feb 28, 2026

🚀 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/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14811

Or

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the CLI’s automatic .NET SDK installation capability (and its feature flag), simplifying the SDK “installer” into a pure availability check while keeping the CLI fail-fast behavior when the required SDK isn’t present.

Changes:

  • Removed DotNetSdkInstallationEnabled feature flag (CLI + VS Code extension schemas) and deleted embedded dotnet-install scripts/workflow.
  • Simplified IDotNetSdkInstaller/DotNetSdkInstaller to only check for SDK availability (no install path).
  • Updated call sites and tests to reflect the new check-only behavior and telemetry outcomes.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/Aspire.Cli.Tests/Utils/SdkInstallHelperTests.cs Updates tests for check-only flow and revised telemetry tags.
tests/Aspire.Cli.Tests/TestServices/TestDotNetSdkInstaller.cs Updates test stub to the new CheckAsync tuple signature.
tests/Aspire.Cli.Tests/Templating/DotNetTemplateFactoryTests.cs Adjusts template tests for updated CheckAsync return shape.
tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs Removes install-script expectations and updates checks to new tuple signature.
tests/Aspire.Cli.Tests/Commands/SdkInstallerTests.cs Updates command tests to use the new CheckAsync tuple signature.
src/Aspire.Cli/Utils/SdkInstallResult.cs Prunes enum values to reflect check-only outcomes.
src/Aspire.Cli/Utils/SdkInstallHelper.cs Removes install UX; now only checks and displays an error on failure.
src/Aspire.Cli/Utils/SdkCheckResult.cs Prunes enum values to reflect check-only outcomes.
src/Aspire.Cli/Utils/EnvironmentChecker/DotNetSdkCheck.cs Updates to the new CheckAsync tuple signature.
src/Aspire.Cli/Templating/DotNetTemplateFactory.cs Calls the simplified EnsureSdkInstalledAsync signature.
src/Aspire.Cli/Resources/dotnet-install.sh Deleted (no longer embedding installer scripts).
src/Aspire.Cli/Resources/dotnet-install.ps1 Deleted (no longer embedding installer scripts).
src/Aspire.Cli/Projects/DotNetAppHostProject.cs Updates SDK check calls prior to run/publish.
src/Aspire.Cli/NuGet/NuGetPackagePrefetcher.cs Updates to the new CheckAsync tuple signature.
src/Aspire.Cli/KnownFeatures.cs Removes the dotnetSdkInstallationEnabled feature definition/metadata.
src/Aspire.Cli/DotNet/IDotNetSdkInstaller.cs Removes install API; CheckAsync now returns a 3-tuple.
src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs Deletes installation logic and simplifies constructor/dependencies.
src/Aspire.Cli/DotNet/DotNetCliRunner.cs Removes DOTNET_ROLL_FORWARD=LatestMajor injection tied to auto-install.
src/Aspire.Cli/Commands/InitCommand.cs Updates SDK check call site for new helper signature.
src/Aspire.Cli/Commands/ExecCommand.cs Updates SDK check call site for new helper signature.
src/Aspire.Cli/Commands/AddCommand.cs Updates SDK check call site for new helper signature.
src/Aspire.Cli/Aspire.Cli.csproj Removes embedded resource entries for installer scripts.
extension/schemas/aspire-settings.schema.json Removes dotnetSdkInstallationEnabled setting.
extension/schemas/aspire-global-settings.schema.json Removes dotnetSdkInstallationEnabled setting.
.github/workflows/update-dotnet-install-scripts.yml Deleted (no longer maintaining embedded scripts).
Comments suppressed due to low confidence (2)

tests/Aspire.Cli.Tests/Utils/SdkInstallHelperTests.cs:92

  • The test EnsureSdkInstalledAsync_WhenSdkMissing_DisplaysError no longer asserts that an error was actually displayed; it only checks telemetry tags. This makes the test name/intent misleading and leaves the user-facing error path unverified.

Set interactionService.DisplayErrorCallback to capture the message and assert it contains the minimum required version and the detected version.

    public async Task EnsureSdkInstalledAsync_WhenSdkMissing_DisplaysError()
    {
        using var fixture = new TelemetryFixture();

        var sdkInstaller = new TestDotNetSdkInstaller
        {
            CheckAsyncCallback = _ => (false, "8.0.100", "9.0.302")
        };

        var interactionService = new TestConsoleInteractionService();

        var result = await SdkInstallHelper.EnsureSdkInstalledAsync(
            sdkInstaller,
            interactionService,
            fixture.Telemetry);

        Assert.False(result);
        Assert.NotNull(fixture.CapturedActivity);

        var tags = fixture.CapturedActivity.Tags.ToDictionary(t => t.Key, t => t.Value);
        Assert.Equal("8.0.100", tags[TelemetryConstants.Tags.SdkDetectedVersion]);
        Assert.Equal("9.0.302", tags[TelemetryConstants.Tags.SdkMinimumRequiredVersion]);
        Assert.Equal("not_installed", tags[TelemetryConstants.Tags.SdkCheckResult]);
        Assert.Equal("not_installed", tags[TelemetryConstants.Tags.SdkInstallResult]);
    }

src/Aspire.Cli/Utils/SdkInstallResult.cs:19

  • SdkInstallResult is now documented as an “availability check”, but the type name still implies an installation result. With installation removed, this mismatch is easy to misread when maintaining telemetry/tagging code.

Consider renaming the enum to reflect the new behavior (or at least clarify in the XML doc that the name is retained for historical/telemetry reasons).

/// <summary>
/// Result of an SDK availability check.
/// </summary>
internal enum SdkInstallResult
{
    /// <summary>
    /// A valid SDK was already installed.
    /// </summary>
    AlreadyInstalled,

    /// <summary>
    /// The SDK is missing or does not meet the minimum required version.
    /// </summary>
    NotInstalled

@github-actions
Copy link
Contributor

github-actions bot commented Feb 28, 2026

🎬 CLI E2E Test Recordings

The following terminal recordings are available for commit 2144011:

Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AgentInitCommand_WithMalformedMcpJson_ShowsErrorAndExitsNonZero ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateEmptyAppHostProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateStartWaitAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ▶️ View Recording
StopNonInteractiveMultipleAppHostsShowsError ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording

📹 Recordings uploaded automatically from CI run #22538430952

@davidfowl davidfowl requested a review from JamesNK March 1, 2026 00:04
@davidfowl
Copy link
Contributor

This looks like an issue with JSON formatting:

Hex1b.Automation.WaitUntilTimeoutException : WaitUntil timed out after 00:08:20 waiting for: snapshot =>
            {
                var successPromptSearcher = new CellPatternSearcher()
                    .FindPattern(counter.Value.ToString())
                    .RightText(" OK] $ ");

                var result = successPromptSearcher.Search(snapshot);
                return result.Count > 0;
            }
  at Hex1bTestHelpers.cs:92
Terminal (160x48, cursor at 13,5, normal screen):
[10 OK] $ aspire run --detach --format json > output.json                                                                                                       
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: createdump                                                                            
\ud83d\udd0d Finding apphosts...                                                                                                                                          
❌ An unexpected error occurred: The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true.    
LineNumber: 0 | BytePositionInLine: 0.                                                                                                                          
[11 ERR:1] $                                                                                                                                                    
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                   at Hex1b.Automation.WaitUntilStep.ExecuteAsync(Hex1bTerminal terminal, Hex1bTerminalInputSequenceOptions options, CancellationToken ct) in /home/runner/work/hex1b/hex1b/src/Hex1b/Automation/WaitUntilStep.cs:line 39
   at Hex1b.Automation.Hex1bTerminalInputSequence.ApplyAsync(Hex1bTerminal terminal, CancellationToken ct) in /home/runner/work/hex1b/hex1b/src/Hex1b/Automation/Hex1bTerminalInputSequence.cs:line 41
   at Aspire.Cli.EndToEnd.Tests.MultipleAppHostTests.DetachFormatJsonProducesValidJson() in /_/tests/Aspire.Cli.EndToEnd.Tests/MultipleAppHostTests.cs:line 128
--- End of stack trace from previous location ---

### StdOut
Temporary workspace created at: /tmp/Aspire.Cli.Tests/TemporaryWorkspaces/d122d61b-905d-4f83-b8a9-26328c152456

… logic

- Remove the dotnetSdkInstallationEnabled feature flag from KnownFeatures
- Remove SDK auto-install prompting logic from SdkInstallHelper
- Simplify EnsureSdkInstalledAsync to only check and report SDK availability
- Remove unused fields from ExecCommand and InitCommand
- Consolidate duplicate SdkCheckResult/SdkInstallResult enums into SdkCheckResult
- Remove duplicate SdkInstallResult telemetry tag
- Update tests accordingly

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl davidfowl force-pushed the copilot/remove-dotnet-sdk-feature-flag branch from ab6ba2a to 2144011 Compare March 1, 2026 07:19
@JamesNK
Copy link
Member

JamesNK commented Mar 1, 2026

This looks like an issue with JSON formatting:

Hex1b.Automation.WaitUntilTimeoutException : WaitUntil timed out after 00:08:20 waiting for: snapshot =>
            {
                var successPromptSearcher = new CellPatternSearcher()
                    .FindPattern(counter.Value.ToString())
                    .RightText(" OK] $ ");

                var result = successPromptSearcher.Search(snapshot);
                return result.Count > 0;
            }
  at Hex1bTestHelpers.cs:92
Terminal (160x48, cursor at 13,5, normal screen):
[10 OK] $ aspire run --detach --format json > output.json                                                                                                       
DOTNET_DbgEnableMiniDump is set and the createdump binary does not exist: createdump                                                                            
\ud83d\udd0d Finding apphosts...                                                                                                                                          
❌ An unexpected error occurred: The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true.    
LineNumber: 0 | BytePositionInLine: 0.                                                                                                                          
[11 ERR:1] $                                                                                                                                                    
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                
                                                                                                                                                                   at Hex1b.Automation.WaitUntilStep.ExecuteAsync(Hex1bTerminal terminal, Hex1bTerminalInputSequenceOptions options, CancellationToken ct) in /home/runner/work/hex1b/hex1b/src/Hex1b/Automation/WaitUntilStep.cs:line 39
   at Hex1b.Automation.Hex1bTerminalInputSequence.ApplyAsync(Hex1bTerminal terminal, CancellationToken ct) in /home/runner/work/hex1b/hex1b/src/Hex1b/Automation/Hex1bTerminalInputSequence.cs:line 41
   at Aspire.Cli.EndToEnd.Tests.MultipleAppHostTests.DetachFormatJsonProducesValidJson() in /_/tests/Aspire.Cli.EndToEnd.Tests/MultipleAppHostTests.cs:line 128
--- End of stack trace from previous location ---

### StdOut
Temporary workspace created at: /tmp/Aspire.Cli.Tests/TemporaryWorkspaces/d122d61b-905d-4f83-b8a9-26328c152456

What was the fix?

@davidfowl
Copy link
Contributor

I re-ran it, which means there's a hidden bug with how we're setting the output

@davidfowl
Copy link
Contributor

Filed this #14819

@davidfowl davidfowl merged commit 67de873 into release/13.2 Mar 1, 2026
681 of 685 checks passed
@davidfowl davidfowl deleted the copilot/remove-dotnet-sdk-feature-flag branch March 1, 2026 09:00
@dotnet-policy-service dotnet-policy-service bot added this to the 13.2 milestone Mar 1, 2026
davidfowl added a commit that referenced this pull request Mar 1, 2026
PR #14811 removed ForceInstall from IDotNetSdkInstaller.CheckAsync, changing from 4-element to 3-element tuple.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
davidfowl added a commit that referenced this pull request Mar 4, 2026
* Add project reference support for polyglot apphost integrations

Allow .aspire/settings.json packages entries to reference local .csproj files instead of NuGet versions. When a value ends in '.csproj', it's treated as a project reference: PrebuiltAppHostServer publishes it via dotnet publish and copies the full transitive DLL closure into the integration libs path. DotNetBasedAppHostServerProject adds ProjectReference elements to the generated csproj.

Introduces IntegrationReference record type to represent both NuGet packages and project references, replacing the (Name, Version) tuple throughout IAppHostServerProject.PrepareAsync and related APIs.

Fixes #14760

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove GetAllPackages, migrate tests to GetIntegrationReferences

Remove the now-unused GetAllPackages methods from AspireJsonConfiguration. Update tests to use GetIntegrationReferences instead. Add test for project reference detection (.csproj paths).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use single dotnet publish for PrebuiltAppHostServer integration resolution

Replace the two-step approach (BundleNuGetService restore + per-project publish) with a single synthetic .csproj that includes all PackageReferences and ProjectReferences, then dotnet publish once to get the full transitive DLL closure. Remove BundleNuGetService dependency from PrebuiltAppHostServer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Only use dotnet publish when project references are present

Restore BundleNuGetService for the NuGet-only path (no SDK required). Only use dotnet publish with a synthetic project when project references are present in settings.json (requires .NET SDK).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use dotnet build with CopyLocalLockFileAssemblies instead of publish

Build the synthetic integration project with OutDir pointing directly to the libs path, eliminating the need for dotnet publish and the extra copy step. Remove PublishProjectAsync from IDotNetCliRunner.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add SDK check for project refs and isolate from parent MSBuild imports

Check SDK availability before building project references and provide a clear error message if missing. Write Directory.Packages.props (CPM opt-out), Directory.Build.props, and Directory.Build.targets to the synthetic project directory to prevent parent MSBuild imports from interfering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove DotNetBasedAppHostServerProject casts from SDK commands

SdkGenerateCommand and SdkDumpCommand now use IAppHostServerProject.PrepareAsync instead of casting to DotNetBasedAppHostServerProject and calling CreateProjectFilesAsync/BuildAsync directly. This means they work in both dev mode and bundle mode with project references.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use CLI version for SDK commands, let project deps resolve transitively

SDK commands no longer reference DotNetBasedAppHostServerProject.DefaultSdkVersion. The codegen package uses VersionHelper.GetDefaultTemplateVersion() (CLI version), and Aspire.Hosting comes transitively from the integration project reference.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add unit tests for IntegrationReference and synthetic project generation

Tests cover IntegrationReference type properties, AspireJsonConfiguration.GetIntegrationReferences detection of .csproj paths, and PrebuiltAppHostServer.GenerateIntegrationProjectFile output (PackageReference, ProjectReference, OutDir, CopyLocalLockFileAssemblies, analyzer suppression).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add E2E test for project reference integration support

Tests the full flow: create a .NET hosting integration with [AspireExport], create a TypeScript AppHost, add the integration as a project reference in settings.json, start the AppHost, and verify the custom addMyService method appears in the generated TypeScript SDK.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Simplify E2E test: use ExecuteCallback for file creation

Replace multiline cat heredocs with C# ExecuteCallback to write the integration project files and update settings.json. Reads sdkVersion from the settings.json that aspire init creates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review feedback

- Null-safe value handling in GetIntegrationReferences (trim, null check before .csproj detection)
- Clean stale libs directory before project ref build to prevent leftover DLLs
- Use XDocument for synthetic project generation instead of string interpolation (XML-safe)
- Filter SDK-only packages from ATS assembly list in DotNetBasedAppHostServerProject
- Restore xmldoc param comments on PrebuiltAppHostServer constructor

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use using directive for System.Xml.Linq

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Improve project reference E2E test with describe/wait verification

Update apphost.ts to use the custom integration (addMyService), then verify with aspire wait and aspire describe that the resource actually runs. Reduce timeouts to be more reasonable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: use redis image instead of nonexistent myservice

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: correct project reference path and force codegen regeneration

The MyIntegration directory is inside the workspace (./MyIntegration not ../MyIntegration). Also delete .modules/ before aspire start to force re-codegen with the new integration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix: write nuget.config with channel sources for project ref builds

NuGetConfigMerger.CreateOrUpdateAsync is a no-op for implicit/hive channels. Instead, use GetNuGetSourcesAsync to get the actual feed URLs and write a nuget.config directly into the synthetic project directory. This ensures dotnet build can resolve Aspire packages from hive feeds in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CheckAsync tuple deconstruction after release/13.2 rebase

PR #14811 removed ForceInstall from IDotNetSdkInstaller.CheckAsync, changing from 4-element to 3-element tuple.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add build output logging for integration project failures

Capture and log stdout/stderr from dotnet build when the synthetic integration project fails, to help diagnose CI failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Dump child log on E2E test failure for CI debugging

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix: use RestoreConfigFile to ensure project references resolve from channel feeds

When the synthetic project has ProjectReferences, MSBuild restores the referenced project's packages from nuget.config nearest to that project's directory — not the synthetic project's directory. Add RestoreConfigFile to the synthetic .csproj so all projects in the build graph use our channel-aware nuget.config.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: write nuget.config in workspace for project reference resolution

MyIntegration.csproj needs to resolve Aspire.Hosting from the hive during dotnet build. MSBuild walks up from the project directory looking for nuget.config — without one in the workspace, it defaults to nuget.org which doesn't have prerelease versions. Write a nuget.config with hive sources in the workspace root.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address JamesNK review feedback

- Add IntegrationReference validation via factory methods (FromPackage/FromProject)
  ensuring exactly one of Version or ProjectPath is set
- Rename GetAllPackagesAsync to GetIntegrationReferencesAsync
- Add explicit null check for Version instead of null-forgiving operator
- Use DotNetBasedAppHostServerProject.TargetFramework constant instead of
  hardcoded "net10.0" in PrebuiltAppHostServer
- Replace RestoreConfigFile with RestoreAdditionalProjectSources MSBuild property
  to add channel sources without replacing the user's NuGet config
- Remove nuget.config generation with <clear/> and unconditional nuget.org addition
- Stop copying/overwriting user nuget.config (RestoreAdditionalProjectSources
  makes this unnecessary)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use RestoreAdditionalProjectSources in DotNetBasedAppHostServerProject

Align with PrebuiltAppHostServer: replace NuGetConfigMerger with RestoreAdditionalProjectSources for channel source resolution. This is additive and propagates to the entire restore graph including project references. Update test to verify csproj contains the correct sources instead of checking nuget.config.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address JamesNK and sebastienros review feedback

- IntegrationReference: change from record to class (JamesNK)
- Rename 'packages' locals to 'integrations' where assigned from GetIntegrationReferencesAsync (JamesNK)
- Call GetNuGetSourcesAsync unconditionally in BuildIntegrationProjectAsync (sebastienros)
- Always regenerate codegen when project references are present by including timestamp in hash (sebastienros)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Resolve project ref assembly names from MSBuild build output

Add a custom MSBuild target to the synthetic project that writes resolved project reference assembly names to a file after build. Use these actual assembly names (which may differ from settings.json key or csproj filename if <AssemblyName> is overridden) for the AtsAssemblies list in appsettings.json. Move GenerateAppSettingsAsync to after build/restore in all cases for a simpler linear flow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI added a commit that referenced this pull request Mar 10, 2026
… logic (#14811)

- Remove the dotnetSdkInstallationEnabled feature flag from KnownFeatures
- Remove SDK auto-install prompting logic from SdkInstallHelper
- Simplify EnsureSdkInstalledAsync to only check and report SDK availability
- Remove unused fields from ExecCommand and InitCommand
- Consolidate duplicate SdkCheckResult/SdkInstallResult enums into SdkCheckResult
- Remove duplicate SdkInstallResult telemetry tag
- Update tests accordingly

Co-authored-by: David Fowler <davidfowl@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI pushed a commit that referenced this pull request Mar 10, 2026
* Add project reference support for polyglot apphost integrations

Allow .aspire/settings.json packages entries to reference local .csproj files instead of NuGet versions. When a value ends in '.csproj', it's treated as a project reference: PrebuiltAppHostServer publishes it via dotnet publish and copies the full transitive DLL closure into the integration libs path. DotNetBasedAppHostServerProject adds ProjectReference elements to the generated csproj.

Introduces IntegrationReference record type to represent both NuGet packages and project references, replacing the (Name, Version) tuple throughout IAppHostServerProject.PrepareAsync and related APIs.

Fixes #14760

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove GetAllPackages, migrate tests to GetIntegrationReferences

Remove the now-unused GetAllPackages methods from AspireJsonConfiguration. Update tests to use GetIntegrationReferences instead. Add test for project reference detection (.csproj paths).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use single dotnet publish for PrebuiltAppHostServer integration resolution

Replace the two-step approach (BundleNuGetService restore + per-project publish) with a single synthetic .csproj that includes all PackageReferences and ProjectReferences, then dotnet publish once to get the full transitive DLL closure. Remove BundleNuGetService dependency from PrebuiltAppHostServer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Only use dotnet publish when project references are present

Restore BundleNuGetService for the NuGet-only path (no SDK required). Only use dotnet publish with a synthetic project when project references are present in settings.json (requires .NET SDK).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use dotnet build with CopyLocalLockFileAssemblies instead of publish

Build the synthetic integration project with OutDir pointing directly to the libs path, eliminating the need for dotnet publish and the extra copy step. Remove PublishProjectAsync from IDotNetCliRunner.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add SDK check for project refs and isolate from parent MSBuild imports

Check SDK availability before building project references and provide a clear error message if missing. Write Directory.Packages.props (CPM opt-out), Directory.Build.props, and Directory.Build.targets to the synthetic project directory to prevent parent MSBuild imports from interfering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove DotNetBasedAppHostServerProject casts from SDK commands

SdkGenerateCommand and SdkDumpCommand now use IAppHostServerProject.PrepareAsync instead of casting to DotNetBasedAppHostServerProject and calling CreateProjectFilesAsync/BuildAsync directly. This means they work in both dev mode and bundle mode with project references.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use CLI version for SDK commands, let project deps resolve transitively

SDK commands no longer reference DotNetBasedAppHostServerProject.DefaultSdkVersion. The codegen package uses VersionHelper.GetDefaultTemplateVersion() (CLI version), and Aspire.Hosting comes transitively from the integration project reference.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add unit tests for IntegrationReference and synthetic project generation

Tests cover IntegrationReference type properties, AspireJsonConfiguration.GetIntegrationReferences detection of .csproj paths, and PrebuiltAppHostServer.GenerateIntegrationProjectFile output (PackageReference, ProjectReference, OutDir, CopyLocalLockFileAssemblies, analyzer suppression).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add E2E test for project reference integration support

Tests the full flow: create a .NET hosting integration with [AspireExport], create a TypeScript AppHost, add the integration as a project reference in settings.json, start the AppHost, and verify the custom addMyService method appears in the generated TypeScript SDK.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Simplify E2E test: use ExecuteCallback for file creation

Replace multiline cat heredocs with C# ExecuteCallback to write the integration project files and update settings.json. Reads sdkVersion from the settings.json that aspire init creates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review feedback

- Null-safe value handling in GetIntegrationReferences (trim, null check before .csproj detection)
- Clean stale libs directory before project ref build to prevent leftover DLLs
- Use XDocument for synthetic project generation instead of string interpolation (XML-safe)
- Filter SDK-only packages from ATS assembly list in DotNetBasedAppHostServerProject
- Restore xmldoc param comments on PrebuiltAppHostServer constructor

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use using directive for System.Xml.Linq

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Improve project reference E2E test with describe/wait verification

Update apphost.ts to use the custom integration (addMyService), then verify with aspire wait and aspire describe that the resource actually runs. Reduce timeouts to be more reasonable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: use redis image instead of nonexistent myservice

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: correct project reference path and force codegen regeneration

The MyIntegration directory is inside the workspace (./MyIntegration not ../MyIntegration). Also delete .modules/ before aspire start to force re-codegen with the new integration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix: write nuget.config with channel sources for project ref builds

NuGetConfigMerger.CreateOrUpdateAsync is a no-op for implicit/hive channels. Instead, use GetNuGetSourcesAsync to get the actual feed URLs and write a nuget.config directly into the synthetic project directory. This ensures dotnet build can resolve Aspire packages from hive feeds in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CheckAsync tuple deconstruction after release/13.2 rebase

PR #14811 removed ForceInstall from IDotNetSdkInstaller.CheckAsync, changing from 4-element to 3-element tuple.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add build output logging for integration project failures

Capture and log stdout/stderr from dotnet build when the synthetic integration project fails, to help diagnose CI failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Dump child log on E2E test failure for CI debugging

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix: use RestoreConfigFile to ensure project references resolve from channel feeds

When the synthetic project has ProjectReferences, MSBuild restores the referenced project's packages from nuget.config nearest to that project's directory — not the synthetic project's directory. Add RestoreConfigFile to the synthetic .csproj so all projects in the build graph use our channel-aware nuget.config.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix E2E test: write nuget.config in workspace for project reference resolution

MyIntegration.csproj needs to resolve Aspire.Hosting from the hive during dotnet build. MSBuild walks up from the project directory looking for nuget.config — without one in the workspace, it defaults to nuget.org which doesn't have prerelease versions. Write a nuget.config with hive sources in the workspace root.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address JamesNK review feedback

- Add IntegrationReference validation via factory methods (FromPackage/FromProject)
  ensuring exactly one of Version or ProjectPath is set
- Rename GetAllPackagesAsync to GetIntegrationReferencesAsync
- Add explicit null check for Version instead of null-forgiving operator
- Use DotNetBasedAppHostServerProject.TargetFramework constant instead of
  hardcoded "net10.0" in PrebuiltAppHostServer
- Replace RestoreConfigFile with RestoreAdditionalProjectSources MSBuild property
  to add channel sources without replacing the user's NuGet config
- Remove nuget.config generation with <clear/> and unconditional nuget.org addition
- Stop copying/overwriting user nuget.config (RestoreAdditionalProjectSources
  makes this unnecessary)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use RestoreAdditionalProjectSources in DotNetBasedAppHostServerProject

Align with PrebuiltAppHostServer: replace NuGetConfigMerger with RestoreAdditionalProjectSources for channel source resolution. This is additive and propagates to the entire restore graph including project references. Update test to verify csproj contains the correct sources instead of checking nuget.config.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address JamesNK and sebastienros review feedback

- IntegrationReference: change from record to class (JamesNK)
- Rename 'packages' locals to 'integrations' where assigned from GetIntegrationReferencesAsync (JamesNK)
- Call GetNuGetSourcesAsync unconditionally in BuildIntegrationProjectAsync (sebastienros)
- Always regenerate codegen when project references are present by including timestamp in hash (sebastienros)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Resolve project ref assembly names from MSBuild build output

Add a custom MSBuild target to the synthetic project that writes resolved project reference assembly names to a file after build. Use these actual assembly names (which may differ from settings.json key or csproj filename if <AssemblyName> is overridden) for the AtsAssemblies list in appsettings.json. Move GenerateAppSettingsAsync to after build/restore in all cases for a simpler linear flow.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

4 participants