Skip to content

Commit

Permalink
Feat: environment Role assignments for Team (#668)
Browse files Browse the repository at this point in the history
* Feat: environment Role assignments for Team

* minor changes in examples
  • Loading branch information
TomerHeber committed Jul 5, 2023
1 parent e2f3f6e commit 573d5cc
Show file tree
Hide file tree
Showing 10 changed files with 629 additions and 0 deletions.
3 changes: 3 additions & 0 deletions client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ type ApiClientInterface interface {
AssignUserRoleToEnvironment(payload *AssignUserRoleToEnvironmentPayload) (*UserRoleEnvironmentAssignment, error)
RemoveUserRoleFromEnvironment(environmentId string, userId string) error
UserRoleEnvironmentAssignments(environmentId string) ([]UserRoleEnvironmentAssignment, error)
AssignTeamRoleToEnvironment(payload *AssignTeamRoleToEnvironmentPayload) (*TeamRoleEnvironmentAssignment, error)
RemoveTeamRoleFromEnvironment(environmentId string, teamId string) error
TeamRoleEnvironmentAssignments(environmentId string) ([]TeamRoleEnvironmentAssignment, error)
}

func NewApiClient(client http.HttpClientInterface, defaultOrganizationId string) ApiClientInterface {
Expand Down
44 changes: 44 additions & 0 deletions client/api_client_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions client/team_environment_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package client

type AssignTeamRoleToEnvironmentPayload struct {
TeamId string `json:"teamId"`
Role string `json:"role" tfschema:"role_id"`
EnvironmentId string `json:"environmentId"`
}

type TeamRoleEnvironmentAssignment struct {
TeamId string `json:"teamId"`
Role string `json:"role" tfschema:"role_id"`
Id string `json:"id"`
}

func (client *ApiClient) AssignTeamRoleToEnvironment(payload *AssignTeamRoleToEnvironmentPayload) (*TeamRoleEnvironmentAssignment, error) {
var result TeamRoleEnvironmentAssignment

if err := client.http.Put("/roles/assignments/teams", payload, &result); err != nil {
return nil, err
}

return &result, nil
}

func (client *ApiClient) RemoveTeamRoleFromEnvironment(environmentId string, teamId string) error {
return client.http.Delete("/roles/assignments/teams", map[string]string{"environmentId": environmentId, "teamId": teamId})
}

func (client *ApiClient) TeamRoleEnvironmentAssignments(environmentId string) ([]TeamRoleEnvironmentAssignment, error) {
var result []TeamRoleEnvironmentAssignment

if err := client.http.Get("/roles/assignments/teams", map[string]string{"environmentId": environmentId}, &result); err != nil {
return nil, err
}

return result, nil
}
136 changes: 136 additions & 0 deletions client/team_environment_assignment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package client_test

import (
"errors"

. "github.com/env0/terraform-provider-env0/client"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Team Envrionment Assignment", func() {
environmentId := "environmentId"
teamId := "teamId"

assignPayload := &AssignTeamRoleToEnvironmentPayload{
TeamId: teamId,
EnvironmentId: environmentId,
Role: "role1",
}

expectedResponse := &TeamRoleEnvironmentAssignment{
Id: "id",
}

errorMock := errors.New("error")

Describe("AssignTeamToEnvironment", func() {

Describe("Successful", func() {
var actualResult *TeamRoleEnvironmentAssignment
var err error

BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Put("/roles/assignments/teams", assignPayload, gomock.Any()).
Do(func(path string, request interface{}, response *TeamRoleEnvironmentAssignment) {
*response = *expectedResponse
}).Times(1)
actualResult, err = apiClient.AssignTeamRoleToEnvironment(assignPayload)

})

It("Should send POST request with params", func() {
httpCall.Times(1)
})

It("should return the PUT result", func() {
Expect(*actualResult).To(Equal(*expectedResponse))
})

It("Should not return error", func() {
Expect(err).To(BeNil())
})
})

Describe("Failure", func() {
var actualResult *TeamRoleEnvironmentAssignment
var err error

BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Put("/roles/assignments/teams", gomock.Any(), gomock.Any()).Return(errorMock)
actualResult, err = apiClient.AssignTeamRoleToEnvironment(assignPayload)
})

It("Should fail if API call fails", func() {
Expect(err).To(Equal(errorMock))
})

It("Should not return results", func() {
Expect(actualResult).To(BeNil())
})
})
})

Describe("RemoveTeamFromEnvironment", func() {
BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().Delete("/roles/assignments/teams", map[string]string{"environmentId": environmentId, "teamId": teamId})
apiClient.RemoveTeamRoleFromEnvironment(environmentId, teamId)
})

It("Should send DELETE request with assignment id", func() {
httpCall.Times(1)
})
})

