diff --git a/src/AWS.Deploy.CLI/ServerMode/Controllers/DeploymentController.cs b/src/AWS.Deploy.CLI/ServerMode/Controllers/DeploymentController.cs index 303524e9..43a94ec0 100644 --- a/src/AWS.Deploy.CLI/ServerMode/Controllers/DeploymentController.cs +++ b/src/AWS.Deploy.CLI/ServerMode/Controllers/DeploymentController.cs @@ -200,7 +200,12 @@ private List ListOptionSettingSummary(IOptionSettingHa foreach (var setting in configurableOptionSettings) { - var settingSummary = new OptionSettingItemSummary(setting.Id, setting.FullyQualifiedId, setting.Name, setting.Description, setting.Type.ToString()) + var settingSummary = new OptionSettingItemSummary( + setting.Id, + setting.FullyQualifiedId, + setting.Name, + setting.Description, + setting.Type.ToString()) { Category = setting.Category, TypeHint = setting.TypeHint?.ToString(), @@ -208,7 +213,11 @@ private List ListOptionSettingSummary(IOptionSettingHa Value = optionSettingHandler.GetOptionSettingValue(recommendation, setting), Advanced = setting.AdvancedSetting, ReadOnly = recommendation.IsExistingCloudApplication && !setting.Updatable, - Visible = optionSettingHandler.IsOptionSettingDisplayable(recommendation, setting), + Visible = + optionSettingHandler.IsOptionSettingDisplayable(recommendation, setting) && + // Updating visibility of settings in server-mode to be determined by 'VisibleOnRedeployment' + // when performing a redeployment and 'Updatable' is set to false. + !(recommendation.IsExistingCloudApplication && !setting.Updatable && !setting.VisibleOnRedeployment), SummaryDisplayable = optionSettingHandler.IsSummaryDisplayable(recommendation, setting), AllowedValues = setting.AllowedValues, ValueMapping = setting.ValueMapping, diff --git a/src/AWS.Deploy.Common/Recipes/OptionSettingItem.cs b/src/AWS.Deploy.Common/Recipes/OptionSettingItem.cs index 14f3ab01..a0f78a96 100644 --- a/src/AWS.Deploy.Common/Recipes/OptionSettingItem.cs +++ b/src/AWS.Deploy.Common/Recipes/OptionSettingItem.cs @@ -124,6 +124,11 @@ public partial class OptionSettingItem : IOptionSettingItem /// public bool Updatable { get; set; } + /// + /// If the value is true, the setting will be displayed during a redeployment. This only applies to server-mode clients. + /// + public bool VisibleOnRedeployment { get; set; } + /// /// List of all validators that should be run when configuring this OptionSettingItem. /// diff --git a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppAppRunner.recipe b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppAppRunner.recipe index 6b993c4d..001346e6 100644 --- a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppAppRunner.recipe +++ b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppAppRunner.recipe @@ -100,6 +100,7 @@ "TypeHint": "AppRunnerService", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DefaultValue": "{StackName}-service", "Validators": [ { @@ -288,6 +289,7 @@ "Type": "String", "AdvancedSetting": true, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", diff --git a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppECSFargate.recipe b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppECSFargate.recipe index 5c23ccc8..4ad11599 100644 --- a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppECSFargate.recipe +++ b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppECSFargate.recipe @@ -118,6 +118,7 @@ "TypeHint": "ECSCluster", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -136,6 +137,7 @@ "TypeHint": "ExistingECSCluster", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -160,6 +162,7 @@ "DefaultValue": "{StackName}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -195,6 +198,7 @@ "DefaultValue": "{StackName}-service", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -304,6 +308,7 @@ "TypeHint": "Vpc", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "IsDefault", @@ -360,6 +365,7 @@ "DefaultValue": "{DefaultVpcId}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -533,6 +539,7 @@ "DefaultValue": null, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -738,7 +745,8 @@ "Type": "Bool", "DefaultValue": true, "AdvancedSetting": false, - "Updatable": false + "Updatable": false, + "VisibleOnRedeployment": true } ] }, diff --git a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkLinux.recipe b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkLinux.recipe index 2b2f89ac..ddc5c626 100644 --- a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkLinux.recipe +++ b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkLinux.recipe @@ -137,6 +137,7 @@ "TypeHint": "BeanstalkApplication", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -155,6 +156,7 @@ "DefaultValue": "{StackName}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "BeanstalkApplication.CreateNew", @@ -187,6 +189,7 @@ "DefaultValue": "{StackName}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "BeanstalkApplication.CreateNew", @@ -215,6 +218,7 @@ "Type": "Object", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "EnvironmentName", @@ -225,6 +229,7 @@ "DefaultValue": "{StackName}-dev", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -342,6 +347,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -363,6 +369,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "ApplicationIAMRole.CreateNew", @@ -393,6 +400,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -414,6 +422,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "ServiceIAMRole.CreateNew", @@ -442,6 +451,7 @@ "DefaultValue": "", "AdvancedSetting": true, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -821,6 +831,7 @@ "DefaultValue": "{DefaultVpcId}", "AdvancedSetting": true, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", diff --git a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkWindows.recipe b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkWindows.recipe index 93f93256..0784dead 100644 --- a/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkWindows.recipe +++ b/src/AWS.Deploy.Recipes/RecipeDefinitions/ASP.NETAppElasticBeanstalkWindows.recipe @@ -137,6 +137,7 @@ "TypeHint": "BeanstalkApplication", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -155,6 +156,7 @@ "DefaultValue": "{StackName}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "BeanstalkApplication.CreateNew", @@ -187,6 +189,7 @@ "DefaultValue": "{StackName}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "BeanstalkApplication.CreateNew", @@ -216,6 +219,7 @@ "DefaultValue": "{StackName}-dev", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -331,6 +335,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -352,6 +357,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "ApplicationIAMRole.CreateNew", @@ -382,6 +388,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -403,6 +410,7 @@ }, "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "DependsOn": [ { "Id": "ServiceIAMRole.CreateNew", @@ -431,6 +439,7 @@ "DefaultValue": "", "AdvancedSetting": true, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -816,6 +825,7 @@ "DefaultValue": "{DefaultVpcId}", "AdvancedSetting": true, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", diff --git a/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateScheduleTask.recipe b/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateScheduleTask.recipe index 33a51c24..f7665903 100644 --- a/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateScheduleTask.recipe +++ b/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateScheduleTask.recipe @@ -136,6 +136,7 @@ "TypeHint": "ECSCluster", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -154,6 +155,7 @@ "TypeHint": "ExistingECSCluster", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -178,6 +180,7 @@ "DefaultValue": "{StackName}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -323,6 +326,7 @@ "DefaultValue": "{DefaultVpcId}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", diff --git a/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateService.recipe b/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateService.recipe index e31c4cb6..fa7026f8 100644 --- a/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateService.recipe +++ b/src/AWS.Deploy.Recipes/RecipeDefinitions/ConsoleAppECSFargateService.recipe @@ -176,6 +176,7 @@ "TypeHint": "ECSCluster", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "CreateNew", @@ -194,6 +195,7 @@ "TypeHint": "ExistingECSCluster", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -218,6 +220,7 @@ "DefaultValue": "{StackName}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -247,6 +250,7 @@ "DefaultValue": "{StackName}-service", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", @@ -336,6 +340,7 @@ "TypeHint": "Vpc", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "ChildOptionSettings": [ { "Id": "IsDefault", @@ -392,6 +397,7 @@ "DefaultValue": "{DefaultVpcId}", "AdvancedSetting": false, "Updatable": false, + "VisibleOnRedeployment": true, "Validators": [ { "ValidatorType": "Regex", diff --git a/src/AWS.Deploy.Recipes/RecipeDefinitions/aws-deploy-recipe-schema.json b/src/AWS.Deploy.Recipes/RecipeDefinitions/aws-deploy-recipe-schema.json index 071a8c6f..99f053e2 100644 --- a/src/AWS.Deploy.Recipes/RecipeDefinitions/aws-deploy-recipe-schema.json +++ b/src/AWS.Deploy.Recipes/RecipeDefinitions/aws-deploy-recipe-schema.json @@ -587,6 +587,12 @@ "description": "If the setting is false the setting can not be changed during redeployment.", "minLength": 1 }, + "VisibleOnRedeployment": { + "type": "boolean", + "title": "VisibleOnRedeployment", + "description": "If the value is true, the setting will be displayed during a redeployment. This only applies to server-mode clients.", + "minLength": 1 + }, "DependsOn": { "type": "array", "title": "", diff --git a/test/AWS.Deploy.CLI.IntegrationTests/ServerModeTests.cs b/test/AWS.Deploy.CLI.IntegrationTests/ServerModeTests.cs index d65eca69..4b9037e1 100644 --- a/test/AWS.Deploy.CLI.IntegrationTests/ServerModeTests.cs +++ b/test/AWS.Deploy.CLI.IntegrationTests/ServerModeTests.cs @@ -190,6 +190,88 @@ public async Task GetRecommendationsWithEncryptedCredentials() } } + [Fact] + public async Task AppRunnerRedeployment_VisibleOnRedeploymentSettings() + { + _stackName = $"ServerModeAppRunner{Guid.NewGuid().ToString().Split('-').Last()}"; + + var projectPath = _testAppManager.GetProjectPath(Path.Combine("testapps", "WebAppWithDockerFile", "WebAppWithDockerFile.csproj")); + var portNumber = 4950; + using var httpClient = ServerModeHttpClientFactory.ConstructHttpClient(ServerModeUtilities.ResolveDefaultCredentials); + + var serverCommand = new ServerModeCommand(_serviceProvider.GetRequiredService(), portNumber, null, true); + var cancelSource = new CancellationTokenSource(); + + var serverTask = serverCommand.ExecuteAsync(cancelSource.Token); + try + { + var baseUrl = $"http://localhost:{portNumber}/"; + var restClient = new RestAPIClient(baseUrl, httpClient); + + await restClient.WaitUntilServerModeReady(); + + var startSessionOutput = await restClient.StartDeploymentSessionAsync(new StartDeploymentSessionInput + { + AwsRegion = _awsRegion, + ProjectPath = projectPath + }); + + var sessionId = startSessionOutput.SessionId; + Assert.NotNull(sessionId); + + var signalRClient = new DeploymentCommunicationClient(baseUrl); + await signalRClient.JoinSession(sessionId); + + var logOutput = new StringBuilder(); + RegisterSignalRMessageCallbacks(signalRClient, logOutput); + + var getRecommendationOutput = await restClient.GetRecommendationsAsync(sessionId); + Assert.NotEmpty(getRecommendationOutput.Recommendations); + + var appRunnerRecommendation = getRecommendationOutput.Recommendations.FirstOrDefault(x => string.Equals(x.RecipeId, "AspNetAppAppRunner")); + Assert.NotNull(appRunnerRecommendation); + + await restClient.SetDeploymentTargetAsync(sessionId, new SetDeploymentTargetInput + { + NewDeploymentName = _stackName, + NewDeploymentRecipeId = appRunnerRecommendation.RecipeId + }); + + await restClient.StartDeploymentAsync(sessionId); + + await restClient.WaitForDeployment(sessionId); + + var stackStatus = await _cloudFormationHelper.GetStackStatus(_stackName); + Assert.Equal(StackStatus.CREATE_COMPLETE, stackStatus); + + Assert.True(logOutput.Length > 0); + + var redeploymentSessionOutput = await restClient.StartDeploymentSessionAsync(new StartDeploymentSessionInput + { + AwsRegion = _awsRegion, + ProjectPath = projectPath + }); + + var redeploymentSessionId = redeploymentSessionOutput.SessionId; + + await restClient.SetDeploymentTargetAsync(redeploymentSessionId, new SetDeploymentTargetInput + { + ExistingDeploymentId = await _cloudFormationHelper.GetStackArn(_stackName) + }); + + var settings = await restClient.GetConfigSettingsAsync(redeploymentSessionId); + + Assert.True(settings.OptionSettings.First(x => x.Id.Equals("ServiceName")).Visible); + Assert.True(settings.OptionSettings.First(x => x.Id.Equals("EncryptionKmsKey")).Visible); + } + finally + { + cancelSource.Cancel(); + await _cloudFormationHelper.DeleteStack(_stackName); + _stackName = null; + } + } + [Fact] public async Task WebFargateDeploymentNoConfigChanges() { diff --git a/version.json b/version.json index 260232ba..cd3e015a 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.21", + "version": "1.22", "publicReleaseRefSpec": [ ".*" ],