Skip to content

Commit

Permalink
Fix Enum Configuration variables (#135)
Browse files Browse the repository at this point in the history
* fix enum

* can create enum vars

* fixed read and update

* fix data

* examples

* export to function

* docs

* rename

* update integ tests

* fix naming

* :=

* no nil
  • Loading branch information
eranelbaz authored Aug 22, 2021
1 parent 76b0882 commit 013f6ea
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 9 deletions.
1 change: 1 addition & 0 deletions docs/data-sources/configuration_variable.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ output "aws_default_region" {

### Read-Only

- **enum** (List of String) possible values of this variable
- **is_sensitive** (Boolean) is the variable defined as sensitive
- **scope** (String) scope of the variable
- **value** (String) value stored in the variable
Expand Down
9 changes: 9 additions & 0 deletions docs/resources/configuration_variable.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ resource "env0_configuration_variable" "example" {
name = "ENVIRONMENT_VARIABLE_NAME"
value = "example value"
}
resource "env0_configuration_variable" "drop_down" {
name = "ENVIRONMENT_VARIABLE_DROP_DOWN"
value = "first option"
enum = [
"first option",
"second option"
]
}
```

<!-- schema generated by tfplugindocs -->
Expand Down
10 changes: 10 additions & 0 deletions env0/data_configuration_variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ func dataConfigurationVariable() *schema.Resource {
Description: "scope of the variable",
Computed: true,
},
"enum": {
Type: schema.TypeList,
Description: "possible values of this variable",
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
Description: "the configuration variable option",
},
},
},
}
}
Expand Down Expand Up @@ -110,6 +119,7 @@ func dataConfigurationVariableRead(ctx context.Context, d *schema.ResourceData,
d.Set("value", variable.Value)
d.Set("is_sensitive", variable.IsSensitive)
d.Set("scope", variable.Scope)
d.Set("enum", variable.Schema.Enum)
if variable.Type == client.ConfigurationVariableTypeEnvironment {
d.Set("type", "environment")
} else if variable.Type == client.ConfigurationVariableTypeTerraform {
Expand Down
44 changes: 44 additions & 0 deletions env0/data_configuration_variable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,50 @@ func TestUnitConfigurationVariableData(t *testing.T) {
Return([]client.ConfigurationVariable{configurationVariable}, nil)
})
})
t.Run("ScopeGlobal Enum", func(t *testing.T) {

configurationVariable := client.ConfigurationVariable{
Id: "id0",
Name: "name0",
ScopeId: "scope0",
Value: "value0",
OrganizationId: "organization0",
UserId: "user0",
IsSensitive: false,
Scope: client.ScopeEnvironment,
Type: client.ConfigurationVariableTypeEnvironment,
Schema: client.ConfigurationVariableSchema{Type: "string", Enum: []string{"a", "b"}},
}

checkResources := resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "id", configurationVariable.Id),
resource.TestCheckResourceAttr(accessor, "name", configurationVariable.Name),
resource.TestCheckResourceAttr(accessor, "type", "environment"),
resource.TestCheckResourceAttr(accessor, "value", configurationVariable.Value),
resource.TestCheckResourceAttr(accessor, "scope", string(configurationVariable.Scope)),
resource.TestCheckResourceAttr(accessor, "is_sensitive", strconv.FormatBool(configurationVariable.IsSensitive)),
resource.TestCheckResourceAttr(accessor, "enum.0", "a"),
resource.TestCheckResourceAttr(accessor, "enum.1", "b"),
)

runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: dataSourceConfigCreate(resourceType, resourceName, map[string]interface{}{"id": configurationVariable.Id}),
Check: checkResources,
},
{
Config: dataSourceConfigCreate(resourceType, resourceName, map[string]interface{}{"name": configurationVariable.Name}),
Check: checkResources,
},
},
},
func(mock *client.MockApiClientInterface) {
mock.EXPECT().ConfigurationVariables(client.ScopeGlobal, "").AnyTimes().
Return([]client.ConfigurationVariable{configurationVariable}, nil)
})
})

t.Run("ScopeTemplate", func(t *testing.T) {
runUnitTest(t,
Expand Down
39 changes: 31 additions & 8 deletions env0/resource_configuration_variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,12 @@ func resourceConfigurationVariableCreate(ctx context.Context, d *schema.Resource
default:
return diag.Errorf("'type' can only receive either 'environment' or 'terraform': %s", typeAsString)
}
var enumValues []string = nil
if specified, ok := d.GetOk("enum_values"); ok {
enumValues = specified.([]string)
actualEnumValues, getEnumErr := getEnum(d, value)
if getEnumErr != nil {
return getEnumErr
}
configurationVariable, err := apiClient.ConfigurationVariableCreate(name, value, isSensitive, scope, scopeId, type_, enumValues)

configurationVariable, err := apiClient.ConfigurationVariableCreate(name, value, isSensitive, scope, scopeId, type_, actualEnumValues)
if err != nil {
return diag.Errorf("could not create configurationVariable: %v", err)
}
Expand All @@ -130,6 +131,25 @@ func resourceConfigurationVariableCreate(ctx context.Context, d *schema.Resource
return nil
}

func getEnum(d *schema.ResourceData, selectedValue string) ([]string, diag.Diagnostics) {
var enumValues []interface{}
var actualEnumValues []string
if specified, ok := d.GetOk("enum"); ok {
enumValues = specified.([]interface{})
valueExists := false
for _, enumValue := range enumValues {
actualEnumValues = append(actualEnumValues, enumValue.(string))
if enumValue == selectedValue {
valueExists = true
}
}
if !valueExists {
return nil, diag.Errorf("value - '%s' is not one of the enum options %v", selectedValue, actualEnumValues)
}
}
return actualEnumValues, nil
}

func resourceConfigurationVariableRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
apiClient := meta.(client.ApiClientInterface)

Expand All @@ -149,6 +169,9 @@ func resourceConfigurationVariableRead(ctx context.Context, d *schema.ResourceDa
} else {
d.Set("type", "environment")
}
if len(variable.Schema.Enum) > 0 {
d.Set("enum", variable.Schema.Enum)
}
return nil
}
}
Expand All @@ -173,11 +196,11 @@ func resourceConfigurationVariableUpdate(ctx context.Context, d *schema.Resource
default:
return diag.Errorf("'type' can only receive either 'environment' or 'terraform': %s", typeAsString)
}
var enumValues []string = nil
if specified, ok := d.GetOk("enum_values"); ok {
enumValues = specified.([]string)
actualEnumValues, getEnumErr := getEnum(d, value)
if getEnumErr != nil {
return getEnumErr
}
_, err := apiClient.ConfigurationVariableUpdate(id, name, value, isSensitive, scope, scopeId, type_, enumValues)
_, err := apiClient.ConfigurationVariableUpdate(id, name, value, isSensitive, scope, scopeId, type_, actualEnumValues)
if err != nil {
return diag.Errorf("could not update configurationVariable: %v", err)
}
Expand Down
58 changes: 58 additions & 0 deletions env0/resource_configuration_variable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package env0

import (
"errors"
"fmt"
"github.com/env0/terraform-provider-env0/client"
"github.com/golang/mock/gomock"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
Expand Down Expand Up @@ -45,6 +46,63 @@ func TestUnitConfigurationVariableResource(t *testing.T) {
mock.EXPECT().ConfigurationVariableDelete(configVar.Id).Times(1).Return(nil)
})
})
t.Run("Create Enum", func(t *testing.T) {
configVar := client.ConfigurationVariable{
Id: "id0",
Name: "name0",
Value: "Variable",
Schema: client.ConfigurationVariableSchema{
Type: "string",
Enum: []string{"Variable", "a"},
},
}
stepConfig := fmt.Sprintf(`
resource "%s" "test" {
name = "%s"
value= "%s"
enum = ["%s","%s"]
}`, resourceType, configVar.Name, configVar.Value, configVar.Schema.Enum[0], configVar.Schema.Enum[1])

createTestCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: stepConfig,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "id", configVar.Id),
resource.TestCheckResourceAttr(accessor, "name", configVar.Name),
resource.TestCheckResourceAttr(accessor, "value", configVar.Value),
resource.TestCheckResourceAttr(accessor, "enum.0", configVar.Schema.Enum[0]),
resource.TestCheckResourceAttr(accessor, "enum.1", configVar.Schema.Enum[1]),
),
},
},
}

runUnitTest(t, createTestCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().ConfigurationVariableCreate(configVar.Name, configVar.Value, false, client.ScopeGlobal, "", client.ConfigurationVariableTypeEnvironment,
configVar.Schema.Enum).Times(1).Return(configVar, nil)
mock.EXPECT().ConfigurationVariables(client.ScopeGlobal, "").Times(1).Return([]client.ConfigurationVariable{configVar}, nil)
mock.EXPECT().ConfigurationVariableDelete(configVar.Id).Times(1).Return(nil)
})
})
t.Run("Create Enum with wrong value", func(t *testing.T) {
stepConfig := fmt.Sprintf(`
resource "%s" "test" {
name = "%s"
value= "%s"
enum = ["a","b"]
}`, resourceType, configVar.Name, configVar.Value)
createTestCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: stepConfig,
ExpectError: regexp.MustCompile(fmt.Sprintf("value - '%s' is not one of the enum options", configVar.Value)),
},
},
}

runUnitTest(t, createTestCase, func(mock *client.MockApiClientInterface) {})
})

t.Run("Create with wrong type", func(t *testing.T) {
createTestCase := resource.TestCase{
Expand Down
10 changes: 10 additions & 0 deletions examples/resources/env0_configuration_variable/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@ resource "env0_configuration_variable" "example" {
name = "ENVIRONMENT_VARIABLE_NAME"
value = "example value"
}

resource "env0_configuration_variable" "drop_down" {
name = "ENVIRONMENT_VARIABLE_DROP_DOWN"
value = "first option"
enum = [
"first option",
"second option"
]
}

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"tested1_value": "fake value 1 after update"
"tested1_value": "fake value 1 after update",
"tested3_enum_1": "First",
"tested3_enum_2": "Second"
}
18 changes: 18 additions & 0 deletions tests/integration/003_configuration_variable/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,21 @@ output "tested1_value" {
data "env0_configuration_variable" "tested2" {
id = env0_configuration_variable.tested1.id
}

resource "env0_configuration_variable" "tested3" {
name = "tested3"
value = "First"
enum = ["First", "Second"]
}
data "env0_configuration_variable" "tested3" {
name = "tested3"
depends_on = [env0_configuration_variable.tested3]
}


output "tested3_enum_1" {
value = data.env0_configuration_variable.tested3.enum[0]
}
output "tested3_enum_2" {
value = data.env0_configuration_variable.tested3.enum[1]
}

0 comments on commit 013f6ea

Please sign in to comment.