From 2ea50a0c092a2924bbf4253fe832e2dc2b246557 Mon Sep 17 00:00:00 2001 From: Tomer Heber Date: Tue, 4 Jun 2024 11:03:20 -0500 Subject: [PATCH] Feat: add auto approve field to sub environment configuration --- client/environment.go | 2 ++ client/remote_state_access_test.go | 2 +- client/user_environment_assignment_test.go | 2 +- env0/provider.go | 2 +- env0/resource_environment.go | 29 ++++++++++++++-------- env0/resource_environment_test.go | 4 +++ env0/resource_project_test.go | 4 +-- env0/resource_variable_set.go | 6 ++--- tests/integration/012_environment/main.tf | 5 ++-- 9 files changed, 36 insertions(+), 20 deletions(-) diff --git a/client/environment.go b/client/environment.go index 0f55cf57..5a1dbe3a 100644 --- a/client/environment.go +++ b/client/environment.go @@ -62,6 +62,7 @@ type SubEnvironment struct { Revision string `json:"revision,omitempty"` Workspace string `json:"workspaceName,omitempty"` ConfigurationChanges ConfigurationChanges `json:"configurationChanges"` + UserRequiresApproval bool `json:"userRequiresApproval"` } type DeployRequest struct { @@ -120,6 +121,7 @@ type Environment struct { IsArchived *bool `json:"isArchived" tfschema:"-"` IsRemoteApplyEnabled bool `json:"isRemoteApplyEnabled"` K8sNamespace string `json:"k8s_namespace"` + IsSingleUseBlueprint bool `json:"isSingleUseBlueprint" tfschema:"-"` } type EnvironmentCreate struct { diff --git a/client/remote_state_access_test.go b/client/remote_state_access_test.go index fdb68ab3..60d058f4 100644 --- a/client/remote_state_access_test.go +++ b/client/remote_state_access_test.go @@ -8,7 +8,7 @@ import ( ) var _ = Describe("RemoteStateAccess", func() { - environmentId := "environmnet_id" + environmentId := "environment_id" remoteStateAccess := RemoteStateAccessConfiguration{ EnvironmentId: environmentId, diff --git a/client/user_environment_assignment_test.go b/client/user_environment_assignment_test.go index 2cfb3ce4..dad96381 100644 --- a/client/user_environment_assignment_test.go +++ b/client/user_environment_assignment_test.go @@ -9,7 +9,7 @@ import ( "go.uber.org/mock/gomock" ) -var _ = Describe("User Envrionment Assignment", func() { +var _ = Describe("User Environment Assignment", func() { environmentId := "environmentId" userId := "userId" diff --git a/env0/provider.go b/env0/provider.go index 891d3ff6..bd1b47b1 100644 --- a/env0/provider.go +++ b/env0/provider.go @@ -199,7 +199,7 @@ func configureProvider(version string, p *schema.Provider) schema.ConfigureConte AddRetryAfterErrorCondition(). AddRetryCondition(func(r *resty.Response, err error) bool { if r == nil { - // No response. Possiblly a networking issue (E.g. DNS lookup failure). + // No response. Possibly a networking issue (E.g. DNS lookup failure). tflog.SubsystemWarn(subCtx, "env0_api_client", "No response, retrying request") return true } diff --git a/env0/resource_environment.go b/env0/resource_environment.go index 63efa627..0b73e137 100644 --- a/env0/resource_environment.go +++ b/env0/resource_environment.go @@ -16,12 +16,13 @@ import ( ) type SubEnvironment struct { - Id string - Alias string - Revision string - Workflow string - Workspace string - Configuration client.ConfigurationChanges `tfschema:"-"` + Id string + Alias string + Revision string + Workflow string + Workspace string + Configuration client.ConfigurationChanges `tfschema:"-"` + ApprovePlanAutomatically bool } func getSubEnvironments(d *schema.ResourceData) ([]SubEnvironment, error) { @@ -290,7 +291,7 @@ func resourceEnvironment() *schema.Resource { }, "sub_environment_configuration": { Type: schema.TypeList, - Description: "the subenvironments for a workflow enviornment. Template type must be 'workflow'. Must match the configuration as defined in 'env0.workflow.yml'", + Description: "the subenvironments for a workflow environment. Template type must be 'workflow'. Must match the configuration as defined in 'env0.workflow.yml'", Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -320,6 +321,12 @@ func resourceEnvironment() *schema.Resource { Optional: true, Elem: configurationSchema, }, + "approve_plan_automatically": { + Type: schema.TypeBool, + Description: "when 'true' (default) plans are approved automatically, otherwise ('false') deployment require manual approval", + Optional: true, + Default: true, + }, }, }, }, @@ -399,16 +406,16 @@ func setEnvironmentSchema(ctx context.Context, d *schema.ResourceData, environme var newSubEnvironments []interface{} for i, iSubEnvironment := range iSubEnvironments.([]interface{}) { - subEnviornment := iSubEnvironment.(map[string]interface{}) + subEnvironment := iSubEnvironment.(map[string]interface{}) alias := d.Get(fmt.Sprintf("sub_environment_configuration.%d.alias", i)).(string) workkflowSubEnvironment, ok := environment.LatestDeploymentLog.WorkflowFile.Environments[alias] if ok { - subEnviornment["id"] = workkflowSubEnvironment.EnvironmentId + subEnvironment["id"] = workkflowSubEnvironment.EnvironmentId } - newSubEnvironments = append(newSubEnvironments, subEnviornment) + newSubEnvironments = append(newSubEnvironments, subEnvironment) } d.Set("sub_environment_configuration", newSubEnvironments) @@ -744,6 +751,7 @@ func deploy(d *schema.ResourceData, apiClient client.ApiClientInterface) diag.Di Revision: subEnvironment.Revision, Workspace: subEnvironment.Workspace, ConfigurationChanges: configurationChanges, + UserRequiresApproval: !subEnvironment.ApprovePlanAutomatically, } } } @@ -885,6 +893,7 @@ func getCreatePayload(d *schema.ResourceData, apiClient client.ApiClientInterfac Revision: subEnvironment.Revision, ConfigurationChanges: subEnvironment.Configuration, Workspace: subEnvironment.Workspace, + UserRequiresApproval: !subEnvironment.ApprovePlanAutomatically, } } } diff --git a/env0/resource_environment_test.go b/env0/resource_environment_test.go index d25ddfda..d3b37d6b 100644 --- a/env0/resource_environment_test.go +++ b/env0/resource_environment_test.go @@ -2353,6 +2353,7 @@ func TestUnitEnvironmentWithSubEnvironment(t *testing.T) { } updatedSubEnvironment := subEnvironment + updatedSubEnvironment.ApprovePlanAutomatically = false updatedSubEnvironment.Configuration = append(updatedSubEnvironment.Configuration, client.ConfigurationVariable{ Name: "name2", Value: "value2", @@ -2437,6 +2438,7 @@ func TestUnitEnvironmentWithSubEnvironment(t *testing.T) { Revision: subEnvironment.Revision, Workspace: updatedSubEnvironment.Workspace, ConfigurationChanges: updatedSubEnvironment.Configuration, + UserRequiresApproval: true, }, }, } @@ -2499,6 +2501,7 @@ func TestUnitEnvironmentWithSubEnvironment(t *testing.T) { alias = "%s" revision = "%s" workspace = "%s" + approve_plan_automatically = false configuration { name = "%s" value = "%s" @@ -2530,6 +2533,7 @@ func TestUnitEnvironmentWithSubEnvironment(t *testing.T) { resource.TestCheckResourceAttr(accessor, "sub_environment_configuration.0.alias", updatedSubEnvironment.Alias), resource.TestCheckResourceAttr(accessor, "sub_environment_configuration.0.revision", updatedSubEnvironment.Revision), resource.TestCheckResourceAttr(accessor, "sub_environment_configuration.0.workspace", updatedSubEnvironment.Workspace), + resource.TestCheckResourceAttr(accessor, "sub_environment_configuration.0.approve_plan_automatically", "false"), resource.TestCheckResourceAttr(accessor, "sub_environment_configuration.0.configuration.0.name", updatedSubEnvironment.Configuration[0].Name), resource.TestCheckResourceAttr(accessor, "sub_environment_configuration.0.configuration.0.value", updatedSubEnvironment.Configuration[0].Value), resource.TestCheckResourceAttr(accessor, "sub_environment_configuration.0.configuration.1.name", updatedSubEnvironment.Configuration[1].Name), diff --git a/env0/resource_project_test.go b/env0/resource_project_test.go index 6411495a..a8e503ce 100644 --- a/env0/resource_project_test.go +++ b/env0/resource_project_test.go @@ -170,7 +170,7 @@ func TestUnitProjectResourceDestroyWithEnvironments(t *testing.T) { Name: "name1", } - t.Run("Success With Force Destory", func(t *testing.T) { + t.Run("Success With Force Destroy", func(t *testing.T) { testCase := resource.TestCase{ Steps: []resource.TestStep{ { @@ -199,7 +199,7 @@ func TestUnitProjectResourceDestroyWithEnvironments(t *testing.T) { }) }) - t.Run("Failure Without Force Destory", func(t *testing.T) { + t.Run("Failure Without Force Destroy", func(t *testing.T) { testCase := resource.TestCase{ Steps: []resource.TestStep{ { diff --git a/env0/resource_variable_set.go b/env0/resource_variable_set.go index f706ffe7..9f8722a4 100644 --- a/env0/resource_variable_set.go +++ b/env0/resource_variable_set.go @@ -39,7 +39,7 @@ var variableSetVariableSchema *schema.Resource = &schema.Resource{ }, "is_sensitive": { Type: schema.TypeBool, - Description: "is the value sensitive (defaults to 'false'). Note: 'dropdown' value format cannot be senstive.", + Description: "is the value sensitive (defaults to 'false'). Note: 'dropdown' value format cannot be sensitive.", Optional: true, Default: false, }, @@ -293,7 +293,7 @@ type mergedVariables struct { func mergeVariables(schema []client.ConfigurationVariable, api []client.ConfigurationVariable) *mergedVariables { var res mergedVariables - // To avoid false drifts, keep the order of the 'currentVariables' list similiar to the schema as much as possible. + // To avoid false drifts, keep the order of the 'currentVariables' list similar to the schema as much as possible. for _, svariable := range schema { found := false @@ -301,7 +301,7 @@ func mergeVariables(schema []client.ConfigurationVariable, api []client.Configur if svariable.Name == avariable.Name && *svariable.Type == *avariable.Type { found = true if avariable.IsSensitive != nil && *avariable.IsSensitive { - // Senstive - to avoid drift use the value from the schema + // Sensitive - to avoid drift use the value from the schema avariable.Value = svariable.Value } res.currentVariables = append(res.currentVariables, avariable) diff --git a/tests/integration/012_environment/main.tf b/tests/integration/012_environment/main.tf index 3e3f2a1d..f91dfeb4 100644 --- a/tests/integration/012_environment/main.tf +++ b/tests/integration/012_environment/main.tf @@ -225,8 +225,9 @@ resource "env0_environment" "workflow-environment" { } sub_environment_configuration { - alias = "rootService1" - revision = "master" + alias = "rootService1" + revision = "master" + approve_plan_automatically = var.second_run ? true : false configuration { name = "sub_env1_var1" value = "hello"