-
Notifications
You must be signed in to change notification settings - Fork 237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat]: [PL-24913]: Add the support for create and update file in bitbucket server #177
Changes from all commits
9201b48
68ec8b9
f0bd616
a148e26
32f7f0e
a741d64
ab42714
ccaa411
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package integration | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/drone/go-scm/scm" | ||
"github.com/drone/go-scm/scm/driver/stash" | ||
"github.com/drone/go-scm/scm/transport" | ||
) | ||
|
||
func TestCreateUpdateDeleteFileStash(t *testing.T) { | ||
if token == "" { | ||
t.Skip("Skipping, Acceptance test") | ||
} | ||
client, _ = stash.New(endpoint) | ||
client.Client = &http.Client{ | ||
Transport: &transport.BasicAuth{ | ||
Username: username, | ||
Password: token, | ||
}, | ||
} | ||
// get latest commit first | ||
currentCommit, commitErr := GetCurrentCommitOfBranch(client, "master") | ||
if commitErr != nil { | ||
t.Errorf("we got an error %v", commitErr) | ||
} | ||
// create a new file | ||
createParams := scm.ContentParams{ | ||
Message: "go-scm create crud file", | ||
Data: []byte("hello"), | ||
Branch: "master", | ||
Sha: currentCommit, | ||
} | ||
createResponse, createErr := client.Contents.Create(context.Background(), repoID, "README5", &createParams) | ||
if createErr != nil { | ||
t.Errorf("Contents.Create we got an error %v", createErr) | ||
} | ||
if createResponse.Status != http.StatusOK { | ||
t.Errorf("Contents.Create we did not get a 201 back %v", createResponse.Status) | ||
} | ||
// get latest commit first | ||
currentCommit, commitErr = GetCurrentCommitOfBranch(client, "main") | ||
if commitErr != nil { | ||
t.Errorf("we got an error %v", commitErr) | ||
} | ||
// update the file | ||
updateParams := scm.ContentParams{ | ||
Message: "go-scm update crud file", | ||
Data: []byte("updated test data"), | ||
Branch: "master", | ||
Sha: currentCommit, | ||
} | ||
updateResponse, updateErr := client.Contents.Update(context.Background(), repoID, "README5", &updateParams) | ||
if updateErr != nil { | ||
t.Errorf("Contents.Update we got an error %v", updateErr) | ||
} | ||
if updateResponse.Status != http.StatusOK { | ||
t.Errorf("Contents.Update we did not get a 201 back %v", updateResponse.Status) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,26 @@ | ||
package integration | ||
|
||
import ( | ||
"context" | ||
"os" | ||
|
||
"github.com/drone/go-scm/scm" | ||
) | ||
|
||
var ( | ||
client *scm.Client | ||
token = os.Getenv("BITBUCKET_SERVER_TOKEN") | ||
client *scm.Client | ||
token = os.Getenv("BITBUCKET_SERVER_TOKEN") | ||
|
||
endpoint = "https://bitbucket.dev.harness.io/" | ||
repoID = "har/scm-integration-test-repo" | ||
username = "harnessadmin" | ||
commitId = "f675c4b55841908d7c338c500c8f4cb844fd9be7" | ||
) | ||
|
||
func GetCurrentCommitOfBranch(client *scm.Client, branch string) (string, error) { | ||
commits, _, err := client.Git.ListCommits(context.Background(), repoID, scm.CommitListOptions{Ref: branch}) | ||
if err != nil { | ||
return "", err | ||
} | ||
return commits[0].Sha, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ import ( | |
"encoding/json" | ||
"fmt" | ||
"io" | ||
"mime/multipart" | ||
"net/url" | ||
"strings" | ||
|
||
|
@@ -74,10 +75,37 @@ func (c *wrapper) do(ctx context.Context, method, path string, in, out interface | |
// if we are posting or putting data, we need to | ||
// write it to the body of the request. | ||
if in != nil { | ||
buf := new(bytes.Buffer) | ||
json.NewEncoder(buf).Encode(in) | ||
req.Header["Content-Type"] = []string{"application/json"} | ||
req.Body = buf | ||
switch content := in.(type) { | ||
case *contentCreateUpdate: | ||
// add the content to the multipart | ||
var b bytes.Buffer | ||
w := multipart.NewWriter(&b) | ||
// add the other fields | ||
if content.Message != "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a reason to check for empty value? Or in the name of readability might it be easier to pass on the empty fields? (there might be, I'm unfamiliar with the API) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For some of the cases this values are not event required for the bitbucket API, hence I added this check that if the value is not null then don't add this value to multipart data |
||
_ = w.WriteField("content", string(content.Content)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please handle these errors. Aware they're repetitive but could be more palatable with something like: type multipartWriter struct {
w mime. Writer
err error
}
func (multipartWriter *mw) Write(f, v string) {
if mw.err == nil {
return
}
if v == "" {
return
}
_, err = mw.WriteField(f, v)
} case *contentCreateUpdate:
var b bytes.Buffer
mw := multipartWriter{w: multipart.NewWriter(&b)}
mw.write("content", string(content.Content))
mw.write("message", content.Message)
mw.write("branch", content.Branch)
mw.write("sha", content.Sha)
if mw.err != nil {
return nil, fmt.Errorf("error writing multipart-content. err: %s", mw.err)
} see https://go.dev/blog/errors-are-values for background There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did this change in another PR |
||
} | ||
if content.Message != "" { | ||
_ = w.WriteField("message", content.Message) | ||
} | ||
if content.Branch != "" { | ||
_ = w.WriteField("branch", content.Branch) | ||
} | ||
if content.Sha != "" { | ||
_ = w.WriteField("sourceCommitId", content.Sha) | ||
} | ||
w.Close() | ||
// write the multipart response to the body | ||
req.Body = &b | ||
// write the content type that contains the length of the multipart | ||
req.Header = map[string][]string{ | ||
"Content-Type": {w.FormDataContentType()}, | ||
} | ||
default: | ||
buf := new(bytes.Buffer) | ||
json.NewEncoder(buf).Encode(in) | ||
req.Header["Content-Type"] = []string{"application/json"} | ||
req.Body = buf | ||
} | ||
} | ||
|
||
// execute the http request | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"id": "abcdef0123abcdef4567abcdef8987abcdef6543", | ||
"displayId": "abcdef0123a", | ||
"author": { | ||
"name": "charlie", | ||
"emailAddress": "charlie@example.com" | ||
}, | ||
"authorTimestamp": 1636089306104, | ||
"committer": { | ||
"name": "charlie", | ||
"emailAddress": "charlie@example.com" | ||
}, | ||
"committerTimestamp": 1636089306104, | ||
"message": "WIP on feature 1", | ||
"parents": [ | ||
{ | ||
"id": "abcdef0123abcdef4567abcdef8987abcdef6543", | ||
"displayId": "abcdef0" | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"id": "abcdef0123abcdef4567abcdef8987abcdef6543", | ||
"displayId": "abcdef0123a", | ||
"author": { | ||
"name": "charlie", | ||
"emailAddress": "charlie@example.com" | ||
}, | ||
"authorTimestamp": 1636089306104, | ||
"committer": { | ||
"name": "charlie", | ||
"emailAddress": "charlie@example.com" | ||
}, | ||
"committerTimestamp": 1636089306104, | ||
"message": "WIP on feature 1", | ||
"parents": [ | ||
{ | ||
"id": "abcdef0123abcdef4567abcdef8987abcdef6543", | ||
"displayId": "abcdef0" | ||
} | ||
] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would a name like "multipartContent" or "multipartUploadContent" be better here?
Also suggest removing the json tags as it's a little confusing to the reader; the purpose of this struct appears to be in the case where json is not used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the current design in scm service is that whenever we are calling the client.do method, we pass it the json value and the client.do method converts it into the multipart data.
Because of which we cannot name it to multipartContent