Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4ed6838

Browse files
authoredDec 16, 2024··
Add vercel_project_members resource (#240)
* Add support for project members resource * Fix test name lint
1 parent 1a90d0b commit 4ed6838

13 files changed

+1096
-25
lines changed
 

‎client/project_member.go

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package client
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-log/tflog"
8+
)
9+
10+
type ProjectMember struct {
11+
UserID string `json:"uid,omitempty"`
12+
Username string `json:"username,omitempty"`
13+
Email string `json:"email,omitempty"`
14+
Role string `json:"role"`
15+
}
16+
17+
type AddProjectMembersRequest struct {
18+
ProjectID string `json:"-"`
19+
TeamID string `json:"-"`
20+
Members []ProjectMember `json:"members"`
21+
}
22+
23+
func (c *Client) AddProjectMembers(ctx context.Context, request AddProjectMembersRequest) error {
24+
url := fmt.Sprintf("%s/v1/projects/%s/members/batch", c.baseURL, request.ProjectID)
25+
if c.teamID(request.TeamID) != "" {
26+
url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(request.TeamID))
27+
}
28+
tflog.Info(ctx, "adding project members", map[string]interface{}{
29+
"url": url,
30+
})
31+
err := c.doRequest(clientRequest{
32+
ctx: ctx,
33+
method: "POST",
34+
url: url,
35+
body: string(mustMarshal(request)),
36+
}, nil)
37+
if err != nil {
38+
tflog.Error(ctx, "error adding project members", map[string]interface{}{
39+
"url": url,
40+
"members": request.Members,
41+
})
42+
}
43+
return err
44+
}
45+
46+
type RemoveProjectMembersRequest struct {
47+
ProjectID string `json:"-"`
48+
TeamID string `json:"-"`
49+
Members []string `json:"members"`
50+
}
51+
52+
func (c *Client) RemoveProjectMembers(ctx context.Context, request RemoveProjectMembersRequest) error {
53+
url := fmt.Sprintf("%s/v1/projects/%s/members/batch", c.baseURL, request.ProjectID)
54+
if c.teamID(request.TeamID) != "" {
55+
url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(request.TeamID))
56+
}
57+
tflog.Info(ctx, "removing project members", map[string]interface{}{
58+
"url": url,
59+
})
60+
err := c.doRequest(clientRequest{
61+
ctx: ctx,
62+
method: "DELETE",
63+
url: url,
64+
body: string(mustMarshal(request)),
65+
}, nil)
66+
if err != nil {
67+
tflog.Error(ctx, "error removing project members", map[string]interface{}{
68+
"url": url,
69+
"members": request.Members,
70+
})
71+
}
72+
return err
73+
}
74+
75+
type UpdateProjectMemberRequest struct {
76+
UserID string `json:"uid,omitempty"`
77+
Role string `json:"role"`
78+
}
79+
80+
type UpdateProjectMembersRequest struct {
81+
ProjectID string `json:"-"`
82+
TeamID string `json:"-"`
83+
Members []UpdateProjectMemberRequest `json:"members"`
84+
}
85+
86+
func (c *Client) UpdateProjectMembers(ctx context.Context, request UpdateProjectMembersRequest) error {
87+
url := fmt.Sprintf("%s/v1/projects/%s/members", c.baseURL, request.ProjectID)
88+
if c.teamID(request.TeamID) != "" {
89+
url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(request.TeamID))
90+
}
91+
payload := string(mustMarshal(request))
92+
tflog.Info(ctx, "updating project members", map[string]interface{}{
93+
"url": url,
94+
"payload": payload,
95+
})
96+
err := c.doRequest(clientRequest{
97+
ctx: ctx,
98+
method: "PATCH",
99+
url: url,
100+
body: payload,
101+
}, nil)
102+
if err != nil {
103+
tflog.Error(ctx, "error updating project members", map[string]interface{}{
104+
"url": url,
105+
"members": request.Members,
106+
})
107+
}
108+
return err
109+
}
110+
111+
type GetProjectMembersRequest struct {
112+
ProjectID string `json:"-"`
113+
TeamID string `json:"-"`
114+
}
115+
116+
func (c *Client) ListProjectMembers(ctx context.Context, request GetProjectMembersRequest) ([]ProjectMember, error) {
117+
url := fmt.Sprintf("%s/v1/projects/%s/members", c.baseURL, request.ProjectID)
118+
if c.teamID(request.TeamID) != "" {
119+
url = fmt.Sprintf("%s?teamId=%s&limit=100", url, c.teamID(request.TeamID))
120+
}
121+
tflog.Info(ctx, "listing project members", map[string]interface{}{
122+
"url": url,
123+
})
124+
125+
var resp struct {
126+
Members []ProjectMember `json:"members"`
127+
}
128+
err := c.doRequest(clientRequest{
129+
ctx: ctx,
130+
method: "GET",
131+
url: url,
132+
body: string(mustMarshal(request)),
133+
}, &resp)
134+
if err != nil {
135+
tflog.Error(ctx, "error getting project members", map[string]interface{}{
136+
"url": url,
137+
})
138+
}
139+
return resp.Members, err
140+
}

