Skip to content

INFRA-20407: Add cortex_team_role resource #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/resources/team_role/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "cortex_team_role" "engineer" {
tag = "se-1"
name = "Software Engineer 1"
description = "A first-level engineer"
notifcations_enabled = true
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/hashicorp/terraform-plugin-testing v1.5.1
github.com/life4/genesis v1.8.1
github.com/motemen/go-loghttp v0.0.0-20170804080138-974ac5ceac27
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.10.0
gopkg.in/yaml.v3 v3.0.1
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
Expand Down
10 changes: 7 additions & 3 deletions internal/cortex/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"context"
"errors"
"fmt"
"github.com/dghubble/sling"
"github.com/motemen/go-loghttp"
_ "github.com/motemen/go-loghttp/global" // Just this line!
"net/http"
"net/url"
"os"

"github.com/dghubble/sling"
"github.com/motemen/go-loghttp"
_ "github.com/motemen/go-loghttp/global" // Just this line!
)

const (
Expand All @@ -19,6 +20,7 @@ const (

var BaseUris = map[string]string{
"teams": "/api/v1/teams/",
"teams_roles": "/api/v1/teams/roles/",
"departments": "/api/v1/teams/departments/",
"scorecards": "/api/v1/scorecards/",
"catalog_entities": "/api/v1/catalog/",
Expand Down Expand Up @@ -157,6 +159,8 @@ func (c *HttpClient) Teams() TeamsClientInterface {
return &TeamsClient{client: c}
}

func (c *HttpClient) TeamRoles() TeamRolesClientInterface { return &TeamRolesClient{client: c} }

func (c *HttpClient) Departments() DepartmentsClientInterface {
return &DepartmentsClient{client: c}
}
Expand Down
204 changes: 204 additions & 0 deletions internal/cortex/team_roles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
package cortex

import (
"context"
"encoding/json"
"errors"
"fmt"
"log"

"github.com/dghubble/sling"
)

type TeamRolesClientInterface interface {
Get(ctx context.Context, id int64) (*TeamRole, error)
List(ctx context.Context, params *TeamRolesListParams) (*TeamRolesListResponse, error)
Create(ctx context.Context, req CreateTeamRoleRequest) (*TeamRole, error)
Update(ctx context.Context, req UpdateTeamRoleRequest) (*TeamRole, error)
Delete(ctx context.Context, id int64) error
}

type TeamRolesClient struct {
client *HttpClient
}

var _ TeamRolesClientInterface = &TeamRolesClient{}

func (c *TeamRolesClient) Client() *sling.Sling {
return c.client.Client()
}

/***********************************************************************************************************************
* Types
**********************************************************************************************************************/

type TeamRole struct {
ID int64 `json:"id"`
Name string `json:"name"`
Tag string `json:"tag"`
Description string `json:"description,omitempty"`
NotificationsEnabled bool `json:"notificationsEnabled,omitempty"`
}

/***********************************************************************************************************************
* GET /api/v1/teams/roles/:id
**********************************************************************************************************************/

func (c *TeamRolesClient) Get(_ context.Context, id int64) (*TeamRole, error) {
apiResponse := &TeamRole{}
apiError := &ApiError{}
response, err := c.Client().Get(Route("teams_roles", fmt.Sprintf("%d", id))).Receive(apiResponse, apiError)
if err != nil {
return apiResponse, errors.New("could not get team role: " + err.Error())
}

err = c.client.handleResponseStatus(response, apiError)
if err != nil {
return apiResponse, errors.Join(errors.New("Failed getting team role: "), err)
}

return apiResponse, nil
}

/***********************************************************************************************************************
* GET /api/v1/teams/roles
**********************************************************************************************************************/

// TeamRolesListParams are the query parameters for the GET /v1/teams/roles endpoint.
type TeamRolesListParams struct {
Page int `url:"page,omitempty"`
PerPage int `url:"size,omitempty"`
Query string `url:"query,omitempty"`
}

// TeamRolesListResponse is the response from the GET /v1/teams/roles endpoint.
type TeamRolesListResponse struct {
Roles []TeamRole `json:"items"`
}

func (c *TeamRolesClient) List(_ context.Context, params *TeamRolesListParams) (*TeamRolesListResponse, error) {
apiResponse := &TeamRolesListResponse{}
apiError := &ApiError{}

response, err := c.Client().Get(Route("teams_roles", "")).QueryStruct(&params).Receive(apiResponse, apiError)
if err != nil {
return nil, errors.New("could not get team roles: " + err.Error())
}

err = c.client.handleResponseStatus(response, apiError)
if err != nil {
return nil, err
}

return apiResponse, nil
}

/***********************************************************************************************************************
* POST /api/v1/teams/roles
**********************************************************************************************************************/

type CreateTeamRoleRequest struct {
Tag string `json:"tag"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
NotificationsEnabled bool `json:"notificationsEnabled,omitempty"`
}

// ToCreateRequest converts a TeamRole to a CreateTeamRoleRequest.
func (r *TeamRole) ToCreateRequest() CreateTeamRoleRequest {
return CreateTeamRoleRequest{
Tag: r.Tag,
Name: r.Name,
Description: r.Description,
NotificationsEnabled: r.NotificationsEnabled,
}
}

func (c *TeamRolesClient) Create(_ context.Context, req CreateTeamRoleRequest) (*TeamRole, error) {
apiResponse := &TeamRole{}
apiError := &ApiError{}

response, err := c.Client().Post(Route("teams_roles", "")).BodyJSON(&req).Receive(apiResponse, apiError)
if err != nil {
return apiResponse, errors.New("could not create team role: " + err.Error())
}

err = c.client.handleResponseStatus(response, apiError)
if err != nil {
reqJson, _ := json.Marshal(req)
log.Printf("Failed creating team role: %+v\n\nRequest:\n%+v", err, string(reqJson))
return apiResponse, err
}

return apiResponse, nil
}

/***********************************************************************************************************************
* PUT /api/v1/teams/roles/:id
**********************************************************************************************************************/

type UpdateTeamRoleRequest struct {
ID int64 `json:"id"`
Tag string `json:"tag"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
NotificationsEnabled bool `json:"notificationsEnabled,omitempty"`
}

// ToUpdateRequest converts a TeamRole to an UpdateTeamRoleRequest.
func (r *TeamRole) ToUpdateRequest() UpdateTeamRoleRequest {
return UpdateTeamRoleRequest{
ID: r.ID,
Tag: r.Tag,
Name: r.Name,
Description: r.Description,
NotificationsEnabled: r.NotificationsEnabled,
}
}

func (c *TeamRolesClient) Update(_ context.Context, req UpdateTeamRoleRequest) (*TeamRole, error) {
apiResponse := &TeamRole{}
apiError := &ApiError{}

response, err := c.Client().Put(Route("teams_roles", fmt.Sprintf("%d", req.ID))).BodyJSON(&req).Receive(apiResponse, apiError)
if err != nil {
return apiResponse, errors.New("could not update team role: " + err.Error())
}

err = c.client.handleResponseStatus(response, apiError)
if err != nil {
reqJson, _ := json.Marshal(req)
log.Printf("Failed updating team role: %+v\n\nRequest:\n%+v\n%+v", err, string(reqJson), apiError.String())
return apiResponse, err
}

return apiResponse, nil
}

/***********************************************************************************************************************
* DELETE /api/v1/teams/roles/:id
**********************************************************************************************************************/

type DeleteTeamRoleResponse struct{}
type DeleteTeamRoleRequest struct {
ID int64 `json:"id"`
}

func (c *TeamRolesClient) Delete(_ context.Context, id int64) error {
apiError := &ApiError{}
apiResponse := &DeleteTeamRoleResponse{}

req := DeleteTeamRoleRequest{ID: id}
resp, err := c.Client().Delete(Route("teams_roles", fmt.Sprintf("%d", id))).QueryStruct(req).Receive(apiResponse, apiError)
if err != nil {
return fmt.Errorf("could not delete team role %d:\n\n%+v", id, err.Error())
}

err = c.client.handleResponseStatus(resp, apiError)
if err != nil {
log.Printf("Could not delete team role %d:\n\n%+v", id, err.Error())
return err
}

return nil
}
117 changes: 117 additions & 0 deletions internal/cortex/team_roles_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package cortex_test

import (
"context"
"fmt"
"testing"

"github.com/cortexapps/terraform-provider-cortex/internal/cortex"
"github.com/stretchr/testify/suite"
)

/** Suite *************************************************************************************************************/

type teamRolesSuite struct {
suite.Suite
}

func TestCortexTeamRoles(t *testing.T) {
suite.Run(t, new(teamRolesSuite))
}

func (s *teamRolesSuite) newTeamRole() *cortex.TeamRole {
return &cortex.TeamRole{
ID: 1,
Tag: "engineer",
Name: "Engineer",
Description: "A team role",
NotificationsEnabled: true,
}
}

func (s *teamRolesSuite) TestGet() {
id := int64(1)
expectedResp := s.newTeamRole()
ctx := context.Background()
c, teardown, err := setupClient(cortex.Route("teams_roles", fmt.Sprintf("%d", id)), expectedResp, AssertRequestMethod(s.T(), "GET"))
defer teardown()
s.NoError(err)

actualResp, err := c.TeamRoles().Get(ctx, id)
s.NoError(err)
s.Equal(expectedResp, actualResp)
}

func (s *teamRolesSuite) TestList() {
expectedResp := &cortex.TeamRolesListResponse{
Roles: []cortex.TeamRole{
*s.newTeamRole(),
},
}
ctx := context.Background()
c, teardown, err := setupClient(cortex.Route("teams_roles", ""), expectedResp, AssertRequestMethod(s.T(), "GET"))
defer teardown()
s.NoError(err)

actualResp, err := c.TeamRoles().List(ctx, &cortex.TeamRolesListParams{})
s.NoError(err)
s.Equal(expectedResp, actualResp)
}

func (s *teamRolesSuite) TestCreate() {
req := cortex.CreateTeamRoleRequest{
Name: "Engineer",
Tag: "engineer",
Description: "A team role",
NotificationsEnabled: true,
}
expectedResp := s.newTeamRole()
ctx := context.Background()
c, teardown, err := setupClient(
cortex.Route("teams_roles", ""),
expectedResp,
AssertRequestMethod(s.T(), "POST"),
AssertRequestBody(s.T(), req),
)
defer teardown()
s.NoError(err)

actualResp, err := c.TeamRoles().Create(ctx, req)
s.NoError(err)
s.Equal(expectedResp, actualResp)
}

func (s *teamRolesSuite) TestUpdate() {
id := int64(1)
req := cortex.UpdateTeamRoleRequest{
ID: id,
Name: "Engineer",
Description: "A team role",
NotificationsEnabled: true,
}
expectedResp := s.newTeamRole()
ctx := context.Background()
c, teardown, err := setupClient(
cortex.Route("teams_roles", fmt.Sprintf("%d", id)),
expectedResp,
AssertRequestMethod(s.T(), "PUT"),
AssertRequestBody(s.T(), req),
)
defer teardown()
s.NoError(err)

actualResp, err := c.TeamRoles().Update(ctx, req)
s.NoError(err)
s.Equal(expectedResp, actualResp)
}

func (s *teamRolesSuite) TestDelete() {
id := int64(2)
ctx := context.Background()
c, teardown, err := setupClient(cortex.Route("teams_roles", fmt.Sprintf("%d", id)), nil, AssertRequestMethod(s.T(), "DELETE"))
defer teardown()
s.NoError(err)

err = c.TeamRoles().Delete(ctx, id)
s.NoError(err)
}
Loading
Loading