Skip to content

Commit e9c53d2

Browse files
authored
Put DeployCommand behind a feature flag (#10613)
1 parent 5542c40 commit e9c53d2

File tree

5 files changed

+53
-26
lines changed

5 files changed

+53
-26
lines changed

src/Aspire.Cli/Commands/RootCommand.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,13 @@ public RootCommand(
8888
Subcommands.Add(addCommand);
8989
Subcommands.Add(publishCommand);
9090
Subcommands.Add(configCommand);
91-
Subcommands.Add(deployCommand);
91+
92+
// Only add the deploy command if the feature flag is enabled
93+
if (featureFlags.IsFeatureEnabled(KnownFeatures.DeployCommandEnabled, defaultValue: false))
94+
{
95+
Subcommands.Add(deployCommand);
96+
}
97+
9298
Subcommands.Add(execCommand);
9399
}
94100
}

src/Aspire.Cli/KnownFeatures.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ internal static class KnownFeatures
99
public static string FeaturePrefix => "features";
1010
public static string UpdateNotificationsEnabled => "updateNotificationsEnabled";
1111
public static string MinimumSdkCheckEnabled => "minimumSdkCheckEnabled";
12+
public static string DeployCommandEnabled => "deployCommandEnabled";
1213
}

tests/Aspire.Cli.Tests/Commands/ConfigCommandTests.cs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public async Task ConfigSetCommand_WithDeepDotNotation_CreatesDeeplyNestedObject
9393
var json = await File.ReadAllTextAsync(settingsPath);
9494
var settings = JsonNode.Parse(json)?.AsObject();
9595
Assert.NotNull(settings);
96-
96+
9797
Assert.True(settings["foo"] is JsonObject);
9898
var fooObject = settings["foo"]!.AsObject();
9999
Assert.True(fooObject["bar"] is JsonObject);
@@ -109,7 +109,7 @@ public async Task ConfigSetCommand_ReplacesPrimitiveWithObject()
109109
var provider = services.BuildServiceProvider();
110110

111111
var command = provider.GetRequiredService<Aspire.Cli.Commands.RootCommand>();
112-
112+
113113
// First set a primitive value
114114
var result1 = command.Parse("config set foo primitive");
115115
var exitCode1 = await result1.InvokeAsync().WaitAsync(CliTestConstants.DefaultTimeout);
@@ -125,7 +125,7 @@ public async Task ConfigSetCommand_ReplacesPrimitiveWithObject()
125125
var json = await File.ReadAllTextAsync(settingsPath);
126126
var settings = JsonNode.Parse(json)?.AsObject();
127127
Assert.NotNull(settings);
128-
128+
129129
Assert.True(settings["foo"] is JsonObject);
130130
var fooObject = settings["foo"]!.AsObject();
131131
Assert.Equal("nested", fooObject["bar"]?.ToString());
@@ -245,7 +245,7 @@ public async Task ConfigDeleteCommand_CleansUpEmptyParentObjects()
245245
var json = await File.ReadAllTextAsync(settingsPath);
246246
var settings = JsonNode.Parse(json)?.AsObject();
247247
Assert.NotNull(settings);
248-
248+
249249
// The deep object should be completely removed since it became empty
250250
Assert.False(settings.ContainsKey("deep"));
251251
}
@@ -341,18 +341,4 @@ public async Task FeatureFlags_WhenSetToInvalidValue_ReturnsFalse()
341341
var featureFlags = provider.GetRequiredService<IFeatures>();
342342
Assert.False(featureFlags.IsFeatureEnabled("testFeature", defaultValue: true));
343343
}
344-
345-
[Fact]
346-
public void DeployCommand_IsAlwaysAvailable()
347-
{
348-
using var workspace = TemporaryWorkspace.Create(outputHelper);
349-
var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper);
350-
var provider = services.BuildServiceProvider();
351-
352-
var rootCommand = provider.GetRequiredService<Aspire.Cli.Commands.RootCommand>();
353-
354-
// Check that deploy command is always available
355-
var hasDeployCommand = rootCommand.Subcommands.Any(cmd => cmd.Name == "deploy");
356-
Assert.True(hasDeployCommand);
357-
}
358-
}
344+
}

tests/Aspire.Cli.Tests/Commands/DeployCommandTests.cs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public async Task DeployCommandWithHelpArgumentReturnsZero()
1818
{
1919
using var tempRepo = TemporaryWorkspace.Create(outputHelper);
2020

21-
var services = CliTestHelper.CreateServiceCollection(tempRepo, outputHelper);
21+
var services = CliTestHelper.CreateServiceCollection(tempRepo, outputHelper, options => options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled]);
2222
var provider = services.BuildServiceProvider();
2323

