diff --git a/client/account.go b/codefresh/cfclient/account.go similarity index 99% rename from client/account.go rename to codefresh/cfclient/account.go index 75fc5210..9cefc90b 100644 --- a/client/account.go +++ b/codefresh/cfclient/account.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "errors" diff --git a/client/api_key.go b/codefresh/cfclient/api_key.go similarity index 99% rename from client/api_key.go rename to codefresh/cfclient/api_key.go index 5d47a87f..3a41dc5b 100644 --- a/client/api_key.go +++ b/codefresh/cfclient/api_key.go @@ -1,10 +1,11 @@ -package client +package cfclient import ( "errors" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" ) type ApiKeySubject struct { diff --git a/client/client.go b/codefresh/cfclient/client.go similarity index 99% rename from client/client.go rename to codefresh/cfclient/client.go index 4228ae43..b8f4442f 100644 --- a/client/client.go +++ b/codefresh/cfclient/client.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "bytes" diff --git a/client/context.go b/codefresh/cfclient/context.go similarity index 99% rename from client/context.go rename to codefresh/cfclient/context.go index 71d51d40..934e718e 100644 --- a/client/context.go +++ b/codefresh/cfclient/context.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/current_account.go b/codefresh/cfclient/current_account.go similarity index 99% rename from client/current_account.go rename to codefresh/cfclient/current_account.go index ffd2dd16..4724ab89 100644 --- a/client/current_account.go +++ b/codefresh/cfclient/current_account.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "encoding/json" diff --git a/client/gitops_abac_rules.go b/codefresh/cfclient/gitops_abac_rules.go similarity index 99% rename from client/gitops_abac_rules.go rename to codefresh/cfclient/gitops_abac_rules.go index 9ec7e5a8..0e09d30c 100644 --- a/client/gitops_abac_rules.go +++ b/codefresh/cfclient/gitops_abac_rules.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/gql_client.go b/codefresh/cfclient/gql_client.go similarity index 98% rename from client/gql_client.go rename to codefresh/cfclient/gql_client.go index 7987a64d..3b81333a 100644 --- a/client/gql_client.go +++ b/codefresh/cfclient/gql_client.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "bytes" diff --git a/client/hermes_trigger.go b/codefresh/cfclient/hermes_trigger.go similarity index 99% rename from client/hermes_trigger.go rename to codefresh/cfclient/hermes_trigger.go index 374feb3b..bf551abd 100644 --- a/client/hermes_trigger.go +++ b/codefresh/cfclient/hermes_trigger.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/hermes_trigger_event.go b/codefresh/cfclient/hermes_trigger_event.go similarity index 98% rename from client/hermes_trigger_event.go rename to codefresh/cfclient/hermes_trigger_event.go index b5c1bb9d..2c303898 100644 --- a/client/hermes_trigger_event.go +++ b/codefresh/cfclient/hermes_trigger_event.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/idp.go b/codefresh/cfclient/idp.go similarity index 99% rename from client/idp.go rename to codefresh/cfclient/idp.go index d1f22c2a..928a034c 100644 --- a/client/idp.go +++ b/codefresh/cfclient/idp.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "errors" diff --git a/client/permission.go b/codefresh/cfclient/permission.go similarity index 99% rename from client/permission.go rename to codefresh/cfclient/permission.go index c27c1bbf..181fc8de 100644 --- a/client/permission.go +++ b/codefresh/cfclient/permission.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/pipeline.go b/codefresh/cfclient/pipeline.go similarity index 99% rename from client/pipeline.go rename to codefresh/cfclient/pipeline.go index 459a7467..442c8d56 100644 --- a/client/pipeline.go +++ b/codefresh/cfclient/pipeline.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "errors" diff --git a/client/project.go b/codefresh/cfclient/project.go similarity index 99% rename from client/project.go rename to codefresh/cfclient/project.go index 70e68969..daf524dd 100644 --- a/client/project.go +++ b/codefresh/cfclient/project.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "errors" diff --git a/client/registry.go b/codefresh/cfclient/registry.go similarity index 99% rename from client/registry.go rename to codefresh/cfclient/registry.go index 732b3c58..dc62a3b9 100644 --- a/client/registry.go +++ b/codefresh/cfclient/registry.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/step_types.go b/codefresh/cfclient/step_types.go similarity index 99% rename from client/step_types.go rename to codefresh/cfclient/step_types.go index 970bbe58..ec1d9ac8 100644 --- a/client/step_types.go +++ b/codefresh/cfclient/step_types.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/team.go b/codefresh/cfclient/team.go similarity index 99% rename from client/team.go rename to codefresh/cfclient/team.go index a7b747ce..1dc34ecb 100644 --- a/client/team.go +++ b/codefresh/cfclient/team.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/user.go b/codefresh/cfclient/user.go similarity index 99% rename from client/user.go rename to codefresh/cfclient/user.go index 68c52876..00846843 100644 --- a/client/user.go +++ b/codefresh/cfclient/user.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "fmt" diff --git a/client/utils.go b/codefresh/cfclient/utils.go similarity index 97% rename from client/utils.go rename to codefresh/cfclient/utils.go index 734c1ba0..93c24585 100644 --- a/client/utils.go +++ b/codefresh/cfclient/utils.go @@ -1,4 +1,4 @@ -package client +package cfclient import ( "net/url" diff --git a/codefresh/context/storage.go b/codefresh/context/storage.go index a866d5e1..99f88404 100644 --- a/codefresh/context/storage.go +++ b/codefresh/context/storage.go @@ -1,7 +1,7 @@ package context import ( - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -30,7 +30,7 @@ func ConvertAzureStorageContext(context []interface{}) map[string]interface{} { return convertStorageContext(context, auth) } -func flattenStorageContextConfig(spec cfClient.ContextSpec, auth map[string]interface{}) []interface{} { +func flattenStorageContextConfig(spec cfclient.ContextSpec, auth map[string]interface{}) []interface{} { var res = make([]interface{}, 0) m := make(map[string]interface{}) @@ -51,14 +51,14 @@ func flattenStorageContextConfig(spec cfClient.ContextSpec, auth map[string]inte } -func FlattenJsonConfigStorageContextConfig(spec cfClient.ContextSpec) []interface{} { +func FlattenJsonConfigStorageContextConfig(spec cfclient.ContextSpec) []interface{} { auth := make(map[string]interface{}) auth["json_config"] = spec.Data["auth"].(map[string]interface{})["jsonConfig"] auth["type"] = spec.Data["type"] return flattenStorageContextConfig(spec, auth) } -func FlattenAzureStorageContextConfig(spec cfClient.ContextSpec) []interface{} { +func FlattenAzureStorageContextConfig(spec cfclient.ContextSpec) []interface{} { auth := make(map[string]interface{}) authParams := spec.Data["auth"].(map[string]interface{}) auth["account_name"] = authParams["accountName"] diff --git a/codefresh/data_account.go b/codefresh/data_account.go index e6e5ffc1..a8875a89 100644 --- a/codefresh/data_account.go +++ b/codefresh/data_account.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -33,8 +33,8 @@ func dataSourceAccount() *schema.Resource { func dataSourceAccountRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) - var account *cfClient.Account + client := meta.(*cfclient.Client) + var account *cfclient.Account var err error if _id, _idOk := d.GetOk("_id"); _idOk { @@ -55,7 +55,7 @@ func dataSourceAccountRead(d *schema.ResourceData, meta interface{}) error { return mapDataAccountToResource(account, d) } -func mapDataAccountToResource(account *cfClient.Account, d *schema.ResourceData) error { +func mapDataAccountToResource(account *cfclient.Account, d *schema.ResourceData) error { if account == nil || account.ID == "" { return fmt.Errorf("data.codefresh_account - failed to mapDataAccountToResource") diff --git a/codefresh/data_context.go b/codefresh/data_context.go index ddabff6b..032b51bb 100644 --- a/codefresh/data_context.go +++ b/codefresh/data_context.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/ghodss/yaml" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -31,8 +31,8 @@ func dataSourceContext() *schema.Resource { func dataSourceContextRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) - var context *cfClient.Context + client := meta.(*cfclient.Client) + var context *cfclient.Context var err error if name, nameOk := d.GetOk("name"); nameOk { @@ -51,7 +51,7 @@ func dataSourceContextRead(d *schema.ResourceData, meta interface{}) error { return mapDataContextToResource(context, d) } -func mapDataContextToResource(context *cfClient.Context, d *schema.ResourceData) error { +func mapDataContextToResource(context *cfclient.Context, d *schema.ResourceData) error { if context == nil || context.Metadata.Name == "" { return fmt.Errorf("data.codefresh_context - failed to mapDataContextToResource") diff --git a/codefresh/data_current_account.go b/codefresh/data_current_account.go index 3214823b..943d4568 100644 --- a/codefresh/data_current_account.go +++ b/codefresh/data_current_account.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -45,8 +45,8 @@ func dataSourceCurrentAccount() *schema.Resource { } func dataSourceCurrentAccountRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) - var currentAccount *cfClient.CurrentAccount + client := meta.(*cfclient.Client) + var currentAccount *cfclient.CurrentAccount var err error currentAccount, err = client.GetCurrentAccount() @@ -62,7 +62,7 @@ func dataSourceCurrentAccountRead(d *schema.ResourceData, meta interface{}) erro } -func mapDataCurrentAccountToResource(currentAccount *cfClient.CurrentAccount, d *schema.ResourceData) error { +func mapDataCurrentAccountToResource(currentAccount *cfclient.CurrentAccount, d *schema.ResourceData) error { if currentAccount == nil || currentAccount.ID == "" { return fmt.Errorf("data.codefresh_current_account - failed to mapDataCurrentAccountToResource") diff --git a/codefresh/data_idps.go b/codefresh/data_idps.go index 9c6b8c8f..0d1ca682 100644 --- a/codefresh/data_idps.go +++ b/codefresh/data_idps.go @@ -3,7 +3,8 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -85,7 +86,7 @@ func IdpSchema() map[string]*schema.Schema { func dataSourceIdpRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) idps, err := client.GetIDPs() if err != nil { @@ -126,13 +127,13 @@ func dataSourceIdpRead(d *schema.ResourceData, meta interface{}) error { return nil } -func mapDataIdpToResource(idp cfClient.IDP, d *schema.ResourceData) error { +func mapDataIdpToResource(idp cfclient.IDP, d *schema.ResourceData) error { d.SetId(idp.ID) d.Set("access_token", idp.Access_token) // string `json:"access_token,omitempty"` - d.Set("accounts", flattenStringArr(idp.Accounts)) // + d.Set("accounts", datautil.FlattenStringArr(idp.Accounts)) // //d.Set("apiHost", idp.ApiHost) // string `json:"apiHost,omitempty"` //d.Set("apiPathPrefix", idp.ApiPathPrefix) // string `json:"apiPathPrefix,omitempty"` //d.Set("apiURL", idp.ApiURL) // string `json:"apiURL,omitempty"` @@ -152,8 +153,8 @@ func mapDataIdpToResource(idp cfClient.IDP, d *schema.ResourceData) error { //d.Set("redirectUiUrl", idp.RedirectUiUrl) // string `json:"redirectUiUrl,omitempty"` //d.Set("redirectUrl", idp.RedirectUrl) // string `json:"redirectUrl,omitempty"` //d.Set("refreshTokenURL", idp.RefreshTokenURL) // string `json:"refreshTokenURL,omitempty"` - d.Set("scopes", flattenStringArr(idp.Scopes)) // []string `json:"scopes,omitempty"` - d.Set("tenant", idp.Tenant) // string `json:"tenant,omitempty"` + d.Set("scopes", datautil.FlattenStringArr(idp.Scopes)) // []string `json:"scopes,omitempty"` + d.Set("tenant", idp.Tenant) // string `json:"tenant,omitempty"` //d.Set("tokenSecret", idp.TokenSecret) // string `json:"tokenSecret,omitempty"` //d.Set("tokenURL", idp.TokenURL) // string `json:"tokenURL,omitempty"` //d.Set("userProfileURL", idp.UserProfileURL) // string `json:"userProfileURL,omitempty"` diff --git a/codefresh/data_pipelines.go b/codefresh/data_pipelines.go index 681489a5..b9a14093 100644 --- a/codefresh/data_pipelines.go +++ b/codefresh/data_pipelines.go @@ -5,7 +5,7 @@ import ( "regexp" "time" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -59,7 +59,7 @@ func dataSourcePipelines() *schema.Resource { func dataSourcePipelinesRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) pipelines, err := client.GetPipelines() if err != nil { @@ -76,7 +76,7 @@ func dataSourcePipelinesRead(d *schema.ResourceData, meta interface{}) error { return nil } -func mapDataPipelinesToResource(pipelines []cfClient.Pipeline, d *schema.ResourceData) error { +func mapDataPipelinesToResource(pipelines []cfclient.Pipeline, d *schema.ResourceData) error { var res = make([]map[string]interface{}, len(pipelines)) for i, p := range pipelines { m := make(map[string]interface{}) diff --git a/codefresh/data_registry.go b/codefresh/data_registry.go index 4e0ea86f..10964757 100644 --- a/codefresh/data_registry.go +++ b/codefresh/data_registry.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -50,8 +50,8 @@ func dataSourceRegistry() *schema.Resource { func dataSourceRegistryRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) - var registry *cfClient.Registry + client := meta.(*cfclient.Client) + var registry *cfclient.Registry var err error if name, nameOk := d.GetOk("name"); nameOk { @@ -70,7 +70,7 @@ func dataSourceRegistryRead(d *schema.ResourceData, meta interface{}) error { return mapDataRegistryToResource(registry, d) } -func mapDataRegistryToResource(registry *cfClient.Registry, d *schema.ResourceData) error { +func mapDataRegistryToResource(registry *cfclient.Registry, d *schema.ResourceData) error { if registry == nil || registry.Name == "" { return fmt.Errorf("data.codefresh_registry - failed to mapDataRegistryToResource") diff --git a/codefresh/data_step_types.go b/codefresh/data_step_types.go index 07eca94f..7e8f9504 100644 --- a/codefresh/data_step_types.go +++ b/codefresh/data_step_types.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -39,14 +39,14 @@ func dataSourceStepTypes() *schema.Resource { func dataSourceStepTypesRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) var err error var versions []string stepTypesIdentifier := d.Get("name").(string) d.SetId(stepTypesIdentifier) if versions, err = client.GetStepTypesVersions(stepTypesIdentifier); err == nil { - var stepVersions cfClient.StepTypesVersions + var stepVersions cfclient.StepTypesVersions stepVersions.Name = stepTypesIdentifier d.Set("versions", versions) for _, version := range versions { @@ -54,7 +54,7 @@ func dataSourceStepTypesRead(d *schema.ResourceData, meta interface{}) error { if err != nil { log.Printf("[DEBUG] Skipping version %v due to error %v", version, err) } else { - stepVersion := cfClient.StepTypesVersion{ + stepVersion := cfclient.StepTypesVersion{ VersionNumber: version, StepTypes: *stepTypes, } @@ -68,7 +68,7 @@ func dataSourceStepTypesRead(d *schema.ResourceData, meta interface{}) error { } -func mapDataSetTypesToResource(stepTypesVersions cfClient.StepTypesVersions, d *schema.ResourceData) error { +func mapDataSetTypesToResource(stepTypesVersions cfclient.StepTypesVersions, d *schema.ResourceData) error { err := d.Set("name", stepTypesVersions.Name) if err != nil { return err diff --git a/codefresh/data_team.go b/codefresh/data_team.go index aa340c84..ce63d6a5 100644 --- a/codefresh/data_team.go +++ b/codefresh/data_team.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -48,8 +48,8 @@ func dataSourceTeam() *schema.Resource { func dataSourceTeamRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) - var team *cfClient.Team + client := meta.(*cfclient.Client) + var team *cfclient.Team var err error if _id, _idOk := d.GetOk("_id"); _idOk { @@ -71,7 +71,7 @@ func dataSourceTeamRead(d *schema.ResourceData, meta interface{}) error { } -func mapDataTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { +func mapDataTeamToResource(team *cfclient.Team, d *schema.ResourceData) error { if team == nil || team.ID == "" { return fmt.Errorf("data.codefresh_team - failed to mapDataTeamToResource") diff --git a/codefresh/data_user.go b/codefresh/data_user.go index ed7f91f8..732646c3 100644 --- a/codefresh/data_user.go +++ b/codefresh/data_user.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -18,7 +18,7 @@ func dataSourceUser() *schema.Resource { func dataSourceUserRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) users, err := client.GetAllUsers() if err != nil { @@ -43,7 +43,7 @@ func dataSourceUserRead(d *schema.ResourceData, meta interface{}) error { return nil } -func mapDataUserToResource(user cfClient.User, d *schema.ResourceData) error { +func mapDataUserToResource(user cfclient.User, d *schema.ResourceData) error { d.SetId(user.ID) d.Set("user_id", user.ID) @@ -63,7 +63,7 @@ func mapDataUserToResource(user cfClient.User, d *schema.ResourceData) error { return nil } -func flattenPersonal(personal *cfClient.Personal) []map[string]interface{} { +func flattenPersonal(personal *cfclient.Personal) []map[string]interface{} { return []map[string]interface{}{ { "first_name": personal.FirstName, @@ -75,7 +75,7 @@ func flattenPersonal(personal *cfClient.Personal) []map[string]interface{} { } } -func flattenLogins(logins *[]cfClient.Login) []map[string]interface{} { +func flattenLogins(logins *[]cfclient.Login) []map[string]interface{} { var res = make([]map[string]interface{}, len(*logins)) for i, login := range *logins { diff --git a/codefresh/data_users.go b/codefresh/data_users.go index 43cd89d1..5ae44de5 100644 --- a/codefresh/data_users.go +++ b/codefresh/data_users.go @@ -3,7 +3,7 @@ package codefresh import ( "time" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -25,7 +25,7 @@ func dataSourceUsers() *schema.Resource { func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) users, err := client.GetAllUsers() if err != nil { @@ -42,7 +42,7 @@ func dataSourceUsersRead(d *schema.ResourceData, meta interface{}) error { return nil } -func mapDataUsersToResource(users []cfClient.User, d *schema.ResourceData) error { +func mapDataUsersToResource(users []cfclient.User, d *schema.ResourceData) error { var res = make([]map[string]interface{}, len(users)) for i, user := range users { diff --git a/codefresh/internal/acctestutil/doc.go b/codefresh/internal/acctestutil/doc.go new file mode 100644 index 00000000..b539d507 --- /dev/null +++ b/codefresh/internal/acctestutil/doc.go @@ -0,0 +1,2 @@ +// Package acctestutil provides utilities for Terraform acceptance tests. +package acctestutil diff --git a/codefresh/internal/acctestutil/resource.go b/codefresh/internal/acctestutil/resource.go new file mode 100644 index 00000000..a8320638 --- /dev/null +++ b/codefresh/internal/acctestutil/resource.go @@ -0,0 +1,20 @@ +package acctestutil + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +// TestAccGetResourceId returns the ID of the resource with the given name, +// when provided with the Terraform state. +// +// This is useful for acceptance tests, in order to verify that a resource has +// been recreated and hence its ID has changed. +func GetResourceId(s *terraform.State, resourceName string) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("resource %s not found", resourceName) + } + return rs.Primary.ID, nil +} diff --git a/codefresh/internal/datautil/doc.go b/codefresh/internal/datautil/doc.go new file mode 100644 index 00000000..64abeee8 --- /dev/null +++ b/codefresh/internal/datautil/doc.go @@ -0,0 +1,2 @@ +// Package datautil provides utilities for working with data types. +package datautil diff --git a/codefresh/internal/datautil/strings.go b/codefresh/internal/datautil/strings.go new file mode 100644 index 00000000..004b544a --- /dev/null +++ b/codefresh/internal/datautil/strings.go @@ -0,0 +1,41 @@ +package datautil + +import ( + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" +) + +// ConvertStringArr converts an array of interfaces to an array of strings. +func ConvertStringArr(ifaceArr []interface{}) []string { + return ConvertAndMapStringArr(ifaceArr, func(s string) string { return s }) +} + +// ConvertAndMapStringArr converts an array of interfaces to an array of strings, +// applying the supplied function to each element. +func ConvertAndMapStringArr(ifaceArr []interface{}, f func(string) string) []string { + var arr []string + for _, v := range ifaceArr { + if v == nil { + continue + } + arr = append(arr, f(v.(string))) + } + return arr +} + +// ConvertVariables converts an array of cfclient.Variables to a map of key/value pairs. +func ConvertVariables(vars []cfclient.Variable) map[string]string { + res := make(map[string]string, len(vars)) + for _, v := range vars { + res[v.Key] = v.Value + } + return res +} + +// FlattenStringArr flattens an array of strings. +func FlattenStringArr(sArr []string) []interface{} { + iArr := []interface{}{} + for _, s := range sArr { + iArr = append(iArr, s) + } + return iArr +} diff --git a/codefresh/internal/datautil/yaml.go b/codefresh/internal/datautil/yaml.go new file mode 100644 index 00000000..f1870222 --- /dev/null +++ b/codefresh/internal/datautil/yaml.go @@ -0,0 +1,52 @@ +package datautil + +import ( + "bytes" + "io/ioutil" + "strings" + + "github.com/mikefarah/yq/v4/pkg/yqlib" + "github.com/sclevine/yj/convert" + "gopkg.in/op/go-logging.v1" +) + +// Yq gets a value from a YAML string using yq +func Yq(yamlString string, expression string) (string, error) { + yqEncoder := yqlib.NewYamlEncoder(0, false, yqlib.NewDefaultYamlPreferences()) + yqDecoder := yqlib.NewYamlDecoder(yqlib.NewDefaultYamlPreferences()) + yqEvaluator := yqlib.NewStringEvaluator() + + // Disable yq logging + yqLogBackend := logging.AddModuleLevel(logging.NewLogBackend(ioutil.Discard, "", 0)) + yqlib.GetLogger().SetBackend(yqLogBackend) + + yamlString, err := yqEvaluator.Evaluate(yamlString, expression, yqEncoder, yqDecoder) + yamlString = strings.TrimSpace(yamlString) + + if yamlString == "null" { // yq's Evaluate() returns "null" if the expression does not match anything + return "", err + } + return yamlString, err +} + +// YamlToJson converts a YAML string to JSON +// +// This function preserves the order of map keys (courtesy of yj package). +// If this were to use yaml.Unmarshal() and json.Marshal() instead, the order of map keys would be lost. +func YamlToJson(yamlString string) (string, error) { + yamlConverter := convert.YAML{} + jsonConverter := convert.JSON{} + + yamlDecoded, err := yamlConverter.Decode(strings.NewReader(yamlString)) + if err != nil { + return "", err + } + + jsonBuffer := new(bytes.Buffer) + err = jsonConverter.Encode(jsonBuffer, yamlDecoded) + if err != nil { + return "", err + } + + return jsonBuffer.String(), nil +} diff --git a/codefresh/internal/schemautil/doc.go b/codefresh/internal/schemautil/doc.go new file mode 100644 index 00000000..eb588a09 --- /dev/null +++ b/codefresh/internal/schemautil/doc.go @@ -0,0 +1,2 @@ +// Package schemautil provides utilities for working with Terraform resource schemas. +package schemautil diff --git a/codefresh/internal/schemautil/normalize.go b/codefresh/internal/schemautil/normalize.go new file mode 100644 index 00000000..12b40ec3 --- /dev/null +++ b/codefresh/internal/schemautil/normalize.go @@ -0,0 +1,57 @@ +package schemautil + +import ( + "log" + "regexp" + + "gopkg.in/yaml.v2" +) + +const ( + NormalizedFieldNameRegex string = `[^a-z0-9_]+` +) + +// NormalizeFieldName normalizes a field name to be lowercase and contain only alphanumeric characters and dashes. +func NormalizeFieldName(fieldName string) (string, error) { + reg, err := regexp.Compile(NormalizedFieldNameRegex) + if err != nil { + return "", err + } + return reg.ReplaceAllString(fieldName, ""), nil +} + +// MustNormalizeFieldName is the same as NormalizeFieldName, but will log an error (legacy logging) instead of returning it. +func MustNormalizeFieldName(fieldName string) string { + normalizedFieldName, err := NormalizeFieldName(fieldName) + if err != nil { + log.Printf("[ERROR] Failed to normalize field name %q: %s", fieldName, err) + } + return normalizedFieldName +} + +// NormalizeYAMLString normalizes a YAML string to a standardized order, format and indentation. +func NormalizeYamlString(yamlString interface{}) (string, error) { + var j map[string]interface{} + + if yamlString == nil || yamlString.(string) == "" { + return "", nil + } + + s := yamlString.(string) + err := yaml.Unmarshal([]byte(s), &j) + if err != nil { + return s, err + } + + bytes, _ := yaml.Marshal(j) + return string(bytes[:]), nil +} + +// MustNormalizeYamlString is the same as NormalizeYamlString, but will log an error (legacy logging) instead of returning it. +func MustNormalizeYamlString(yamlString interface{}) string { + normalizedYamlString, err := NormalizeYamlString(yamlString) + if err != nil { + log.Printf("[ERROR] Failed to normalize YAML string %q: %s", yamlString, err) + } + return normalizedYamlString +} diff --git a/codefresh/internal/schemautil/supressdiff.go b/codefresh/internal/schemautil/supressdiff.go new file mode 100644 index 00000000..ff49330b --- /dev/null +++ b/codefresh/internal/schemautil/supressdiff.go @@ -0,0 +1,34 @@ +// Package schemautil provides utilities for working with Terraform resource schemas. +// +// Note that this package uses legacy logging because the provider context is not available +package schemautil + +import ( + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + normalizationFailedErrorFormat = "[ERROR] Unable to normalize data body: %s" +) + +// SuppressEquivalentYamlDiffs returns SchemaDiffSuppressFunc that suppresses diffs between +// equivalent YAML strings. +func SuppressEquivalentYamlDiffs() schema.SchemaDiffSuppressFunc { + return func(k, old, new string, d *schema.ResourceData) bool { + normalizedOld, err := NormalizeYamlString(old) + if err != nil { + log.Printf(normalizationFailedErrorFormat, err) + return false + } + + normalizedNew, err := NormalizeYamlString(new) + if err != nil { + log.Printf(normalizationFailedErrorFormat, err) + return false + } + + return normalizedOld == normalizedNew + } +} diff --git a/codefresh/internal/schemautil/validation.go b/codefresh/internal/schemautil/validation.go new file mode 100644 index 00000000..263ae1fa --- /dev/null +++ b/codefresh/internal/schemautil/validation.go @@ -0,0 +1,92 @@ +package schemautil + +import ( + "github.com/dlclark/regexp2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/robfig/cron" +) + +type ValidationOptions struct { + severity diag.Severity + summary string + detailFormat string + cronValidationOptions *CronValidationOptions + stringValidationOptions *StringValidationOptions +} + +type ValidationOptionSetter func(*ValidationOptions) + +// NewValidationOptions returns a new ValidationOptions struct with default values. +func NewValidationOptions() *ValidationOptions { + return &ValidationOptions{ + severity: diag.Error, + summary: "", + detailFormat: "", + cronValidationOptions: &CronValidationOptions{ + parser: cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow), + }, + stringValidationOptions: &StringValidationOptions{ + regexp2.RE2, + }, + } +} + +// WithSeverity overrides the severity of the validation error. +func WithSeverity(severity diag.Severity) ValidationOptionSetter { + return func(o *ValidationOptions) { + o.setSeverity(severity) + } +} + +// WithSummary overrides the summary of the validation error. +func WithSummary(summary string) ValidationOptionSetter { + return func(o *ValidationOptions) { + o.setSummary(summary) + } +} + +// WithDetailFormat overrides the detail format string of the validation error. +// +// This string is passed to fmt.Sprintf. +// The verbs used in the format string depend on the implementation of the validation function. +func WithDetailFormat(detailFormat string) ValidationOptionSetter { + return func(o *ValidationOptions) { + o.setDetailFormat(detailFormat) + } +} + +// WithParser overrides the cron parser used to validate cron expressions. +func WithCronParser(parser cron.Parser) ValidationOptionSetter { + return func(o *ValidationOptions) { + o.setCronParser(parser) + } +} + +// WithRegexOptions overrides the regex options used to validate regular expressions. +func WithRegexOptions(options regexp2.RegexOptions) ValidationOptionSetter { + return func(o *ValidationOptions) { + o.setRegexOptions(options) + } +} + +func (o *ValidationOptions) apply(setters []ValidationOptionSetter) *ValidationOptions { + for _, opt := range setters { + opt(o) + } + return o +} + +func (o *ValidationOptions) setSeverity(severity diag.Severity) *ValidationOptions { + o.severity = severity + return o +} + +func (o *ValidationOptions) setSummary(summary string) *ValidationOptions { + o.summary = summary + return o +} + +func (o *ValidationOptions) setDetailFormat(detailFormat string) *ValidationOptions { + o.detailFormat = detailFormat + return o +} \ No newline at end of file diff --git a/codefresh/internal/schemautil/validation_cron.go b/codefresh/internal/schemautil/validation_cron.go new file mode 100644 index 00000000..de33cde1 --- /dev/null +++ b/codefresh/internal/schemautil/validation_cron.go @@ -0,0 +1,46 @@ +package schemautil + +import ( + "fmt" + + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/robfig/cron" +) + +// CronValidationOptions contains options for validating cron expressions. +type CronValidationOptions struct { + parser cron.Parser +} + +func (o *ValidationOptions) setCronParser(parser cron.Parser) *ValidationOptions { + o.cronValidationOptions.parser = parser + return o +} + +// CronExpression returns a SchemaValidateDiagFunc that validates a cron expression. +func CronExpression(opts ...ValidationOptionSetter) schema.SchemaValidateDiagFunc { + // Cron expression requirements: 5 fields, with ability to use descriptors (e.g. @yearly) + parser := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor) + options := NewValidationOptions(). + setSeverity(diag.Error). + setSummary("Invalid cron expression."). + setDetailFormat("The cron expression %q is invalid: %s"). + setCronParser(parser). + apply(opts) + + return func(v interface{}, path cty.Path) (diags diag.Diagnostics) { + expression := v.(string) + + if _, err := options.cronValidationOptions.parser.Parse(expression); err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: options.severity, + Summary: options.summary, + Detail: fmt.Sprintf(options.detailFormat, expression, err), + }) + } + + return diags + } +} diff --git a/codefresh/internal/schemautil/validation_strings.go b/codefresh/internal/schemautil/validation_strings.go new file mode 100644 index 00000000..0f47b009 --- /dev/null +++ b/codefresh/internal/schemautil/validation_strings.go @@ -0,0 +1,99 @@ +package schemautil + +import ( + "fmt" + "regexp" + + "github.com/dlclark/regexp2" + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// StringValidationOptions contains options for validating strings. +type StringValidationOptions struct { + regexOptions regexp2.RegexOptions +} + +// See: https://github.com/dlclark/regexp2/blob/03d34d8ad254ae4e2fb4f58e0723420efa1c7c07/regexp.go#L124-L142 +func (o *ValidationOptions) setRegexOptions(regexOptions regexp2.RegexOptions) *ValidationOptions { + o.stringValidationOptions.regexOptions = regexOptions + return o +} + +// StringIsValidRegExp returns a SchemaValidateDiagFunc which validates that a string is a valid regular expression. +// +// This function has similar functionality to StringIsValidRegExp from the terraform plugin SDK. +// https://github.com/hashicorp/terraform-plugin-sdk/blob/695f0c7b92e26444786b8963e00c665f1b4ef400/helper/validation/strings.go#L225 +// It has been modified to use the library https://github.com/dlclark/regexp2 instead of the standard regex golang package +// in order to support complex regular expressions including perl regex syntax. +// +// It has also been modified to conform to the SchemaValidateDiagFunc type instead of the deprecated SchemaValidateFunc type. +func StringIsValidRegExp(opts ...ValidationOptionSetter) schema.SchemaValidateDiagFunc { + options := NewValidationOptions(). + setSeverity(diag.Error). + setSummary("Invalid regular expression."). + setDetailFormat("%q: %s"). + apply(opts) + + return func(v any, p cty.Path) diag.Diagnostics { + value := v.(string) + var diags diag.Diagnostics + if _, err := regexp2.Compile(value, regexp2.RE2); err != nil { + diag := diag.Diagnostic{ + Severity: options.severity, + Summary: options.summary, + Detail: fmt.Sprintf(options.detailFormat, p, err), + } + diags = append(diags, diag) + } + + return diags + } +} + +// StringIsValidYaml returns a SchemaValidateDiagFunc which validates that a string is valid YAML. +func StringIsValidYaml(opts ...ValidationOptionSetter) schema.SchemaValidateDiagFunc { + options := NewValidationOptions(). + setSeverity(diag.Error). + setSummary("Invalid YAML"). + setDetailFormat("%s is not valid YAML: %s"). + apply(opts) + + return func(v any, p cty.Path) diag.Diagnostics { + value := v.(string) + var diags diag.Diagnostics + if _, err := NormalizeYamlString(value); err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: options.severity, + Summary: options.summary, + Detail: fmt.Sprintf(options.detailFormat, p, err), + }) + } + return diags + } +} + +// StringMatchesRegExp returns a SchemaValidateDiagFunc which validates that a string matches a regular expression. +func StringMatchesRegExp(regex string, opts ...ValidationOptionSetter) schema.SchemaValidateDiagFunc { + options := NewValidationOptions(). + setSeverity(diag.Error). + setSummary("Invalid value"). + setDetailFormat("%s is invalid (must match %q)"). + setRegexOptions(regexp2.RE2). + apply(opts) + + return func(v any, p cty.Path) diag.Diagnostics { + value := v.(string) + var diags diag.Diagnostics + re := regexp.MustCompile(regex) + if !re.MatchString(value) { + diags = append(diags, diag.Diagnostic{ + Severity: options.severity, + Summary: options.summary, + Detail: fmt.Sprintf(options.detailFormat, value, re.String()), + }) + } + return diags + } +} diff --git a/codefresh/internal/schemautil/validation_values.go b/codefresh/internal/schemautil/validation_values.go new file mode 100644 index 00000000..1b8231f9 --- /dev/null +++ b/codefresh/internal/schemautil/validation_values.go @@ -0,0 +1,6 @@ +package schemautil + +const ( + // https://github.com/codefresh-io/hermes/blob/6d75b347cb8ff471ce970a766b2285788e5e19fe/pkg/backend/dev_compose_types.json#L226 + ValidCronMessageRegex string = `^[a-zA-Z0-9_+\s-#?.:]{2,128}$` +) diff --git a/codefresh/provider.go b/codefresh/provider.go index 5a7003a1..c79e8086 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -3,7 +3,7 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "os" @@ -81,5 +81,5 @@ func configureProvider(d *schema.ResourceData) (interface{}, error) { if token == "" { token = os.Getenv(ENV_CODEFRESH_API_KEY) } - return cfClient.NewClient(apiURL, apiURLV2, token, ""), nil + return cfclient.NewClient(apiURL, apiURLV2, token, ""), nil } diff --git a/codefresh/resource_abac_rules.go b/codefresh/resource_abac_rules.go index 648b2564..ec7561ed 100644 --- a/codefresh/resource_abac_rules.go +++ b/codefresh/resource_abac_rules.go @@ -5,7 +5,8 @@ import ( "fmt" "log" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -118,7 +119,7 @@ func contains(slice []string, element string) bool { } func resourceGitopsAbacRuleCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) abacRule := *mapResourceToGitopsAbacRule(d) @@ -137,7 +138,7 @@ func resourceGitopsAbacRuleCreate(d *schema.ResourceData, meta interface{}) erro func resourceGitopsAbacRuleRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) abacRuleID := d.Id() if abacRuleID == "" { @@ -159,7 +160,7 @@ func resourceGitopsAbacRuleRead(d *schema.ResourceData, meta interface{}) error } func resourceGitopsAbacRuleUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) abacRule := *mapResourceToGitopsAbacRule(d) resp, err := client.CreateAbacRule(&abacRule) @@ -177,7 +178,7 @@ func resourceGitopsAbacRuleUpdate(d *schema.ResourceData, meta interface{}) erro } func resourceGitopsAbacRuleDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) _, err := client.DeleteAbacRule(d.Id()) if err != nil { @@ -187,7 +188,7 @@ func resourceGitopsAbacRuleDelete(d *schema.ResourceData, meta interface{}) erro return nil } -func flattenAttributes(attributes []cfClient.EntityAbacAttribute) []map[string]interface{} { +func flattenAttributes(attributes []cfclient.EntityAbacAttribute) []map[string]interface{} { var res = make([]map[string]interface{}, len(attributes)) for i, attribute := range attributes { m := make(map[string]interface{}) @@ -199,7 +200,7 @@ func flattenAttributes(attributes []cfClient.EntityAbacAttribute) []map[string]i return res } -func mapGitopsAbacRuleToResource(abacRule *cfClient.GitopsAbacRule, d *schema.ResourceData) error { +func mapGitopsAbacRuleToResource(abacRule *cfclient.GitopsAbacRule, d *schema.ResourceData) error { err := d.Set("id", abacRule.ID) if err != nil { @@ -236,28 +237,28 @@ func mapGitopsAbacRuleToResource(abacRule *cfClient.GitopsAbacRule, d *schema.Re return nil } -func mapResourceToGitopsAbacRule(d *schema.ResourceData) *cfClient.GitopsAbacRule { +func mapResourceToGitopsAbacRule(d *schema.ResourceData) *cfclient.GitopsAbacRule { tagsI := d.Get("tags").(*schema.Set).List() var tags []string if len(tagsI) > 0 { - tags = convertStringArr(tagsI) + tags = datautil.ConvertStringArr(tagsI) } else { tags = []string{"*", "untagged"} } - abacRule := &cfClient.GitopsAbacRule{ + abacRule := &cfclient.GitopsAbacRule{ ID: d.Id(), EntityType: d.Get("entity_type").(string), - Teams: convertStringArr(d.Get("teams").(*schema.Set).List()), + Teams: datautil.ConvertStringArr(d.Get("teams").(*schema.Set).List()), Tags: tags, - Actions: convertStringArr(d.Get("actions").(*schema.Set).List()), - Attributes: []cfClient.EntityAbacAttribute{}, + Actions: datautil.ConvertStringArr(d.Get("actions").(*schema.Set).List()), + Attributes: []cfclient.EntityAbacAttribute{}, } attributes := d.Get("attribute").([]interface{}) for idx := range attributes { - attr := cfClient.EntityAbacAttribute{ + attr := cfclient.EntityAbacAttribute{ Name: d.Get(fmt.Sprintf("attribute.%v.name", idx)).(string), Key: d.Get(fmt.Sprintf("attribute.%v.key", idx)).(string), Value: d.Get(fmt.Sprintf("attribute.%v.value", idx)).(string), diff --git a/codefresh/resource_abac_rules_test.go b/codefresh/resource_abac_rules_test.go index b7f2e657..caa10aad 100644 --- a/codefresh/resource_abac_rules_test.go +++ b/codefresh/resource_abac_rules_test.go @@ -2,11 +2,12 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "strings" "testing" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" funk "github.com/thoas/go-funk" ) @@ -61,7 +62,7 @@ func testAccCheckCodefreshAbacRulesExists(resource string) resource.TestCheckFun abacRuleID := rs.Primary.ID - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) _, err := apiClient.GetAbacRuleByID(abacRuleID) if err != nil { diff --git a/codefresh/resource_account.go b/codefresh/resource_account.go index 63a3e120..0fbb7bf0 100644 --- a/codefresh/resource_account.go +++ b/codefresh/resource_account.go @@ -1,7 +1,7 @@ package codefresh import ( - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -92,7 +92,7 @@ customKubernetesCluster: true func resourceAccountCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) account := *mapResourceToAccount(d) @@ -108,7 +108,7 @@ func resourceAccountCreate(d *schema.ResourceData, meta interface{}) error { func resourceAccountRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) accountID := d.Id() if accountID == "" { @@ -131,7 +131,7 @@ func resourceAccountRead(d *schema.ResourceData, meta interface{}) error { func resourceAccountUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) account := *mapResourceToAccount(d) @@ -144,7 +144,7 @@ func resourceAccountUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceAccountDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) err := client.DeleteAccount(d.Id()) if err != nil { @@ -154,7 +154,7 @@ func resourceAccountDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapAccountToResource(account *cfClient.Account, d *schema.ResourceData) error { +func mapAccountToResource(account *cfclient.Account, d *schema.ResourceData) error { err := d.Set("name", account.Name) if err != nil { return err @@ -180,21 +180,21 @@ func mapAccountToResource(account *cfClient.Account, d *schema.ResourceData) err return nil } -func flattenLimits(limits cfClient.Limits) map[string]interface{} { +func flattenLimits(limits cfclient.Limits) map[string]interface{} { res := make(map[string]interface{}) res["collaborators"] = limits.Collaborators.Limit res["data_retention_weeks"] = limits.DataRetention.Weeks return res } -func flattenBuild(build cfClient.Build) map[string]interface{} { +func flattenBuild(build cfclient.Build) map[string]interface{} { res := make(map[string]interface{}) res["parallel"] = build.Parallel res["nodes"] = build.Nodes return res } -func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { - account := &cfClient.Account{ +func mapResourceToAccount(d *schema.ResourceData) *cfclient.Account { + account := &cfclient.Account{ ID: d.Id(), Name: d.Get("name").(string), } @@ -203,18 +203,18 @@ func mapResourceToAccount(d *schema.ResourceData) *cfClient.Account { account.SetFeatures(d.Get("features").(map[string]interface{})) } if _, ok := d.GetOk("limits"); ok { - account.Limits = &cfClient.Limits{ - Collaborators: cfClient.Collaborators{ + account.Limits = &cfclient.Limits{ + Collaborators: cfclient.Collaborators{ Limit: d.Get("limits.0.collaborators").(int), }, - DataRetention: cfClient.DataRetention{ + DataRetention: cfclient.DataRetention{ Weeks: d.Get("limits.0.data_retention_weeks").(int), }, } } if _, ok := d.GetOk("build"); ok { - account.Build = &cfClient.Build{ + account.Build = &cfclient.Build{ Parallel: d.Get("build.0.parallel").(int), Nodes: d.Get("build.0.nodes").(int), } diff --git a/codefresh/resource_account_admins.go b/codefresh/resource_account_admins.go index 85342b8b..93b39376 100644 --- a/codefresh/resource_account_admins.go +++ b/codefresh/resource_account_admins.go @@ -1,7 +1,8 @@ package codefresh import ( - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -37,13 +38,13 @@ func resourceAccountAdmins() *schema.Resource { func resourceAccountAdminsCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) admins := d.Get("users").(*schema.Set).List() accountId := d.Get("account_id").(string) - for _, admin := range convertStringArr(admins) { + for _, admin := range datautil.ConvertStringArr(admins) { err := client.SetUserAsAccountAdmin(accountId, admin) if err != nil { return err @@ -58,13 +59,13 @@ func resourceAccountAdminsCreate(d *schema.ResourceData, meta interface{}) error func resourceAccountAdminsDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) admins := d.Get("users").(*schema.Set).List() accountId := d.Get("account_id").(string) - for _, admin := range convertStringArr(admins) { + for _, admin := range datautil.ConvertStringArr(admins) { err := client.DeleteUserAsAccountAdmin(accountId, admin) if err != nil { return err @@ -76,7 +77,7 @@ func resourceAccountAdminsDelete(d *schema.ResourceData, meta interface{}) error func resourceAccountAdminsRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) accountId := d.Id() @@ -96,7 +97,7 @@ func resourceAccountAdminsRead(d *schema.ResourceData, meta interface{}) error { func resourceAccountAdminsUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) accountId := d.Get("account_id").(string) desiredAdmins := d.Get("users").(*schema.Set).List() @@ -106,7 +107,7 @@ func resourceAccountAdminsUpdate(d *schema.ResourceData, meta interface{}) error return err } - adminsToAdd, AdminsToDelete := cfClient.GetAccountAdminsDiff(convertStringArr(desiredAdmins), account.Admins) + adminsToAdd, AdminsToDelete := cfclient.GetAccountAdminsDiff(datautil.ConvertStringArr(desiredAdmins), account.Admins) for _, userId := range AdminsToDelete { err := client.DeleteUserAsAccountAdmin(accountId, userId) diff --git a/codefresh/resource_account_user_association.go b/codefresh/resource_account_user_association.go index 7b3e9f02..a036844f 100644 --- a/codefresh/resource_account_user_association.go +++ b/codefresh/resource_account_user_association.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -58,7 +58,7 @@ func resourceAccountUserAssociation() *schema.Resource { } func resourceAccountUserAssociationCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) currentAccount, err := client.GetCurrentAccount() if err != nil { return err @@ -84,7 +84,7 @@ func resourceAccountUserAssociationCreate(d *schema.ResourceData, meta interface } func resourceAccountUserAssociationRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) currentAccount, err := client.GetCurrentAccount() if err != nil { return err @@ -118,7 +118,7 @@ func resourceAccountUserAssociationRead(d *schema.ResourceData, meta interface{} } func resourceAccountUserAssociationUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) currentAccount, err := client.GetCurrentAccount() if err != nil { @@ -153,7 +153,7 @@ func resourceAccountUserAssociationUpdate(d *schema.ResourceData, meta interface } func resourceAccountUserAssociationDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) currentAccount, err := client.GetCurrentAccount() if err != nil { diff --git a/codefresh/resource_account_user_association_test.go b/codefresh/resource_account_user_association_test.go index 426317d3..a74084db 100644 --- a/codefresh/resource_account_user_association_test.go +++ b/codefresh/resource_account_user_association_test.go @@ -4,7 +4,8 @@ import ( "fmt" "testing" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/acctestutil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -16,7 +17,7 @@ func testAccCodefreshAccountUserAssociationGenerateUserEmail() string { } func testAccCodefreshActivateUser(s *terraform.State, email string) error { - c := testAccProvider.Meta().(*cfClient.Client) + c := testAccProvider.Meta().(*cfclient.Client) currentAccount, err := c.GetCurrentAccount() if err != nil { return fmt.Errorf("failed to get current account: %s", err) @@ -94,7 +95,7 @@ func TestAccCodefreshAccountUserAssociation_StatusPending_Email_ForceNew(t *test { RefreshState: true, Check: func(s *terraform.State) error { - resourceId, err = testAccGetResourceId(s, resourceName) + resourceId, err = acctestutil.GetResourceId(s, resourceName) return err }, }, @@ -110,7 +111,7 @@ func TestAccCodefreshAccountUserAssociation_StatusPending_Email_ForceNew(t *test // Test that an email change on a pending user does NOT force a new resource RefreshState: true, Check: func(s *terraform.State) error { - newResourceId, err := testAccGetResourceId(s, resourceName) + newResourceId, err := acctestutil.GetResourceId(s, resourceName) if err != nil { return err } @@ -147,7 +148,7 @@ func TestAccCodefreshAccountUserAssociation_StatusNew_Email_ForceNew(t *testing. { RefreshState: true, Check: func(s *terraform.State) error { - resourceId, err = testAccGetResourceId(s, resourceName) + resourceId, err = acctestutil.GetResourceId(s, resourceName) return err }, }, @@ -169,7 +170,7 @@ func TestAccCodefreshAccountUserAssociation_StatusNew_Email_ForceNew(t *testing. { RefreshState: true, Check: func(s *terraform.State) error { - newResourceId, err := testAccGetResourceId(s, resourceName) + newResourceId, err := acctestutil.GetResourceId(s, resourceName) if err != nil { return err } diff --git a/codefresh/resource_api_key.go b/codefresh/resource_api_key.go index 12c4d409..02fa573a 100644 --- a/codefresh/resource_api_key.go +++ b/codefresh/resource_api_key.go @@ -4,7 +4,8 @@ import ( "errors" "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -75,7 +76,7 @@ A list of access scopes for the API key. The possible values: } func resourceApiKeyCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) apiKey := *mapResourceToApiKey(d) accountID := d.Get("account_id").(string) @@ -117,7 +118,7 @@ func resourceApiKeyCreate(d *schema.ResourceData, meta interface{}) error { func resourceApiKeyRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) keyID := d.Id() if keyID == "" { @@ -147,7 +148,7 @@ func resourceApiKeyRead(d *schema.ResourceData, meta interface{}) error { } func resourceApiKeyUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) apiKey := *mapResourceToApiKey(d) @@ -167,7 +168,7 @@ func resourceApiKeyUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceApiKeyDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) token := d.Get("token").(string) if token == "" { @@ -182,7 +183,7 @@ func resourceApiKeyDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapApiKeyToResource(apiKey *cfClient.ApiKey, d *schema.ResourceData) error { +func mapApiKeyToResource(apiKey *cfclient.ApiKey, d *schema.ResourceData) error { err := d.Set("name", apiKey.Name) if err != nil { @@ -196,12 +197,12 @@ func mapApiKeyToResource(apiKey *cfClient.ApiKey, d *schema.ResourceData) error return nil } -func mapResourceToApiKey(d *schema.ResourceData) *cfClient.ApiKey { +func mapResourceToApiKey(d *schema.ResourceData) *cfclient.ApiKey { scopes := d.Get("scopes").(*schema.Set).List() - apiKey := &cfClient.ApiKey{ + apiKey := &cfclient.ApiKey{ ID: d.Id(), Name: d.Get("name").(string), - Scopes: convertStringArr(scopes), + Scopes: datautil.ConvertStringArr(scopes), } return apiKey } diff --git a/codefresh/resource_context.go b/codefresh/resource_context.go index eba49e94..bde0fc55 100644 --- a/codefresh/resource_context.go +++ b/codefresh/resource_context.go @@ -4,8 +4,9 @@ import ( "log" storageContext "github.com/codefresh-io/terraform-provider-codefresh/codefresh/context" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/schemautil" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/ghodss/yaml" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -29,9 +30,9 @@ var supportedContextType = []string{ func getConflictingContexts(context string) []string { var conflictingTypes []string - normalizedContext := normalizeFieldName(context) + normalizedContext := schemautil.MustNormalizeFieldName(context) for _, value := range supportedContextType { - normlizedValue := normalizeFieldName(value) + normlizedValue := schemautil.MustNormalizeFieldName(value) if normlizedValue != normalizedContext { conflictingTypes = append(conflictingTypes, "spec.0."+normlizedValue) } @@ -63,7 +64,7 @@ func resourceContext() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - normalizeFieldName(contextConfig): { + schemautil.MustNormalizeFieldName(contextConfig): { Type: schema.TypeList, ForceNew: true, Optional: true, @@ -82,7 +83,7 @@ func resourceContext() *schema.Resource { }, }, }, - normalizeFieldName(contextSecret): { + schemautil.MustNormalizeFieldName(contextSecret): { Type: schema.TypeList, Optional: true, ForceNew: true, @@ -102,7 +103,7 @@ func resourceContext() *schema.Resource { }, }, }, - normalizeFieldName(contextYaml): { + schemautil.MustNormalizeFieldName(contextYaml): { Type: schema.TypeList, Optional: true, ForceNew: true, @@ -114,17 +115,16 @@ func resourceContext() *schema.Resource { Description: "The YAML string representing the shared config.", Type: schema.TypeString, Required: true, - ValidateFunc: stringIsYaml, - DiffSuppressFunc: suppressEquivalentYamlDiffs, + ValidateDiagFunc: schemautil.StringIsValidYaml(), + DiffSuppressFunc: schemautil.SuppressEquivalentYamlDiffs(), StateFunc: func(v interface{}) string { - template, _ := normalizeYamlString(v) - return template + return schemautil.MustNormalizeYamlString(v) }, }, }, }, }, - normalizeFieldName(contextSecretYaml): { + schemautil.MustNormalizeFieldName(contextSecretYaml): { Type: schema.TypeList, Optional: true, ForceNew: true, @@ -137,19 +137,18 @@ func resourceContext() *schema.Resource { Type: schema.TypeString, Required: true, Sensitive: true, - ValidateFunc: stringIsYaml, - DiffSuppressFunc: suppressEquivalentYamlDiffs, + ValidateDiagFunc: schemautil.StringIsValidYaml(), + DiffSuppressFunc: schemautil.SuppressEquivalentYamlDiffs(), StateFunc: func(v interface{}) string { - template, _ := normalizeYamlString(v) - return template + return schemautil.MustNormalizeYamlString(v) }, }, }, }, }, - normalizeFieldName(contextGoogleStorage): storageContext.GcsSchema(), - normalizeFieldName(contextS3Storage): storageContext.S3Schema(), - normalizeFieldName(contextAzureStorage): storageContext.AzureStorage(), + schemautil.MustNormalizeFieldName(contextGoogleStorage): storageContext.GcsSchema(), + schemautil.MustNormalizeFieldName(contextS3Storage): storageContext.S3Schema(), + schemautil.MustNormalizeFieldName(contextAzureStorage): storageContext.AzureStorage(), }, }, }, @@ -159,7 +158,7 @@ func resourceContext() *schema.Resource { func resourceContextCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) resp, err := client.CreateContext(mapResourceToContext(d)) if err != nil { log.Printf("[DEBUG] Error while creating context. Error = %v", err) @@ -171,7 +170,7 @@ func resourceContextCreate(d *schema.ResourceData, meta interface{}) error { } func resourceContextRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) contextName := d.Id() @@ -197,7 +196,7 @@ func resourceContextRead(d *schema.ResourceData, meta interface{}) error { func resourceContextUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) context := *mapResourceToContext(d) context.Metadata.Name = d.Id() @@ -213,7 +212,7 @@ func resourceContextUpdate(d *schema.ResourceData, meta interface{}) error { func resourceContextDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) err := client.DeleteContext(d.Id()) if err != nil { @@ -223,7 +222,7 @@ func resourceContextDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapContextToResource(context cfClient.Context, d *schema.ResourceData) error { +func mapContextToResource(context cfclient.Context, d *schema.ResourceData) error { err := d.Set("name", context.Metadata.Name) if err != nil { @@ -239,20 +238,20 @@ func mapContextToResource(context cfClient.Context, d *schema.ResourceData) erro return nil } -func flattenContextSpec(spec cfClient.ContextSpec) []interface{} { +func flattenContextSpec(spec cfclient.ContextSpec) []interface{} { var res = make([]interface{}, 0) m := make(map[string]interface{}) switch currentContextType := spec.Type; currentContextType { case contextConfig, contextSecret: - m[normalizeFieldName(currentContextType)] = flattenContextConfig(spec) + m[schemautil.MustNormalizeFieldName(currentContextType)] = flattenContextConfig(spec) case contextYaml, contextSecretYaml: - m[normalizeFieldName(currentContextType)] = flattenContextYaml(spec) + m[schemautil.MustNormalizeFieldName(currentContextType)] = flattenContextYaml(spec) case contextGoogleStorage, contextS3Storage: - m[normalizeFieldName(currentContextType)] = storageContext.FlattenJsonConfigStorageContextConfig(spec) + m[schemautil.MustNormalizeFieldName(currentContextType)] = storageContext.FlattenJsonConfigStorageContextConfig(spec) case contextAzureStorage: - m[normalizeFieldName(currentContextType)] = storageContext.FlattenAzureStorageContextConfig(spec) + m[schemautil.MustNormalizeFieldName(currentContextType)] = storageContext.FlattenAzureStorageContextConfig(spec) default: log.Printf("[DEBUG] Invalid context type = %v", currentContextType) return nil @@ -262,7 +261,7 @@ func flattenContextSpec(spec cfClient.ContextSpec) []interface{} { return res } -func flattenContextConfig(spec cfClient.ContextSpec) []interface{} { +func flattenContextConfig(spec cfclient.ContextSpec) []interface{} { var res = make([]interface{}, 0) m := make(map[string]interface{}) m["data"] = spec.Data @@ -270,7 +269,7 @@ func flattenContextConfig(spec cfClient.ContextSpec) []interface{} { return res } -func flattenContextYaml(spec cfClient.ContextSpec) []interface{} { +func flattenContextYaml(spec cfclient.ContextSpec) []interface{} { var res = make([]interface{}, 0) m := make(map[string]interface{}) data, err := yaml.Marshal(spec.Data) @@ -282,39 +281,39 @@ func flattenContextYaml(spec cfClient.ContextSpec) []interface{} { return res } -func mapResourceToContext(d *schema.ResourceData) *cfClient.Context { +func mapResourceToContext(d *schema.ResourceData) *cfclient.Context { var normalizedContextType string var normalizedContextData map[string]interface{} - if data, ok := d.GetOk("spec.0." + normalizeFieldName(contextConfig) + ".0.data"); ok { + if data, ok := d.GetOk("spec.0." + schemautil.MustNormalizeFieldName(contextConfig) + ".0.data"); ok { normalizedContextType = contextConfig normalizedContextData = data.(map[string]interface{}) - } else if data, ok := d.GetOk("spec.0." + normalizeFieldName(contextSecret) + ".0.data"); ok { + } else if data, ok := d.GetOk("spec.0." + schemautil.MustNormalizeFieldName(contextSecret) + ".0.data"); ok { normalizedContextType = contextSecret normalizedContextData = data.(map[string]interface{}) - } else if data, ok := d.GetOk("spec.0." + normalizeFieldName(contextYaml) + ".0.data"); ok { + } else if data, ok := d.GetOk("spec.0." + schemautil.MustNormalizeFieldName(contextYaml) + ".0.data"); ok { normalizedContextType = contextYaml _ = yaml.Unmarshal([]byte(data.(string)), &normalizedContextData) - } else if data, ok := d.GetOk("spec.0." + normalizeFieldName(contextSecretYaml) + ".0.data"); ok { + } else if data, ok := d.GetOk("spec.0." + schemautil.MustNormalizeFieldName(contextSecretYaml) + ".0.data"); ok { normalizedContextType = contextSecretYaml _ = yaml.Unmarshal([]byte(data.(string)), &normalizedContextData) - } else if data, ok := d.GetOk("spec.0." + normalizeFieldName(contextGoogleStorage) + ".0.data"); ok { + } else if data, ok := d.GetOk("spec.0." + schemautil.MustNormalizeFieldName(contextGoogleStorage) + ".0.data"); ok { normalizedContextType = contextGoogleStorage normalizedContextData = storageContext.ConvertJsonConfigStorageContext(data.([]interface{})) - } else if data, ok := d.GetOk("spec.0." + normalizeFieldName(contextS3Storage) + ".0.data"); ok { + } else if data, ok := d.GetOk("spec.0." + schemautil.MustNormalizeFieldName(contextS3Storage) + ".0.data"); ok { normalizedContextType = contextS3Storage normalizedContextData = storageContext.ConvertJsonConfigStorageContext(data.([]interface{})) - } else if data, ok := d.GetOk("spec.0." + normalizeFieldName(contextAzureStorage) + ".0.data"); ok { + } else if data, ok := d.GetOk("spec.0." + schemautil.MustNormalizeFieldName(contextAzureStorage) + ".0.data"); ok { normalizedContextType = contextAzureStorage normalizedContextData = storageContext.ConvertAzureStorageContext(data.([]interface{})) } - return &cfClient.Context{ - Metadata: cfClient.ContextMetadata{ + return &cfclient.Context{ + Metadata: cfclient.ContextMetadata{ Name: d.Get("name").(string), }, - Spec: cfClient.ContextSpec{ + Spec: cfclient.ContextSpec{ Type: normalizedContextType, Data: normalizedContextData, }, diff --git a/codefresh/resource_context_test.go b/codefresh/resource_context_test.go index 5bf6a619..4e634c16 100644 --- a/codefresh/resource_context_test.go +++ b/codefresh/resource_context_test.go @@ -5,7 +5,7 @@ import ( "regexp" "testing" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -158,7 +158,7 @@ func testAccCheckCodefreshContextExists(resource string) resource.TestCheckFunc contextID := rs.Primary.ID - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) _, err := apiClient.GetContext(contextID) if err != nil { @@ -169,7 +169,7 @@ func testAccCheckCodefreshContextExists(resource string) resource.TestCheckFunc } func testAccCheckCodefreshContextDestroy(s *terraform.State) error { - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) for _, rs := range s.RootModule().Resources { diff --git a/codefresh/resource_idp_accounts.go b/codefresh/resource_idp_accounts.go index f836c228..64f24d84 100644 --- a/codefresh/resource_idp_accounts.go +++ b/codefresh/resource_idp_accounts.go @@ -1,7 +1,8 @@ package codefresh import ( - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -38,9 +39,9 @@ Because of the current Codefresh API limitation it's impossible to remove accoun func resourceAccountIDPCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) - accountIds := convertStringArr(d.Get("account_ids").(*schema.Set).List()) + accountIds := datautil.ConvertStringArr(d.Get("account_ids").(*schema.Set).List()) idpID := d.Get("idp_id").(string) @@ -60,7 +61,7 @@ func resourceAccountIDPCreate(d *schema.ResourceData, meta interface{}) error { func resourceAccountIDPRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) idpID := d.Id() if idpID == "" { @@ -94,7 +95,7 @@ func resourceAccountIDPDelete(_ *schema.ResourceData, _ interface{}) error { func resourceAccountIDPUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) idpID := d.Id() @@ -105,10 +106,10 @@ func resourceAccountIDPUpdate(d *schema.ResourceData, meta interface{}) error { existingAccounts := idp.Accounts - desiredAccounts := convertStringArr(d.Get("account_ids").(*schema.Set).List()) + desiredAccounts := datautil.ConvertStringArr(d.Get("account_ids").(*schema.Set).List()) for _, account := range desiredAccounts { - if ok := cfClient.FindInSlice(existingAccounts, account); !ok { + if ok := cfclient.FindInSlice(existingAccounts, account); !ok { client.AddAccountToIDP(account, idp.ID) } } diff --git a/codefresh/resource_permission.go b/codefresh/resource_permission.go index 82aa53cb..9b7de69c 100644 --- a/codefresh/resource_permission.go +++ b/codefresh/resource_permission.go @@ -5,7 +5,8 @@ import ( "fmt" "log" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" funk "github.com/thoas/go-funk" @@ -114,7 +115,7 @@ func resourcePermissionCustomDiff(ctx context.Context, diff *schema.ResourceDiff } func resourcePermissionCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) permission := *mapResourceToPermission(d) @@ -133,7 +134,7 @@ func resourcePermissionCreate(d *schema.ResourceData, meta interface{}) error { func resourcePermissionRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) permissionID := d.Id() if permissionID == "" { @@ -155,7 +156,7 @@ func resourcePermissionRead(d *schema.ResourceData, meta interface{}) error { } func resourcePermissionUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) permission := *mapResourceToPermission(d) resp, err := client.CreatePermission(&permission) @@ -173,7 +174,7 @@ func resourcePermissionUpdate(d *schema.ResourceData, meta interface{}) error { } func resourcePermissionDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) err := client.DeletePermission(d.Id()) if err != nil { @@ -183,7 +184,7 @@ func resourcePermissionDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapPermissionToResource(permission *cfClient.Permission, d *schema.ResourceData) error { +func mapPermissionToResource(permission *cfclient.Permission, d *schema.ResourceData) error { err := d.Set("_id", permission.ID) if err != nil { @@ -213,16 +214,16 @@ func mapPermissionToResource(permission *cfClient.Permission, d *schema.Resource return nil } -func mapResourceToPermission(d *schema.ResourceData) *cfClient.Permission { +func mapResourceToPermission(d *schema.ResourceData) *cfclient.Permission { tagsI := d.Get("tags").(*schema.Set).List() var tags []string if len(tagsI) > 0 { - tags = convertStringArr(tagsI) + tags = datautil.ConvertStringArr(tagsI) } else { tags = []string{"*", "untagged"} } - permission := &cfClient.Permission{ + permission := &cfclient.Permission{ ID: d.Id(), Team: d.Get("team").(string), Action: d.Get("action").(string), diff --git a/codefresh/resource_permission_test.go b/codefresh/resource_permission_test.go index 870b941a..5dd356ec 100644 --- a/codefresh/resource_permission_test.go +++ b/codefresh/resource_permission_test.go @@ -2,11 +2,12 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "strings" "testing" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" funk "github.com/thoas/go-funk" ) @@ -49,7 +50,7 @@ func testAccCheckCodefreshPermissionExists(resource string) resource.TestCheckFu permissionID := rs.Primary.ID - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) _, err := apiClient.GetPermissionByID(permissionID) if err != nil { diff --git a/codefresh/resource_pipeline.go b/codefresh/resource_pipeline.go index db595b33..f1ff3754 100644 --- a/codefresh/resource_pipeline.go +++ b/codefresh/resource_pipeline.go @@ -2,14 +2,14 @@ package codefresh import ( "fmt" - "github.com/robfig/cron" "log" "regexp" "strconv" "strings" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/go-cty/cty" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/schemautil" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -166,20 +166,11 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") Type: schema.TypeString, Optional: true, Default: "git", - ValidateDiagFunc: func(v any, p cty.Path) diag.Diagnostics { - value := v.(string) - expected := "git" - var diags diag.Diagnostics - if value != expected { - diag := diag.Diagnostic{ - Severity: diag.Error, - Summary: "Only triggers of type git are supported for nested triggers. For other trigger types, use the codefresh_pipeline_*_trigger resources.", - Detail: fmt.Sprintf("%q is not %q", value, expected), - } - diags = append(diags, diag) - } - return diags - }, + ValidateDiagFunc: schemautil.StringMatchesRegExp( + "git", + schemautil.WithSummary("Invalid trigger type"), + schemautil.WithDetailFormat("The trigger type %s is invalid. The only supported type is %s."), + ), }, "repo": { Description: "The repository name, (owner/repo)", @@ -187,11 +178,11 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") Optional: true, }, "branch_regex": { - Description: " A regular expression and will only trigger for branches that match this naming pattern (default: `/.*/gi`).", - Type: schema.TypeString, - Optional: true, - Default: "/.*/gi", - ValidateFunc: stringIsValidRe2RegExp, + Description: " A regular expression and will only trigger for branches that match this naming pattern (default: `/.*/gi`).", + Type: schema.TypeString, + Optional: true, + Default: "/.*/gi", + ValidateDiagFunc: schemautil.StringIsValidRegExp(), }, "branch_regex_input": { Description: "Flag to manage how the `branch_regex` field is interpreted. Possible values: `multiselect-exclude`, `multiselect`, `regex` (default: `regex`).", @@ -201,17 +192,17 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") ValidateFunc: validation.StringInSlice([]string{"multiselect-exclude", "multiselect", "regex"}, false), }, "pull_request_target_branch_regex": { - Description: "A regular expression and will only trigger for pull requests to branches that match this naming pattern.", - Type: schema.TypeString, - Optional: true, - ValidateFunc: stringIsValidRe2RegExp, + Description: "A regular expression and will only trigger for pull requests to branches that match this naming pattern.", + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: schemautil.StringIsValidRegExp(), }, "comment_regex": { - Description: " A regular expression and will only trigger for pull requests where a comment matches this naming pattern (default: `/.*/gi`).", - Type: schema.TypeString, - Optional: true, - Default: "/.*/gi", - ValidateFunc: stringIsValidRe2RegExp, + Description: " A regular expression and will only trigger for pull requests where a comment matches this naming pattern (default: `/.*/gi`).", + Type: schema.TypeString, + Optional: true, + Default: "/.*/gi", + ValidateDiagFunc: schemautil.StringIsValidRegExp(), }, "modified_files_glob": { Description: "Allows to constrain the build and trigger it only if the modified files from the commit match this glob expression (default: `\"\"`).", @@ -358,20 +349,11 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") Type: schema.TypeString, Optional: true, Default: "cron", - ValidateDiagFunc: func(v any, p cty.Path) diag.Diagnostics { - value := v.(string) - expected := "cron" - var diags diag.Diagnostics - if value != expected { - diag := diag.Diagnostic{ - Severity: diag.Error, - Summary: "Only triggers of type cron are supported for cron triggers. For other trigger types, use the codefresh_pipeline_*_trigger resources.", - Detail: fmt.Sprintf("%q is not %q", value, expected), - } - diags = append(diags, diag) - } - return diags - }, + ValidateDiagFunc: schemautil.StringMatchesRegExp( + "cron", + schemautil.WithSummary("Invalid cron trigger type"), + schemautil.WithDetailFormat("The cron trigger type %s is invalid. The only supported type is %s."), + ), }, "disabled": { Description: "Flag to disable the trigger.", @@ -380,43 +362,19 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") Default: false, }, "expression": { - Type: schema.TypeString, - Required: true, - ValidateDiagFunc: func(v interface{}, path cty.Path) (diags diag.Diagnostics) { - expression := v.(string) - - // Cron expression requirements: 6 fields, with ability to use descriptors (e.g. @yearly) - parser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor) - if _, err := parser.Parse(expression); err != nil { - diags = append(diags, diag.Diagnostic{ - Severity: diag.Error, - Summary: "Invalid cron expression.", - Detail: fmt.Sprintf("The cron expression %q is invalid: %s", expression, err), - }) - } - - return - }, + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: schemautil.CronExpression(), }, "message": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: func(v interface{}, path cty.Path) (diags diag.Diagnostics) { - message := v.(string) - - // https://github.com/codefresh-io/hermes/blob/6d75b347cb8ff471ce970a766b2285788e5e19fe/pkg/backend/dev_compose_types.json#L226 - re := regexp.MustCompile(`^[a-zA-Z0-9_+\s-#?.:]{2,128}$`) - - if !re.MatchString(message) { - diags = append(diags, diag.Diagnostic{ - Severity: diag.Error, - Summary: "Invalid message.", - Detail: fmt.Sprintf("The message %q is invalid (must match %q).", message, re.String()), - }) - } - - return - }, + ValidateDiagFunc: schemautil.StringMatchesRegExp( + schemautil.ValidCronMessageRegex, + schemautil.WithSeverity(diag.Error), + schemautil.WithSummary("Invalid cron trigger message"), + schemautil.WithDetailFormat("The message %q is invalid (must match %q)."), + ), }, "git_trigger_id": { Description: "Related git-trigger id. Will by used to take all possible git information by branch.", @@ -543,11 +501,11 @@ The following table presents how to configure this block based on the options av Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "branch_name": { - Description: "A regular expression to filter the branches on with the termination policy applies.", - Type: schema.TypeString, - Optional: true, - ValidateFunc: stringIsValidRe2RegExp, - ConflictsWith: []string{"spec.0.termination_policy.0.on_create_branch.0.ignore_branch"}, + Description: "A regular expression to filter the branches on with the termination policy applies.", + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: schemautil.StringIsValidRegExp(), + ConflictsWith: []string{"spec.0.termination_policy.0.on_create_branch.0.ignore_branch"}, }, "ignore_trigger": { Description: "Whether to ignore the trigger.", @@ -654,7 +612,7 @@ Pipeline concurrency policy: Builds on 'Pending Approval' state should be: func resourcePipelineCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) pipeline, err := mapResourceToPipeline(d) if err != nil { @@ -673,7 +631,7 @@ func resourcePipelineCreate(d *schema.ResourceData, meta interface{}) error { func resourcePipelineRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) pipelineID := d.Id() @@ -697,7 +655,7 @@ func resourcePipelineRead(d *schema.ResourceData, meta interface{}) error { func resourcePipelineUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) pipeline, err := mapResourceToPipeline(d) if err != nil { @@ -716,7 +674,7 @@ func resourcePipelineUpdate(d *schema.ResourceData, meta interface{}) error { func resourcePipelineDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) err := client.DeletePipeline(d.Id()) if err != nil { @@ -726,7 +684,7 @@ func resourcePipelineDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapPipelineToResource(pipeline cfClient.Pipeline, d *schema.ResourceData) error { +func mapPipelineToResource(pipeline cfclient.Pipeline, d *schema.ResourceData) error { err := d.Set("name", pipeline.Metadata.Name) if err != nil { @@ -766,7 +724,7 @@ func mapPipelineToResource(pipeline cfClient.Pipeline, d *schema.ResourceData) e return nil } -func flattenSpec(spec cfClient.Spec) []interface{} { +func flattenSpec(spec cfclient.Spec) []interface{} { var res = make([]interface{}, 0) m := make(map[string]interface{}) @@ -784,10 +742,10 @@ func flattenSpec(spec cfClient.Spec) []interface{} { } if len(spec.Variables) != 0 { - m["variables"] = convertVariables(spec.Variables) + m["variables"] = datautil.ConvertVariables(spec.Variables) } - if spec.RuntimeEnvironment != (cfClient.RuntimeEnvironment{}) { + if spec.RuntimeEnvironment != (cfclient.RuntimeEnvironment{}) { m["runtime_environment"] = flattenSpecRuntimeEnvironment(spec.RuntimeEnvironment) } @@ -854,7 +812,7 @@ func flattenSpecTerminationPolicy(terminationPolicy []map[string]interface{}) [] return res } -func flattenSpecTemplate(spec cfClient.SpecTemplate) []map[string]interface{} { +func flattenSpecTemplate(spec cfclient.SpecTemplate) []map[string]interface{} { return []map[string]interface{}{ { "location": spec.Location, @@ -866,7 +824,7 @@ func flattenSpecTemplate(spec cfClient.SpecTemplate) []map[string]interface{} { } } -func flattenSpecRuntimeEnvironment(spec cfClient.RuntimeEnvironment) []map[string]interface{} { +func flattenSpecRuntimeEnvironment(spec cfclient.RuntimeEnvironment) []map[string]interface{} { return []map[string]interface{}{ { "name": spec.Name, @@ -878,7 +836,7 @@ func flattenSpecRuntimeEnvironment(spec cfClient.RuntimeEnvironment) []map[strin } } -func flattenTriggerOptions(options cfClient.TriggerOptions) []map[string]interface{} { +func flattenTriggerOptions(options cfclient.TriggerOptions) []map[string]interface{} { return []map[string]interface{}{ { "no_cache": options.NoCache, @@ -889,7 +847,7 @@ func flattenTriggerOptions(options cfClient.TriggerOptions) []map[string]interfa } } -func flattenTriggers(triggers []cfClient.Trigger) []map[string]interface{} { +func flattenTriggers(triggers []cfclient.Trigger) []map[string]interface{} { var res = make([]map[string]interface{}, len(triggers)) for i, trigger := range triggers { m := make(map[string]interface{}) @@ -912,7 +870,7 @@ func flattenTriggers(triggers []cfClient.Trigger) []map[string]interface{} { m["provider"] = trigger.Provider m["type"] = trigger.Type m["events"] = trigger.Events - m["variables"] = convertVariables(trigger.Variables) + m["variables"] = datautil.ConvertVariables(trigger.Variables) if trigger.RuntimeEnvironment != nil { m["runtime_environment"] = flattenSpecRuntimeEnvironment(*trigger.RuntimeEnvironment) } @@ -921,7 +879,7 @@ func flattenTriggers(triggers []cfClient.Trigger) []map[string]interface{} { return res } -func flattenCronTriggers(cronTriggers []cfClient.CronTrigger) []map[string]interface{} { +func flattenCronTriggers(cronTriggers []cfclient.CronTrigger) []map[string]interface{} { var res = make([]map[string]interface{}, len(cronTriggers)) for i, trigger := range cronTriggers { m := make(map[string]interface{}) @@ -932,7 +890,7 @@ func flattenCronTriggers(cronTriggers []cfClient.CronTrigger) []map[string]inter m["disabled"] = trigger.Disabled m["git_trigger_id"] = trigger.GitTriggerId m["branch"] = trigger.Branch - m["variables"] = convertVariables(trigger.Variables) + m["variables"] = datautil.ConvertVariables(trigger.Variables) if trigger.Options != nil { m["options"] = flattenTriggerOptions(*trigger.Options) } @@ -944,7 +902,7 @@ func flattenCronTriggers(cronTriggers []cfClient.CronTrigger) []map[string]inter return res } -func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { +func mapResourceToPipeline(d *schema.ResourceData) (*cfclient.Pipeline, error) { tags := d.Get("tags").(*schema.Set).List() @@ -953,18 +911,18 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { "\n", "\n", -1) - pipeline := &cfClient.Pipeline{ - Metadata: cfClient.Metadata{ + pipeline := &cfclient.Pipeline{ + Metadata: cfclient.Metadata{ Name: d.Get("name").(string), Revision: d.Get("revision").(int), ProjectId: d.Get("project_id").(string), IsPublic: d.Get("is_public").(bool), - Labels: cfClient.Labels{ - Tags: convertStringArr(tags), + Labels: cfclient.Labels{ + Tags: datautil.ConvertStringArr(tags), }, OriginalYamlString: originalYamlString, }, - Spec: cfClient.Spec{ + Spec: cfclient.Spec{ PackId: d.Get("spec.0.pack_id").(string), RequiredAvailableStorage: d.Get("spec.0.required_available_storage").(string), Priority: d.Get("spec.0.priority").(int), @@ -975,7 +933,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { } if _, ok := d.GetOk("spec.0.spec_template"); ok { - pipeline.Spec.SpecTemplate = &cfClient.SpecTemplate{ + pipeline.Spec.SpecTemplate = &cfclient.SpecTemplate{ Location: d.Get("spec.0.spec_template.0.location").(string), Repo: d.Get("spec.0.spec_template.0.repo").(string), Path: d.Get("spec.0.spec_template.0.path").(string), @@ -990,7 +948,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { } if _, ok := d.GetOk("spec.0.runtime_environment"); ok { - pipeline.Spec.RuntimeEnvironment = cfClient.RuntimeEnvironment{ + pipeline.Spec.RuntimeEnvironment = cfclient.RuntimeEnvironment{ Name: d.Get("spec.0.runtime_environment.0.name").(string), Memory: d.Get("spec.0.runtime_environment.0.memory").(string), CPU: d.Get("spec.0.runtime_environment.0.cpu").(string), @@ -1011,7 +969,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { for idx := range triggers.([]interface{}) { events := d.Get(fmt.Sprintf("spec.0.trigger.%v.events", idx)).([]interface{}) contexts := d.Get(fmt.Sprintf("spec.0.trigger.%v.contexts", idx)).([]interface{}) - codefreshTrigger := cfClient.Trigger{ + codefreshTrigger := cfclient.Trigger{ Name: d.Get(fmt.Sprintf("spec.0.trigger.%v.name", idx)).(string), Description: d.Get(fmt.Sprintf("spec.0.trigger.%v.description", idx)).(string), Type: d.Get(fmt.Sprintf("spec.0.trigger.%v.type", idx)).(string), @@ -1026,13 +984,13 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { PullRequestAllowForkEvents: d.Get(fmt.Sprintf("spec.0.trigger.%v.pull_request_allow_fork_events", idx)).(bool), CommitStatusTitle: d.Get(fmt.Sprintf("spec.0.trigger.%v.commit_status_title", idx)).(string), Context: d.Get(fmt.Sprintf("spec.0.trigger.%v.context", idx)).(string), - Contexts: convertStringArr(contexts), - Events: convertStringArr(events), + Contexts: datautil.ConvertStringArr(contexts), + Events: datautil.ConvertStringArr(events), } variables := d.Get(fmt.Sprintf("spec.0.trigger.%v.variables", idx)).(map[string]interface{}) codefreshTrigger.SetVariables(variables) if _, ok := d.GetOk(fmt.Sprintf("spec.0.trigger.%v.options", idx)); ok { - options := cfClient.TriggerOptions{ + options := cfclient.TriggerOptions{ NoCache: d.Get(fmt.Sprintf("spec.0.trigger.%v.options.0.no_cache", idx)).(bool), NoCfCache: d.Get(fmt.Sprintf("spec.0.trigger.%v.options.0.no_cf_cache", idx)).(bool), ResetVolume: d.Get(fmt.Sprintf("spec.0.trigger.%v.options.0.reset_volume", idx)).(bool), @@ -1041,7 +999,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { codefreshTrigger.Options = &options } if _, ok := d.GetOk(fmt.Sprintf("spec.0.trigger.%v.runtime_environment", idx)); ok { - triggerRuntime := cfClient.RuntimeEnvironment{ + triggerRuntime := cfclient.RuntimeEnvironment{ Name: d.Get(fmt.Sprintf("spec.0.trigger.%v.runtime_environment.0.name", idx)).(string), Memory: d.Get(fmt.Sprintf("spec.0.trigger.%v.runtime_environment.0.memory", idx)).(string), CPU: d.Get(fmt.Sprintf("spec.0.trigger.%v.runtime_environment.0.cpu", idx)).(string), @@ -1056,7 +1014,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { if cronTriggers, ok := d.GetOk("spec.0.cron_trigger"); ok { for idx := range cronTriggers.([]interface{}) { - codefreshCronTrigger := cfClient.CronTrigger{ + codefreshCronTrigger := cfclient.CronTrigger{ Name: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.name", idx)).(string), Type: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.type", idx)).(string), Expression: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.expression", idx)).(string), @@ -1068,7 +1026,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { variables := d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.variables", idx)).(map[string]interface{}) codefreshCronTrigger.SetVariables(variables) if _, ok := d.GetOk(fmt.Sprintf("spec.0.cron_trigger.%v.options", idx)); ok { - options := cfClient.TriggerOptions{ + options := cfclient.TriggerOptions{ NoCache: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.options.0.no_cache", idx)).(bool), NoCfCache: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.options.0.no_cf_cache", idx)).(bool), ResetVolume: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.options.0.reset_volume", idx)).(bool), @@ -1077,7 +1035,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { codefreshCronTrigger.Options = &options } if _, ok := d.GetOk(fmt.Sprintf("spec.0.cron_trigger.%v.runtime_environment", idx)); ok { - triggerRuntime := cfClient.RuntimeEnvironment{ + triggerRuntime := cfclient.RuntimeEnvironment{ Name: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.runtime_environment.0.name", idx)).(string), Memory: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.runtime_environment.0.memory", idx)).(string), CPU: d.Get(fmt.Sprintf("spec.0.cron_trigger.%v.runtime_environment.0.cpu", idx)).(string), @@ -1130,44 +1088,44 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfClient.Pipeline, error) { // Typically, unmarshalling the YAML string is problematic because the order of the attributes is not preserved. // Namely, we care a lot about the order of the steps and stages attributes. // Luckily, the yj package introduces a MapSlice type that preserves the order Map items (see utils.go). -func extractSpecAttributesFromOriginalYamlString(originalYamlString string, pipeline *cfClient.Pipeline) error { +func extractSpecAttributesFromOriginalYamlString(originalYamlString string, pipeline *cfclient.Pipeline) error { for _, attribute := range []string{"stages", "steps", "hooks"} { - yamlString, err := yq(fmt.Sprintf(".%s", attribute), originalYamlString) + yamlString, err := datautil.Yq(fmt.Sprintf(".%s", attribute), originalYamlString) if err != nil { return fmt.Errorf("error while extracting '%s' from original YAML string: %v", attribute, err) } else if yamlString == "" { continue } - attributeJson, err := yamlToJson(yamlString) + attributeJson, err := datautil.YamlToJson(yamlString) if err != nil { return fmt.Errorf("error while converting '%s' YAML to JSON: %v", attribute, err) } switch attribute { case "stages": - pipeline.Spec.Stages = &cfClient.Stages{ + pipeline.Spec.Stages = &cfclient.Stages{ Stages: attributeJson, } case "steps": - pipeline.Spec.Steps = &cfClient.Steps{ + pipeline.Spec.Steps = &cfclient.Steps{ Steps: attributeJson, } case "hooks": - pipeline.Spec.Hooks = &cfClient.Hooks{ + pipeline.Spec.Hooks = &cfclient.Hooks{ Hooks: attributeJson, } } } - mode, err := yq(".mode", originalYamlString) + mode, err := datautil.Yq(".mode", originalYamlString) if err != nil { return fmt.Errorf("error while extracting 'mode' from original YAML string: %v", err) } else if mode != "" { pipeline.Spec.Mode = mode } - ff, err := yq(".fail_fast", originalYamlString) + ff, err := datautil.Yq(".fail_fast", originalYamlString) if err != nil { return fmt.Errorf("error while extracting 'mode' from original YAML string: %v", err) } else if ff != "" { diff --git a/codefresh/resource_pipeline_cron_trigger.go b/codefresh/resource_pipeline_cron_trigger.go index 6e5933b8..55b94892 100644 --- a/codefresh/resource_pipeline_cron_trigger.go +++ b/codefresh/resource_pipeline_cron_trigger.go @@ -6,8 +6,8 @@ import ( "regexp" "strings" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/hashicorp/go-cty/cty" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/schemautil" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -17,11 +17,11 @@ import ( func resourcePipelineCronTrigger() *schema.Resource { return &schema.Resource{ DeprecationMessage: "This resource is deprecated and will be removed in a future version of the Codefresh Terraform provider. Please use the cron_triggers attribute of the codefresh_pipeline resource instead.", - Description: "This resource is used to create cron-based triggers for pipeilnes.", - Create: resourcePipelineCronTriggerCreate, - Read: resourcePipelineCronTriggerRead, - Update: resourcePipelineCronTriggerUpdate, - Delete: resourcePipelineCronTriggerDelete, + Description: "This resource is used to create cron-based triggers for pipeilnes.", + Create: resourcePipelineCronTriggerCreate, + Read: resourcePipelineCronTriggerRead, + Update: resourcePipelineCronTriggerUpdate, + Delete: resourcePipelineCronTriggerDelete, Importer: &schema.ResourceImporter{ State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { idParts := strings.Split(d.Id(), ",") @@ -46,41 +46,20 @@ func resourcePipelineCronTrigger() *schema.Resource { "expression": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: func(v interface{}, path cty.Path) (diags diag.Diagnostics) { - expression := v.(string) - - // Cron expression requirements: 6 fields, with ability to use descriptors (e.g. @yearly) - parser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor) - if _, err := parser.Parse(expression); err != nil { - diags = append(diags, diag.Diagnostic{ - Severity: diag.Error, - Summary: "Invalid cron expression.", - Detail: fmt.Sprintf("The cron expression %q is invalid: %s", expression, err), - }) - } - - return - }, + ValidateDiagFunc: schemautil.CronExpression( + // Legacy cron parser, still used by standalone cron triggers + schemautil.WithCronParser(cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)), + ), }, "message": { Type: schema.TypeString, Required: true, - ValidateDiagFunc: func(v interface{}, path cty.Path) (diags diag.Diagnostics) { - message := v.(string) - - // https://github.com/codefresh-io/hermes/blob/6d75b347cb8ff471ce970a766b2285788e5e19fe/pkg/backend/dev_compose_types.json#L226 - re := regexp.MustCompile(`^[a-zA-Z0-9_+\s-#?.:]{2,128}$`) - - if !re.MatchString(message) { - diags = append(diags, diag.Diagnostic{ - Severity: diag.Error, - Summary: "Invalid message.", - Detail: fmt.Sprintf("The message %q is invalid (must match %q).", message, re.String()), - }) - } - - return - }, + ValidateDiagFunc: schemautil.StringMatchesRegExp( + schemautil.ValidCronMessageRegex, + schemautil.WithSeverity(diag.Error), + schemautil.WithSummary("Invalid cron trigger message"), + schemautil.WithDetailFormat("The message %q is invalid (must match %q)."), + ), }, }, // Force new resource if any field changes. This is because the Codefresh API does not support updating cron triggers. @@ -99,9 +78,9 @@ func resourcePipelineCronTrigger() *schema.Resource { } func resourcePipelineCronTriggerCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) - eventString, err := client.CreateHermesTriggerEvent(&cfClient.HermesTriggerEvent{ + eventString, err := client.CreateHermesTriggerEvent(&cfclient.HermesTriggerEvent{ Type: "cron", Kind: "codefresh", Secret: "!generate", @@ -128,7 +107,7 @@ func resourcePipelineCronTriggerCreate(d *schema.ResourceData, meta interface{}) func resourcePipelineCronTriggerRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) event := d.Id() pipeline := d.Get("pipeline_id").(string) @@ -152,7 +131,7 @@ func resourcePipelineCronTriggerUpdate(d *schema.ResourceData, meta interface{}) } func resourcePipelineCronTriggerDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) hermesTrigger := *mapResourceToPipelineCronTrigger(d) @@ -164,7 +143,7 @@ func resourcePipelineCronTriggerDelete(d *schema.ResourceData, meta interface{}) return nil } -func mapPipelineCronTriggerToResource(hermesTrigger *cfClient.HermesTrigger, d *schema.ResourceData) error { +func mapPipelineCronTriggerToResource(hermesTrigger *cfclient.HermesTrigger, d *schema.ResourceData) error { d.SetId(hermesTrigger.Event) d.Set("pipeline_id", hermesTrigger.PipelineID) @@ -182,10 +161,10 @@ func mapPipelineCronTriggerToResource(hermesTrigger *cfClient.HermesTrigger, d * return nil } -func mapResourceToPipelineCronTrigger(d *schema.ResourceData) *cfClient.HermesTrigger { +func mapResourceToPipelineCronTrigger(d *schema.ResourceData) *cfclient.HermesTrigger { triggerId := d.Id() - hermesTrigger := &cfClient.HermesTrigger{ + hermesTrigger := &cfclient.HermesTrigger{ Event: triggerId, PipelineID: d.Get("pipeline_id").(string), } diff --git a/codefresh/resource_pipeline_cron_trigger_test.go b/codefresh/resource_pipeline_cron_trigger_test.go index c4809ff1..1c33ee8f 100644 --- a/codefresh/resource_pipeline_cron_trigger_test.go +++ b/codefresh/resource_pipeline_cron_trigger_test.go @@ -5,7 +5,7 @@ import ( "regexp" "testing" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -15,7 +15,7 @@ import ( func TestAccCodefreshPipelineCronTriggerValidExpressions(t *testing.T) { pipelineName := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline_cron_trigger.test" - var pipelineCronTrigger cfClient.HermesTrigger + var pipelineCronTrigger cfclient.HermesTrigger resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -63,7 +63,7 @@ func TestAccCodefreshPipelineCronTriggerValidExpressions(t *testing.T) { func TestAccCodefreshPipelineCronTriggerInvalidExpressions(t *testing.T) { pipelineName := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline_cron_trigger.test" - var pipelineCronTrigger cfClient.HermesTrigger + var pipelineCronTrigger cfclient.HermesTrigger expectedError := regexp.MustCompile("The cron expression .* is invalid: .*") resource.ParallelTest(t, resource.TestCase{ @@ -128,7 +128,7 @@ func TestAccCodefreshPipelineCronTriggerInvalidExpressions(t *testing.T) { func TestAccCodefreshPipelineCronTriggerValidMessages(t *testing.T) { pipelineName := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline_cron_trigger.test" - var pipelineCronTrigger cfClient.HermesTrigger + var pipelineCronTrigger cfclient.HermesTrigger resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -151,7 +151,7 @@ func TestAccCodefreshPipelineCronTriggerValidMessages(t *testing.T) { func TestAccCodefreshPipelineCronTriggerInvalidMessages(t *testing.T) { pipelineName := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline_cron_trigger.test" - var pipelineCronTrigger cfClient.HermesTrigger + var pipelineCronTrigger cfclient.HermesTrigger expectedError := regexp.MustCompile("The message .* is invalid.*") resource.ParallelTest(t, resource.TestCase{ @@ -210,7 +210,7 @@ func TestAccCodefreshPipelineCronTriggerInvalidMessages(t *testing.T) { func TestAccCodefreshPipelineCronTriggerUpdateNoDuplicates(t *testing.T) { pipelineName := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline_cron_trigger.test" - var pipelineCronTrigger cfClient.HermesTrigger + var pipelineCronTrigger cfclient.HermesTrigger resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -248,7 +248,7 @@ resource "codefresh_pipeline_cron_trigger" "test" { } func testAccCheckCodefreshPipelineCronTriggerDestroy(s *terraform.State) error { - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) for _, rs := range s.RootModule().Resources { @@ -273,7 +273,7 @@ func testAccCheckCodefreshPipelineCronTriggerDestroy(s *terraform.State) error { return nil } -func testAccCheckCodefreshPipelineCronTriggerExists(resource string, pipelineCronTrigger *cfClient.HermesTrigger) resource.TestCheckFunc { +func testAccCheckCodefreshPipelineCronTriggerExists(resource string, pipelineCronTrigger *cfclient.HermesTrigger) resource.TestCheckFunc { return func(state *terraform.State) error { rs, ok := state.RootModule().Resources[resource] @@ -284,7 +284,7 @@ func testAccCheckCodefreshPipelineCronTriggerExists(resource string, pipelineCro return fmt.Errorf("no Record ID is set") } - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) retrievedHermesTrigger, err := apiClient.GetHermesTriggerByEventAndPipeline(rs.Primary.ID, rs.Primary.Attributes["pipeline_id"]) if err != nil { diff --git a/codefresh/resource_pipeline_test.go b/codefresh/resource_pipeline_test.go index cb14c200..4bfcfdf9 100644 --- a/codefresh/resource_pipeline_test.go +++ b/codefresh/resource_pipeline_test.go @@ -6,7 +6,7 @@ import ( "regexp" "testing" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -17,7 +17,7 @@ var pipelineNamePrefix = "TerraformAccTest_" func TestAccCodefreshPipeline_basic(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -45,7 +45,7 @@ func TestAccCodefreshPipeline_basic(t *testing.T) { func TestAccCodefreshPipeline_Concurrency(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -82,7 +82,7 @@ func TestAccCodefreshPipeline_Concurrency(t *testing.T) { func TestAccCodefreshPipeline_Tags(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -109,7 +109,7 @@ func TestAccCodefreshPipeline_Tags(t *testing.T) { func TestAccCodefreshPipeline_Variables(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -145,7 +145,7 @@ func TestAccCodefreshPipeline_RuntimeEnvironment(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" runtimeName := "system/default/hybrid/k8s" // must be present in test environment - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -186,16 +186,16 @@ steps: commands: - echo Hello World Third Step` - expectedSpecAttributes := &cfClient.Spec{ - Steps: &cfClient.Steps{ + expectedSpecAttributes := &cfclient.Spec{ + Steps: &cfclient.Steps{ Steps: `{"cc_firstStep":{"image":"alpine","commands":["echo Hello World First Step"]},"bb_secondStep":{"image":"alpine","commands":["echo Hello World Second jStep"]},"aa_secondStep":{"image":"alpine","commands":["echo Hello World Third Step"]}}`, }, - Stages: &cfClient.Stages{ + Stages: &cfclient.Stages{ Stages: `[]`, }, } - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -262,19 +262,19 @@ steps: commands: - echo Hello World Second Step` - expectedSpecAttributes := &cfClient.Spec{ - Steps: &cfClient.Steps{ + expectedSpecAttributes := &cfclient.Spec{ + Steps: &cfclient.Steps{ Steps: `{"zz_firstStep":{"stage":"test","image":"alpine","commands":["echo Hello World First Step"]},"aa_secondStep":{"stage":"test","image":"alpine","commands":["echo Hello World Second Step"]}}`, }, - Stages: &cfClient.Stages{ + Stages: &cfclient.Stages{ Stages: `["test"]`, }, - Hooks: &cfClient.Hooks{ + Hooks: &cfclient.Hooks{ Hooks: `{"on_finish":{"steps":{"secondmycleanup":{"commands":["echo echo cleanup step"],"image":"alpine:3.9"},"firstmynotification":{"commands":["echo Notify slack"],"image":"cloudposse/slack-notifier"}}},"on_elected":{"exec":{"commands":["echo 'Creating an adhoc test environment'"],"image":"alpine:3.9"},"annotations":{"set":[{"annotations":[{"my_annotation_example1":10.45},{"my_string_annotation":"Hello World"}],"entity_type":"build"}]}}}`, }, } - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -302,7 +302,7 @@ steps: func TestAccCodefreshPipeline_Triggers(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -409,7 +409,7 @@ func TestAccCodefreshPipeline_Triggers(t *testing.T) { func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -425,7 +425,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { "git", "cT1", "first", - "0 0/1 * 1/1 * *", + "0/1 * 1/1 * *", "64abd1550f02a62699b10df7", "runtime1", "100mb", @@ -434,7 +434,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { "1gb", "cT2", "second", - "0 0/1 * 1/1 * *", + "0/1 * 1/1 * *", "64abd1550f02a62699b10df7", true, true, @@ -448,7 +448,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.#", "2"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.name", "cT1"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.message", "first"), - resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.expression", "0 0/1 * 1/1 * *"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.expression", "0/1 * 1/1 * *"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.name", "runtime1"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.memory", "100mb"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.cpu", "1cpu"), @@ -458,7 +458,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.#", "2"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.name", "cT2"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.message", "second"), - resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.expression", "0 0/1 * 1/1 * *"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.expression", "0/1 * 1/1 * *"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.git_trigger_id", "64abd1550f02a62699b10df7"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.no_cache", "true"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.no_cf_cache", "true"), @@ -480,7 +480,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { "git", "cT1", "first-1", - "0 0/1 * 1/1 * *", + "0/1 * 1/1 * *", "00abd1550f02a62699b10df7", "runtime2", "500mb", @@ -489,7 +489,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { "3gb", "cT2", "second", - "0 1/1 * 1/1 * *", + "1/1 * 1/1 * *", "00abd1550f02a62699b10df7", true, true, @@ -503,7 +503,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.#", "2"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.name", "cT1"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.message", "first-1"), - resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.expression", "0 0/1 * 1/1 * *"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.expression", "0/1 * 1/1 * *"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.name", "runtime2"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.memory", "500mb"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.cpu", "2cpu"), @@ -513,7 +513,7 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.#", "2"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.name", "cT2"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.message", "second"), - resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.expression", "0 1/1 * 1/1 * *"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.expression", "1/1 * 1/1 * *"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.git_trigger_id", "00abd1550f02a62699b10df7"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.no_cache", "true"), resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.no_cf_cache", "true"), @@ -525,10 +525,75 @@ func TestAccCodefreshPipeline_CronTriggers(t *testing.T) { }) } +// Same config as TestAccCodefreshPipeline_CronTriggers but with invalid cron expression (too many fields) +func TestAccCodefreshPipeline_CronTriggersInvalid(t *testing.T) { + name := pipelineNamePrefix + acctest.RandString(10) + resourceName := "codefresh_pipeline.test" + var pipeline cfclient.Pipeline + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCodefreshPipelineBasicConfigCronTriggers( + name, + "codefresh-contrib/react-sample-app", + "./codefresh.yml", + "master", + "git", + "cT1", + "first", + "0 0/1 * 1/1 * *", + "64abd1550f02a62699b10df7", + "runtime1", + "100mb", + "1cpu", + "1gb", + "1gb", + "cT2", + "second", + "0 0/1 * 1/1 * *", + "64abd1550f02a62699b10df7", + true, + true, + true, + true, + "MY_VAR", + "test", + ), + Check: resource.ComposeTestCheckFunc( + testAccCheckCodefreshPipelineExists(resourceName, &pipeline), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.#", "2"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.name", "cT1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.message", "first"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.expression", "0 0/1 * 1/1 * *"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.name", "runtime1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.memory", "100mb"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.cpu", "1cpu"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.dind_storage", "1gb"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.0.runtime_environment.0.required_available_storage", "1gb"), + + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.#", "2"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.name", "cT2"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.message", "second"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.expression", "0 0/1 * 1/1 * *"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.git_trigger_id", "64abd1550f02a62699b10df7"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.no_cache", "true"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.no_cf_cache", "true"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.reset_volume", "true"), + resource.TestCheckResourceAttr(resourceName, "spec.0.cron_trigger.1.options.0.enable_notifications", "true"), + ), + ExpectError: regexp.MustCompile("The cron expression .* is invalid: Expected exactly 5 fields.*"), + }, + }, + }) +} + func TestAccCodefreshPipeline_Revision(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -561,7 +626,7 @@ func TestAccCodefreshPipeline_Revision(t *testing.T) { func TestAccCodefreshPipeline_IsPublic(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -594,7 +659,7 @@ func TestAccCodefreshPipeline_IsPublic(t *testing.T) { func TestAccCodefreshPipelineOnCreateBranchIgnoreTrigger(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -629,7 +694,7 @@ func TestAccCodefreshPipelineOnCreateBranchIgnoreTrigger(t *testing.T) { func TestAccCodefreshPipelineOptions(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -664,7 +729,7 @@ func TestAccCodefreshPipelineOptions(t *testing.T) { }) } -func testAccCheckCodefreshPipelineExists(resource string, pipeline *cfClient.Pipeline) resource.TestCheckFunc { +func testAccCheckCodefreshPipelineExists(resource string, pipeline *cfclient.Pipeline) resource.TestCheckFunc { return func(state *terraform.State) error { rs, ok := state.RootModule().Resources[resource] @@ -677,7 +742,7 @@ func testAccCheckCodefreshPipelineExists(resource string, pipeline *cfClient.Pip pipelineID := rs.Primary.ID - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) retrievedPipeline, err := apiClient.GetPipeline(pipelineID) if err != nil { @@ -691,7 +756,7 @@ func testAccCheckCodefreshPipelineExists(resource string, pipeline *cfClient.Pip } func testAccCheckCodefreshPipelineDestroy(s *terraform.State) error { - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) for _, rs := range s.RootModule().Resources { @@ -716,7 +781,7 @@ func testAccCheckCodefreshPipelineDestroy(s *terraform.State) error { return nil } -func testAccCheckCodefreshPipelineOriginalYamlStringAttributePropagation(resource string, spec *cfClient.Spec) resource.TestCheckFunc { +func testAccCheckCodefreshPipelineOriginalYamlStringAttributePropagation(resource string, spec *cfclient.Spec) resource.TestCheckFunc { return func(state *terraform.State) error { rs, ok := state.RootModule().Resources[resource] @@ -729,7 +794,7 @@ func testAccCheckCodefreshPipelineOriginalYamlStringAttributePropagation(resourc pipelineID := rs.Primary.ID - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) pipeline, err := apiClient.GetPipeline(pipelineID) if !reflect.DeepEqual(pipeline.Spec.Steps, spec.Steps) { @@ -1181,7 +1246,7 @@ resource "codefresh_pipeline" "test" { func TestAccCodefreshPipeline_Contexts(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" - var pipeline cfClient.Pipeline + var pipeline cfclient.Pipeline resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/codefresh/resource_project.go b/codefresh/resource_project.go index 6034506a..b4506347 100644 --- a/codefresh/resource_project.go +++ b/codefresh/resource_project.go @@ -5,7 +5,8 @@ import ( "time" "github.com/cenkalti/backoff" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -50,7 +51,7 @@ You are free to use projects as you see fit. For example, you could create a pro } func resourceProjectCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) project := *mapResourceToProject(d) @@ -66,7 +67,7 @@ func resourceProjectCreate(d *schema.ResourceData, meta interface{}) error { func resourceProjectRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) projectID := d.Id() if projectID == "" { @@ -88,7 +89,7 @@ func resourceProjectRead(d *schema.ResourceData, meta interface{}) error { } func resourceProjectUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) project := *mapResourceToProject(d) @@ -101,7 +102,7 @@ func resourceProjectUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceProjectDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) // Adding a Retry backoff to address eventual consistency for the API expBackoff := backoff.NewExponentialBackOff() expBackoff.MaxElapsedTime = 2 * time.Second @@ -120,7 +121,7 @@ func resourceProjectDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapProjectToResource(project *cfClient.Project, d *schema.ResourceData) error { +func mapProjectToResource(project *cfclient.Project, d *schema.ResourceData) error { err := d.Set("name", project.ProjectName) if err != nil { @@ -132,19 +133,19 @@ func mapProjectToResource(project *cfClient.Project, d *schema.ResourceData) err return err } - err = d.Set("variables", convertVariables(project.Variables)) + err = d.Set("variables", datautil.ConvertVariables(project.Variables)) if err != nil { return err } return nil } -func mapResourceToProject(d *schema.ResourceData) *cfClient.Project { +func mapResourceToProject(d *schema.ResourceData) *cfclient.Project { tags := d.Get("tags").(*schema.Set).List() - project := &cfClient.Project{ + project := &cfclient.Project{ ID: d.Id(), ProjectName: d.Get("name").(string), - Tags: convertStringArr(tags), + Tags: datautil.ConvertStringArr(tags), } variables := d.Get("variables").(map[string]interface{}) project.SetVariables(variables) diff --git a/codefresh/resource_project_test.go b/codefresh/resource_project_test.go index 6b6fc5f6..6123c19c 100644 --- a/codefresh/resource_project_test.go +++ b/codefresh/resource_project_test.go @@ -2,12 +2,13 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "regexp" + "testing" + + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "regexp" - "testing" ) var projectNamePrefix = "TerraformAccTest_" @@ -110,7 +111,7 @@ func testAccCheckCodefreshProjectExists(resource string) resource.TestCheckFunc projectID := rs.Primary.ID - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) _, err := apiClient.GetProjectByID(projectID) if err != nil { @@ -121,7 +122,7 @@ func testAccCheckCodefreshProjectExists(resource string) resource.TestCheckFunc } func testAccCheckCodefreshProjectDestroy(s *terraform.State) error { - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) for _, rs := range s.RootModule().Resources { diff --git a/codefresh/resource_registry.go b/codefresh/resource_registry.go index 25fef54a..88d236fb 100644 --- a/codefresh/resource_registry.go +++ b/codefresh/resource_registry.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -307,7 +307,7 @@ func resourceRegistry() *schema.Resource { func resourceRegistryCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) resp, err := client.CreateRegistry(mapResourceToRegistry(d)) if err != nil { log.Printf("[DEBUG] Error while creating registry. Error = %v", err) @@ -319,7 +319,7 @@ func resourceRegistryCreate(d *schema.ResourceData, meta interface{}) error { } func resourceRegistryRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) registryId := d.Id() @@ -345,7 +345,7 @@ func resourceRegistryRead(d *schema.ResourceData, meta interface{}) error { func resourceRegistryUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) registry := *mapResourceToRegistry(d) registry.Id = d.Id() @@ -361,7 +361,7 @@ func resourceRegistryUpdate(d *schema.ResourceData, meta interface{}) error { func resourceRegistryDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) err := client.DeleteRegistry(d.Id()) if err != nil { @@ -371,8 +371,8 @@ func resourceRegistryDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapResourceToRegistry(d *schema.ResourceData) *cfClient.Registry { - registry := &cfClient.Registry{ +func mapResourceToRegistry(d *schema.ResourceData) *cfclient.Registry { + registry := &cfclient.Registry{ Id: d.Id(), Name: d.Get("name").(string), Kind: d.Get("kind").(string), @@ -452,7 +452,7 @@ func mapResourceToRegistry(d *schema.ResourceData) *cfClient.Registry { return registry } -func mapRegistryToResource(registry cfClient.Registry, d *schema.ResourceData) error { +func mapRegistryToResource(registry cfclient.Registry, d *schema.ResourceData) error { d.SetId(registry.Id) d.Set("name", registry.Name) d.Set("kind", registry.Kind) diff --git a/codefresh/resource_step_types.go b/codefresh/resource_step_types.go index f8221bb6..2ef0622f 100644 --- a/codefresh/resource_step_types.go +++ b/codefresh/resource_step_types.go @@ -10,7 +10,8 @@ import ( "strings" "github.com/Masterminds/semver" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/schemautil" ghodss "github.com/ghodss/yaml" "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -57,8 +58,8 @@ The resource allows to handle the life-cycle of the version by allowing specifyi Description: "YAML containing a valid definition of a typed plugin", Type: schema.TypeString, Required: true, - ValidateFunc: stringIsYaml, - DiffSuppressFunc: suppressEquivalentYamlDiffs, + ValidateDiagFunc: schemautil.StringIsValidYaml(), + DiffSuppressFunc: schemautil.SuppressEquivalentYamlDiffs(), StateFunc: func(v interface{}) string { template, _ := normalizeYamlStringStepTypes(v) return template @@ -95,14 +96,14 @@ func normalizeYamlStringStepTypes(yamlString interface{}) (string, error) { func resourceStepTypesCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) stepTypes := *mapResourceToStepTypesVersions(d) name := d.Get("name").(string) d.SetId(name) // Extract all the versions so that we can order the set based on semantic versioning - mapVersion := make(map[string]cfClient.StepTypes) + mapVersion := make(map[string]cfclient.StepTypes) var versions []string for _, version := range stepTypes.Versions { version.StepTypes.Metadata["name"] = name @@ -129,7 +130,7 @@ func resourceStepTypesCreate(ctx context.Context, d *schema.ResourceData, meta i } func resourceStepTypesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) stepTypesIdentifier := d.Id() if stepTypesIdentifier == "" { @@ -146,7 +147,7 @@ func resourceStepTypesRead(ctx context.Context, d *schema.ResourceData, meta int return nil } - var stepVersions cfClient.StepTypesVersions + var stepVersions cfclient.StepTypesVersions name := stepTypes.Metadata["name"].(string) stepVersions.Name = name versions := d.Get("version").(*schema.Set) @@ -161,7 +162,7 @@ func resourceStepTypesRead(ctx context.Context, d *schema.ResourceData, meta int log.Printf("[DEBUG] StepVersion not found %v. Error = %v", stepTypesIdentifier+":"+version, err) } else { cleanUpStepFromTransientValues(stepTypes, name, version) - stepVersion := cfClient.StepTypesVersion{ + stepVersion := cfclient.StepTypesVersion{ VersionNumber: version, StepTypes: *stepTypes, } @@ -182,10 +183,10 @@ func resourceStepTypesRead(ctx context.Context, d *schema.ResourceData, meta int func resourceStepTypesUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) name := d.Get("name").(string) stepTypesVersions := mapResourceToStepTypesVersions(d) - mapVersionToCreate := make(map[string]cfClient.StepTypes) + mapVersionToCreate := make(map[string]cfclient.StepTypes) versionsPreviouslyDefined := make(map[string]string) versionsDefined := make(map[string]string) // Name is set to ForceNew so if we reach this function "version" is changed. Skipping check on HasChange @@ -254,7 +255,7 @@ func resourceStepTypesUpdate(ctx context.Context, d *schema.ResourceData, meta i func resourceStepTypesDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) log.Printf("[DEBUG] Deleting step type: %s", d.Id()) err := client.DeleteStepTypes(d.Id()) if err != nil { @@ -264,7 +265,7 @@ func resourceStepTypesDelete(ctx context.Context, d *schema.ResourceData, meta i return nil } -func cleanUpStepFromTransientValues(stepTypes *cfClient.StepTypes, name, version string) { +func cleanUpStepFromTransientValues(stepTypes *cfclient.StepTypes, name, version string) { if stepTypes != nil { // Remove transient attributes from metadata for _, attribute := range []string{"created_at", "accountId", "id", "updated_at"} { @@ -310,7 +311,7 @@ func sortVersions(versions []string) []*semver.Version { return vs } -func mapStepTypesVersionsToResource(stepTypesVersions cfClient.StepTypesVersions, d *schema.ResourceData) error { +func mapStepTypesVersionsToResource(stepTypesVersions cfclient.StepTypesVersions, d *schema.ResourceData) error { err := d.Set("name", stepTypesVersions.Name) if err != nil { @@ -328,7 +329,7 @@ func resourceStepTypesVersionsConfigHash(v interface{}) int { m := v.(map[string]interface{}) buf.WriteString(fmt.Sprintf("%s", m["version_number"].(string))) - var stepTypes cfClient.StepTypes + var stepTypes cfclient.StepTypes stepTypesYaml := m["step_types_yaml"].(string) ghodss.Unmarshal([]byte(stepTypesYaml), &stepTypes) // Remove runtime attributes, name and version to avoid discrepancies when comparing hashes @@ -339,7 +340,7 @@ func resourceStepTypesVersionsConfigHash(v interface{}) int { return hash } -func flattenVersions(name string, versions []cfClient.StepTypesVersion) *schema.Set { +func flattenVersions(name string, versions []cfclient.StepTypesVersion) *schema.Set { stepVersions := make([]interface{}, 0) for _, version := range versions { @@ -358,15 +359,15 @@ func flattenVersions(name string, versions []cfClient.StepTypesVersion) *schema. return schema.NewSet(resourceStepTypesVersionsConfigHash, stepVersions) } -func mapResourceToStepTypesVersions(d *schema.ResourceData) *cfClient.StepTypesVersions { - var stepTypesVersions cfClient.StepTypesVersions +func mapResourceToStepTypesVersions(d *schema.ResourceData) *cfclient.StepTypesVersions { + var stepTypesVersions cfclient.StepTypesVersions stepTypesVersions.Name = d.Get("name").(string) versions := d.Get("version").(*schema.Set) for _, step := range versions.List() { version := step.(map[string]interface{})["version_number"].(string) if version != "" { - var stepTypes cfClient.StepTypes + var stepTypes cfclient.StepTypes stepTypesYaml := step.(map[string]interface{})["step_types_yaml"].(string) err := ghodss.Unmarshal([]byte(stepTypesYaml), &stepTypes) @@ -375,7 +376,7 @@ func mapResourceToStepTypesVersions(d *schema.ResourceData) *cfClient.StepTypesV } cleanUpStepFromTransientValues(&stepTypes, stepTypesVersions.Name, version) - stepVersion := cfClient.StepTypesVersion{ + stepVersion := cfclient.StepTypesVersion{ VersionNumber: version, StepTypes: stepTypes, } diff --git a/codefresh/resource_step_types_test.go b/codefresh/resource_step_types_test.go index 8ae88565..74857f8f 100644 --- a/codefresh/resource_step_types_test.go +++ b/codefresh/resource_step_types_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/Masterminds/semver" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -20,7 +20,7 @@ var stepTypesNamePrefix = "TerraformAccTest_" // Unit Testing func TestCleanUpStepFromTransientValues(t *testing.T) { - stepTypes := cfClient.StepTypes{ + stepTypes := cfclient.StepTypes{ Metadata: map[string]interface{}{ "accountId": "test", "created_at": "test", @@ -101,9 +101,9 @@ func TestExtractSteps(t *testing.T) { // Acceptance testing func TestAccCodefreshStepTypes(t *testing.T) { // Adding check if we are executing Acceptance test - // This is needed to ensure we have cfClient initialised so that we can retrieve the accountName dynamically + // This is needed to ensure we have cfclient initialised so that we can retrieve the accountName dynamically if os.Getenv("TF_ACC") == "1" { - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) var accountName string if account, err := apiClient.GetCurrentAccount(); err == nil { accountName = account.Name @@ -167,7 +167,7 @@ func testAccCheckCodefreshStepTypesExists(resource string) resource.TestCheckFun stepTypeID := rs.Primary.ID - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) _, err := apiClient.GetStepTypes(stepTypeID) if err != nil { @@ -178,7 +178,7 @@ func testAccCheckCodefreshStepTypesExists(resource string) resource.TestCheckFun } func testAccCheckCodefreshStepTypesDestroy(s *terraform.State) error { - apiClient := testAccProvider.Meta().(*cfClient.Client) + apiClient := testAccProvider.Meta().(*cfclient.Client) for _, rs := range s.RootModule().Resources { diff --git a/codefresh/resource_team.go b/codefresh/resource_team.go index 987b33da..81080092 100644 --- a/codefresh/resource_team.go +++ b/codefresh/resource_team.go @@ -3,7 +3,8 @@ package codefresh import ( "fmt" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -59,7 +60,7 @@ The type of the team. Possible values: } func resourceTeamCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) team := *mapResourceToTeam(d) @@ -76,7 +77,7 @@ func resourceTeamCreate(d *schema.ResourceData, meta interface{}) error { func resourceTeamRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) teamID := d.Id() if teamID == "" { @@ -98,7 +99,7 @@ func resourceTeamRead(d *schema.ResourceData, meta interface{}) error { } func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) team := *mapResourceToTeam(d) @@ -116,7 +117,7 @@ func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) error { desiredUsers := d.Get("users").(*schema.Set).List() - usersToAdd, usersToDelete := cfClient.GetUsersDiff(convertStringArr(desiredUsers), existingTeam.Users) + usersToAdd, usersToDelete := cfclient.GetUsersDiff(datautil.ConvertStringArr(desiredUsers), existingTeam.Users) for _, userId := range usersToDelete { err := client.DeleteUserFromTeam(team.ID, userId) @@ -136,7 +137,7 @@ func resourceTeamUpdate(d *schema.ResourceData, meta interface{}) error { } func resourceTeamDelete(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) err := client.DeleteTeam(d.Id()) if err != nil { @@ -146,7 +147,7 @@ func resourceTeamDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { +func mapTeamToResource(team *cfclient.Team, d *schema.ResourceData) error { if team == nil { return fmt.Errorf("mapTeamToResource - cannot find team") @@ -179,7 +180,7 @@ func mapTeamToResource(team *cfClient.Team, d *schema.ResourceData) error { return nil } -func flattenTeamUsers(users []cfClient.TeamUser) []string { +func flattenTeamUsers(users []cfclient.TeamUser) []string { res := []string{} for _, user := range users { res = append(res, user.ID) @@ -187,20 +188,20 @@ func flattenTeamUsers(users []cfClient.TeamUser) []string { return res } -func mapResourceToTeam(d *schema.ResourceData) *cfClient.Team { +func mapResourceToTeam(d *schema.ResourceData) *cfclient.Team { tags := d.Get("tags").(*schema.Set).List() - team := &cfClient.Team{ + team := &cfclient.Team{ ID: d.Id(), Name: d.Get("name").(string), Type: d.Get("type").(string), Account: d.Get("account_id").(string), - Tags: convertStringArr(tags), + Tags: datautil.ConvertStringArr(tags), } if _, ok := d.GetOk("users"); ok { users := d.Get("users").(*schema.Set).List() for _, id := range users { - user := cfClient.TeamUser{ + user := cfclient.TeamUser{ ID: id.(string), } team.Users = append(team.Users, user) diff --git a/codefresh/resource_user.go b/codefresh/resource_user.go index a6fa3bc7..3dc90e83 100644 --- a/codefresh/resource_user.go +++ b/codefresh/resource_user.go @@ -3,7 +3,8 @@ package codefresh import ( "log" - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/codefresh-io/terraform-provider-codefresh/codefresh/internal/datautil" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -127,7 +128,7 @@ func resourceUser() *schema.Resource { func resourceUsersCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) user := mapResourceToNewUser(d) @@ -152,7 +153,7 @@ func resourceUsersCreate(d *schema.ResourceData, meta interface{}) error { func resourceUsersRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) userId := d.Id() @@ -177,13 +178,13 @@ func resourceUsersRead(d *schema.ResourceData, meta interface{}) error { func resourceUsersUpdate(d *schema.ResourceData, meta interface{}) error { // only accounts list - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) accountList := d.Get("accounts").(*schema.Set).List() userId := d.Id() - accounts, err := client.GetAccountsList(convertStringArr(accountList)) + accounts, err := client.GetAccountsList(datautil.ConvertStringArr(accountList)) if err != nil { return err } @@ -205,7 +206,7 @@ func resourceUsersDelete(d *schema.ResourceData, meta interface{}) error { // To research // it's impossible sometimes to delete user - limit of runtimes or collaborators should be increased. - client := meta.(*cfClient.Client) + client := meta.(*cfclient.Client) userName := d.Get("user_name").(string) @@ -217,7 +218,7 @@ func resourceUsersDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func mapUserToResource(user cfClient.User, d *schema.ResourceData) error { +func mapUserToResource(user cfclient.User, d *schema.ResourceData) error { d.Set("user_name", user.UserName) d.Set("email", user.Email) @@ -236,7 +237,7 @@ func mapUserToResource(user cfClient.User, d *schema.ResourceData) error { return nil } -func flattenUserAccounts(accounts []cfClient.Account) []string { +func flattenUserAccounts(accounts []cfclient.Account) []string { var accountList []string @@ -247,7 +248,7 @@ func flattenUserAccounts(accounts []cfClient.Account) []string { return accountList } -func flattenUserLogins(logins *[]cfClient.Login) []map[string]interface{} { +func flattenUserLogins(logins *[]cfclient.Login) []map[string]interface{} { var res = make([]map[string]interface{}, len(*logins)) for i, login := range *logins { @@ -265,21 +266,21 @@ func flattenUserLogins(logins *[]cfClient.Login) []map[string]interface{} { return res } -func mapResourceToNewUser(d *schema.ResourceData) *cfClient.NewUser { +func mapResourceToNewUser(d *schema.ResourceData) *cfclient.NewUser { roles := d.Get("roles").(*schema.Set).List() accounts := d.Get("accounts").(*schema.Set).List() - user := &cfClient.NewUser{ + user := &cfclient.NewUser{ ID: d.Id(), UserName: d.Get("user_name").(string), Email: d.Get("email").(string), - Roles: convertStringArr(roles), - Account: convertStringArr(accounts), + Roles: datautil.ConvertStringArr(roles), + Account: datautil.ConvertStringArr(accounts), } if _, ok := d.GetOk("personal"); ok { - user.Personal = &cfClient.Personal{ + user.Personal = &cfclient.Personal{ FirstName: d.Get("personal.0.first_name").(string), LastName: d.Get("personal.0.last_name").(string), CompanyName: d.Get("personal.0.company_name").(string), @@ -293,11 +294,11 @@ func mapResourceToNewUser(d *schema.ResourceData) *cfClient.NewUser { for _, loginDataI := range loginsList { if loginData, isMap := loginDataI.(map[string]interface{}); isMap { idpID := loginData["idp_id"].(string) - login := cfClient.Login{ - // Credentials: cfClient.Credentials{ + login := cfclient.Login{ + // Credentials: cfclient.Credentials{ // Permissions: loginData.Get("credentials.permissions").([]string), // }, - IDP: cfClient.IDP{ + IDP: cfclient.IDP{ ID: idpID, }, Sso: loginData["sso"].(bool), @@ -311,9 +312,9 @@ func mapResourceToNewUser(d *schema.ResourceData) *cfClient.NewUser { // for idx := range logins { - // permissions := convertStringArr(d.Get(fmt.Sprintf("login.%v.credentials.0.permissions", idx)).([]interface{})) - // login := cfClient.Login{ - // Credentials: cfClient.Credentials{ + // permissions := datautil.ConvertStringArr(d.Get(fmt.Sprintf("login.%v.credentials.0.permissions", idx)).([]interface{})) + // login := cfclient.Login{ + // Credentials: cfclient.Credentials{ // Permissions: permissions, // }, // Idp: d.Get(fmt.Sprintf("login.%v.idp_id", idx)).(string), diff --git a/codefresh/utils.go b/codefresh/utils.go deleted file mode 100644 index a60ebf15..00000000 --- a/codefresh/utils.go +++ /dev/null @@ -1,173 +0,0 @@ -package codefresh - -import ( - "bytes" - "fmt" - "io/ioutil" - "log" - "regexp" - "strings" - - "github.com/sclevine/yj/convert" - - cfClient "github.com/codefresh-io/terraform-provider-codefresh/client" - "github.com/dlclark/regexp2" - "github.com/ghodss/yaml" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - "github.com/mikefarah/yq/v4/pkg/yqlib" - logging "gopkg.in/op/go-logging.v1" -) - -func convertStringArr(ifaceArr []interface{}) []string { - return convertAndMapStringArr(ifaceArr, func(s string) string { return s }) -} - -func convertAndMapStringArr(ifaceArr []interface{}, f func(string) string) []string { - var arr []string - for _, v := range ifaceArr { - if v == nil { - continue - } - arr = append(arr, f(v.(string))) - } - return arr -} - -func convertVariables(vars []cfClient.Variable) map[string]string { - res := make(map[string]string, len(vars)) - for _, v := range vars { - res[v.Key] = v.Value - } - return res -} - -func flattenStringArr(sArr []string) []interface{} { - iArr := []interface{}{} - for _, s := range sArr { - iArr = append(iArr, s) - } - return iArr -} - -func stringIsYaml(i interface{}, k string) (warnings []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) - return warnings, errors - } - - if _, err := normalizeYamlString(v); err != nil { - errors = append(errors, fmt.Errorf("%q contains an invalid YAML: %s", k, err)) - } - - return warnings, errors -} - -func normalizeFieldName(fieldName string) string { - reg, err := regexp.Compile("[^a-z0-9_]+") - if err != nil { - log.Printf("[DEBUG] Unable to compile regexp for field name normalization. Error = %v", err) - } - return reg.ReplaceAllString(fieldName, "") -} - -func normalizeYamlString(yamlString interface{}) (string, error) { - var j map[string]interface{} - - if yamlString == nil || yamlString.(string) == "" { - return "", nil - } - - s := yamlString.(string) - err := yaml.Unmarshal([]byte(s), &j) - if err != nil { - return s, err - } - - bytes, _ := yaml.Marshal(j) - return string(bytes[:]), nil -} - -func suppressEquivalentYamlDiffs(k, old, new string, d *schema.ResourceData) bool { - normalizedOld, err := normalizeYamlString(old) - - if err != nil { - log.Printf("[ERROR] Unable to normalize data body: %s", err) - return false - } - - normalizedNew, err := normalizeYamlString(new) - - if err != nil { - log.Printf("[ERROR] Unable to normalize data body: %s", err) - return false - } - - return normalizedOld == normalizedNew -} - -// This function has the same structure of StringIsValidRegExp from the terraform plugin SDK -// https://github.com/hashicorp/terraform-plugin-sdk/blob/695f0c7b92e26444786b8963e00c665f1b4ef400/helper/validation/strings.go#L225 -// It has been modified to use the library https://github.com/dlclark/regexp2 instead of the standard regex golang package -// in order to support complex regular expressions including perl regex syntax -func stringIsValidRe2RegExp(i interface{}, k string) (warnings []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) - return warnings, errors - } - - if _, err := regexp2.Compile(v, regexp2.RE2); err != nil { - errors = append(errors, fmt.Errorf("%q: %s", k, err)) - } - - return warnings, errors -} - -// Get a value from a YAML string using yq -func yq(yamlString string, expression string) (string, error) { - yqEncoder := yqlib.NewYamlEncoder(0, false, yqlib.NewDefaultYamlPreferences()) - yqDecoder := yqlib.NewYamlDecoder(yqlib.NewDefaultYamlPreferences()) - yqEvaluator := yqlib.NewStringEvaluator() - - // Disable yq logging - yqLogBackend := logging.AddModuleLevel(logging.NewLogBackend(ioutil.Discard, "", 0)) - yqlib.GetLogger().SetBackend(yqLogBackend) - - yamlString, err := yqEvaluator.Evaluate(yamlString, expression, yqEncoder, yqDecoder) - yamlString = strings.TrimSpace(yamlString) - - if yamlString == "null" { // yq's Evaluate() returns "null" if the expression does not match anything - return "", err - } - return yamlString, err -} - -// Convert a YAML string to JSON while preserving the order of map keys (courtesy of yj package). -// If this were to use yaml.Unmarshal() and json.Marshal() instead, the order of map keys would be lost. -func yamlToJson(yamlString string) (string, error) { - yamlConverter := convert.YAML{} - jsonConverter := convert.JSON{} - - yamlDecoded, err := yamlConverter.Decode(strings.NewReader(yamlString)) - if err != nil { - return "", err - } - - jsonBuffer := new(bytes.Buffer) - err = jsonConverter.Encode(jsonBuffer, yamlDecoded) - if err != nil { - return "", err - } - - return jsonBuffer.String(), nil -} - -func testAccGetResourceId(s *terraform.State, resourceName string) (string, error) { - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return "", fmt.Errorf("resource %s not found", resourceName) - } - return rs.Primary.ID, nil -} \ No newline at end of file