Skip to content

Auto-enable staging channel when channel is set to staging#15422

Open
mitchdenny wants to merge 1 commit intomainfrom
staging-channel-auto-enable
Open

Auto-enable staging channel when channel is set to staging#15422
mitchdenny wants to merge 1 commit intomainfrom
staging-channel-auto-enable

Conversation

@mitchdenny
Copy link
Member

Description

Auto-enable the staging channel when channel is configured as "staging", removing the need to also explicitly set features.stagingChannelEnabled: true.

Previously, users had to set both channel: staging and features.stagingChannelEnabled: true for the staging channel to work. If they forgot the feature flag, the staging channel was silently unavailable. Now, setting channel: staging alone is sufficient — the feature flag still works as an independent toggle for cases where the channel isn't set to staging.

Changes

  • Added KnownFeatures.IsStagingChannelEnabled(IFeatures, IConfiguration) static helper that returns true if the feature flag is on OR the configured channel is "staging" (case-insensitive)
  • Updated all 5 staging channel check sites to use the helper: PackagingService, InitCommand, NewCommand, UpdateCommand (2 locations)
  • Added IConfiguration to command constructors where needed (already in DI container)
  • Added 8 unit tests for the helper method
  • Updated E2E StagingChannelTests to verify staging works without the feature flag

Validation

  • Full CLI test suite: 1680/1680 passed
  • New KnownFeaturesTests: 8/8 passed
  • PackagingServiceTests + UpdateCommandTests: 44/44 passed

Fixes # (issue)

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
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

Add KnownFeatures.IsStagingChannelEnabled helper that checks both the
feature flag and the configured channel. The staging channel is now
considered enabled if either features.stagingChannelEnabled is true OR
the channel setting is "staging" (case-insensitive).

This removes the need to explicitly set features.stagingChannelEnabled
when the user already has channel set to staging in their config.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 20, 2026 01:36
@github-actions
Copy link
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/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15422

Or

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

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 improves Aspire CLI staging-channel UX by making the staging channel automatically available whenever the configured channel is set to "staging", eliminating the need for users to also enable features.stagingChannelEnabled.

Changes:

  • Added KnownFeatures.IsStagingChannelEnabled(IFeatures, IConfiguration) to treat staging as enabled when either the feature flag is on or channel == "staging" (case-insensitive).
  • Updated staging checks across CLI commands and packaging channel discovery to use the new helper.
  • Added unit tests for the helper and updated E2E staging-channel coverage to validate behavior without the feature flag.

Reviewed changes

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

Show a summary per file
File Description
src/Aspire.Cli/KnownFeatures.cs Adds helper method that centralizes “staging enabled” logic (flag OR channel==staging).
src/Aspire.Cli/Packaging/PackagingService.cs Uses helper to decide whether to include the staging channel in discovered channels.
src/Aspire.Cli/Commands/InitCommand.cs Switches staging availability checks to helper and injects IConfiguration for evaluation.
src/Aspire.Cli/Commands/NewCommand.cs Switches staging availability checks to helper and injects IConfiguration for evaluation.
src/Aspire.Cli/Commands/UpdateCommand.cs Switches both staging checks to helper and injects/stores IConfiguration.
tests/Aspire.Cli.Tests/Configuration/KnownFeaturesTests.cs Adds unit tests for the helper method behavior.
tests/Aspire.Cli.EndToEnd.Tests/StagingChannelTests.cs Updates E2E flow to verify staging works without explicitly enabling the staging feature flag.

Comment on lines +12 to +19
[Fact]
public void IsStagingChannelEnabled_ReturnsTrue_WhenChannelIsStaging()
{
var features = new TestFeatures(stagingChannelEnabled: false);
var configuration = BuildConfiguration(channel: PackageChannelNames.Staging);

Assert.True(KnownFeatures.IsStagingChannelEnabled(features, configuration));
}
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

The test IsStagingChannelEnabled_ReturnsTrue_WhenChannelIsStaging duplicates IsStagingChannelEnabled_ReturnsTrue_WhenChannelIsStagingAndFlagExplicitlyFalse (same inputs/expectation). Consider removing one or consolidating into a single theory case to keep the suite focused on distinct behaviors.

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +75
[Fact]
public void IsStagingChannelEnabled_IsCaseInsensitive_ForChannelValue()
{
var features = new TestFeatures(stagingChannelEnabled: false);
var configuration = BuildConfiguration(channel: "Staging");

Assert.True(KnownFeatures.IsStagingChannelEnabled(features, configuration));
}

[Fact]
public void IsStagingChannelEnabled_IsCaseInsensitive_ForUppercaseChannelValue()
{
var features = new TestFeatures(stagingChannelEnabled: false);
var configuration = BuildConfiguration(channel: "STAGING");

Assert.True(KnownFeatures.IsStagingChannelEnabled(features, configuration));
}

[Fact]
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

The two case-insensitivity tests ("Staging" and "STAGING") cover the same behavior. Consider using a single [Theory] with multiple InlineData values (or keep one) to reduce duplication while still validating OrdinalIgnoreCase behavior.

Suggested change
[Fact]
public void IsStagingChannelEnabled_IsCaseInsensitive_ForChannelValue()
{
var features = new TestFeatures(stagingChannelEnabled: false);
var configuration = BuildConfiguration(channel: "Staging");
Assert.True(KnownFeatures.IsStagingChannelEnabled(features, configuration));
}
[Fact]
public void IsStagingChannelEnabled_IsCaseInsensitive_ForUppercaseChannelValue()
{
var features = new TestFeatures(stagingChannelEnabled: false);
var configuration = BuildConfiguration(channel: "STAGING");
Assert.True(KnownFeatures.IsStagingChannelEnabled(features, configuration));
}
[Fact]
[Theory]
[InlineData("Staging")]
[InlineData("STAGING")]
public void IsStagingChannelEnabled_IsCaseInsensitive_ForChannelValue(string channel)
{
var features = new TestFeatures(stagingChannelEnabled: false);
var configuration = BuildConfiguration(channel: channel);
Assert.True(KnownFeatures.IsStagingChannelEnabled(features, configuration));
}
[Fact]
public void IsStagingChannelEnabled_ReturnsFalse_WhenChannelIsDailyAndFlagNotSet()
{
var features = new TestFeatures(stagingChannelEnabled: false);
var configuration = BuildConfiguration(channel: PackageChannelNames.Daily);
Assert.False(KnownFeatures.IsStagingChannelEnabled(features, configuration));
}

Copilot uses AI. Check for mistakes.
Comment on lines 36 to 53
@@ -49,7 +47,7 @@ public async Task StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels()
await auto.EnterAsync();
await auto.WaitForSuccessPromptAsync(counter);

// Set channel to staging
// Set channel to staging — this alone enables staging channel behavior
await auto.TypeAsync("aspire config set channel staging -g");
await auto.EnterAsync();
await auto.WaitForSuccessPromptAsync(counter);
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

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

This test is meant to validate staging works without features.stagingChannelEnabled, but it never explicitly ensures the flag is unset/false. To avoid accidental false positives if the default/fixture environment changes, consider deleting the flag (or setting it to false) at the start of the test before setting channel to staging.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Contributor

🎬 CLI E2E Test Recordings — 52 recordings uploaded (commit d49c385)

View recordings
Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CertificatesClean_RemovesCertificates ▶️ View Recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View Recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ 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
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RunWithMissingAwaitShowsHelpfulError ▶️ 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
TypeScriptAppHostWithProjectReferenceIntegration ▶️ View Recording

📹 Recordings uploaded automatically from CI run #23325335320

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