Skip to content

Commit

Permalink
Merge pull request #44 from DrFaust92/group-member
Browse files Browse the repository at this point in the history
Group member resource
  • Loading branch information
DrFaust92 authored Mar 11, 2022
2 parents 596a049 + e31798a commit 687a678
Show file tree
Hide file tree
Showing 5 changed files with 339 additions and 2 deletions.
1 change: 1 addition & 0 deletions bitbucket/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func Provider() *schema.Provider {
ResourcesMap: map[string]*schema.Resource{
"bitbucket_hook": resourceHook(),
"bitbucket_group": resourceGroup(),
"bitbucket_group_membership": resourceGroupMembership(),
"bitbucket_default_reviewers": resourceDefaultReviewers(),
"bitbucket_repository": resourceRepository(),
"bitbucket_repository_variable": resourceRepositoryVariable(),
Expand Down
3 changes: 1 addition & 2 deletions bitbucket/resource_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ func resourceGroupsRead(d *schema.ResourceData, m interface{}) error {
return err
}

// filter := fmt.Sprintf("group=%s/%s", workspace, slug)
groupsReq, _ := client.Get(fmt.Sprintf("1.0/groups/%s/%s", workspace, slug))

if groupsReq.StatusCode == 404 {
Expand All @@ -106,7 +105,7 @@ func resourceGroupsRead(d *schema.ResourceData, m interface{}) error {
}

if groupsReq.Body == nil {
return fmt.Errorf("error readong Group (%s): empty response", d.Id())
return fmt.Errorf("error reading Group (%s): empty response", d.Id())
}

var grp *UserGroup
Expand Down
155 changes: 155 additions & 0 deletions bitbucket/resource_group_membership.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package bitbucket

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"strings"

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

type UserGroupMembership struct {
UUID string `json:"uuid,omitempty"`
}

func resourceGroupMembership() *schema.Resource {
return &schema.Resource{
Create: resourceGroupMembershipsPut,
Read: resourceGroupMembershipsRead,
Delete: resourceGroupMembershipsDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"workspace": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"group_slug": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"uuid": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"slug": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceGroupMembershipsPut(d *schema.ResourceData, m interface{}) error {
client := m.(*Client)

workspace := d.Get("workspace").(string)
groupSlug := d.Get("group_slug").(string)
uuid := d.Get("uuid").(string)

_, err := client.PutOnly(fmt.Sprintf("1.0/groups/%s/%s/members/%s",
workspace, groupSlug, uuid))
if err != nil {
return err
}

d.SetId(string(fmt.Sprintf("%s/%s/%s", workspace, groupSlug, uuid)))

return resourceGroupMembershipsRead(d, m)
}

func resourceGroupMembershipsRead(d *schema.ResourceData, m interface{}) error {
client := m.(*Client)

workspace, slug, uuid, err := groupMemberId(d.Id())
if err != nil {
return err
}

groupsReq, _ := client.Get(fmt.Sprintf("1.0/groups/%s/%s/members", workspace, slug))

if groupsReq.StatusCode == 404 {
log.Printf("[WARN] Group Membership (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if groupsReq.Body == nil {
return fmt.Errorf("error reading Group Membership (%s): empty response", d.Id())
}

var members []*UserGroupMembership

body, readerr := ioutil.ReadAll(groupsReq.Body)
if readerr != nil {
return readerr
}

log.Printf("[DEBUG] Group Membership Response JSON: %v", string(body))

decodeerr := json.Unmarshal(body, &members)
if decodeerr != nil {
return decodeerr
}

log.Printf("[DEBUG] Group Membership Response Decoded: %#v", members)

if len(members) == 0 {
return fmt.Errorf("error getting Group Members (%s): empty response", d.Id())
}

var member *UserGroupMembership
for _, mbr := range members {
if mbr.UUID == uuid {
member = mbr
break
}
}

if member == nil {
return fmt.Errorf("error getting Group Member (%s): not found", d.Id())
}

log.Printf("[DEBUG] Group Member Response Decoded: %#v", member)

d.Set("workspace", workspace)
d.Set("group_slug", slug)
d.Set("uuid", member.UUID)

return nil
}

func resourceGroupMembershipsDelete(d *schema.ResourceData, m interface{}) error {
client := m.(*Client)

workspace, slug, uuid, err := groupMemberId(d.Id())
if err != nil {
return err
}

_, err = client.Delete(fmt.Sprintf("1.0/groups/%s/%s/members/%s",
workspace, slug, uuid))

if err != nil {
return err
}

return err
}

func groupMemberId(id string) (string, string, string, error) {
parts := strings.Split(id, "/")

if len(parts) != 3 {
return "", "", "", fmt.Errorf("unexpected format of ID (%q), expected WORKSPACE-ID/GROUP-SLUG-ID/MEMBER-UUID", id)
}

return parts[0], parts[1], parts[2], nil
}
132 changes: 132 additions & 0 deletions bitbucket/resource_group_membership_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package bitbucket

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"testing"

"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"
)

func TestAccBitbucketGroupMembership_basic(t *testing.T) {
var group UserGroup
resourceName := "bitbucket_group_membership.test"
grpResourceName := "bitbucket_group.test"

workspace := os.Getenv("BITBUCKET_TEAM")
rName := acctest.RandomWithPrefix("tf-test")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckBitbucketGroupMembershipDestroy,
Steps: []resource.TestStep{
{
Config: testAccBitbucketGroupMembershipConfig(workspace, rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckBitbucketGroupMembershipExists(resourceName, &group),
resource.TestCheckResourceAttrPair(resourceName, "workspace", grpResourceName, "workspace"),
resource.TestCheckResourceAttrPair(resourceName, "group_slug", grpResourceName, "slug"),
resource.TestCheckResourceAttrPair(resourceName, "uuid", "data.bitbucket_current_user.test", "id"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckBitbucketGroupMembershipDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*Client)
for _, rs := range s.RootModule().Resources {
if rs.Type != "bitbucket_group_membership" {
continue
}

workspace, slug, uuid, err := groupMemberId(rs.Primary.ID)
if err != nil {
return err
}

response, _ := client.Get(fmt.Sprintf("1.0/groups/%s/%s/members",
workspace, slug))

if response.StatusCode == 404 {
continue
}

if err != nil {
return err
}

var members []*UserGroupMembership
body, readerr := ioutil.ReadAll(response.Body)
if readerr != nil {
return readerr
}

log.Printf("[DEBUG] Group Membership Response Test JSON: %v", string(body))

decodeerr := json.Unmarshal(body, &members)
if decodeerr != nil {
return decodeerr
}

log.Printf("[DEBUG] Group Membership Response Test Decoded: %#v", members)

var member *UserGroupMembership
for _, mbr := range members {
if mbr.UUID == uuid {
member = mbr
continue
}
}

if member != nil {
return fmt.Errorf("Group Member still exists")
}
}
return nil
}

func testAccCheckBitbucketGroupMembershipExists(n string, group *UserGroup) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Group Membership ID is set")
}
return nil
}
}

func testAccBitbucketGroupMembershipConfig(workspace, rName string) string {
return fmt.Sprintf(`
data "bitbucket_workspace" "test" {
workspace = %[1]q
}
resource "bitbucket_group" "test" {
workspace = data.bitbucket_workspace.test.id
name = %[2]q
}
data "bitbucket_current_user" "test" {}
resource "bitbucket_group_membership" "test" {
workspace = bitbucket_group.test.workspace
group_slug = bitbucket_group.test.slug
uuid = data.bitbucket_current_user.test.id
}
`, workspace, rName)
}
50 changes: 50 additions & 0 deletions docs/resources/group_membership.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
layout: "bitbucket"
page_title: "Bitbucket: bitbucket_group_membership"
sidebar_current: "docs-bitbucket-resource-group-membership"
description: |-
Provides a Bitbucket Group
---

# bitbucket\_group

Provides a Bitbucket group membership resource.

This allows you to manage your group membership.

## Example Usage

```hcl
data "bitbucket_workspace" "test" {
workspace = "example"
}
resource "bitbucket_group" "test" {
workspace = data.bitbucket_workspace.test.id
name = "example"
}
data "bitbucket_current_user" "test" {}
resource "bitbucket_group_membership" "test" {
workspace = bitbucket_group.test.workspace
group_slug = bitbucket_group.test.slug
uuid = data.bitbucket_current_user.test.id
}
```

## Argument Reference

The following arguments are supported:

* `workspace` - (Required) The workspace of this repository.
* `group_slug` - (Required) The slug of the group.
* `uuid` - (Required) The member UUID to add to the group.

## Import

Group Memberss can be imported using their `workspace/group-slug/member-uuid` ID, e.g.

```sh
terraform import bitbucket_group_membership.group my-workspace/group-slug/member-uuid
```

0 comments on commit 687a678

Please sign in to comment.