Add merge policy

This commit is contained in:
John Reese
2020-04-10 16:27:04 -04:00
parent 01aae5e9e4
commit 3efcd8feee
4 changed files with 73 additions and 38 deletions

View File

@@ -6,6 +6,7 @@ import (
"net/http"
"net/url"
"path/filepath"
"strconv"
"strings"
"time"
@@ -176,13 +177,16 @@ func (g *AzureDevopsClient) PullIsMergeable(repo models.Repo, pull models.PullRe
}
projectID := *adPull.Repository.Project.ID
artifactID := g.Client.PolicyEvaluations.GetPullRequestArtifactID(projectID, string(pull.Num))
artifactID := g.Client.PolicyEvaluations.GetPullRequestArtifactID(projectID, strconv.Itoa(pull.Num))
policyEvaluations, _, err := g.Client.PolicyEvaluations.List(g.ctx, owner, project, artifactID, &azuredevops.PolicyEvaluationsListOptions{})
if err != nil {
return false, fmt.Errorf("list policy evaluations: %w", err)
}
for _, policyEvaluation := range policyEvaluations {
if *policyEvaluation.Configuration.IsEnabled == false || *policyEvaluation.Configuration.IsDeleted {
continue
}
// Ignore the Atlantis status, even if its set as a blocker.
// This status should not be considered when evaluating if the pull request can be applied.
@@ -191,7 +195,7 @@ func (g *AzureDevopsClient) PullIsMergeable(repo models.Repo, pull models.PullRe
continue
}
if *policyEvaluation.Configuration.IsBlocking && *policyEvaluation.Status != "succeeded" {
if *policyEvaluation.Configuration.IsBlocking && *policyEvaluation.Status != "approved" {
return false, nil
}
}

View File

@@ -278,53 +278,59 @@ func TestAzureDevopsClient_GetModifiedFiles(t *testing.T) {
func TestAzureDevopsClient_PullIsMergeable(t *testing.T) {
cases := []struct {
state string
testName string
mergeStatus string
policyStatus string
expMergeable bool
}{
{
"merge conflicts",
azuredevops.MergeConflicts.String(),
"approved",
false,
},
{
azuredevops.MergeRejectedByPolicy.String(),
false,
},
{
azuredevops.MergeFailure.String(),
true,
},
{
azuredevops.MergeNotSet.String(),
true,
},
{
azuredevops.MergeQueued.String(),
true,
},
{
"rejected policy status",
azuredevops.MergeSucceeded.String(),
"rejected",
false,
},
{
"rejected policy status on disabled policy",
azuredevops.MergeSucceeded.String(),
"rejected",
true,
},
{
"merge succeeded",
azuredevops.MergeSucceeded.String(),
"approved",
true,
},
}
// Use a real Azure DevOps json response and edit the mergeable_state field.
jsBytes, err := ioutil.ReadFile("fixtures/azuredevops-pr.json")
jsonPullRequestBytes, err := ioutil.ReadFile("fixtures/azuredevops-pr.json")
Ok(t, err)
json := string(jsBytes)
jsonPolicyEvaluationBytes, err := ioutil.ReadFile("fixtures/azuredevops-policyevaluations.json")
Ok(t, err)
pullRequestBody := string(jsonPullRequestBytes)
policyEvaluationsBody := string(jsonPolicyEvaluationBytes)
for _, c := range cases {
t.Run(c.state, func(t *testing.T) {
response := strings.Replace(json,
`"mergeStatus": "NotSet"`,
fmt.Sprintf(`"mergeStatus": "%s"`, c.state),
1,
)
t.Run(c.testName, func(t *testing.T) {
pullRequestResponse := strings.Replace(pullRequestBody, `"mergeStatus": "notSet"`, fmt.Sprintf(`"mergeStatus": "%s"`, c.mergeStatus), 1)
policyEvaluationsResponse := strings.Replace(policyEvaluationsBody, `"status": "approved"`, fmt.Sprintf(`"status": "%s"`, c.policyStatus), 1)
testServer := httptest.NewTLSServer(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case "/owner/project/_apis/git/repositories/repo/pullrequests/1?api-version=5.1-preview.1&includeWorkItemRefs=true":
w.Write([]byte(response)) // nolint: errcheck
w.Write([]byte(pullRequestResponse)) // nolint: errcheck
return
case "/owner/project/_apis/policy/evaluations?api-version=5.1-preview&artifactId=vstfs%3A%2F%2F%2FCodeReview%2FCodeReviewId%2F33333333-3333-3333-333333333333%2F1":
w.Write([]byte(policyEvaluationsResponse)) // nolint: errcheck
return
default:
t.Errorf("got unexpected request at %q", r.RequestURI)
@@ -332,10 +338,13 @@ func TestAzureDevopsClient_PullIsMergeable(t *testing.T) {
return
}
}))
testServerURL, err := url.Parse(testServer.URL)
Ok(t, err)
client, err := vcs.NewAzureDevopsClient(testServerURL.Host, "token")
Ok(t, err)
defer disableSSLVerification()()
actMergeable, err := client.PullIsMergeable(models.Repo{
@@ -402,11 +411,10 @@ func TestAzureDevopsClient_PullIsApproved(t *testing.T) {
},
}
// Use a real Azure DevOps json response and edit the mergeable_state field.
jsBytes, err := ioutil.ReadFile("fixtures/azuredevops-pr.json")
Ok(t, err)
json := string(jsBytes)
json := string(jsBytes)
for _, c := range cases {
t.Run(c.testName, func(t *testing.T) {
response := strings.Replace(json, `"vote": 0,`, fmt.Sprintf(`"vote": %d,`, c.reviewerVote), 1)

View File

@@ -0,0 +1,16 @@
{
"value": [
{
"configuration": {
"isDeleted": false,
"isEnabled": true,
"isBlocking": true,
"settings": {
"statusName": "pending"
}
},
"status": "approved"
}
],
"count": 1
}

View File

@@ -1,18 +1,25 @@
{
"status": "completed",
"repository": {
"id": "22222222-2222-2222-222222222222",
"name": "MyRepository",
"project": {
"id": "33333333-3333-3333-333333333333",
"name": "MyProject",
"description": "The place for MyProject"
}
},
"status": "active",
"createdBy": {
"displayName": "Atlantis Author",
"url": "https://spsprodeus23.vssps.visualstudio.com/11111111-2222-3333-444444444444/_apis/Identities/55555555-6666-7777-888888888888",
"id": "11111111-2222-3333-444444444444",
"id": "11111111-1111-1111-111111111111",
"uniqueName": "atlantis.author@example.com"
},
"mergeStatus": "notSet",
"isDraft": false,
"autoCompleteSetBy": {
"id": "11111111-2222-3333-444444444444",
"id": "11111111-1111-1111-111111111111",
"displayName": "Atlantis Author",
"uniqueName": "atlantis.author@example.com",
"url": "https://spsprodeus23.vssps.visualstudio.com/11111111-2222-3333-444444444444/_apis/Identities/55555555-6666-7777-888888888888",
"imageUrl": "https://dev.azure.com/owner/DefaultCollection/_api/_common/identityImage?id=8010495e-1002-438d-acbf-aaf245dac7c2"
"uniqueName": "atlantis.author@example.com"
},
"pullRequestId": 22,
"completionOptions": {