Skip to content

Commit

Permalink
Merge pull request #259 from jstrachan/frazergibsonntt-master
Browse files Browse the repository at this point in the history
fix: added bitbucket cloud comment support
  • Loading branch information
jenkins-x-bot-test authored Mar 25, 2021
2 parents ee723d0 + 27c2c7d commit e4c033d
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 20 deletions.
2 changes: 2 additions & 0 deletions scm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ package scm
import (
"context"
"errors"

"io"
"net/http"

"net/url"
"strconv"
"strings"
Expand Down
69 changes: 66 additions & 3 deletions scm/driver/bitbucket/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (

"github.com/jenkins-x/go-scm/scm/labels"

"fmt"
"time"

"github.com/jenkins-x/go-scm/scm"
)

Expand Down Expand Up @@ -66,20 +69,80 @@ func (s *issueService) List(ctx context.Context, repo string, opts scm.IssueList
return nil, nil, scm.ErrNotSupported
}

func convertIssueCommentList(from []*issueComment) []*scm.Comment {
to := []*scm.Comment{}
for _, v := range from {
to = append(to, convertIssueComment(v))
}
return to
}

func (s *issueService) ListComments(ctx context.Context, repo string, index int, opts scm.ListOptions) ([]*scm.Comment, *scm.Response, error) {
return nil, nil, scm.ErrNotSupported
path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/comments?%s", repo, index, encodeListOptions(opts))
out := []*issueComment{}
res, err := s.client.do(ctx, "GET", path, nil, &out)
return convertIssueCommentList(out), res, err
}

func (s *issueService) Create(ctx context.Context, repo string, input *scm.IssueInput) (*scm.Issue, *scm.Response, error) {
return nil, nil, scm.ErrNotSupported
}

type issueCommentInput struct {
Content struct {
Raw string `json:"raw,omitempty"`
} `json:"content"`
}

type issueComment struct {
ID int `json:"id"`
Links struct {
HTML struct {
Href string `json:"href"`
} `json:"html"`
} `json:"links"`
User struct {
AccountID string `json:"account_id"`
DisplayName string `json:"display_name"`
Links struct {
Avatar struct {
Href string `json:"href"`
} `json:"avatar"`
} `json:"links"`
} `json:"user"`
Content struct {
Raw string `json:"raw"`
} `json:"content"`
CreatedOn time.Time `json:"created_on"`
UpdatedOn time.Time `json:"updated_on"`
}

func convertIssueComment(from *issueComment) *scm.Comment {
return &scm.Comment{
ID: from.ID,
Body: from.Content.Raw,
Author: scm.User{
Login: from.User.DisplayName,
Avatar: from.User.Links.Avatar.Href,
},
Link: from.Links.HTML.Href,
Created: from.CreatedOn,
Updated: from.UpdatedOn,
}
}

func (s *issueService) CreateComment(ctx context.Context, repo string, number int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) {
return nil, nil, scm.ErrNotSupported
path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/comments", repo, number)
in := new(issueCommentInput)
in.Content.Raw = input.Body
out := new(issueComment)
res, err := s.client.do(ctx, "POST", path, in, out)
return convertIssueComment(out), res, err
}

func (s *issueService) DeleteComment(ctx context.Context, repo string, number, id int) (*scm.Response, error) {
return nil, scm.ErrNotSupported
path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/comments/%d", repo, number, id)
return s.client.do(ctx, "DELETE", path, nil, nil)
}

func (s *issueService) EditComment(ctx context.Context, repo string, number int, id int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) {
Expand Down
15 changes: 3 additions & 12 deletions scm/driver/bitbucket/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ func TestIssueList(t *testing.T) {
}

func TestIssueListComments(t *testing.T) {
_, _, err := NewDefault().Issues.ListComments(context.Background(), "", 0, scm.ListOptions{})
if err != nil && err != scm.ErrNotSupported {
t.Errorf("Expect Not Supported error")
}
// TODO
}

func TestIssueCreate(t *testing.T) {
Expand All @@ -47,17 +44,11 @@ func TestIssueCreate(t *testing.T) {
}

func TestIssueCreateComment(t *testing.T) {
_, _, err := NewDefault().Issues.CreateComment(context.Background(), "", 0, &scm.CommentInput{})
if err != nil && err != scm.ErrNotSupported {
t.Errorf("Expect Not Supported error")
}
// TODO
}

func TestIssueCommentDelete(t *testing.T) {
_, err := NewDefault().Issues.DeleteComment(context.Background(), "", 0, 0)
if err != nil && err != scm.ErrNotSupported {
t.Errorf("Expect Not Supported error")
}
// TODO
}

func TestIssueClose(t *testing.T) {
Expand Down
116 changes: 116 additions & 0 deletions scm/driver/bitbucket/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,122 @@ func (s *pullService) List(ctx context.Context, repo string, opts scm.PullReques
return convertPullRequests(out), res, err
}

type prCommentInput struct {
Content struct {
Raw string `json:"raw,omitempty"`
} `json:"content"`
}

type pullRequestComments struct {
pagination
Values []*prComment `json:"values"`
}

type prComment struct {
ID int `json:"id"`
Type string `json:"type"`
Links struct {
HTML struct {
Href string `json:"href"`
} `json:"html,omitempty"`
Self struct {
Href string `json:"href"`
} `json:"self,omitempty"`
Code struct {
Href string `json:"href"`
} `json:"code,omitempty"`
} `json:"links"`
PR struct {
Title string `json:"title"`
ID int `json:"id"`
Type string `json:"type"`
Links struct {
HTML struct {
Href string `json:"href"`
} `json:"html"`
Self struct {
Href string `json:"href"`
} `json:"self"`
} `json:"links"`
} `json:"pullrequest"`
User struct {
AccountID string `json:"account_id"`
DisplayName string `json:"display_name"`
UUID string `json:"uuid"`
Type string `json:"type"`
NickName string `json:"nickname"`
Links struct {
HTML struct {
Href string `json:"href"`
} `json:"html"`
Self struct {
Href string `json:"href"`
} `json:"self"`
Avatar struct {
Href string `json:"href"`
} `json:"avatar"`
} `json:"links"`
} `json:"user"`
Content struct {
Raw string `json:"raw"`
Markup string `json:"markup"`
HTML string `json:"html"`
Type string `json:"type"`
} `json:"content"`
Inline struct {
To int `json:"to,omitempty"`
From int `json:"from,omitempty"`
Path string `json:"path,omitempty"`
} `json:"inline,omitempty"`
Deleted bool `json:"deleted"`
UpdatedOn time.Time `json:"updated_on"`
CreatedOn time.Time `json:"created_on"`
}

func convertPRComment(from *prComment) *scm.Comment {

return &scm.Comment{
ID: from.ID,
Body: from.Content.Raw,
Author: scm.User{
Login: from.User.DisplayName,
Avatar: from.User.Links.Avatar.Href,
},
Link: from.Links.HTML.Href,
Created: from.CreatedOn,
Updated: from.UpdatedOn,
}
}

func (s *pullService) CreateComment(ctx context.Context, repo string, number int, input *scm.CommentInput) (*scm.Comment, *scm.Response, error) {
path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/comments", repo, number)
in := new(prCommentInput)
in.Content.Raw = input.Body
out := new(prComment)
res, err := s.client.do(ctx, "POST", path, in, out)
return convertPRComment(out), res, err
}

func (s *pullService) DeleteComment(ctx context.Context, repo string, number, id int) (*scm.Response, error) {
path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/comments/%d", repo, number, id)
return s.client.do(ctx, "DELETE", path, nil, nil)
}

func convertPRCommentList(from *pullRequestComments) []*scm.Comment {
to := []*scm.Comment{}
for _, v := range from.Values {
to = append(to, convertPRComment(v))
}
return to
}

func (s *pullService) ListComments(ctx context.Context, repo string, index int, opts scm.ListOptions) ([]*scm.Comment, *scm.Response, error) {
path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/comments?%s", repo, index, encodeListOptions(opts))
out := new(pullRequestComments)
res, err := s.client.do(ctx, "GET", path, nil, &out)
return convertPRCommentList(out), res, err
}

func (s *pullService) ListChanges(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.Change, *scm.Response, error) {
path := fmt.Sprintf("2.0/repositories/%s/pullrequests/%d/diffstat?%s", repo, number, encodeListOptions(opts))
out := new(diffstats)
Expand Down
38 changes: 37 additions & 1 deletion scm/driver/bitbucket/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io/ioutil"
"net/url"
"sort"
"strings"
"time"

Expand Down Expand Up @@ -122,7 +123,42 @@ func (s *repositoryService) Fork(context.Context, *scm.RepositoryInput, string)
}

func (s *repositoryService) FindCombinedStatus(ctx context.Context, repo, ref string) (*scm.CombinedStatus, *scm.Response, error) {
return nil, nil, scm.ErrNotSupported
statusList, resp, err := s.ListStatus(ctx, repo, ref, scm.ListOptions{})
if err != nil {
return nil, resp, errors.Wrapf(err, "failed to list statuses")
}

combinedState := scm.StateUnknown

byContext := make(map[string]*scm.Status)
for _, s := range statusList {
byContext[s.Target] = s
}

keys := make([]string, 0, len(byContext))
for k := range byContext {
keys = append(keys, k)
}
sort.Strings(keys)
var statuses []*scm.Status
for _, k := range keys {
s := byContext[k]
statuses = append(statuses, s)
}

for _, s := range statuses {
// If we've still got a default state, or the state of the current status is worse than the current state, set it.
if combinedState == scm.StateUnknown || combinedState > s.State {
combinedState = s.State
}
}

combined := &scm.CombinedStatus{
State: 0,
Sha: ref,
Statuses: statuses,
}
return combined, resp, nil
}

func (s *repositoryService) FindUserPermission(ctx context.Context, repo string, user string) (string, *scm.Response, error) {
Expand Down
16 changes: 12 additions & 4 deletions scm/driver/bitbucket/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ func encodeListOptions(opts scm.ListOptions) string {
if opts.Page != 0 {
params.Set("page", strconv.Itoa(opts.Page))
}
if opts.Size != 0 {
params.Set("pagelen", strconv.Itoa(opts.Size))
if opts.Size == 0 {
opts.Size = 50
}
if opts.Size > 50 {
opts.Size = 50
}
params.Set("pagelen", strconv.Itoa(opts.Size))
return params.Encode()
}

Expand Down Expand Up @@ -85,9 +89,13 @@ func encodePullRequestListOptions(opts scm.PullRequestListOptions) string {
if opts.Page != 0 {
params.Set("page", strconv.Itoa(opts.Page))
}
if opts.Size != 0 {
params.Set("pagelen", strconv.Itoa(opts.Size))
if opts.Size == 0 {
opts.Size = 50
}
if opts.Size > 50 {
opts.Size = 50
}
params.Set("pagelen", strconv.Itoa(opts.Size))
if opts.Open && opts.Closed {
params.Set("state", "all")
} else if opts.Closed {
Expand Down
44 changes: 44 additions & 0 deletions scm/factory/examples/combinedstatus/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import (
"context"
"fmt"
"os"

"github.com/jenkins-x/go-scm/scm/factory"
"github.com/jenkins-x/go-scm/scm/factory/examples/helpers"
)

func main() {
args := os.Args
if len(args) < 2 {
fmt.Println("usage: repo ref")
os.Exit(1)
return
}
repo := args[1]
ref := "master"
if len(args) > 2 {
ref = args[2]
}

client, err := factory.NewClientFromEnvironment()
if err != nil {
helpers.Fail(err)
return
}

fmt.Printf("finding combined status in repo: %s ref: %s\n", repo, ref)

ctx := context.Background()
results, _, err := client.Repositories.FindCombinedStatus(ctx, repo, ref)
if err != nil {
helpers.Fail(err)
return
}
fmt.Printf("state: %v sha: %s\n", results.State, results.Sha)

for _, s := range results.Statuses {
fmt.Printf("target %s state %v label %s\n", s.Target, s.State, s.Label)
}
}

0 comments on commit e4c033d

Please sign in to comment.