Skip to content

Commit 0a7d64c

Browse files
committed
Added team project access resource and tests
1 parent 50db25d commit 0a7d64c

6 files changed

+561
-0
lines changed

errors.go

+8
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ var (
152152

153153
ErrInvalidAccessTeamID = errors.New("invalid value for team access ID")
154154

155+
ErrInvalidTeamProjectAccessID = errors.New("invalid value for team project access ID")
156+
155157
ErrInvalidTeamID = errors.New("invalid value for team ID")
156158

157159
ErrInvalidUsernames = errors.New("invalid value for usernames")
@@ -247,8 +249,12 @@ var (
247249

248250
ErrRequiredWorkspace = errors.New("workspace is required")
249251

252+
ErrRequiredProject = errors.New("project is required")
253+
250254
ErrRequiredWorkspaceID = errors.New("workspace ID is required")
251255

256+
ErrRequiredProjectID = errors.New("project ID is required")
257+
252258
ErrWorkspacesRequired = errors.New("workspaces is required")
253259

254260
ErrWorkspaceMinLimit = errors.New("must provide at least one workspace")
@@ -279,6 +285,8 @@ var (
279285

280286
ErrRequiredTeamAccessListOps = errors.New("TeamAccessListOptions is required")
281287

288+
ErrRequiredTeamProjectAccessListOps = errors.New("TeamProjectAccessListOptions is required")
289+
282290
ErrRequiredRunTriggerListOps = errors.New("RunTriggerListOptions is required")
283291

284292
ErrRequiredTFVerCreateOps = errors.New("version, URL and sha is required for AdminTerraformVersionCreateOptions")

helper_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,52 @@ func createTeamAccess(t *testing.T, client *Client, tm *Team, w *Workspace, org
16451645
}
16461646
}
16471647

1648+
func createTeamProjectAccess(t *testing.T, client *Client, tm *Team, p *Project, org *Organization) (*TeamProjectAccess, func()) {
1649+
var orgCleanup, tmCleanup, pCleanup func()
1650+
1651+
if org == nil {
1652+
org, orgCleanup = createOrganization(t, client)
1653+
}
1654+
1655+
if tm == nil {
1656+
tm, tmCleanup = createTeam(t, client, org)
1657+
}
1658+
1659+
if p == nil {
1660+
p, pCleanup = createProject(t, client, org)
1661+
}
1662+
1663+
ctx := context.Background()
1664+
tpa, err := client.TeamProjectAccess.Add(ctx, TeamProjectAccessAddOptions{
1665+
Access: ProjectAccess(TeamProjectAccessAdmin),
1666+
Team: tm,
1667+
Project: p,
1668+
})
1669+
if err != nil {
1670+
t.Fatal(err)
1671+
}
1672+
1673+
return tpa, func() {
1674+
if err := client.TeamProjectAccess.Remove(ctx, tpa.ID); err != nil {
1675+
t.Errorf("Error removing team access! WARNING: Dangling resources\n"+
1676+
"may exist! The full error is shown below.\n\n"+
1677+
"TeamAccess: %s\nError: %s", tpa.ID, err)
1678+
}
1679+
1680+
if tmCleanup != nil {
1681+
tmCleanup()
1682+
}
1683+
1684+
if orgCleanup != nil {
1685+
orgCleanup()
1686+
}
1687+
1688+
if pCleanup != nil {
1689+
pCleanup()
1690+
}
1691+
}
1692+
}
1693+
16481694
func createTeamToken(t *testing.T, client *Client, tm *Team) (*TeamToken, func()) {
16491695
var tmCleanup func()
16501696

team_project_access.go

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package tfe
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/url"
7+
)
8+
9+
// Compile-time proof of interface implementation.
10+
var _ TeamProjectAccesses = (*teamProjectAccesses)(nil)
11+
12+
// TeamProjectAccesses describes all the team project access related methods that the Terraform
13+
// Enterprise API supports
14+
//
15+
// TFE API docs: (TODO: ADD DOCS URL)
16+
type TeamProjectAccesses interface {
17+
// List all project accesses for a given project.
18+
List(ctx context.Context, options *TeamProjectAccessListOptions) (*TeamProjectAccessList, error)
19+
20+
// Add team access for a project.
21+
Add(ctx context.Context, options TeamProjectAccessAddOptions) (*TeamProjectAccess, error)
22+
23+
// Read team access by project ID.
24+
Read(ctx context.Context, teamProjectAccessID string) (*TeamProjectAccess, error)
25+
26+
// Update team access on a project.
27+
Update(ctx context.Context, teamProjectAccessID string, options TeamProjectAccessUpdateOptions) (*TeamProjectAccess, error)
28+
29+
// Remove team access from a project.
30+
Remove(ctx context.Context, teamProjectAccessID string) error
31+
}
32+
33+
// teamProjectAccesses implements TeamProjectAccesses
34+
type teamProjectAccesses struct {
35+
client *Client
36+
}
37+
38+
// TeamProjectAccessType represents a team project access type.
39+
type TeamProjectAccessType string
40+
41+
const (
42+
TeamProjectAccessAdmin TeamProjectAccessType = "admin"
43+
TeamProjectAccessRead TeamProjectAccessType = "read"
44+
)
45+
46+
// TeamProjectAccessList represents a list of team project accesses
47+
type TeamProjectAccessList struct {
48+
*Pagination
49+
Items []*TeamProjectAccess
50+
}
51+
52+
// TeamProjectAccess represents a project access for a team
53+
type TeamProjectAccess struct {
54+
ID string `jsonapi:"primary,team-projects"`
55+
Access TeamProjectAccessType `jsonapi:"attr,access"`
56+
57+
// Relations
58+
Team *Team `jsonapi:"relation,team"`
59+
Project *Project `jsonapi:"relation,project"`
60+
}
61+
62+
// TeamProjectAccessListOptions represents the options for listing team project accesses
63+
type TeamProjectAccessListOptions struct {
64+
ListOptions
65+
ProjectID string `url:"filter[project][id]"`
66+
}
67+
68+
// TeamProjectAccessAddOptions represents the options for adding team access for a project
69+
type TeamProjectAccessAddOptions struct {
70+
// Type is a public field utilized by JSON:API to
71+
// set the resource type via the field tag.
72+
// It is not a user-defined value and does not need to be set.
73+
// https://jsonapi.org/format/#crud-creating
74+
Type string `jsonapi:"primary,team-projects"`
75+
// The type of access to grant.
76+
Access *TeamProjectAccessType `jsonapi:"attr,access"`
77+
78+
// The team to add to the project
79+
Team *Team `jsonapi:"relation,team"`
80+
81+
// The project to which the team is to be added.
82+
Project *Project `jsonapi:"relation,project"`
83+
}
84+
85+
// TeamProjectAccessUpdateOptions represents the options for updating a team project access
86+
type TeamProjectAccessUpdateOptions struct {
87+
// Type is a public field utilized by JSON:API to
88+
// set the resource type via the field tag.
89+
// It is not a user-defined value and does not need to be set.
90+
// https://jsonapi.org/format/#crud-creating
91+
ID string `jsonapi:"primary,team-projects"`
92+
93+
// The type of access to grant.
94+
Access *TeamProjectAccessType `jsonapi:"attr,access,omitempty"`
95+
}
96+
97+
// List all team accesses for a given project.
98+
func (s *teamProjectAccesses) List(ctx context.Context, options *TeamProjectAccessListOptions) (*TeamProjectAccessList, error) {
99+
if err := options.valid(); err != nil {
100+
return nil, err
101+
}
102+
103+
req, err := s.client.NewRequest("GET", "team-projects", options)
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
tpal := &TeamProjectAccessList{}
109+
err = req.Do(ctx, tpal)
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
return tpal, nil
115+
}
116+
117+
// Add team access for a project.
118+
func (s *teamProjectAccesses) Add(ctx context.Context, options TeamProjectAccessAddOptions) (*TeamProjectAccess, error) {
119+
if err := options.valid(); err != nil {
120+
return nil, err
121+
}
122+
123+
req, err := s.client.NewRequest("POST", "team-projects", &options)
124+
if err != nil {
125+
return nil, err
126+
}
127+
128+
tpa := &TeamProjectAccess{}
129+
err = req.Do(ctx, tpa)
130+
if err != nil {
131+
return nil, err
132+
}
133+
134+
return tpa, nil
135+
}
136+
137+
// Read a team project access by its ID.
138+
func (s *teamProjectAccesses) Read(ctx context.Context, teamProjectAccessID string) (*TeamProjectAccess, error) {
139+
if !validStringID(&teamProjectAccessID) {
140+
return nil, ErrInvalidTeamProjectAccessID
141+
}
142+
143+
u := fmt.Sprintf("team-projects/%s", url.QueryEscape(teamProjectAccessID))
144+
req, err := s.client.NewRequest("GET", u, nil)
145+
if err != nil {
146+
return nil, err
147+
}
148+
149+
tpa := &TeamProjectAccess{}
150+
err = req.Do(ctx, tpa)
151+
if err != nil {
152+
return nil, err
153+
}
154+
155+
return tpa, nil
156+
}
157+
158+
// Update team access for a project.
159+
func (s *teamProjectAccesses) Update(ctx context.Context, teamProjectAccessID string, options TeamProjectAccessUpdateOptions) (*TeamProjectAccess, error) {
160+
if !validStringID(&teamProjectAccessID) {
161+
return nil, ErrInvalidTeamProjectAccessID
162+
}
163+
164+
u := fmt.Sprintf("team-projects/%s", url.QueryEscape(teamProjectAccessID))
165+
req, err := s.client.NewRequest("PATCH", u, &options)
166+
if err != nil {
167+
return nil, err
168+
}
169+
170+
ta := &TeamProjectAccess{}
171+
err = req.Do(ctx, ta)
172+
if err != nil {
173+
return nil, err
174+
}
175+
176+
return ta, err
177+
}
178+
179+
// Remove team access from a project.
180+
func (s *teamProjectAccesses) Remove(ctx context.Context, teamProjectAccessID string) error {
181+
if !validStringID(&teamProjectAccessID) {
182+
return ErrInvalidTeamProjectAccessID
183+
}
184+
185+
u := fmt.Sprintf("team-projects/%s", url.QueryEscape(teamProjectAccessID))
186+
req, err := s.client.NewRequest("DELETE", u, nil)
187+
if err != nil {
188+
return err
189+
}
190+
191+
return req.Do(ctx, nil)
192+
}
193+
194+
func (o *TeamProjectAccessListOptions) valid() error {
195+
if o == nil {
196+
return ErrRequiredTeamProjectAccessListOps
197+
}
198+
if !validString(&o.ProjectID) {
199+
return ErrRequiredProjectID
200+
}
201+
if !validStringID(&o.ProjectID) {
202+
return ErrInvalidProjectID
203+
}
204+
205+
return nil
206+
}
207+
208+
func (o TeamProjectAccessAddOptions) valid() error {
209+
if o.Access == nil {
210+
return ErrRequiredAccess
211+
}
212+
if o.Team == nil {
213+
return ErrRequiredTeam
214+
}
215+
if o.Project == nil {
216+
return ErrRequiredProject
217+
}
218+
return nil
219+
}

0 commit comments

Comments
 (0)