Skip to content

Commit

Permalink
Merge branch 'main' into feat-add-filter-for-teams-#982
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerHeber authored Dec 11, 2024
2 parents 0438162 + d658cfa commit 927c8aa
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 141 deletions.
7 changes: 6 additions & 1 deletion client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type ApiClient struct {
http http.HttpClientInterface
cachedOrganizationId string
defaultOrganizationId string
memoizedGetTeams func(string) ([]Team, error)
}

type ApiClientInterface interface {
Expand Down Expand Up @@ -172,9 +173,13 @@ type ApiClientInterface interface {
}

func NewApiClient(client http.HttpClientInterface, defaultOrganizationId string) ApiClientInterface {
return &ApiClient{
apiClient := &ApiClient{
http: client,
cachedOrganizationId: "",
defaultOrganizationId: defaultOrganizationId,
}

apiClient.memoizedGetTeams = memoize(apiClient.GetTeams)

return apiClient
}
5 changes: 2 additions & 3 deletions client/configuration_variable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package client_test

import (
"encoding/json"
"strings"
"testing"

. "github.com/env0/terraform-provider-env0/client"
Expand Down Expand Up @@ -309,7 +308,7 @@ func TestConfigurationVariableMarshelling(t *testing.T) {

b, err := json.Marshal(&variable)
if assert.NoError(t, err) {
assert.False(t, strings.Contains(string(b), str))
assert.NotContains(t, string(b), str)
}

type ConfigurationVariableDummy ConfigurationVariable
Expand All @@ -318,7 +317,7 @@ func TestConfigurationVariableMarshelling(t *testing.T) {

b, err = json.Marshal(&dummy)
if assert.NoError(t, err) {
assert.True(t, strings.Contains(string(b), str))
assert.Contains(t, string(b), str)
}

var variable2 ConfigurationVariable
Expand Down
27 changes: 27 additions & 0 deletions client/memoize.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package client

type memoizedResult[V any] struct {
value V
err error
}

func memoize[K comparable, V any](f func(K) (V, error)) func(K) (V, error) {
cache := make(map[K]memoizedResult[V])

return func(key K) (V, error) {
if res, ok := cache[key]; ok {
return res.value, res.err
}

value, err := f(key)

cache[key] = memoizedResult[V]{value: value, err: err}

return value, err
}
}

// MemoizeExported exports the memoize function for testing
func MemoizeExported[K comparable, V any](f func(K) (V, error)) func(K) (V, error) {
return memoize(f)
}
68 changes: 68 additions & 0 deletions client/memoize_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package client_test

import (
"errors"
"testing"

"github.com/env0/terraform-provider-env0/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestMemoize(t *testing.T) {
t.Run("should cache successful results", func(t *testing.T) {
callCount := 0
f := func(s string) ([]client.Team, error) {
callCount++

return []client.Team{{Name: s}}, nil
}

memoized := client.MemoizeExported(f)

// First call
result1, err1 := memoized("")
require.NoError(t, err1)
assert.Len(t, result1, 1)
assert.Equal(t, 1, callCount)

// Second call with same input - should use cache
result2, err2 := memoized("")
require.NoError(t, err2)
assert.Len(t, result2, 1)
assert.Equal(t, 1, callCount) // Count shouldn't increase

// Different input - should call function again
result3, err3 := memoized("test")
require.NoError(t, err3)
assert.Len(t, result3, 1)
assert.Equal(t, "test", result3[0].Name)
assert.Equal(t, 2, callCount)
})

t.Run("should cache errors", func(t *testing.T) {
callCount := 0
expectedError := errors.New("test error")
f := func(s string) ([]client.Team, error) {
callCount++

return nil, expectedError
}

memoized := client.MemoizeExported(f)

// First call
result1, err1 := memoized("")
require.Error(t, err1)
assert.Equal(t, expectedError, err1)
assert.Nil(t, result1)
assert.Equal(t, 1, callCount)

// Second call - should return cached error
result2, err2 := memoized("")
require.Error(t, err2)
assert.Equal(t, expectedError, err2)
assert.Nil(t, result2)
assert.Equal(t, 1, callCount) // Count shouldn't increase
})
}
11 changes: 8 additions & 3 deletions client/team.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,12 @@ func (client *ApiClient) TeamUpdate(id string, payload TeamUpdatePayload) (Team,
return result, nil
}

func (client *ApiClient) GetTeams(params map[string]string) ([]Team, error) {
func (client *ApiClient) GetTeams(name string) ([]Team, error) {
params := map[string]string{"limit": "100"}
if name != "" {
params["name"] = name
}

organizationId, err := client.OrganizationId()
if err != nil {
return nil, err
Expand Down Expand Up @@ -112,9 +117,9 @@ func (client *ApiClient) GetTeams(params map[string]string) ([]Team, error) {
}

func (client *ApiClient) Teams() ([]Team, error) {
return client.GetTeams(map[string]string{"limit": "100"})
return client.memoizedGetTeams("")
}

func (client *ApiClient) TeamsByName(name string) ([]Team, error) {
return client.GetTeams(map[string]string{"name": name, "limit": "100"})
return client.memoizedGetTeams(name)
}
33 changes: 24 additions & 9 deletions client/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,22 +127,37 @@ func (payload *TemplateCreatePayload) Invalidate() error {
return errors.New("must not specify organizationId")
}

if payload.Type != TERRAGRUNT && payload.TerragruntVersion != "" {
return errors.New("can't define terragrunt version for non-terragrunt template")
}
if payload.Type == TERRAGRUNT {
if payload.TerragruntVersion == "" {
return errors.New("must supply terragrunt version")
}

// The provider implicitly defaults to "opentofu".
if payload.TerragruntTfBinary == "" {
payload.TerragruntTfBinary = OPENTOFU
}

if payload.TerragruntTfBinary == OPENTOFU && payload.OpentofuVersion == "" {
return errors.New("must supply opentofu version")
}

if payload.Type == TERRAGRUNT && payload.TerragruntVersion == "" {
return errors.New("must supply terragrunt version")
if payload.TerragruntTfBinary == TERRAFORM && payload.TerraformVersion == "" {
return errors.New("must supply terraform version")
}
} else {
if payload.TerragruntVersion != "" {
return errors.New("can't define terragrunt version for non-terragrunt template")
}

if payload.TerragruntTfBinary != "" {
return errors.New("can't define terragrunt_tf_binary for non-terragrunt template")
}
}

if payload.Type == OPENTOFU && payload.OpentofuVersion == "" {
return errors.New("must supply opentofu version")
}

if payload.TerragruntTfBinary != "" && payload.Type != TERRAGRUNT {
return fmt.Errorf("terragrunt_tf_binary should only be used when the template type is 'terragrunt', but type is '%s'", payload.Type)
}

if payload.IsTerragruntRunAll {
if payload.Type != TERRAGRUNT {
return errors.New(`can't set is_terragrunt_run_all to "true" for non-terragrunt template`)
Expand Down
4 changes: 2 additions & 2 deletions docs/data-sources/teams.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
page_title: "env0_teams Data Source - terraform-provider-env0"
subcategory: ""
description: |-
Note: this data source is cached, once fetched it will not be updated until the next plan/apply
---

# env0_teams (Data Source)


Note: this data source is cached, once fetched it will not be updated until the next plan/apply

## Example Usage

Expand Down
2 changes: 1 addition & 1 deletion docs/resources/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ Optional:
- `revision` (String) source code revision (branch / tag) to use
- `ssh_keys` (List of Map of String) an array of references to 'data_ssh_key' to use when accessing git over ssh
- `terraform_version` (String) the Terraform version to use (example: 0.15.1). Setting to `RESOLVE_FROM_TERRAFORM_CODE` defaults to the version of `terraform.required_version` during run-time (resolve from terraform code). Setting to `latest`, the version used will be the most recent one available for Terraform.
- `terragrunt_tf_binary` (String) the binary to use if the template type is 'terragrunt'. Valid values 'opentofu' and 'terraform'. For new templates defaults to 'opentofu'
- `terragrunt_tf_binary` (String) the binary to use if the template type is 'terragrunt'. Valid values 'opentofu' and 'terraform'. Defaults to 'opentofu'
- `terragrunt_version` (String) the Terragrunt version to use (example: 0.36.5)
- `token_id` (String) the git token id to be used
- `token_name` (String) token name for Gitlab
Expand Down
2 changes: 1 addition & 1 deletion docs/resources/template.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ resource "env0_template_project_assignment" "assignment" {
- `revision` (String) source code revision (branch / tag) to use
- `ssh_keys` (List of Map of String) an array of references to 'data_ssh_key' to use when accessing git over ssh
- `terraform_version` (String) the Terraform version to use (example: 0.15.1). Setting to `RESOLVE_FROM_TERRAFORM_CODE` defaults to the version of `terraform.required_version` during run-time (resolve from terraform code). Setting to `latest`, the version used will be the most recent one available for Terraform.
- `terragrunt_tf_binary` (String) the binary to use if the template type is 'terragrunt'. Valid values 'opentofu' and 'terraform'. For new templates defaults to 'opentofu'
- `terragrunt_tf_binary` (String) the binary to use if the template type is 'terragrunt'. Valid values 'opentofu' and 'terraform'. Defaults to 'opentofu'
- `terragrunt_version` (String) the Terragrunt version to use (example: 0.36.5)
- `token_id` (String) the git token id to be used
- `token_name` (String) token name for Gitlab
Expand Down
1 change: 1 addition & 0 deletions env0/data_teams.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
func dataTeams() *schema.Resource {
return &schema.Resource{
ReadContext: dataTeamsRead,
Description: "Note: this data source is cached, once fetched it will not be updated until the next plan/apply",

Schema: map[string]*schema.Schema{
"names": {
Expand Down
4 changes: 2 additions & 2 deletions env0/resource_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ func resourceEnvironmentRead(ctx context.Context, d *schema.ResourceData, meta i
return diag.Errorf("could not get template: %v", err)
}

if err := templateRead("without_template_settings", template, d, false); err != nil {
if err := templateRead("without_template_settings", template, d); err != nil {
return diag.Errorf("schema resource data serialization failed: %v", err)
}
}
Expand Down Expand Up @@ -1443,7 +1443,7 @@ func resourceEnvironmentImport(ctx context.Context, d *schema.ResourceData, meta
return nil, fmt.Errorf("failed to get template with id %s: %w", templateId, err)
}

if err := templateRead("without_template_settings", template, d, true); err != nil {
if err := templateRead("without_template_settings", template, d); err != nil {
return nil, fmt.Errorf("failed to write template to schema: %w", err)
}
}
Expand Down
8 changes: 0 additions & 8 deletions env0/resource_environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2736,11 +2736,6 @@ func TestUnitEnvironmentWithoutTemplateResource(t *testing.T) {
terragruntVersion = "terragrunt_version = \"" + template.TerragruntVersion + "\""
}

terragruntTfBinary := ""
if template.TerragruntTfBinary != "" {
terragruntTfBinary = "terragrunt_tf_binary = \"" + template.TerragruntTfBinary + "\""
}

openTofuVersion := ""
if template.OpentofuVersion != "" {
openTofuVersion = "opentofu_version = \"" + template.OpentofuVersion + "\""
Expand Down Expand Up @@ -2769,7 +2764,6 @@ func TestUnitEnvironmentWithoutTemplateResource(t *testing.T) {
github_installation_id = %d
%s
%s
%s
}
}`,
resourceType, resourceName,
Expand All @@ -2790,7 +2784,6 @@ func TestUnitEnvironmentWithoutTemplateResource(t *testing.T) {
template.Description,
template.GithubInstallationId,
terragruntVersion,
terragruntTfBinary,
openTofuVersion,
)
}
Expand Down Expand Up @@ -2837,7 +2830,6 @@ func TestUnitEnvironmentWithoutTemplateResource(t *testing.T) {
resource.TestCheckResourceAttr(accessor, "without_template_settings.0.type", updatedTemplate.Type),
resource.TestCheckResourceAttr(accessor, "without_template_settings.0.path", updatedTemplate.Path),
resource.TestCheckResourceAttr(accessor, "without_template_settings.0.terragrunt_version", updatedTemplate.TerragruntVersion),
resource.TestCheckResourceAttr(accessor, "without_template_settings.0.terragrunt_tf_binary", updatedTemplate.TerragruntTfBinary),
resource.TestCheckResourceAttr(accessor, "without_template_settings.0.revision", updatedTemplate.Revision),
resource.TestCheckResourceAttr(accessor, "without_template_settings.0.retries_on_deploy", strconv.Itoa(updatedTemplate.Retry.OnDeploy.Times)),
resource.TestCheckResourceAttr(accessor, "without_template_settings.0.retry_on_deploy_only_when_matches_regex", updatedTemplate.Retry.OnDeploy.ErrorRegex),
Expand Down
Loading

0 comments on commit 927c8aa

Please sign in to comment.