Skip to content

Commit

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

* wording changes

* updated example
  • Loading branch information
TomerHeber committed Mar 27, 2024
1 parent cc7a446 commit d2efd0c
Show file tree
Hide file tree
Showing 9 changed files with 603 additions and 1 deletion.
3 changes: 3 additions & 0 deletions client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ type ApiClientInterface interface {
AssignTeamRoleToEnvironment(payload *AssignTeamRoleToEnvironmentPayload) (*TeamRoleEnvironmentAssignment, error)
RemoveTeamRoleFromEnvironment(environmentId string, teamId string) error
TeamRoleEnvironmentAssignments(environmentId string) ([]TeamRoleEnvironmentAssignment, error)
AssignOrganizationRoleToTeam(payload *AssignOrganizationRoleToTeamPayload) (*OrganizationRoleTeamAssignment, error)
RemoveOrganizationRoleFromTeam(teamId string) error
OrganizationRoleTeamAssignments() ([]OrganizationRoleTeamAssignment, error)
ApprovalPolicies(name string) ([]ApprovalPolicy, error)
ApprovalPolicyAssign(assignment *ApprovalPolicyAssignment) (*ApprovalPolicyAssignment, error)
ApprovalPolicyUnassign(scope string, scopeId string) error
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.

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

type AssignOrganizationRoleToTeamPayload struct {
TeamId string `json:"teamId"`
Role string `json:"role" tfschema:"role_id"`
}

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

func (client *ApiClient) AssignOrganizationRoleToTeam(payload *AssignOrganizationRoleToTeamPayload) (*OrganizationRoleTeamAssignment, error) {
var result OrganizationRoleTeamAssignment

organizationId, err := client.OrganizationId()
if err != nil {
return nil, err
}

payloadWithOrganizationId := struct {
*AssignOrganizationRoleToTeamPayload
OrganizationId string `json:"organizationId"`
}{
payload,
organizationId,
}

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

return &result, nil
}

func (client *ApiClient) RemoveOrganizationRoleFromTeam(teamId string) error {
organizationId, err := client.OrganizationId()
if err != nil {
return err
}

return client.http.Delete("/roles/assignments/teams", map[string]string{"organizationId": organizationId, "teamId": teamId})
}

func (client *ApiClient) OrganizationRoleTeamAssignments() ([]OrganizationRoleTeamAssignment, error) {
organizationId, err := client.OrganizationId()
if err != nil {
return nil, err
}

var result []OrganizationRoleTeamAssignment

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

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

import (
"errors"

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

var _ = Describe("Team Orgnization Assignment", func() {
organizationId := "organizationId"
teamId := "teamId"

assignPayload := &AssignOrganizationRoleToTeamPayload{
TeamId: teamId,
Role: "role1",
}

assignPayloadWithOrganizationId := struct {
*AssignOrganizationRoleToTeamPayload
OrganizationId string `json:"organizationId"`
}{
assignPayload,
organizationId,
}

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

errorMock := errors.New("error")

Describe("AssignTeamToOrganization", func() {

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

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

})

It("Should send POST request with params", func() {})

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 *OrganizationRoleTeamAssignment
var err error

BeforeEach(func() {
mockOrganizationIdCall(organizationId).Times(1)
httpCall = mockHttpClient.EXPECT().
Put("/roles/assignments/teams", gomock.Any(), gomock.Any()).Return(errorMock).Times(1)
actualResult, err = apiClient.AssignOrganizationRoleToTeam(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("RemoveTeamFromOrganization", func() {
BeforeEach(func() {
mockOrganizationIdCall(organizationId).Times(1)
httpCall = mockHttpClient.EXPECT().Delete("/roles/assignments/teams", map[string]string{"organizationId": organizationId, "teamId": teamId}).Times(1)
apiClient.RemoveOrganizationRoleFromTeam(teamId)
})

It("Should send DELETE request with assignment id", func() {})
})

Describe("TeamOrganizationAssignments", func() {

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

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

})

It("Should send GET request with params", func() {})

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

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

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

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

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 @@ -143,6 +143,7 @@ func Provider(version string) plugin.ProviderFunc {
"env0_provider": resourceProvider(),
"env0_user_environment_assignment": resourceUserEnvironmentAssignment(),
"env0_team_environment_assignment": resourceTeamEnvironmentAssignment(),
"env0_team_organization_assignment": resourceTeamOrganizationAssignment(),
"env0_approval_policy": resourceApprovalPolicy(),
"env0_approval_policy_assignment": resourceApprovalPolicyAssignment(),
"env0_project_budget": resourceProjectBudget(),
Expand Down
112 changes: 112 additions & 0 deletions env0/resource_team_organization_assignment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package env0

import (
"context"

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

func resourceTeamOrganizationAssignment() *schema.Resource {
return &schema.Resource{
CreateContext: resourceTeamOrganizationAssignmentCreate,
UpdateContext: resourceTeamOrganizationAssignmentUpdate,
ReadContext: resourceTeamOrganizationAssignmentRead,
DeleteContext: resourceTeamOrganizationAssignmentDelete,

Description: "assigns an organization role to a team",

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

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

var newAssignment client.AssignOrganizationRoleToTeamPayload
if err := readResourceData(&newAssignment, d); err != nil {
return diag.Errorf("schema resource data deserialization failed: %v", err)
}

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

d.SetId(assignment.Id)

return nil
}

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

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

id := d.Id()

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
}
}

tflog.Warn(ctx, "Drift Detected: Terraform will remove id from state", map[string]interface{}{"id": d.Id()})
d.SetId("")

return nil
}

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

var payload client.AssignOrganizationRoleToTeamPayload
if err := readResourceData(&payload, d); err != nil {
return diag.Errorf("schema resource data deserialization failed: %v", err)
}

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

d.SetId(assignment.Id)

return nil
}

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

teamId := d.Get("team_id").(string)

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

return nil
}
Loading

0 comments on commit d2efd0c

Please sign in to comment.