Skip to content

Commit

Permalink
Feat: add data source for env0_variable_set
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerHeber committed Jul 18, 2024
1 parent 1bc1849 commit 06c3d2d
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 1 deletion.
1 change: 1 addition & 0 deletions client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ type ApiClientInterface interface {
ConfigurationSetCreate(payload *CreateConfigurationSetPayload) (*ConfigurationSet, error)
ConfigurationSetUpdate(id string, payload *UpdateConfigurationSetPayload) (*ConfigurationSet, error)
ConfigurationSet(id string) (*ConfigurationSet, error)
ConfigurationSets(organizationId string, projectId string) ([]ConfigurationSet, error)
ConfigurationSetDelete(id string) error
ConfigurationVariablesBySetId(setId string) ([]ConfigurationVariable, error)
AssignConfigurationSets(scope string, scopeId string, sets []string) error
Expand Down
15 changes: 15 additions & 0 deletions client/api_client_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions client/configuration_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type ConfigurationSet struct {
Name string `json:"name"`
Description string `json:"description"`
AssignmentScope string `json:"assignmentScope"`
CreationScopeId string `json:"creationScopeId"`
}

func (client *ApiClient) ConfigurationSetCreate(payload *CreateConfigurationSetPayload) (*ConfigurationSet, error) {
Expand Down Expand Up @@ -62,6 +63,26 @@ func (client *ApiClient) ConfigurationSet(id string) (*ConfigurationSet, error)
return &result, nil
}

func (client *ApiClient) ConfigurationSets(organizationId string, projectId string) ([]ConfigurationSet, error) {
var result []ConfigurationSet

params := map[string]string{}

if organizationId != "" {
params["organizationId"] = organizationId
}

if projectId != "" {
params["projectId"] = projectId
}

if err := client.http.Get("/configuration-sets", params, &result); err != nil {
return nil, err
}

return result, nil
}

func (client *ApiClient) ConfigurationSetDelete(id string) error {
return client.http.Delete("/configuration-sets/"+id, nil)
}
Expand Down
56 changes: 56 additions & 0 deletions client/configuration_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,60 @@ var _ = Describe("Configuration Set", func() {
Expect(variables).To(Equal(mockVariables))
})
})

Describe("get configuration variables by set project id", func() {
mockVariables := []ConfigurationSet{
{
Id: "id",
Name: "name",
CreationScopeId: "create_scope_id",
},
}

var variables []ConfigurationSet

BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Get("/configuration-sets", map[string]string{
"projectId": mockVariables[0].CreationScopeId,
}, gomock.Any()).
Do(func(path string, request interface{}, response *[]ConfigurationSet) {
*response = mockVariables
}).Times(1)

variables, _ = apiClient.ConfigurationSets("", mockVariables[0].CreationScopeId)
})

It("Should return configuration sets", func() {
Expect(variables).To(Equal(mockVariables))
})
})

Describe("get configuration variables by set organization id", func() {
mockVariables := []ConfigurationSet{
{
Id: "id",
Name: "name",
CreationScopeId: "create_scope_id",
},
}

var variables []ConfigurationSet

BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Get("/configuration-sets", map[string]string{
"organizationId": mockVariables[0].CreationScopeId,
}, gomock.Any()).
Do(func(path string, request interface{}, response *[]ConfigurationSet) {
*response = mockVariables
}).Times(1)

variables, _ = apiClient.ConfigurationSets(mockVariables[0].CreationScopeId, "")
})

It("Should return configuration sets", func() {
Expect(variables).To(Equal(mockVariables))
})
})
})
82 changes: 82 additions & 0 deletions env0/data_variable_set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package env0

import (
"context"

"github.com/env0/terraform-provider-env0/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataVariableSet() *schema.Resource {
return &schema.Resource{
ReadContext: dataVariableSetRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "the name of the variable set",
Required: true,
},
"scope": {
Type: schema.TypeString,
Description: "the scope of the variable set. Valid values: 'ORGANIZATION', or 'PROJECT'",
Required: true,
ValidateDiagFunc: NewStringInValidator([]string{"ORGANIZATION", "PROJECT"}),
},
"project_id": {
Type: schema.TypeString,
Description: "the id of the 'PROJECT' scope. Is not required for 'ORGANIZATION' scope",
Optional: true,
},
"id": {
Type: schema.TypeString,
Description: "the id variable set",
Computed: true,
},
},
}
}

func dataVariableSetRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
resource := struct {
Name string
Scope string
ProjectId string
}{}

if err := readResourceData(&resource, d); err != nil {
return diag.Errorf("schema resource data deserialization failed: %v", err)
}

apiClient := meta.(client.ApiClientInterface)

organizationId := ""

switch resource.Scope {
case "ORGANIZATION":
var err error
organizationId, err = apiClient.OrganizationId()
if err != nil {
return diag.Errorf("could not get organization id: %v", err)
}
case "PROJECT":
if resource.ProjectId == "" {
return diag.Errorf("'project_id' is required")
}
}

variableSets, err := apiClient.ConfigurationSets(organizationId, resource.ProjectId)
if err != nil {
return diag.Errorf("could not get variable sets: %v", err)
}

