mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-08-03 18:58:56 +00:00
Add merge policy
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"value": [
|
||||
{
|
||||
"configuration": {
|
||||
"isDeleted": false,
|
||||
"isEnabled": true,
|
||||
"isBlocking": true,
|
||||
"settings": {
|
||||
"statusName": "pending"
|
||||
}
|
||||
},
|
||||
"status": "approved"
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
}
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user