Skip to content

Commit

Permalink
Feat: Add Project Policies Support to client (#150)
Browse files Browse the repository at this point in the history
Co-authored-by: Yaron Yarimi <[email protected]>
  • Loading branch information
bernot-dev and yaronya committed Oct 13, 2021
1 parent 165b3fa commit f1e32fb
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 2 deletions.
2 changes: 2 additions & 0 deletions client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type ApiClientInterface interface {
ConfigurationVariableDelete(id string) error
Organization() (Organization, error)
organizationId() (string, error)
Policy(projectId string) (Policy, error)
PolicyUpdate(payload PolicyUpdatePayload) (Policy, error)
Projects() ([]Project, error)
Project(id string) (Project, error)
ProjectCreate(payload ProjectCreatePayload) (Project, error)
Expand Down
30 changes: 30 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.

7 changes: 5 additions & 2 deletions client/client_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package client_test

import (
"testing"

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

// This file wraps the test suite for the entire client folder

const organizationId = "organization0"
const (
organizationId = "organization0"
)

var (
ctrl *gomock.Controller
Expand Down
21 changes: 21 additions & 0 deletions client/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,24 @@ type TeamProjectAssignment struct {
ProjectId string `json:"projectId"`
ProjectRole Role `json:"projectRole"`
}

type Policy struct {
Id string `json:"id"`
ProjectId string `json:"projectId"`
NumberOfEnvironments int `json:"numberOfEnvironments"`
NumberOfEnvironmentsPerProject int `json:"numberOfEnvironmentsPerProject"`
RequiresApprovalDefault bool `json:"requiresApprovalDefault"`
IncludeCostEstimation bool `json:"includeCostEstimation"`
SkipApplyWhenPlanIsEmpty bool `json:"skipApplyWhenPlanIsEmpty"`
DisableDestroyEnvironments bool `json:"disableDestroyEnvironments"`
UpdatedBy string `json:"updatedBy"`
}

type PolicyUpdatePayload struct {
ProjectId string `json:"projectId"`
NumberOfEnvironments int `json:"numberOfEnvironments"`
RequiresApprovalDefault bool `json:"requiresApprovalDefault"`
IncludeCostEstimation bool `json:"includeCostEstimation"`
SkipApplyWhenPlanIsEmpty bool `json:"skipApplyWhenPlanIsEmpty"`
DisableDestroyEnvironments bool `json:"disableDestroyEnvironments"`
}
26 changes: 26 additions & 0 deletions client/policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package client

// Policy retrieves a policy from the API
func (self *ApiClient) Policy(projectId string) (Policy, error) {
u, err := newQueryURL("/policies", parameter{"projectId", projectId})
if err != nil {
return Policy{}, err
}

var result Policy
err = self.http.Get(u.String(), nil, &result)
if err != nil {
return Policy{}, err
}
return result, nil
}

// PolicyUpdate updates a policy through the API
func (self *ApiClient) PolicyUpdate(payload PolicyUpdatePayload) (Policy, error) {
var result Policy
err := self.http.Put("/policies", payload, &result)
if err != nil {
return Policy{}, err
}
return result, nil
}
107 changes: 107 additions & 0 deletions client/policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package client_test

import (
"errors"
"fmt"

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

const (
policyId = "policy0"
)

var _ = Describe("Policy", func() {
mockPolicy := Policy{
Id: policyId,
}

Describe("Policy", func() {
var policy Policy
var err error

path := fmt.Sprintf("/policies?projectId=%s", mockPolicy.ProjectId)

Describe("Success", func() {
BeforeEach(func() {
policiesResult := mockPolicy
httpCall = mockHttpClient.EXPECT().
Get(path, nil, gomock.Any()).
Do(func(path string, request interface{}, response *Policy) {
*response = policiesResult
})

policy, err = apiClient.Policy(mockPolicy.ProjectId)
})

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

It("Should return policy", func() {
Expect(policy).Should(Equal(mockPolicy))
})

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

Describe("Failure", func() {
It("On error from server return the error", func() {
expectedErr := errors.New("some error")
httpCall = mockHttpClient.EXPECT().
Get(path, nil, gomock.Any()).
Return(expectedErr)

_, err = apiClient.Policy(mockPolicy.ProjectId)
Expect(expectedErr).Should(Equal(err))
})
})
})

Describe("PolicyUpdate", func() {
updatePolicyPayload := PolicyUpdatePayload{ProjectId: "project0"}
Describe("Success", func() {
var updatedPolicy Policy
var err error

BeforeEach(func() {
httpCall = mockHttpClient.EXPECT().
Put("/policies", updatePolicyPayload, gomock.Any()).
Do(func(path string, request interface{}, response *Policy) {
*response = mockPolicy
})

updatedPolicy, err = apiClient.PolicyUpdate(updatePolicyPayload)
})

It("Should send Put request with expected payload", func() {
httpCall.Times(1)
})

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

It("Should return team received from API", func() {
Expect(updatedPolicy).To(Equal(mockPolicy))
})
})

Describe("Failure", func() {
It("On error from server return the error", func() {
expectedErr := errors.New("some error")
httpCall = mockHttpClient.EXPECT().
Put("/policies", updatePolicyPayload, gomock.Any()).
Return(expectedErr)

_, err := apiClient.PolicyUpdate(updatePolicyPayload)
Expect(expectedErr).Should(Equal(err))
})
})
})
})
25 changes: 25 additions & 0 deletions client/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package client

import "net/url"

type parameter struct {
key string
value string
}

func newQueryURL(path string, params ...parameter) (*url.URL, error) {
u, err := url.Parse(path)
if err != nil {
return nil, err
}

q := u.Query()

for _, param := range params {
q.Add(param.key, param.value)
}

u.RawQuery = q.Encode()

return u, nil
}

0 comments on commit f1e32fb

Please sign in to comment.