Skip to content

Commit f6bded3

Browse files
Merge pull request #468 from zakisk/imple-create-content-endpoint
Implement Content Add Endpoint for Bitbucket Server (stash)
2 parents 6c8f164 + 0c9c56b commit f6bded3

File tree

5 files changed

+118
-11
lines changed

5 files changed

+118
-11
lines changed

scm/driver/stash/content.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,18 @@ func (s *contentService) List(ctx context.Context, repo, path, ref string) ([]*s
3333
}
3434

3535
func (s *contentService) Create(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) {
36-
return nil, scm.ErrNotSupported
36+
namespace, repoName := scm.Split(repo)
37+
endpoint := fmt.Sprintf("rest/api/1.0/projects/%s/repos/%s/browse/%s", namespace, repoName, path)
38+
message := params.Message
39+
if params.Signature.Name != "" && params.Signature.Email != "" {
40+
message = fmt.Sprintf("%s\nSigned-off-by: %s <%s>", params.Message, params.Signature.Name, params.Signature.Email)
41+
}
42+
in := &contentCreateUpdate{
43+
Message: message,
44+
Branch: params.Branch,
45+
Content: params.Data,
46+
}
47+
return s.client.do(ctx, "PUT", endpoint, in, nil)
3748
}
3849

3950
func (s *contentService) Update(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) {
@@ -43,3 +54,10 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params *
4354
func (s *contentService) Delete(ctx context.Context, repo, path string, params *scm.ContentParams) (*scm.Response, error) {
4455
return nil, scm.ErrNotSupported
4556
}
57+
58+
type contentCreateUpdate struct {
59+
Branch string `json:"branch"`
60+
Message string `json:"message"`
61+
Content []byte `json:"content"`
62+
Sha string `json:"sourceCommitId"`
63+
}

scm/driver/stash/content_test.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,31 @@ func TestContentFind(t *testing.T) {
4646
}
4747

4848
func TestContentCreate(t *testing.T) {
49-
content := new(contentService)
50-
_, err := content.Create(context.Background(), "atlassian/atlaskit", "README", nil)
51-
if err != scm.ErrNotSupported {
52-
t.Errorf("Expect Not Supported error")
49+
defer gock.Off()
50+
51+
gock.New("http://example.com:7990").
52+
Put("/rest/api/1.0/projects/octocat/repos/hello-world/browse/README").
53+
Reply(200).
54+
Type("application/json").
55+
File("testdata/content_create.json")
56+
57+
params := &scm.ContentParams{
58+
Message: "my commit message",
59+
Data: []byte("bXkgbmV3IGZpbGUgY29udGVudHM="),
60+
Signature: scm.Signature{
61+
Name: "Zaki",
62+
63+
},
64+
}
65+
66+
client, _ := New("http://example.com:7990")
67+
resp, err := client.Contents.Create(context.Background(), "octocat/hello-world", "README", params)
68+
if err != nil {
69+
t.Error(err)
70+
}
71+
72+
if resp.Status != 200 {
73+
t.Error(err)
5374
}
5475
}
5576

scm/driver/stash/multipart.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package stash
2+
3+
import "mime/multipart"
4+
5+
type MultipartWriter struct {
6+
Writer *multipart.Writer
7+
Error error
8+
}
9+
10+
func (mw *MultipartWriter) Write(f, v string) {
11+
if mw.Error != nil {
12+
return
13+
}
14+
if v == "" {
15+
return
16+
}
17+
mw.Error = mw.Writer.WriteField(f, v)
18+
}
19+
20+
func (mw *MultipartWriter) Close() {
21+
mw.Writer.Close()
22+
}
23+
24+
func (mw *MultipartWriter) FormDataContentType() string {
25+
return mw.Writer.FormDataContentType()
26+
}

scm/driver/stash/stash.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
"bytes"
1010
"context"
1111
"encoding/json"
12+
"fmt"
1213
"io"
14+
"mime/multipart"
1315
"net/url"
1416
"strings"
1517

@@ -74,13 +76,32 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface
7476
// if we are posting or putting data, we need to
7577
// write it to the body of the request.
7678
if in != nil {
77-
buf := new(bytes.Buffer)
78-
err := json.NewEncoder(buf).Encode(in) // #nosec
79-
if err != nil {
80-
return nil, err
79+
switch contentInput := in.(type) {
80+
case *contentCreateUpdate:
81+
var b bytes.Buffer
82+
mw := &MultipartWriter{Writer: multipart.NewWriter(&b)}
83+
mw.Write("content", string(contentInput.Content))
84+
mw.Write("message", contentInput.Message)
85+
mw.Write("branch", contentInput.Branch)
86+
mw.Write("sourceCommitId", contentInput.Sha)
87+
if mw.Error != nil {
88+
return nil, fmt.Errorf("error writing multipart-content. err: %s", mw.Error)
89+
}
90+
mw.Close()
91+
req.Body = &b
92+
req.Header = map[string][]string{
93+
"Content-Type": {mw.FormDataContentType()},
94+
"x-atlassian-token": {"no-check"},
95+
}
96+
default:
97+
buf := new(bytes.Buffer)
98+
err := json.NewEncoder(buf).Encode(in) // #nosec
99+
if err != nil {
100+
return nil, err
101+
}
102+
req.Header.Add("Content-Type", "application/json")
103+
req.Body = buf
81104
}
82-
req.Header.Add("Content-Type", "application/json")
83-
req.Body = buf
84105
}
85106
req.Header.Add("X-Atlassian-Token", "no-check")
86107

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": "Zaki",
6+
"emailAddress": "[email protected]"
7+
},
8+
"authorTimestamp": 1734286823374,
9+
"committer": {
10+
"name": "Zaki",
11+
"emailAddress": "[email protected]"
12+
},
13+
"committerTimestamp": 1734286823374,
14+
"message": "WIP on feature 1",
15+
"parents": [
16+
{
17+
"id": "abcdef0123abcdef4567abcdef8987abcdef6543",
18+
"displayId": "abcdef0"
19+
}
20+
]
21+
}

0 commit comments

Comments
 (0)