Fix automerge bug in Bitbucket Server

BB Server requires we send a 'version' parameter along with our call to
/merge.
This commit is contained in:
Luke Kysow
2019-02-19 17:30:28 -05:00
parent cceb979ee4
commit bebbcb8a4d
5 changed files with 182 additions and 46 deletions

View File

@@ -247,7 +247,7 @@ func (c *DefaultCommandRunner) automerge(ctx *CommandContext, pullStatus *models
if err != nil {
ctx.Log.Err("automerging failed: %s", err)
failureComment := fmt.Sprintf("Automerging failed: %s", err)
failureComment := fmt.Sprintf("Automerging failed:\n```\n%s\n```", err)
if commentErr := c.VCSClient.CreateComment(ctx.BaseRepo, ctx.Pull.Num, failureComment); commentErr != nil {
ctx.Log.Err("failed to comment about automerge failing: %s", err)
}

View File

@@ -241,7 +241,21 @@ func (b *Client) MergePull(pull models.PullRequest) error {
if err != nil {
return err
}
path := fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/merge", b.BaseURL, projectKey, pull.BaseRepo.Name, pull.Num)
// We need to make a get pull request API call to get the correct "version".
path := fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d", b.BaseURL, projectKey, pull.BaseRepo.Name, pull.Num)
resp, err := b.makeRequest("GET", path, nil)
if err != nil {
return err
}
var pullResp PullRequest
if err := json.Unmarshal(resp, &pullResp); err != nil {
return errors.Wrapf(err, "Could not parse response %q", string(resp))
}
if err := validator.New().Struct(pullResp); err != nil {
return errors.Wrapf(err, "API response %q was missing fields", string(resp))
}
path = fmt.Sprintf("%s/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d/merge?version=%d", b.BaseURL, projectKey, pull.BaseRepo.Name, pull.Num, *pullResp.Version)
_, err = b.makeRequest("POST", path, nil)
return err
}

View File

@@ -2,13 +2,14 @@ package bitbucketserver_test
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud"
"github.com/runatlantis/atlantis/server/events/vcs/bitbucketserver"
. "github.com/runatlantis/atlantis/testing"
)
@@ -79,39 +80,20 @@ func TestClient_GetModifiedFilesPagination(t *testing.T) {
Equals(t, []string{"file1.txt", "file2.txt", "file3.txt"}, files)
}
// If the "old" key in the list of files is nil we shouldn't error.
func TestClient_GetModifiedFilesOldNil(t *testing.T) {
resp := `
{
"pagelen": 500,
"values": [
{
"status": "added",
"old": null,
"lines_removed": 0,
"lines_added": 2,
"new": {
"path": "parent/child/file1.txt",
"type": "commit_file",
"links": {
"self": {
"href": "https://api.bitbucket.org/2.0/repositories/lkysow/atlantis-example/src/1ed8205eec00dab4f1c0a8c486a4492c98c51f8e/main.tf"
}
}
},
"type": "diffstat"
}
],
"page": 1,
"size": 1
}`
// Test that we use the correct version parameter in our call to merge the pull
// request.
func TestClient_MergePull(t *testing.T) {
pullRequest, err := ioutil.ReadFile(filepath.Join("testdata", "pull-request.json"))
Ok(t, err)
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
// The first request should hit this URL.
case "/2.0/repositories/owner/repo/pullrequests/1/diffstat":
w.Write([]byte(resp)) // nolint: errcheck
case "/rest/api/1.0/projects/ow/repos/repo/pull-requests/1":
w.Write(pullRequest) // nolint: errcheck
return
case "/rest/api/1.0/projects/ow/repos/repo/pull-requests/1/merge?version=3":
Equals(t, "POST", r.Method)
w.Write(pullRequest) // nolint: errcheck
default:
t.Errorf("got unexpected request at %q", r.RequestURI)
http.Error(w, "not found", http.StatusNotFound)
@@ -120,22 +102,27 @@ func TestClient_GetModifiedFilesOldNil(t *testing.T) {
}))
defer testServer.Close()
client := bitbucketcloud.NewClient(http.DefaultClient, "user", "pass", "runatlantis.io")
client.BaseURL = testServer.URL
client, err := bitbucketserver.NewClient(http.DefaultClient, "user", "pass", testServer.URL, "runatlantis.io")
Ok(t, err)
files, err := client.GetModifiedFiles(models.Repo{
FullName: "owner/repo",
Owner: "owner",
Name: "repo",
CloneURL: "",
SanitizedCloneURL: "",
VCSHost: models.VCSHost{
Type: models.BitbucketCloud,
Hostname: "bitbucket.org",
err = client.MergePull(models.PullRequest{
Num: 1,
HeadCommit: "",
URL: "",
HeadBranch: "",
BaseBranch: "",
Author: "",
State: 0,
BaseRepo: models.Repo{
FullName: "owner/repo",
Owner: "owner",
Name: "repo",
SanitizedCloneURL: fmt.Sprintf("%s/scm/ow/repo.git", testServer.URL),
VCSHost: models.VCSHost{
Type: models.BitbucketCloud,
Hostname: "bitbucket.org",
},
},
}, models.PullRequest{
Num: 1,
})
Ok(t, err)
Equals(t, []string{"parent/child/file1.txt"}, files)
}

View File

@@ -23,6 +23,7 @@ type CommonEventData struct {
}
type PullRequest struct {
Version *int `json:"version,omitempty" validate:"required"`
ID *int `json:"id,omitempty" validate:"required"`
FromRef *Ref `json:"fromRef,omitempty" validate:"required"`
ToRef *Ref `json:"toRef,omitempty" validate:"required"`

View File

@@ -0,0 +1,134 @@
{
"id": 2,
"version": 3,
"title": "hi",
"state": "MERGED",
"open": false,
"closed": true,
"createdDate": 1550611116280,
"updatedDate": 1550611904547,
"closedDate": 1550611904547,
"fromRef": {
"id": "refs/heads/hi",
"displayId": "hi",
"latestCommit": "bdcaa224f4b65edb853a689404ef79cf47d8cdda",
"repository": {
"slug": "example",
"id": 1,
"name": "example",
"scmId": "git",
"state": "AVAILABLE",
"statusMessage": "Available",
"forkable": true,
"project": {
"key": "AT",
"id": 1,
"name": "atlantis",
"public": false,
"type": "NORMAL",
"links": {
"self": [
{
"href": "http://localhost:7990/projects/AT"
}
]
}
},
"public": false,
"links": {
"clone": [
{
"href": "ssh://git@localhost:7999/at/example.git",
"name": "ssh"
},
{
"href": "http://localhost:7990/scm/at/example.git",
"name": "http"
}
],
"self": [
{
"href": "http://localhost:7990/projects/AT/repos/example/browse"
}
]
}
}
},
"toRef": {
"id": "refs/heads/master",
"displayId": "master",
"latestCommit": "59e03b9cc44e16e20741e328faaac26e377c07bf",
"repository": {
"slug": "example",
"id": 1,
"name": "example",
"scmId": "git",
"state": "AVAILABLE",
"statusMessage": "Available",
"forkable": true,
"project": {
"key": "AT",
"id": 1,
"name": "atlantis",
"public": false,
"type": "NORMAL",
"links": {
"self": [
{
"href": "http://localhost:7990/projects/AT"
}
]
}
},
"public": false,
"links": {
"clone": [
{
"href": "ssh://git@localhost:7999/at/example.git",
"name": "ssh"
},
{
"href": "http://localhost:7990/scm/at/example.git",
"name": "http"
}
],
"self": [
{
"href": "http://localhost:7990/projects/AT/repos/example/browse"
}
]
}
}
},
"locked": false,
"author": {
"user": {
"name": "admin",
"emailAddress": "luke@hashicorp.com",
"id": 1,
"displayName": "admin",
"active": true,
"slug": "admin",
"type": "NORMAL",
"links": {
"self": [
{
"href": "http://localhost:7990/users/admin"
}
]
}
},
"role": "AUTHOR",
"approved": false,
"status": "UNAPPROVED"
},
"reviewers": [],
"participants": [],
"links": {
"self": [
{
"href": "http://localhost:7990/projects/AT/repos/example/pull-requests/2"
}
]
}
}