for _, variableSet := range variableSets {
if variableSet.Name == resource.Name {
d.SetId(variableSet.Id)
return nil
}
}

return diag.Errorf("variable set not found")
}
158 changes: 158 additions & 0 deletions env0/data_variable_set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package env0

import (
"errors"
"regexp"
"testing"

"github.com/env0/terraform-provider-env0/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestVariableSetDataSource(t *testing.T) {
projectId := "project_id"
organizationId := "organization_id"

v1 := client.ConfigurationSet{
Id: "id1",
Name: "name1",
CreationScopeId: projectId,
}

v2 := client.ConfigurationSet{
Id: "id2",
Name: "name2",
CreationScopeId: projectId,
}

v3 := client.ConfigurationSet{
Id: "id3",
Name: "name3",
CreationScopeId: organizationId,
}

v4 := client.ConfigurationSet{
Id: "id4",
Name: "name4",
CreationScopeId: "some_other_id",
}

resourceType := "env0_variable_set"
resourceName := "test_variable_set"
accessor := dataSourceAccessor(resourceType, resourceName)

getConfig := func(name string, scope string, projectId string) string {
fields := map[string]interface{}{"name": name, "scope": scope}
if projectId != "" {
fields["project_id"] = projectId
}
return dataSourceConfigCreate(resourceType, resourceName, fields)
}

mockVariableSetsCall := func(organizationId string, projectId string, returnValue []client.ConfigurationSet) func(mockFunc *client.MockApiClientInterface) {
return func(mock *client.MockApiClientInterface) {
if organizationId != "" {
mock.EXPECT().OrganizationId().AnyTimes().Return(organizationId, nil)
}
mock.EXPECT().ConfigurationSets(organizationId, projectId).AnyTimes().Return(returnValue, nil)
}
}

t.Run("project id scope", func(t *testing.T) {
runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: getConfig(v2.Name, "PROJECT", v2.CreationScopeId),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "id", v2.Id),
),
},
},
},
mockVariableSetsCall("", projectId, []client.ConfigurationSet{
v4, v1, v2,
}),
)
})

t.Run("organization id scope", func(t *testing.T) {
runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: getConfig(v3.Name, "ORGANIZATION", ""),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "id", v3.Id),
),
},
},
},
mockVariableSetsCall(organizationId, "", []client.ConfigurationSet{
v4, v3,
}),
)
})

t.Run("name not found", func(t *testing.T) {
runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: getConfig("name that isn't found", "PROJECT", v2.CreationScopeId),
ExpectError: regexp.MustCompile("variable set not found"),
},
},
},
mockVariableSetsCall("", projectId, []client.ConfigurationSet{
v4, v1, v2, v3,
}),
)
})

t.Run("get configuration sets api call failed", func(t *testing.T) {
runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: getConfig(v2.Name, "PROJECT", v2.CreationScopeId),
ExpectError: regexp.MustCompile("could not get variable sets: error"),
},
},
},
func(mock *client.MockApiClientInterface) {
mock.EXPECT().ConfigurationSets("", projectId).AnyTimes().Return(nil, errors.New("error"))
},
)
})

t.Run("get organization id api call failed", func(t *testing.T) {
runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: getConfig(v3.Name, "ORGANIZATION", ""),
ExpectError: regexp.MustCompile("could not get organization id: error"),
},
},
},
func(mock *client.MockApiClientInterface) {
mock.EXPECT().OrganizationId().AnyTimes().Return("", errors.New("error"))
},
)
})

t.Run("project_id is required", func(t *testing.T) {
runUnitTest(t,
resource.TestCase{
Steps: []resource.TestStep{
{
Config: getConfig(v2.Name, "PROJECT", ""),
ExpectError: regexp.MustCompile("'project_id' is required"),
},
},
},
func(mock *client.MockApiClientInterface) {},
)
})
}
1 change: 1 addition & 0 deletions env0/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func Provider(version string) plugin.ProviderFunc {
"env0_custom_flow": dataCustomFlow(),
"env0_projects": dataProjects(),
"env0_module_testing_project": dataModuleTestingProject(),
"env0_variable_set": dataVariableSet(),
},
ResourcesMap: map[string]*schema.Resource{
"env0_project": resourceProject(),
Expand Down
1 change: 0 additions & 1 deletion env0/resource_team_organization_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ func resourceTeamOrganizationAssignmentCreateOrUpdate(ctx context.Context, d *sc
organizationId, err := apiClient.OrganizationId()
if err != nil {
return diag.Errorf("could not get organization id: %v", err)

}

var payload client.TeamRoleAssignmentCreateOrUpdatePayload
Expand Down
14 changes: 14 additions & 0 deletions examples/data-sources/env0_variable_set/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
data "env0_project" "project" {
name = "my project name"
}

data "env0_variable_set" "variable_set_project_scope" {
name = "variable set name"
scope = "PROJECT"
project_id = data.env0_project.project.id
}

data "env0_variable_set" "variable_set_organization_scope" {
name = "variable set name"
scope = "ORGANIZATION"
}
Loading

0 comments on commit 06c3d2d

Please sign in to comment.