Describe("TeamEnvironmentAssignments", func() {

Describe("Successful", func() {
var actualResult []TeamRoleEnvironmentAssignment
var err error

BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Get("/roles/assignments/teams", map[string]string{"environmentId": environmentId}, gomock.Any()).
Do(func(path string, request interface{}, response *[]TeamRoleEnvironmentAssignment) {
*response = []TeamRoleEnvironmentAssignment{*expectedResponse}
}).Times(1)
actualResult, err = apiClient.TeamRoleEnvironmentAssignments(environmentId)

})

It("Should send GET request with params", func() {
httpCall.Times(1)
})

It("should return the GET result", func() {
Expect(actualResult).To(Equal([]TeamRoleEnvironmentAssignment{*expectedResponse}))
})

It("Should not return error", func() {
Expect(err).To(BeNil())
})
})

Describe("Failure", func() {
var actualResult []TeamRoleEnvironmentAssignment
var err error

BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Get("/roles/assignments/teams", map[string]string{"environmentId": environmentId}, gomock.Any()).Return(errorMock)
actualResult, err = apiClient.TeamRoleEnvironmentAssignments(environmentId)
})

It("Should fail if API call fails", func() {
Expect(err).To(Equal(errorMock))
})

It("Should not return results", func() {
Expect(actualResult).To(BeNil())
})
})
})
})
1 change: 1 addition & 0 deletions env0/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ func Provider(version string) plugin.ProviderFunc {
"env0_gpg_key": resourceGpgKey(),
"env0_provider": resourceProvider(),
"env0_user_environment_assignment": resourceUserEnvironmentAssignment(),
"env0_team_environment_assignment": resourceTeamEnvironmentAssignment(),
},
}

Expand Down
118 changes: 118 additions & 0 deletions env0/resource_team_environment_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package env0

import (
"context"
"log"

"github.com/env0/terraform-provider-env0/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceTeamEnvironmentAssignment() *schema.Resource {
return &schema.Resource{
CreateContext: resourceTeamEnvironmentAssignmentCreate,
UpdateContext: resourceTeamEnvironmentAssignmentUpdate,
ReadContext: resourceTeamEnvironmentAssignmentRead,
DeleteContext: resourceTeamEnvironmentAssignmentDelete,

Schema: map[string]*schema.Schema{
"team_id": {
Type: schema.TypeString,
Description: "id of the team",
Required: true,
ForceNew: true,
},
"environment_id": {
Type: schema.TypeString,
Description: "id of the environment",
Required: true,
ForceNew: true,
},
"role_id": {
Type: schema.TypeString,
Description: "id of the assigned role",
Required: true,
ValidateDiagFunc: ValidateNotEmptyString,
},
},
}
}

func resourceTeamEnvironmentAssignmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var newAssignment client.AssignTeamRoleToEnvironmentPayload
if err := readResourceData(&newAssignment, d); err != nil {
return diag.Errorf("schema resource data deserialization failed: %v", err)
}

client := meta.(client.ApiClientInterface)

assignment, err := client.AssignTeamRoleToEnvironment(&newAssignment)
if err != nil {
return diag.Errorf("could not create assignment: %v", err)
}

d.SetId(assignment.Id)

return nil
}

func resourceTeamEnvironmentAssignmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(client.ApiClientInterface)

id := d.Id()
environmentId := d.Get("environment_id").(string)

assignments, err := client.TeamRoleEnvironmentAssignments(environmentId)
if err != nil {
return diag.Errorf("could not get assignments: %v", err)
}

for _, assignment := range assignments {
if assignment.Id == id {
if err := writeResourceData(&assignment, d); err != nil {
return diag.Errorf("schema resource data serialization failed: %v", err)
}

d.Set("role_id", assignment.Role)

return nil
}
}

log.Printf("[WARN] Drift Detected: Terraform will remove %s from state", d.Id())
d.SetId("")

return nil
}

func resourceTeamEnvironmentAssignmentUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var payload client.AssignTeamRoleToEnvironmentPayload
if err := readResourceData(&payload, d); err != nil {
return diag.Errorf("schema resource data deserialization failed: %v", err)
}

client := meta.(client.ApiClientInterface)

assignment, err := client.AssignTeamRoleToEnvironment(&payload)
if err != nil {
return diag.Errorf("could not update assignment: %v", err)
}

d.SetId(assignment.Id)

return nil
}

func resourceTeamEnvironmentAssignmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
environmentId := d.Get("environment_id").(string)
teamId := d.Get("team_id").(string)

client := meta.(client.ApiClientInterface)

if err := client.RemoveTeamRoleFromEnvironment(environmentId, teamId); err != nil {
return diag.Errorf("could not delete assignment: %v", err)
}

return nil
}
Loading

0 comments on commit 573d5cc

Please sign in to comment.