Skip to content

Commit 78b5e76

Browse files
[feat]: [PL-24913]: Add the support for create and update file in bitbucket server (#177)
* [PL-24913]: Add the support for create and update api in bitbucket server * [PL-24913]: Add the tests for create and update of file in bitbucket server
1 parent 30f8094 commit 78b5e76

File tree

7 files changed

+237
-16
lines changed

7 files changed

+237
-16
lines changed

scm/driver/stash/content.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,26 @@ func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm
2828
}
2929

3030
func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) {
31-
return nil, scm.ErrNotSupported
31+
namespace, repoName := scm.Split(repo)
32+
endpoint := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/browse/%s", namespace, repoName, path)
33+
in := &contentCreateUpdate{
34+
Message: params.Message,
35+
Branch: params.Branch,
36+
Content: params.Data,
37+
}
38+
return s.client.do(ctx, "PUT", endpoint, in, nil)
3239
}
3340

3441
func (s *contentService) Update(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) {
35-
return nil, scm.ErrNotSupported
42+
namespace, repoName := scm.Split(repo)
43+
endpoint := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/browse/%s", namespace, repoName, path)
44+
in := &contentCreateUpdate{
45+
Message: params.Message,
46+
Branch: params.Branch,
47+
Content: params.Data,
48+
Sha: params.Sha,
49+
}
50+
return s.client.do(ctx, "PUT", endpoint, in, nil)
3651
}
3752

