Skip to content

Commit

Permalink
Feat: refactor resources/data to use the new serialization/deserializ… (
Browse files Browse the repository at this point in the history
#423)

* Feat: refactor resources/data to use the new serialization/deserialization logic

* removed leftovers

* fixed a bug
  • Loading branch information
TomerHeber committed Jun 20, 2022
1 parent 29fd96b commit 4c22475
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 125 deletions.
4 changes: 2 additions & 2 deletions client/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type Template struct {
TerragruntVersion string `json:"terragruntVersion,omitempty"`
IsDeleted bool `json:"isDeleted,omitempty"`
BitbucketClientKey string `json:"bitbucketClientKey"`
IsGitHubEnterprise bool `json:"isGitHubEnterprise"`
IsGithubEnterprise bool `json:"isGitHubEnterprise"`
IsBitbucketServer bool `json:"isBitbucketServer"`
}

Expand All @@ -81,7 +81,7 @@ type TemplateCreatePayload struct {
TerragruntVersion string `json:"terragruntVersion,omitempty"`
IsGitlabEnterprise bool `json:"isGitLabEnterprise"`
BitbucketClientKey string `json:"bitbucketClientKey,omitempty"`
IsGitHubEnterprise bool `json:"isGitHubEnterprise"`
IsGithubEnterprise bool `json:"isGitHubEnterprise"`
IsBitbucketServer bool `json:"isBitbucketServer"`
}

Expand Down
4 changes: 2 additions & 2 deletions env0/data_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ func dataTemplateRead(ctx context.Context, d *schema.ResourceData, meta interfac
d.Set("is_bitbucket_server", template.IsBitbucketServer)
}

if template.IsGitHubEnterprise {
d.Set("is_github_enterprise", template.IsGitHubEnterprise)
if template.IsGithubEnterprise {
d.Set("is_github_enterprise", template.IsGithubEnterprise)
}

var sshKeys []interface{}
Expand Down
113 changes: 20 additions & 93 deletions env0/resource_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,107 +24,34 @@ func resourceTemplate() *schema.Resource {
}
}

func templateCreatePayloadFromParameters(d *schema.ResourceData) (client.TemplateCreatePayload, diag.Diagnostics) {
result := client.TemplateCreatePayload{
Name: d.Get("name").(string),
Repository: d.Get("repository").(string),
}
if description, ok := d.GetOk("description"); ok {
result.Description = description.(string)
}
if githubInstallationId, ok := d.GetOk("github_installation_id"); ok {
result.GithubInstallationId = githubInstallationId.(int)
}
if tokenId, ok := d.GetOk("token_id"); ok {
result.TokenId = tokenId.(string)
result.GitlabProjectId = d.Get("gitlab_project_id").(int)
result.IsGitLab = result.TokenId != ""
}
if isGitlabEnterprise, ok := d.GetOk("is_gitlab_enterprise"); ok {
result.IsGitlabEnterprise = isGitlabEnterprise.(bool)
}
if isBitbucketServer, ok := d.GetOk("is_bitbucket_server"); ok {
result.IsBitbucketServer = isBitbucketServer.(bool)
}
if isGitHubEnterprise, ok := d.GetOk("is_github_enterprise"); ok {
result.IsGitHubEnterprise = isGitHubEnterprise.(bool)
}

if path, ok := d.GetOk("path"); ok {
result.Path = path.(string)
}
if revision, ok := d.GetOk("revision"); ok {
result.Revision = revision.(string)
}
if type_, ok := d.GetOk("type"); ok {
if type_ == string(client.TemplateTypeTerraform) {
result.Type = client.TemplateTypeTerraform
} else if type_ == string(client.TemplateTypeTerragrunt) {
result.Type = client.TemplateTypeTerragrunt
} else {
return client.TemplateCreatePayload{}, diag.Errorf("'type' can either be 'terraform' or 'terragrunt': %s", type_)
}
}
if sshKeys, ok := d.GetOk("ssh_keys"); ok {
result.SshKeys = []client.TemplateSshKey{}
for _, sshKey := range sshKeys.([]interface{}) {
result.SshKeys = append(result.SshKeys, client.TemplateSshKey{
Name: sshKey.(map[string]interface{})["name"].(string),
Id: sshKey.(map[string]interface{})["id"].(string)})
}
}
onDeployRetries, hasRetriesOnDeploy := d.GetOk("retries_on_deploy")
var onDeploy *client.TemplateRetryOn = nil
var onDestroy *client.TemplateRetryOn = nil
if hasRetriesOnDeploy {
onDeploy = &client.TemplateRetryOn{
Times: onDeployRetries.(int),
func templateCreatePayloadRetryOnHelper(d *schema.ResourceData, retryType string, retryOnPtr **client.TemplateRetryOn) {
retries, hasRetries := d.GetOk("retries_on_" + retryType)
if hasRetries {
retryOn := &client.TemplateRetryOn{
Times: retries.(int),
}
}
if retryOnDeployOnlyIfMatchesRegex, ok := d.GetOk("retry_on_deploy_only_when_matches_regex"); ok {
if !hasRetriesOnDeploy {
return client.TemplateCreatePayload{}, diag.Errorf("may only specify 'retry_on_deploy_only_when_matches_regex'")
if retryIfMatchesRegex, ok := d.GetOk("retry_on_" + retryType + "_only_when_matches_regex"); ok {
retryOn.ErrorRegex = retryIfMatchesRegex.(string)
}
onDeploy.ErrorRegex = retryOnDeployOnlyIfMatchesRegex.(string)
}

onDestroyRetries, hasRetriesOnDestroy := d.GetOk("retries_on_destroy")
if hasRetriesOnDestroy {
onDestroy = &client.TemplateRetryOn{
Times: onDestroyRetries.(int),
}
}
if retryOnDestroyOnlyIfMatchesRegex, ok := d.GetOk("retry_on_destroy_only_when_matches_regex"); ok {
if !hasRetriesOnDestroy {
return client.TemplateCreatePayload{}, diag.Errorf("may only specify 'retry_on_destroy_only_when_matches_regex'")
}
onDestroy.ErrorRegex = retryOnDestroyOnlyIfMatchesRegex.(string)
*retryOnPtr = retryOn
}
}

if onDeploy != nil || onDestroy != nil {
result.Retry = client.TemplateRetry{}
if onDeploy != nil {
result.Retry.OnDeploy = onDeploy
}
if onDestroy != nil {
result.Retry.OnDestroy = onDestroy
}
func templateCreatePayloadFromParameters(d *schema.ResourceData) (client.TemplateCreatePayload, diag.Diagnostics) {
var payload client.TemplateCreatePayload
if err := readResourceData(&payload, d); err != nil {
return payload, diag.Errorf("schema resource data serialization failed: %v", err)
}

if terraformVersion, ok := d.GetOk("terraform_version"); ok {
result.TerraformVersion = terraformVersion.(string)
}
if terragruntVersion, ok := d.GetOk("terragrunt_version"); ok {
result.TerragruntVersion = terragruntVersion.(string)
}
if bitbucketClientKey, ok := d.GetOk("bitbucket_client_key"); ok {
result.BitbucketClientKey = bitbucketClientKey.(string)
if tokenId, ok := d.GetOk("token_id"); ok {
payload.IsGitLab = tokenId != ""
}

if terragruntVersion, ok := d.GetOk("terragrunt_version"); ok {
result.TerragruntVersion = terragruntVersion.(string)
}
return result, nil
templateCreatePayloadRetryOnHelper(d, "deploy", &payload.Retry.OnDeploy)
templateCreatePayloadRetryOnHelper(d, "destroy", &payload.Retry.OnDestroy)

return payload, nil
}

func resourceTemplateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
Expand Down Expand Up @@ -200,7 +127,7 @@ func resourceTemplateRead(ctx context.Context, d *schema.ResourceData, meta inte

d.Set("is_gitlab_enterprise", template.IsGitlabEnterprise)
d.Set("is_bitbucket_server", template.IsBitbucketServer)
d.Set("is_github_enterprise", template.IsGitHubEnterprise)
d.Set("is_github_enterprise", template.IsGithubEnterprise)

return nil
}
Expand Down
14 changes: 7 additions & 7 deletions env0/resource_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func TestUnitTemplateResource(t *testing.T) {
},
Type: "terraform",
TerraformVersion: "0.12.24",
IsGitHubEnterprise: true,
IsGithubEnterprise: true,
}
gheeUpdatedTemplate := client.Template{
Id: gheeTemplate.Id,
Expand All @@ -228,7 +228,7 @@ func TestUnitTemplateResource(t *testing.T) {
},
Type: "terraform",
TerraformVersion: "0.12.24",
IsGitHubEnterprise: true,
IsGithubEnterprise: true,
}
bitbucketServerTemplate := client.Template{
Id: "id011",
Expand Down Expand Up @@ -320,8 +320,8 @@ func TestUnitTemplateResource(t *testing.T) {
if template.BitbucketClientKey != "" {
templateAsDictionary["bitbucket_client_key"] = template.BitbucketClientKey
}
if template.IsGitHubEnterprise != false {
templateAsDictionary["is_github_enterprise"] = template.IsGitHubEnterprise
if template.IsGithubEnterprise != false {
templateAsDictionary["is_github_enterprise"] = template.IsGithubEnterprise
}
if template.IsBitbucketServer != false {
templateAsDictionary["is_bitbucket_server"] = template.IsBitbucketServer
Expand Down Expand Up @@ -393,7 +393,7 @@ func TestUnitTemplateResource(t *testing.T) {
Retry: templateUseCase.template.Retry,
TerraformVersion: templateUseCase.template.TerraformVersion,
BitbucketClientKey: templateUseCase.template.BitbucketClientKey,
IsGitHubEnterprise: templateUseCase.template.IsGitHubEnterprise,
IsGithubEnterprise: templateUseCase.template.IsGithubEnterprise,
IsBitbucketServer: templateUseCase.template.IsBitbucketServer,
}
updateTemplateCreateTemplate := client.TemplateCreatePayload{
Expand All @@ -411,7 +411,7 @@ func TestUnitTemplateResource(t *testing.T) {
Retry: templateUseCase.updatedTemplate.Retry,
TerraformVersion: templateUseCase.updatedTemplate.TerraformVersion,
BitbucketClientKey: templateUseCase.updatedTemplate.BitbucketClientKey,
IsGitHubEnterprise: templateUseCase.updatedTemplate.IsGitHubEnterprise,
IsGithubEnterprise: templateUseCase.updatedTemplate.IsGithubEnterprise,
IsBitbucketServer: templateUseCase.updatedTemplate.IsBitbucketServer,
}

Expand Down Expand Up @@ -502,7 +502,7 @@ func TestUnitTemplateResource(t *testing.T) {
"repository": template.Repository,
"type": "gruntyform",
}),
ExpectError: regexp.MustCompile(`'type' can either be 'terraform' or 'terragrunt'`),
ExpectError: regexp.MustCompile(`must be one of: terragrunt, terraform`),
},
},
}
Expand Down
9 changes: 5 additions & 4 deletions env0/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ func getTemplateSchema(templateType TemplateType) map[string]*schema.Schema {
Optional: true,
},
"type": {
Type: schema.TypeString,
Description: "'terraform' or 'terragrunt'",
Optional: true,
Default: "terraform",
Type: schema.TypeString,
Description: "'terraform' or 'terragrunt'",
Optional: true,
Default: "terraform",
ValidateDiagFunc: NewStringInValidator([]string{"terragrunt", "terraform"}),
},
"ssh_keys": {
Type: schema.TypeList,
Expand Down
68 changes: 51 additions & 17 deletions env0/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"regexp"
"strings"

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

Expand Down Expand Up @@ -107,23 +106,9 @@ func readResourceData(i interface{}, d *schema.ResourceData) error {
return fmt.Errorf("internal error - unhandled field pointer kind %v", fieldType.Elem().Kind())
}
case reflect.Slice:
switch fieldType {
case reflect.TypeOf([]client.ModuleSshKey{}):
sshKeys := []client.ModuleSshKey{}
for _, sshKey := range dval.([]interface{}) {
sshKeys = append(sshKeys, client.ModuleSshKey{
Name: sshKey.(map[string]interface{})["name"].(string),
Id: sshKey.(map[string]interface{})["id"].(string)})
}
field.Set(reflect.ValueOf(sshKeys))
case reflect.TypeOf([]string{}):
strs := []string{}
for _, str := range dval.([]interface{}) {
strs = append(strs, str.(string))
}
field.Set(reflect.ValueOf(strs))
if err := readResourceDataSlice(field, dval.([]interface{})); err != nil {
return err
}

case reflect.String, reflect.Bool, reflect.Int:
field.Set(reflect.ValueOf(dval).Convert(fieldType))
default:
Expand All @@ -134,6 +119,55 @@ func readResourceData(i interface{}, d *schema.ResourceData) error {
return nil
}

func readResourceDataSliceStructHelper(field reflect.Value, resource interface{}) error {
val := field.Elem()
m := resource.(map[string]interface{})

for i := 0; i < val.NumField(); i++ {
fieldName, skip := getFieldName(val.Type().Field(i))
if skip {
continue
}

fieldValue, ok := m[fieldName]
if !ok {
continue
}

field := val.Field(i)
field.Set(reflect.ValueOf(fieldValue))
}

return nil
}

// Extracts a list of values from the resourcedata, and writes it to the struct field.
func readResourceDataSlice(field reflect.Value, resources []interface{}) error {
elemType := field.Type().Elem()
vals := reflect.MakeSlice(field.Type(), 0, len(resources))

for _, resource := range resources {
var val reflect.Value
switch elemType.Kind() {
case reflect.String:
val = reflect.ValueOf(resource.(string))
case reflect.Struct:
val = reflect.New(elemType)
if err := readResourceDataSliceStructHelper(val, resource); err != nil {
return err
}
val = val.Elem()
default:
return fmt.Errorf("internal error - unhandled slice element kind %v", elemType.Kind())
}
vals = reflect.Append(vals, val)
}

field.Set(vals)

return nil
}

// Returns the field name or skip.
func getFieldName(field reflect.StructField) (string, bool) {
name := field.Name
Expand Down

0 comments on commit 4c22475

Please sign in to comment.