-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: approval policy support (#687)
* Feat: approval policy support * updated code to fix api issues * added an example * updates based on PR comments and Slack discussions * minor changes based on last PR comments
- Loading branch information
1 parent
3826095
commit 6beab51
Showing
17 changed files
with
1,386 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package client | ||
|
||
import "fmt" | ||
|
||
type ApprovalPolicy struct { | ||
Id string `json:"id"` | ||
Name string `json:"name"` | ||
Repository string `json:"repository"` | ||
Path string `json:"path" tfschema:",omitempty"` | ||
Revision string `json:"revision" tfschema:",omitempty"` | ||
TokenId string `json:"tokenId" tfschema:",omitempty"` | ||
SshKeys []TemplateSshKey `json:"sshKeys"` | ||
GithubInstallationId int `json:"githubInstallationId" tfschema:",omitempty"` | ||
BitbucketClientKey string `json:"bitbucketClientKey" tfschema:",omitempty"` | ||
IsBitbucketServer bool `json:"isBitbucketServer"` | ||
IsGitlabEnterprise bool `json:"isGitLabEnterprise"` | ||
IsGithubEnterprise bool `json:"isGitHubEnterprise"` | ||
IsGitLab bool `json:"isGitLab" tfschema:"is_gitlab"` | ||
IsAzureDevOps bool `json:"isAzureDevOps" tfschema:"is_azure_devops"` | ||
IsTerragruntRunAll bool `json:"isTerragruntRunAll"` | ||
} | ||
|
||
type ApprovalPolicyByScope struct { | ||
Scope string `json:"scope"` | ||
ScopeId string `json:"scopeId"` | ||
ApprovalPolicy *ApprovalPolicy `json:"blueprint"` | ||
} | ||
|
||
type ApprovalPolicyAssignmentScope string | ||
|
||
const ( | ||
ApprovalPolicyProjectScope ApprovalPolicyAssignmentScope = "PROJECT" | ||
) | ||
|
||
type ApprovalPolicyAssignment struct { | ||
Scope ApprovalPolicyAssignmentScope `json:"scope"` | ||
ScopeId string `json:"scopeId"` | ||
BlueprintId string `json:"blueprintId"` | ||
} | ||
|
||
func (client *ApiClient) ApprovalPolicies(name string) ([]ApprovalPolicy, error) { | ||
organizationId, err := client.OrganizationId() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var result []ApprovalPolicy | ||
if err := client.http.Get("/approval-policy", map[string]string{"organizationId": organizationId, "name": name}, &result); err != nil { | ||
return nil, err | ||
} | ||
|
||
return result, err | ||
} | ||
|
||
func (client *ApiClient) ApprovalPolicyAssign(assignment *ApprovalPolicyAssignment) (*ApprovalPolicyAssignment, error) { | ||
var result ApprovalPolicyAssignment | ||
|
||
if err := client.http.Post("/approval-policy/assignment", assignment, &result); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &result, nil | ||
} | ||
|
||
func (client *ApiClient) ApprovalPolicyUnassign(scope string, scopeId string) error { | ||
return client.http.Delete(fmt.Sprintf("/approval-policy/assignment/%s/%s", scope, scopeId), nil) | ||
} | ||
|
||
func (client *ApiClient) ApprovalPolicyByScope(scope string, scopeId string) ([]ApprovalPolicyByScope, error) { | ||
var result []ApprovalPolicyByScope | ||
|
||
if err := client.http.Get(fmt.Sprintf("/approval-policy/%s/%s", scope, scopeId), nil, &result); err != nil { | ||
return nil, err | ||
} | ||
|
||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package client_test | ||
|
||
import ( | ||
"fmt" | ||
|
||
. "github.com/env0/terraform-provider-env0/client" | ||
"github.com/golang/mock/gomock" | ||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("Approval Policy Client", func() { | ||
mockApprovalPolicy := ApprovalPolicy{ | ||
Id: "id", | ||
Name: "name", | ||
Repository: "repository", | ||
Path: "path", | ||
Revision: "revision", | ||
TokenId: "tokenId", | ||
SshKeys: []TemplateSshKey{ | ||
{Id: "id", Name: "name"}, | ||
}, | ||
GithubInstallationId: 1, | ||
BitbucketClientKey: "bitbucket-key", | ||
IsBitbucketServer: true, | ||
IsGitlabEnterprise: false, | ||
IsGithubEnterprise: true, | ||
IsGitLab: false, | ||
IsAzureDevOps: true, | ||
IsTerragruntRunAll: false, | ||
} | ||
|
||
Describe("Get Custom Flows By Name", func() { | ||
var returnedApprovalPolicies []ApprovalPolicy | ||
mockApprovalPolicies := []ApprovalPolicy{mockApprovalPolicy} | ||
|
||
BeforeEach(func() { | ||
mockOrganizationIdCall(organizationId) | ||
httpCall = mockHttpClient.EXPECT(). | ||
Get("/approval-policy", map[string]string{"organizationId": organizationId, "name": mockApprovalPolicy.Name}, gomock.Any()). | ||
Do(func(path string, request interface{}, response *[]ApprovalPolicy) { | ||
*response = mockApprovalPolicies | ||
}) | ||
organizationIdCall.Times(1) | ||
httpCall.Times(1) | ||
returnedApprovalPolicies, _ = apiClient.ApprovalPolicies(mockApprovalPolicy.Name) | ||
}) | ||
|
||
It("Should return approval policies", func() { | ||
Expect(returnedApprovalPolicies).To(Equal(mockApprovalPolicies)) | ||
}) | ||
}) | ||
|
||
mockAssignment := ApprovalPolicyAssignment{ | ||
Scope: ApprovalPolicyProjectScope, | ||
ScopeId: "scope_id", | ||
BlueprintId: "blueprint_id", | ||
} | ||
|
||
Describe("Assign Approval Policy", func() { | ||
var returnedApprovalPolicyAssignment *ApprovalPolicyAssignment | ||
|
||
BeforeEach(func() { | ||
httpCall = mockHttpClient.EXPECT(). | ||
Post("/approval-policy/assignment", &mockAssignment, gomock.Any()). | ||
Do(func(path string, request interface{}, response *ApprovalPolicyAssignment) { | ||
*response = mockAssignment | ||
}) | ||
httpCall.Times(1) | ||
returnedApprovalPolicyAssignment, _ = apiClient.ApprovalPolicyAssign(&mockAssignment) | ||
}) | ||
|
||
It("Should return approval policy assignment", func() { | ||
Expect(*returnedApprovalPolicyAssignment).To(Equal(mockAssignment)) | ||
}) | ||
}) | ||
|
||
Describe("Unassign Custom Flow", func() { | ||
var err error | ||
|
||
BeforeEach(func() { | ||
httpCall = mockHttpClient.EXPECT().Delete(fmt.Sprintf("/approval-policy/assignment/%s/%s", ApprovalPolicyProjectScope, "scope_id"), nil) | ||
httpCall.Times(1) | ||
err = apiClient.ApprovalPolicyUnassign(string(ApprovalPolicyProjectScope), "scope_id") | ||
}) | ||
|
||
It("Should not return an error", func() { | ||
Expect(err).To(BeNil()) | ||
}) | ||
}) | ||
|
||
Describe("Get Approval Policy By Scope", func() { | ||
var ret []ApprovalPolicyByScope | ||
|
||
scope := string(mockAssignment.Scope) | ||
scopeId := mockAssignment.ScopeId | ||
|
||
mockApprovalPolicyByScope := ApprovalPolicyByScope{ | ||
Scope: scope, | ||
ScopeId: scopeId, | ||
ApprovalPolicy: &mockApprovalPolicy, | ||
} | ||
|
||
mockApprovalPolicyByScopeArr := []ApprovalPolicyByScope{mockApprovalPolicyByScope} | ||
|
||
BeforeEach(func() { | ||
httpCall = mockHttpClient.EXPECT(). | ||
Get(fmt.Sprintf("/approval-policy/%s/%s", scope, scopeId), nil, gomock.Any()). | ||
Do(func(path string, request interface{}, response *[]ApprovalPolicyByScope) { | ||
*response = mockApprovalPolicyByScopeArr | ||
}) | ||
httpCall.Times(1) | ||
ret, _ = apiClient.ApprovalPolicyByScope(scope, scopeId) | ||
}) | ||
|
||
It("Should return approval policy assignment", func() { | ||
Expect(ret).To(Equal(mockApprovalPolicyByScopeArr)) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package env0 | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
type TemplateType string | ||
|
||
const ( | ||
CustomFlow TemplateType = "custom-flow" | ||
ApprovalPolicy TemplateType = "approval-policy" | ||
) | ||
|
||
func getConfigurationTemplateSchema(templateType TemplateType) map[string]*schema.Schema { | ||
var text string | ||
|
||
switch templateType { | ||
case CustomFlow: | ||
text = "custom flow" | ||
case ApprovalPolicy: | ||
text = "approval policy" | ||
} | ||
|
||
s := map[string]*schema.Schema{ | ||
"id": { | ||
Type: schema.TypeString, | ||
Description: fmt.Sprintf("id of the %s", text), | ||
Computed: true, | ||
}, | ||
"repository": { | ||
Type: schema.TypeString, | ||
Description: fmt.Sprintf("repository url for the %s source code", text), | ||
Required: true, | ||
}, | ||
"path": { | ||
Type: schema.TypeString, | ||
Description: "terraform / terragrunt file folder inside source code. Should be the full path including the .yaml/.yml file", | ||
Optional: true, | ||
}, | ||
"revision": { | ||
Type: schema.TypeString, | ||
Description: "source code revision (branch / tag) to use", | ||
Optional: true, | ||
}, | ||
"token_id": { | ||
Type: schema.TypeString, | ||
Description: "the git token id to be used", | ||
Optional: true, | ||
}, | ||
"ssh_keys": { | ||
Type: schema.TypeList, | ||
Description: "an array of references to 'data_ssh_key' to use when accessing git over ssh", | ||
Optional: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeMap, | ||
Description: "a map of env0_ssh_key.id and env0_ssh_key.name for each project", | ||
}, | ||
}, | ||
"gitlab_project_id": { | ||
Type: schema.TypeInt, | ||
Description: "the project id of the relevant repository", | ||
Optional: true, | ||
RequiredWith: []string{"token_id"}, | ||
}, | ||
"github_installation_id": { | ||
Type: schema.TypeInt, | ||
Description: "the env0 application installation id on the relevant github repository", | ||
Optional: true, | ||
}, | ||
"bitbucket_client_key": { | ||
Type: schema.TypeString, | ||
Description: "the bitbucket client key used for integration", | ||
Optional: true, | ||
}, | ||
"is_bitbucket_server": { | ||
Type: schema.TypeBool, | ||
Description: fmt.Sprintf("true if this %s uses bitbucket server repository", text), | ||
Optional: true, | ||
Default: false, | ||
}, | ||
"is_gitlab_enterprise": { | ||
Type: schema.TypeBool, | ||
Description: fmt.Sprintf("true if this %s uses gitlab enterprise repository", text), | ||
Optional: true, | ||
Default: false, | ||
}, | ||
"is_github_enterprise": { | ||
Type: schema.TypeBool, | ||
Description: fmt.Sprintf("true if this %s uses github enterprise repository", text), | ||
Optional: true, | ||
Default: false, | ||
}, | ||
"is_gitlab": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Description: fmt.Sprintf("true if this %s integrates with gitlab repository", text), | ||
Default: false, | ||
}, | ||
"is_azure_devops": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Description: fmt.Sprintf("true if this %s integrates with azure dev ops repository", text), | ||
Default: false, | ||
}, | ||
"name": { | ||
Type: schema.TypeString, | ||
Description: fmt.Sprintf("name for the %s", text), | ||
Required: true, | ||
}, | ||
} | ||
|
||
return s | ||
} |
Oops, something went wrong.