diff --git a/client/user.go b/client/user.go index 8394912..68c5287 100644 --- a/client/user.go +++ b/client/user.go @@ -63,20 +63,22 @@ type UserAccounts struct { Account []Account `json:"account"` } -func (client *Client) AddNewUserToAccount(accountId, userName, userEmail string) (*User, error) { - - // For whatever reason, this endpoint accep - userDetails := fmt.Sprintf(`{"userDetails": "%s"}`, userEmail) +// The API accepts two different schemas when updating the user details +func generateUserDetailsBody(userName, userEmail string) string { + userDetails := fmt.Sprintf(`{"userDetails": "%s"}`, userEmail) if userName != "" { userDetails = fmt.Sprintf(`{"userName": "%s", "email": "%s"}`, userName, userEmail) } + return userDetails +} - fullPath := fmt.Sprintf("/accounts/%s/adduser", accountId) +func (client *Client) AddNewUserToAccount(accountId, userName, userEmail string) (*User, error) { + fullPath := fmt.Sprintf("/accounts/%s/adduser", accountId) opts := RequestOptions{ Path: fullPath, Method: "POST", - Body: []byte(userDetails), + Body: []byte(generateUserDetailsBody(userName, userEmail)), } resp, err := client.RequestAPI(&opts) @@ -342,3 +344,27 @@ func (client *Client) UpdateUserAccounts(userId string, accounts []Account) erro return nil } + +func (client *Client) UpdateUserDetails(accountId, userId, userName, userEmail string) (*User, error) { + + fullPath := fmt.Sprintf("/accounts/%s/%s/updateuser", accountId, userId) + opts := RequestOptions{ + Path: fullPath, + Method: "POST", + Body: []byte(generateUserDetailsBody(userName, userEmail)), + } + + resp, err := client.RequestAPI(&opts) + if err != nil { + return nil, err + } + + var respUser User + + err = DecodeResponseInto(resp, &respUser) + if err != nil { + return nil, err + } + + return &respUser, nil +} diff --git a/codefresh/provider_test.go b/codefresh/provider_test.go index ac007c8..7fa6bce 100644 --- a/codefresh/provider_test.go +++ b/codefresh/provider_test.go @@ -24,7 +24,7 @@ func TestProvider(t *testing.T) { } func testAccPreCheck(t *testing.T) { - if v := os.Getenv("CODEFRESH_API_KEY"); v == "" { - t.Fatal("CODEFRESH_API_KEY must be set for acceptance tests") + if v := os.Getenv(ENV_CODEFRESH_API_KEY); v == "" { + t.Fatalf("%s must be set for acceptance tests", ENV_CODEFRESH_API_KEY) } } diff --git a/codefresh/resource_account_user_association.go b/codefresh/resource_account_user_association.go index d5a2b70..7b3e9f0 100644 --- a/codefresh/resource_account_user_association.go +++ b/codefresh/resource_account_user_association.go @@ -37,6 +37,11 @@ func resourceAccountUserAssociation() *schema.Resource { Optional: true, Default: false, }, + "username": { + Computed: true, + Type: schema.TypeString, + Description: "The username of the associated user.", + }, "status": { Computed: true, Type: schema.TypeString, @@ -94,6 +99,7 @@ func resourceAccountUserAssociationRead(d *schema.ResourceData, meta interface{} for _, user := range currentAccount.Users { if user.ID == userID { d.Set("email", user.Email) + d.Set("username", user.UserName) d.Set("status", user.Status) d.Set("admin", false) // avoid missing attributes after import for _, admin := range currentAccount.Admins { @@ -119,6 +125,16 @@ func resourceAccountUserAssociationUpdate(d *schema.ResourceData, meta interface return err } + if d.HasChange("email") { + user, err := client.UpdateUserDetails(currentAccount.ID, d.Id(), d.Get("username").(string), d.Get("email").(string)) + if err != nil { + return err + } + if user.Email != d.Get("email").(string) { + return fmt.Errorf("failed to update user email, despite successful API response") + } + } + if d.HasChange("admin") { if d.Get("admin").(bool) { err = client.SetUserAsAccountAdmin(currentAccount.ID, d.Id()) diff --git a/codefresh/resource_account_user_association_test.go b/codefresh/resource_account_user_association_test.go index edcb038..a81ceae 100644 --- a/codefresh/resource_account_user_association_test.go +++ b/codefresh/resource_account_user_association_test.go @@ -37,7 +37,7 @@ func TestAccCodefreshAccountUserAssociation_Activation(t *testing.T) { testUserEmail := testAccCodefreshAccountUserAssociationGenerateUserEmail() - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ @@ -78,7 +78,7 @@ func TestAccCodefreshAccountUserAssociation_StatusPending_Email_ForceNew(t *test var resourceId string var err error - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ @@ -98,7 +98,6 @@ func TestAccCodefreshAccountUserAssociation_StatusPending_Email_ForceNew(t *test }, }, { - // Test that an email change on a pending user does NOT force a new resource PreConfig: func() { testUserEmail = testAccCodefreshAccountUserAssociationGenerateUserEmail() }, @@ -107,18 +106,22 @@ func TestAccCodefreshAccountUserAssociation_StatusPending_Email_ForceNew(t *test resource.TestCheckResourceAttr(resourceName, "email", testUserEmail), resource.TestCheckResourceAttr(resourceName, "admin", "true"), resource.TestCheckResourceAttr(resourceName, "status", "pending"), - func(s *terraform.State) error { - newResourceId, err := testAccGetResourceId(s, resourceName) - if err != nil { - return err - } - if resourceId != newResourceId { - return fmt.Errorf("did not expect email change on pending user to force a new resource") - } - return nil - }, ), }, + { + // 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) + if err != nil { + return err + } + if resourceId != newResourceId { + return fmt.Errorf("did not expect email change on pending user to force a new resource") + } + return nil + }, + }, }, }) } @@ -128,8 +131,9 @@ func TestAccCodefreshAccountUserAssociation_StatusNew_Email_ForceNew(t *testing. testUserEmail := testAccCodefreshAccountUserAssociationGenerateUserEmail() var resourceId string + var err error - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ @@ -144,7 +148,7 @@ func TestAccCodefreshAccountUserAssociation_StatusNew_Email_ForceNew(t *testing. { RefreshState: true, Check: func(s *terraform.State) error { - _, err := testAccGetResourceId(s, resourceName) + resourceId, err = testAccGetResourceId(s, resourceName) return err }, }, @@ -164,18 +168,21 @@ func TestAccCodefreshAccountUserAssociation_StatusNew_Email_ForceNew(t *testing. resource.TestCheckResourceAttr(resourceName, "email", testUserEmail), resource.TestCheckResourceAttr(resourceName, "admin", "true"), resource.TestCheckResourceAttr(resourceName, "status", "new"), - func(s *terraform.State) error { - newResourceId, err := testAccGetResourceId(s, resourceName) - if err != nil { - return err - } - if resourceId == newResourceId { - return fmt.Errorf("expected email change on activated user to force a new resource") - } - return nil - }, ), }, + { + RefreshState: true, + Check: func(s *terraform.State) error { + newResourceId, err := testAccGetResourceId(s, resourceName) + if err != nil { + return err + } + if resourceId == newResourceId { + return fmt.Errorf("expected email change on activated user to force a new resource") + } + return nil + }, + }, }, }) } diff --git a/examples/account_user_associations/main.tf b/examples/account_user_associations/main.tf new file mode 100644 index 0000000..580ad88 --- /dev/null +++ b/examples/account_user_associations/main.tf @@ -0,0 +1,8 @@ +resource "codefresh_account_user_association" "user" { + email = "terraform-test-user+user-change@codefresh.io" +} + +resource "codefresh_account_user_association" "admin" { + email = "terraform-test-user+admin-change@codefresh.io" + admin = true +} \ No newline at end of file diff --git a/examples/account_user_associations/versions.tf b/examples/account_user_associations/versions.tf new file mode 100644 index 0000000..588936b --- /dev/null +++ b/examples/account_user_associations/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + codefresh = { + source = "codefresh-io/codefresh" + } + } +} \ No newline at end of file diff --git a/tf_modules/accounts_users/main.tf b/tf_modules/accounts_users/main.tf index e350db5..4578dfd 100644 --- a/tf_modules/accounts_users/main.tf +++ b/tf_modules/accounts_users/main.tf @@ -66,4 +66,4 @@ resource "codefresh_account_admins" "acc_admins" { for k, u in var.users: codefresh_user.users[k].id if contains(u.admin_of_accounts, each.key) ] -} +} \ No newline at end of file