Skip to content

Commit ce3870a

Browse files
authored
Merge pull request #137 from DrFaust92/user-repo-permission
user repo permission resource
2 parents a9746ed + a968e7a commit ce3870a

File tree

4 files changed

+332
-0
lines changed

4 files changed

+332
-0
lines changed

bitbucket/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func Provider() *schema.Provider {
8686
"bitbucket_project_default_reviewers": resourceProjectDefaultReviewers(),
8787
"bitbucket_repository": resourceRepository(),
8888
"bitbucket_repository_group_permission": resourceRepositoryGroupPermission(),
89+
"bitbucket_repository_user_permission": resourceRepositoryUserPermission(),
8990
"bitbucket_repository_variable": resourceRepositoryVariable(),
9091
"bitbucket_ssh_key": resourceSshKey(),
9192
"bitbucket_workspace_hook": resourceWorkspaceHook(),
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package bitbucket
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"log"
10+
"net/http"
11+
"strings"
12+
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
14+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
15+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
16+
)
17+
18+
type RepositoryUserPermission struct {
19+
Permission string `json:"permission"`
20+
User *RepositoryUser `json:"user,omitempty"`
21+
}
22+
23+
type RepositoryUser struct {
24+
UUID string `json:"uuid,omitempty"`
25+
}
26+
27+
func resourceRepositoryUserPermission() *schema.Resource {
28+
return &schema.Resource{
29+
CreateWithoutTimeout: resourceRepositoryUserPermissionPut,
30+
ReadWithoutTimeout: resourceRepositoryUserPermissionRead,
31+
UpdateWithoutTimeout: resourceRepositoryUserPermissionPut,
32+
DeleteWithoutTimeout: resourceRepositoryUserPermissionDelete,
33+
Importer: &schema.ResourceImporter{
34+
StateContext: schema.ImportStatePassthroughContext,
35+
},
36+
37+
Schema: map[string]*schema.Schema{
38+
"workspace": {
39+
Type: schema.TypeString,
40+
Required: true,
41+
ForceNew: true,
42+
},
43+
"repo_slug": {
44+
Type: schema.TypeString,
45+
Required: true,
46+
ForceNew: true,
47+
},
48+
"user_id": {
49+
Type: schema.TypeString,
50+
Required: true,
51+
ForceNew: true,
52+
},
53+
"permission": {
54+
Type: schema.TypeString,
55+
Required: true,
56+
ValidateFunc: validation.StringInSlice([]string{"admin", "write", "read", "none"}, false),
57+
},
58+
},
59+
}
60+
}
61+
62+
func createRepositoryUserPermission(d *schema.ResourceData) *RepositoryUserPermission {
63+
64+
permission := &RepositoryUserPermission{
65+
Permission: d.Get("permission").(string),
66+
}
67+
68+
return permission
69+
}
70+
71+
func resourceRepositoryUserPermissionPut(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
72+
client := m.(Clients).httpClient
73+
permission := createRepositoryUserPermission(d)
74+
75+
payload, err := json.Marshal(permission)
76+
if err != nil {
77+
return diag.FromErr(err)
78+
}
79+
80+
workspace := d.Get("workspace").(string)
81+
repoSlug := d.Get("repo_slug").(string)
82+
userSlug := d.Get("user_id").(string)
83+
84+
permissionReq, err := client.Put(fmt.Sprintf("2.0/repositories/%s/%s/permissions-config/users/%s",
85+
workspace,
86+
repoSlug,
87+
userSlug,
88+
), bytes.NewBuffer(payload))
89+
90+
if err != nil {
91+
return diag.FromErr(err)
92+
}
93+
94+
body, readerr := io.ReadAll(permissionReq.Body)
95+
if readerr != nil {
96+
return diag.FromErr(readerr)
97+
}
98+
99+
decodeerr := json.Unmarshal(body, &permission)
100+
if decodeerr != nil {
101+
return diag.FromErr(decodeerr)
102+
}
103+
104+
if d.IsNewResource() {
105+
d.SetId(fmt.Sprintf("%s:%s:%s", workspace, repoSlug, userSlug))
106+
}
107+
108+
return resourceRepositoryUserPermissionRead(ctx, d, m)
109+
}
110+
111+
func resourceRepositoryUserPermissionRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
112+
client := m.(Clients).httpClient
113+
114+
workspace, repoSlug, userSlug, err := repositoryUserPermissionId(d.Id())
115+
if err != nil {
116+
return diag.FromErr(err)
117+
}
118+
119+
permissionReq, err := client.Get(fmt.Sprintf("2.0/repositories/%s/%s/permissions-config/users/%s",
120+
workspace,
121+
repoSlug,
122+
userSlug,
123+
))
124+
125+
if permissionReq.StatusCode == http.StatusNotFound {
126+
log.Printf("[WARN] Repository User Permission (%s) not found, removing from state", d.Id())
127+
d.SetId("")
128+
return nil
129+
}
130+
131+
if err != nil {
132+
return diag.FromErr(err)
133+
}
134+
135+
var permission RepositoryUserPermission
136+
137+
body, readerr := io.ReadAll(permissionReq.Body)
138+
if readerr != nil {
139+
return diag.FromErr(readerr)
140+
}
141+
142+
log.Printf("Repository User Permission raw is: %#v", string(body))
143+
144+
decodeerr := json.Unmarshal(body, &permission)
145+
if decodeerr != nil {
146+
return diag.FromErr(decodeerr)
147+
}
148+
149+
log.Printf("Repository User Permission decoded is: %#v", permission)
150+
151+
d.Set("permission", permission.Permission)
152+
d.Set("user_id", permission.User.UUID)
153+
d.Set("workspace", workspace)
154+
d.Set("repo_slug", repoSlug)
155+
156+
return nil
157+
}
158+
159+
func resourceRepositoryUserPermissionDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
160+
client := m.(Clients).httpClient
161+
162+
workspace, repoSlug, userSlug, err := repositoryUserPermissionId(d.Id())
163+
if err != nil {
164+
return diag.FromErr(err)
165+
}
166+
167+
_, err = client.Delete(fmt.Sprintf("2.0/repositories/%s/%s/permissions-config/users/%s",
168+
workspace,
169+
repoSlug,
170+
userSlug,
171+
))
172+
173+
return diag.FromErr(err)
174+
}
175+
176+
func repositoryUserPermissionId(id string) (string, string, string, error) {
177+
parts := strings.Split(id, ":")
178+
179+
if len(parts) != 3 {
180+
return "", "", "", fmt.Errorf("unexpected format of ID (%q), expected WORKSPACE:REPO-SLUG:GROUP-SLUG", id)
181+
}
182+
183+
return parts[0], parts[1], parts[2], nil
184+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package bitbucket
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"os"
7+
"testing"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
12+
)
13+
14+
func TestAccBitbucketRepositoryUserPermission_basic(t *testing.T) {
15+
var repositoryUserPermission RepositoryUserPermission
16+
resourceName := "bitbucket_repository_user_permission.test"
17+
workspace := os.Getenv("BITBUCKET_TEAM")
18+
rName := acctest.RandomWithPrefix("tf-test")
19+
20+
resource.Test(t, resource.TestCase{
21+
PreCheck: func() { testAccPreCheck(t) },
22+
Providers: testAccProviders,
23+
CheckDestroy: testAccCheckBitbucketRepositoryUserPermissionDestroy,
24+
Steps: []resource.TestStep{
25+
{
26+
Config: testAccBitbucketRepositoryUserPermissionConfig(workspace, rName, "read"),
27+
Check: resource.ComposeTestCheckFunc(
28+
testAccCheckBitbucketRepositoryUserPermissionExists(resourceName, &repositoryUserPermission),
29+
resource.TestCheckResourceAttrPair(resourceName, "repo_slug", "bitbucket_repository.test", "name"),
30+
resource.TestCheckResourceAttrPair(resourceName, "user_id", "data.bitbucket_current_user.test", "id"),
31+
resource.TestCheckResourceAttr(resourceName, "workspace", workspace),
32+
resource.TestCheckResourceAttr(resourceName, "permission", "read"),
33+
),
34+
},
35+
{
36+
ResourceName: resourceName,
37+
ImportState: true,
38+
ImportStateVerify: true,
39+
},
40+
{
41+
Config: testAccBitbucketRepositoryUserPermissionConfig(workspace, rName, "write"),
42+
Check: resource.ComposeTestCheckFunc(
43+
testAccCheckBitbucketRepositoryUserPermissionExists(resourceName, &repositoryUserPermission),
44+
resource.TestCheckResourceAttrPair(resourceName, "repo_slug", "bitbucket_repository.test", "name"),
45+
resource.TestCheckResourceAttrPair(resourceName, "user_id", "data.bitbucket_current_user.test", "id"),
46+
resource.TestCheckResourceAttr(resourceName, "workspace", workspace),
47+
resource.TestCheckResourceAttr(resourceName, "permission", "write"),
48+
),
49+
},
50+
},
51+
})
52+
}
53+
54+
func testAccCheckBitbucketRepositoryUserPermissionDestroy(s *terraform.State) error {
55+
client := testAccProvider.Meta().(Clients).httpClient
56+
for _, rs := range s.RootModule().Resources {
57+
if rs.Type != "bitbucket_repository_user_permission" {
58+
continue
59+
}
60+
61+
response, err := client.Get(fmt.Sprintf("2.0/repositories/%s/%s/permissions-config/users/%s", rs.Primary.Attributes["workspace"], rs.Primary.Attributes["repo_slug"], rs.Primary.Attributes["user_id"]))
62+
63+
if err == nil {
64+
return fmt.Errorf("The resource was found should have errored")
65+
}
66+
67+
if response.StatusCode != http.StatusNotFound {
68+
return fmt.Errorf("Repository User Permission still exists")
69+
}
70+
71+
}
72+
return nil
73+
}
74+
75+
func testAccCheckBitbucketRepositoryUserPermissionExists(n string, repositoryUserPermission *RepositoryUserPermission) resource.TestCheckFunc {
76+
return func(s *terraform.State) error {
77+
rs, ok := s.RootModule().Resources[n]
78+
if !ok {
79+
return fmt.Errorf("Not found %s", n)
80+
}
81+
if rs.Primary.ID == "" {
82+
return fmt.Errorf("No Repository User Permission ID is set")
83+
}
84+
return nil
85+
}
86+
}
87+
88+
func testAccBitbucketRepositoryUserPermissionConfig(workspace, rName, permission string) string {
89+
return fmt.Sprintf(`
90+
resource "bitbucket_repository" "test" {
91+
owner = %[1]q
92+
name = %[2]q
93+
}
94+
95+
data "bitbucket_current_user" "test" {}
96+
97+
resource "bitbucket_repository_user_permission" "test" {
98+
workspace = %[1]q
99+
repo_slug = bitbucket_repository.test.name
100+
user_id = data.bitbucket_current_user.test.id
101+
permission = %[3]q
102+
}
103+
`, workspace, rName, permission)
104+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
layout: "bitbucket"
3+
page_title: "Bitbucket: bitbucket_repository_user_permission"
4+
sidebar_current: "docs-bitbucket-resource-repository-user-permission"
5+
description: |-
6+
Provides a Bitbucket Repository User Permission Resource
7+
---
8+
9+
# bitbucket\_hook
10+
11+
Provides a Bitbucket Repository User Permission Resource.
12+
13+
This allows you set explicit user permission for a repository.
14+
15+
OAuth2 Scopes: `repository:admin`
16+
17+
## Example Usage
18+
19+
```hcl
20+
resource "bitbucket_repository_user_permission" "example" {
21+
workspace = "example"
22+
repo_slug = bitbucket_repository.example.name
23+
user_id = "user-id"
24+
permission = "read"
25+
}
26+
```
27+
28+
## Argument Reference
29+
30+
The following arguments are supported:
31+
32+
* `workspace` - (Required) The workspace id.
33+
* `repo_slug` - (Required) The repository slug.
34+
* `user_id` - (Required) The UUID of the user.
35+
* `permission` - (Required) Permissions can be one of `read`, `write`, `none`, and `admin`.
36+
37+
## Import
38+
39+
Repository User Permissions can be imported using their `workspace:repo-slug:user-id` ID, e.g.
40+
41+
```sh
42+
terraform import bitbucket_repository_user_permission.example workspace:repo-slug:user-id
43+
```

0 commit comments

Comments
 (0)