2424
var command = provider.GetRequiredService<RootCommand>();
@@ -36,6 +36,7 @@ public async Task DeployCommandFailsWithInvalidProjectFile()
3636
// Arrange
3737
var services = CliTestHelper.CreateServiceCollection(tempRepo, outputHelper, options =>
3838
{
39+
options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled];
3940
options.DotNetCliRunnerFactory = (sp) =>
4041
{
4142
var runner = new TestDotNetCliRunner
@@ -69,7 +70,7 @@ public async Task DeployCommandFailsWhenAppHostIsNotCompatible()
6970
var services = CliTestHelper.CreateServiceCollection(tempRepo, outputHelper, options =>
7071
{
7172
options.ProjectLocatorFactory = (sp) => new TestProjectLocator();
72-
73+
options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled];
7374
options.DotNetCliRunnerFactory = (sp) =>
7475
{
7576
var runner = new TestDotNetCliRunner
@@ -103,7 +104,7 @@ public async Task DeployCommandFailsWhenAppHostBuildFails()
103104
var services = CliTestHelper.CreateServiceCollection(tempRepo, outputHelper, options =>
104105
{
105106
options.ProjectLocatorFactory = (sp) => new TestProjectLocator();
106-
107+
options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled];
107108
options.DotNetCliRunnerFactory = (sp) =>
108109
{
109110
var runner = new TestDotNetCliRunner
@@ -137,7 +138,7 @@ public async Task DeployCommandSucceedsEndToEnd()
137138
var services = CliTestHelper.CreateServiceCollection(tempRepo, outputHelper, options =>
138139
{
139140
options.ProjectLocatorFactory = (sp) => new TestProjectLocator();
140-
141+
options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled];
141142
options.DotNetCliRunnerFactory = (sp) =>
142143
{
143144
var runner = new TestDotNetCliRunner
@@ -201,7 +202,7 @@ public async Task DeployCommandIncludesDeployFlagInArguments()
201202
var services = CliTestHelper.CreateServiceCollection(tempRepo, outputHelper, options =>
202203
{
203204
options.ProjectLocatorFactory = (sp) => new TestProjectLocator();
204-
205+
options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled];
205206
options.DotNetCliRunnerFactory = (sp) =>
206207
{
207208
var runner = new TestDotNetCliRunner
@@ -257,6 +258,38 @@ public async Task DeployCommandIncludesDeployFlagInArguments()
257258
// Assert
258259
Assert.Equal(0, exitCode);
259260
}
261+
262+
[Fact]
263+
public void DeployCommand_WhenFeatureFlagDisabled_IsNotAvailable()
264+
{
265+
using var workspace = TemporaryWorkspace.Create(outputHelper);
266+
var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper);
267+
var provider = services.BuildServiceProvider();
268+
269+
var command = provider.GetRequiredService<RootCommand>();
270+
271+
// Check that the deploy command is not available in the subcommands
272+
var deployCommand = command.Subcommands.FirstOrDefault(c => c.Name == "deploy");
273+
Assert.Null(deployCommand);
274+
}
275+
276+
[Fact]
277+
public void DeployCommand_WhenFeatureFlagEnabled_IsAvailable()
278+
{
279+
using var workspace = TemporaryWorkspace.Create(outputHelper);
280+
var services = CliTestHelper.CreateServiceCollection(
281+
workspace,
282+
outputHelper,
283+
options => options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled]
284+
);
285+
var provider = services.BuildServiceProvider();
286+
287+
var command = provider.GetRequiredService<RootCommand>();
288+
289+
// Check that the deploy command is available in the subcommands
290+
var deployCommand = command.Subcommands.FirstOrDefault(c => c.Name == "deploy");
291+
Assert.NotNull(deployCommand);
292+
}
260293
}
261294

262295
internal sealed class TestDeployCommandPrompter(IInteractionService interactionService) : PublishCommandPrompter(interactionService)

tests/Aspire.Cli.Tests/Commands/SdkInstallerTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public async Task DeployCommand_WhenSdkNotInstalled_ReturnsCorrectExitCode()
9797
using var workspace = TemporaryWorkspace.Create(outputHelper);
9898
var services = CliTestHelper.CreateServiceCollection(workspace, outputHelper, options =>
9999
{
100+
options.EnabledFeatures = [KnownFeatures.DeployCommandEnabled];
100101
options.DotNetSdkInstallerFactory = _ => new TestDotNetSdkInstaller
101102
{
102103
CheckAsyncCallback = _ => false // SDK not installed
@@ -153,4 +154,4 @@ public async Task RunCommand_WhenSdkInstalled_ContinuesNormalExecution()
153154
// Should fail at project location, not SDK check
154155
Assert.Equal(ExitCodeConstants.FailedToFindProject, exitCode);
155156
}
156-
}
157+
}

0 commit comments

Comments
 (0)