‎docs/data-sources/project_members.md

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "vercel_project_members Data Source - terraform-provider-vercel"
4+
subcategory: ""
5+
description: |-
6+
Retrieves members and their roles for a Vercel Project.
7+
---
8+
9+
# vercel_project_members (Data Source)
10+
11+
Retrieves members and their roles for a Vercel Project.
12+
13+
## Example Usage
14+
15+
```terraform
16+
data "vercel_project" "example" {
17+
name = "example-with-members"
18+
}
19+
20+
data "vercel_project_members" "example" {
21+
project_id = data.vercel_project.example.id
22+
}
23+
```
24+
25+
<!-- schema generated by tfplugindocs -->
26+
## Schema
27+
28+
### Required
29+
30+
- `project_id` (String) The ID of the Vercel Project.
31+
32+
### Optional
33+
34+
- `team_id` (String) The team ID to which the project belongs. Required when accessing a team project if a default team has not been set in the provider.
35+
36+
### Read-Only
37+
38+
- `members` (Attributes Set) The set of members in this project. (see [below for nested schema](#nestedatt--members))
39+
40+
<a id="nestedatt--members"></a>
41+
### Nested Schema for `members`
42+
43+
Read-Only:
44+
45+
- `email` (String) The email of the user.
46+
- `role` (String) The role of the user in the project. One of 'MEMBER', 'PROJECT_DEVELOPER', or 'PROJECT_VIEWER'.
47+
- `user_id` (String) The ID of the user.
48+
- `username` (String) The username of the user.

‎docs/resources/project_members.md

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "vercel_project_members Resource - terraform-provider-vercel"
4+
subcategory: ""
5+
description: |-
6+
Manages members and their roles for a Vercel Project.
7+
~> Note that this resource does not manage the complete set of members for a project, only the members that
8+
are explicitly configured here. This is deliberately done to allow granular additions.
9+
This, however, means config drift will not be detected for members that are added or removed outside of terraform.
10+
---
11+
12+
# vercel_project_members (Resource)
13+
14+
Manages members and their roles for a Vercel Project.
15+
16+
~> Note that this resource does not manage the complete set of members for a project, only the members that
17+
are explicitly configured here. This is deliberately done to allow granular additions.
18+
This, however, means config drift will not be detected for members that are added or removed outside of terraform.
19+
20+
## Example Usage
21+
22+
```terraform
23+
resource "vercel_project" "example" {
24+
name = "example-with-members"
25+
}
26+
27+
resource "vercel_project_members" "example" {
28+
project_id = vercel_project.example.id
29+
30+
members = [{
31+
email = "user@example.com"
32+
role = "PROJECT_VIEWER"
33+
}, {
34+
username = "some-example-user"
35+
role = "PROJECT_DEVELOPER"
36+
}]
37+
}
38+
```
39+
40+
<!-- schema generated by tfplugindocs -->
41+
## Schema
42+
43+
### Required
44+
45+
- `members` (Attributes Set) The set of members to manage for this project. (see [below for nested schema](#nestedatt--members))
46+
- `project_id` (String) The ID of the existing Vercel Project.
47+
48+
### Optional
49+
50+
- `team_id` (String) The team ID to add the project to. Required when configuring a team resource if a default team has not been set in the provider.
51+
52+
<a id="nestedatt--members"></a>
53+
### Nested Schema for `members`
54+
55+
Required:
56+
57+
- `role` (String) The role that the user should have in the project. One of 'MEMBER', 'PROJECT_DEVELOPER', or 'PROJECT_VIEWER'.
58+
59+
Optional:
60+
61+
- `email` (String) The email of the user to add to the project. Exactly one of `user_id`, `email`, or `username` must be specified.
62+
- `user_id` (String) The ID of the user to add to the project. Exactly one of `user_id`, `email`, or `username` must be specified.
63+
- `username` (String) The username of the user to add to the project. Exactly one of `user_id`, `email`, or `username` must be specified.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
data "vercel_project" "example" {
2+
name = "example-with-members"
3+
}
4+
5+
data "vercel_project_members" "example" {
6+
project_id = data.vercel_project.example.id
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
resource "vercel_project" "example" {
2+
name = "example-with-members"
3+
}
4+
5+
resource "vercel_project_members" "example" {
6+
project_id = vercel_project.example.id
7+
8+
members = [{
9+
email = "user@example.com"
10+
role = "PROJECT_VIEWER"
11+
}, {
12+
username = "some-example-user"
13+
role = "PROJECT_DEVELOPER"
14+
}]
15+
}

‎go.mod

-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ require (
4545
github.com/mitchellh/mapstructure v1.5.0 // indirect
4646
github.com/mitchellh/reflectwalk v1.0.2 // indirect
4747
github.com/oklog/run v1.1.0 // indirect
48-
github.com/vercel/terraform-provider-vercel v1.14.1
4948
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
5049
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
5150
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect

‎go.sum

-2
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
140140
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
141141
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
142142
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
143-
github.com/vercel/terraform-provider-vercel v1.14.1 h1:ghAjFkMMzka4XuoBYdu1OXM/K7FQEj8wUd+xMPPOGrg=
144-
github.com/vercel/terraform-provider-vercel v1.14.1/go.mod h1:AdFCiUD0XP8XOi6tnhaCh7I0vyq2TAPmI+GcIp3+7SI=
145143
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
146144
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
147145
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.