3853
func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) {
@@ -53,6 +68,13 @@ type contents struct {
5368
Values []string `json:"values"`
5469
}
5570

71+
type contentCreateUpdate struct {
72+
Branch string `json:"branch"`
73+
Message string `json:"message"`
74+
Content []byte `json:"content"`
75+
Sha string `json:"sourceCommitId"`
76+
}
77+
5678
func convertContentInfoList(from *contents) []*scm.ContentInfo {
5779
to := []*scm.ContentInfo{}
5880
for _, v := range from.Values {

scm/driver/stash/content_test.go

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,75 @@ func TestContentFind(t *testing.T) {
4343
}
4444

4545
func TestContentCreate(t *testing.T) {
46-
content := new(contentService)
47-
_, err := content.Create(context.Background(), "atlassian/atlaskit", "README", nil)
48-
if err != scm.ErrNotSupported {
49-
t.Errorf("Expect Not Supported error")
46+
defer gock.Off()
47+
48+
gock.New("http://localhost:7990").
49+
Put("/rest/api/1.0/projects/octocat/repos/hello-world/browse/README").
50+
Reply(200).
51+
Type("application/json").
52+
File("testdata/content_create.json")
53+
54+
params := &scm.ContentParams{
55+
Message: "my commit message",
56+
Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="),
57+
Signature: scm.Signature{
58+
Name: "Monalisa Octocat",
59+
60+
},
61+
}
62+
63+
client := NewDefault()
64+
res, err := client.Contents.Create(
65+
context.Background(),
66+
"octocat/hello-world",
67+
"README",
68+
params,
69+
)
70+
71+
if err != nil {
72+
t.Error(err)
73+
return
74+
}
75+
76+
if res.Status != 200 {
77+
t.Errorf("Unexpected Results")
5078
}
5179
}
5280

5381
func TestContentUpdate(t *testing.T) {
54-
content := new(contentService)
55-
_, err := content.Update(context.Background(), "atlassian/atlaskit", "README", nil)
56-
if err != scm.ErrNotSupported {
57-
t.Errorf("Expect Not Supported error")
82+
defer gock.Off()
83+
84+
gock.New("http://localhost:7990").
85+
Put("/rest/api/1.0/projects/octocat/repos/hello-world/browse/README").
86+
Reply(200).
87+
Type("application/json").
88+
File("testdata/content_update.json")
89+
90+
params := &scm.ContentParams{
91+
Message: "a new commit message",
92+
Data: []byte("bXkgdXBkYXRlZCBmaWxlIGNvbnRlbnRz"),
93+
BlobID: "95b966ae1c166bd92f8ae7d1c313e738c731dfc3",
94+
Signature: scm.Signature{
95+
Name: "Monalisa Octocat",
96+
97+
},
98+
}
99+
100+
client := NewDefault()
101+
res, err := client.Contents.Update(
102+
context.Background(),
103+
"octocat/hello-world",
104+
"README",
105+
params,
106+
)
107+
108+
if err != nil {
109+
t.Error(err)
110+
return
111+
}
112+
113+
if res.Status != 200 {
114+
t.Errorf("Unexpected Results")
58115
}
59116
}
60117

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package integration
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/drone/go-scm/scm"
9+
"github.com/drone/go-scm/scm/driver/stash"
10+
"github.com/drone/go-scm/scm/transport"
11+
)
12+
13+
func TestCreateUpdateDeleteFileStash(t *testing.T) {
14+
if token == "" {
15+
t.Skip("Skipping, Acceptance test")
16+
}
17+
client, _ = stash.New(endpoint)
18+
client.Client = &http.Client{
19+
Transport: &transport.BasicAuth{
20+
Username: username,
21+
Password: token,
22+
},
23+
}
24+
// get latest commit first
25+
currentCommit, commitErr := GetCurrentCommitOfBranch(client, "master")
26+
if commitErr != nil {
27+
t.Errorf("we got an error %v", commitErr)
28+
}
29+
// create a new file
30+
createParams := scm.ContentParams{
31+
Message: "go-scm create crud file",
32+
Data: []byte("hello"),
33+
Branch: "master",
34+
Sha: currentCommit,
35+
}
36+
createResponse, createErr := client.Contents.Create(context.Background(), repoID, "README5", &createParams)
37+
if createErr != nil {
38+
t.Errorf("Contents.Create we got an error %v", createErr)
39+
}
40+
if createResponse.Status != http.StatusOK {
41+
t.Errorf("Contents.Create we did not get a 201 back %v", createResponse.Status)
42+
}
43+
// get latest commit first
44+
currentCommit, commitErr = GetCurrentCommitOfBranch(client, "main")
45+
if commitErr != nil {
46+
t.Errorf("we got an error %v", commitErr)
47+
}
48+
// update the file
49+
updateParams := scm.ContentParams{
50+
Message: "go-scm update crud file",
51+
Data: []byte("updated test data"),
52+
Branch: "master",
53+
Sha: currentCommit,
54+
}
55+
updateResponse, updateErr := client.Contents.Update(context.Background(), repoID, "README5", &updateParams)
56+
if updateErr != nil {
57+
t.Errorf("Contents.Update we got an error %v", updateErr)
58+
}
59+
if updateResponse.Status != http.StatusOK {
60+
t.Errorf("Contents.Update we did not get a 201 back %v", updateResponse.Status)
61+
}
62+
}
Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
package integration
22

33
import (
4+
"context"
45
"os"
56

67
"github.com/drone/go-scm/scm"
78
)
89

910
var (
10-
client *scm.Client
11-
token = os.Getenv("BITBUCKET_SERVER_TOKEN")
11+
client *scm.Client
12+
token = os.Getenv("BITBUCKET_SERVER_TOKEN")
13+
1214
endpoint = "https://bitbucket.dev.harness.io/"
1315
repoID = "har/scm-integration-test-repo"
1416
username = "harnessadmin"
1517
commitId = "f675c4b55841908d7c338c500c8f4cb844fd9be7"
1618
)
19+
20+
func GetCurrentCommitOfBranch(client *scm.Client, branch string) (string, error) {
21+
commits, _, err := client.Git.ListCommits(context.Background(), repoID, scm.CommitListOptions{Ref: branch})
22+
if err != nil {
23+
return "", err
24+
}
25+
return commits[0].Sha, nil
26+
}

scm/driver/stash/stash.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"encoding/json"
1212
"fmt"
1313
"io"
14+
"mime/multipart"
1415
"net/url"
1516
"strings"
1617

@@ -74,10 +75,37 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface
7475
// if we are posting or putting data, we need to
7576
// write it to the body of the request.
7677
if in != nil {
77-
buf := new(bytes.Buffer)
78-
json.NewEncoder(buf).Encode(in)
79-
req.Header["Content-Type"] = []string{"application/json"}
80-
req.Body = buf
78+
switch content := in.(type) {
79+
case *contentCreateUpdate:
80+
// add the content to the multipart
81+
var b bytes.Buffer
82+
w := multipart.NewWriter(&b)
83+
// add the other fields
84+
if content.Message != "" {
85+
_ = w.WriteField("content", string(content.Content))
86+
}
87+
if content.Message != "" {
88+
_ = w.WriteField("message", content.Message)
89+
}
90+
if content.Branch != "" {
91+
_ = w.WriteField("branch", content.Branch)
92+
}
93+
if content.Sha != "" {
94+
_ = w.WriteField("sourceCommitId", content.Sha)
95+
}
96+
w.Close()
97+
// write the multipart response to the body
98+
req.Body = &b
99+
// write the content type that contains the length of the multipart
100+
req.Header = map[string][]string{
101+
"Content-Type": {w.FormDataContentType()},
102+
}
103+
default:
104+
buf := new(bytes.Buffer)
105+
json.NewEncoder(buf).Encode(in)
106+
req.Header["Content-Type"] = []string{"application/json"}
107+
req.Body = buf
108+
}
81109
}
82110

83111
// execute the http request
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"id": "abcdef0123abcdef4567abcdef8987abcdef6543",
3+
"displayId": "abcdef0123a",
4+
"author": {
5+
"name": "charlie",
6+
"emailAddress": "[email protected]"
7+
},
8+
"authorTimestamp": 1636089306104,
9+
"committer": {
10+
"name": "charlie",
11+
"emailAddress": "[email protected]"
12+
},
13+
"committerTimestamp": 1636089306104,
14+
"message": "WIP on feature 1",
15+
"parents": [
16+
{
17+
"id": "abcdef0123abcdef4567abcdef8987abcdef6543",
18+
"displayId": "abcdef0"
19+
}
20+
]
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"id": "abcdef0123abcdef4567abcdef8987abcdef6543",
3+
"displayId": "abcdef0123a",
4+
"author": {
5+
"name": "charlie",
6+
"emailAddress": "[email protected]"
7+
},
8+
"authorTimestamp": 1636089306104,
9+
"committer": {
10+
"name": "charlie",
11+
"emailAddress": "[email protected]"
12+
},
13+
"committerTimestamp": 1636089306104,
14+
"message": "WIP on feature 1",
15+
"parents": [
16+
{
17+
"id": "abcdef0123abcdef4567abcdef8987abcdef6543",
18+
"displayId": "abcdef0"
19+
}
20+
]
21+
}

0 commit comments

Comments
 (0)