Skip to content

Commit 4476a28

Browse files
Merge pull request drone#29 from jstrachan/stuff
fix: add another example program + add GraphQL api
2 parents 2386fd0 + 7300a1e commit 4476a28

28 files changed

+1248
-45
lines changed

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
module github.com/jenkins-x/go-scm
22

33
require (
4+
github.com/ghodss/yaml v1.0.0
45
github.com/google/go-cmp v0.3.0
56
github.com/h2non/gock v1.0.9
7+
github.com/pkg/errors v0.8.1
8+
github.com/shurcooL/githubv4 v0.0.0-20190718010115-4ba037080260
9+
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f // indirect
10+
github.com/sirupsen/logrus v1.4.2 // indirect
611
github.com/stretchr/testify v1.3.0
712
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
813
k8s.io/apimachinery v0.0.0-20190703205208-4cfb76a8bf76

go.sum

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ
66
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
77
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
88
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
9+
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
10+
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
911
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
1012
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
1113
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -21,6 +23,7 @@ github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1
2123
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
2224
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
2325
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
26+
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
2427
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
2528
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
2629
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -30,10 +33,20 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
3033
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
3134
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
3235
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
36+
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
37+
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3338
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3439
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
40+
github.com/shurcooL/githubv4 v0.0.0-20190718010115-4ba037080260 h1:xKXiRdBUtMVp64NaxACcyX4kvfmHJ9KrLU+JvyB1mdM=
41+
github.com/shurcooL/githubv4 v0.0.0-20190718010115-4ba037080260/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo=
42+
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk=
43+
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg=
44+
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
45+
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
3546
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
3647
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
48+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
49+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
3750
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
3851
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
3952
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -48,6 +61,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
4861
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
4962
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
5063
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
64+
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
65+
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4=
5166
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5267
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
5368
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -59,6 +74,7 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
5974
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
6075
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
6176
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
77+
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
6278
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
6379
k8s.io/apimachinery v0.0.0-20190703205208-4cfb76a8bf76 h1:vxMYBaJgczGAIpJAOBco2eHuFYIyDdNIebt60jxLauA=
6480
k8s.io/apimachinery v0.0.0-20190703205208-4cfb76a8bf76/go.mod h1:M2fZgZL9DbLfeJaPBCDqSqNsdsmLN+V29knYJnIXlMA=

scm/client.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ type (
7575
Size int
7676
}
7777

78+
// GraphQLService the API to performing GraphQL queries
79+
GraphQLService interface {
80+
Query(ctx context.Context, q interface{}, vars map[string]interface{}) error
81+
}
82+
7883
// Client manages communication with a version control
7984
// system API.
8085
Client struct {
@@ -97,6 +102,7 @@ type (
97102
Reviews ReviewService
98103
Users UserService
99104
Webhooks WebhookService
105+
GraphQL GraphQLService
100106

101107
// DumpResponse optionally specifies a function to
102108
// dump the the response body for debugging purposes.

scm/const.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package scm
66

77
import (
88
"encoding/json"
9+
"strings"
910
)
1011

1112
// State represents the commit state.
@@ -20,6 +21,7 @@ const (
2021
StateFailure
2122
StateCanceled
2223
StateError
24+
StateExpected
2325
)
2426

2527
// String returns a string representation of the State
@@ -37,13 +39,37 @@ func (s State) String() string {
3739
return "failure"
3840
case StateCanceled:
3941
return "cancelled"
42+
case StateExpected:
43+
return "expected"
4044
case StateError:
4145
return "error"
4246
default:
4347
return "unknown"
4448
}
4549
}
4650

51+
// ToState converts the given text to a state
52+
func ToState(s string) State {
53+
switch strings.ToLower(s) {
54+
case "pending":
55+
return StatePending
56+
case "running":
57+
return StateRunning
58+
case "success":
59+
return StateSuccess
60+
case "failure":
61+
return StateFailure
62+
case "cancelled":
63+
return StateCanceled
64+
case "expected":
65+
return StateExpected
66+
case "error":
67+
return StateError
68+
default:
69+
return StateUnknown
70+
}
71+
}
72+
4773
// Action identifies webhook actions.
4874
type Action int
4975

scm/driver/bitbucket/issue.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ type issueService struct {
1414
client *wrapper
1515
}
1616

17+
func (s *issueService) Search(context.Context, scm.SearchOptions) ([]*scm.SearchIssue, *scm.Response, error) {
18+
// TODO implemment
19+
return nil, nil, nil
20+
}
21+
1722
func (s *issueService) AssignIssue(ctx context.Context, repo string, number int, logins []string) (*scm.Response, error) {
1823
panic("implement me")
1924
}

scm/driver/fake/issue.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ type issueService struct {
1616

1717
const botName = "k8s-ci-robot"
1818

19+
func (s *issueService) Search(context.Context, scm.SearchOptions) ([]*scm.SearchIssue, *scm.Response, error) {
20+
// TODO implemment
21+
return nil, nil, nil
22+
}
23+
1924
func (s *issueService) ListEvents(ctx context.Context, repo string, number int, opts scm.ListOptions) ([]*scm.ListedIssueEvent, *scm.Response, error) {
2025
f := s.data
2126
return append([]*scm.ListedIssueEvent{}, f.IssueEvents[number]...), nil, nil

scm/driver/gitea/issue.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ type issueService struct {
1616
client *wrapper
1717
}
1818

19+
func (s *issueService) Search(context.Context, scm.SearchOptions) ([]*scm.SearchIssue, *scm.Response, error) {
20+
// TODO implemment
21+
return nil, nil, nil
22+
}
23+
1924
func (s *issueService) AssignIssue(ctx context.Context, repo string, number int, logins []string) (*scm.Response, error) {
2025
panic("implement me")
2126
}

scm/driver/github/github.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,22 @@ import (
99
"bytes"
1010
"context"
1111
"encoding/json"
12+
"fmt"
13+
"net/http"
1214
"net/url"
1315
"strconv"
1416
"strings"
17+
"time"
1518

1619
"github.com/jenkins-x/go-scm/scm"
20+
githubql "github.com/shurcooL/githubv4"
1721
)
1822

23+
// Abort requests that don't return in 5 mins. Longest graphql calls can
24+
// take up to 2 minutes. This limit should ensure all successful calls return
25+
// but will prevent an indefinite stall if GitHub never responds.
26+
const maxRequestTime = 5 * time.Minute
27+
1928
// New returns a new GitHub API client.
2029
func New(uri string) (*scm.Client, error) {
2130
base, err := url.Parse(uri)
@@ -38,9 +47,37 @@ func New(uri string) (*scm.Client, error) {
3847
client.Reviews = &reviewService{client}
3948
client.Users = &userService{client}
4049
client.Webhooks = &webhookService{client}
50+
51+
graphqlEndpoint := scm.UrlJoin(uri, "/graphql")
52+
client.GraphQL = &dynamicGraphQLClient{client, graphqlEndpoint}
53+
4154
return client.Client, nil
4255
}
4356

57+
type dynamicGraphQLClient struct {
58+
wrapper *wrapper
59+
graphqlEndpoint string
60+
}
61+
62+
func (d *dynamicGraphQLClient) Query(ctx context.Context, q interface{}, vars map[string]interface{}) error {
63+
httpClient := d.wrapper.Client.Client
64+
if httpClient != nil {
65+
66+
transport := httpClient.Transport
67+
if transport != nil {
68+
query := githubql.NewEnterpriseClient(
69+
d.graphqlEndpoint,
70+
&http.Client{
71+
Timeout: maxRequestTime,
72+
Transport: transport,
73+
})
74+
return query.Query(ctx, q, vars)
75+
}
76+
}
77+
fmt.Println("WARNING: no http transport configured for GraphQL and GitHub")
78+
return nil
79+
}
80+
4481
// NewDefault returns a new GitHub API client using the
4582
// default api.github.com address.
4683
func NewDefault() *scm.Client {

scm/driver/github/issue.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"fmt"
1010
"net/http"
11+
"strings"
1112
"time"
1213

1314
"github.com/jenkins-x/go-scm/scm"
@@ -17,6 +18,36 @@ type issueService struct {
1718
client *wrapper
1819
}
1920

21+
type searchIssue struct {
22+
issue
23+
Score float32 `json:"score"`
24+
AuthorAssociation string `json:"author_association"`
25+
URL string `json:"url"`
26+
RepositoryURL string `json:"repository_url"`
27+
LabelsURL string `json:"labels_url"`
28+
CommentsURL string `json:"comments_url"`
29+
EventsURL string `json:"events_url"`
30+
Comments int `json:"comments"`
31+
}
32+
33+
type searchResults struct {
34+
TotalCount int `json:"total_count"`
35+
IncompleteResults bool `json:"incomplete_results"`
36+
Items []*searchIssue `json:"items"`
37+
}
38+
39+
func (s *issueService) Search(ctx context.Context, opts scm.SearchOptions) ([]*scm.SearchIssue, *scm.Response, error) {
40+
suffix := encodeIssueSearchOptions(opts)
41+
query := opts.QueryArgument()
42+
if suffix != "" {
43+
query += "&" + suffix
44+
}
45+
path := fmt.Sprintf("/search/issues?q=%s", query)
46+
out := searchResults{}
47+
res, err := s.client.do(ctx, "GET", path, nil, &out)
48+
return convertSearchIssueList(out.Items), res, err
49+
}
50+
2051
// AssignIssue adds logins to org/repo#number, returning an error if any login is missing after making the call.
2152
//
2253
// See https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue
@@ -237,6 +268,35 @@ func convertIssueList(from []*issue) []*scm.Issue {
237268
return to
238269
}
239270

271+
// helper function to convert from the gogs issue list to
272+
// the common issue structure.
273+
func convertSearchIssueList(from []*searchIssue) []*scm.SearchIssue {
274+
to := []*scm.SearchIssue{}
275+
for _, v := range from {
276+
issue := convertIssue(&v.issue)
277+
searchIssue := &scm.SearchIssue{
278+
Issue: *issue,
279+
}
280+
populateRepositoryFromURL(&searchIssue.Repository, v.RepositoryURL)
281+
to = append(to, searchIssue)
282+
}
283+
return to
284+
}
285+
286+
func populateRepositoryFromURL(repo *scm.Repository, u string) {
287+
if u == "" {
288+
return
289+
}
290+
paths := strings.Split(strings.TrimSuffix(u, "/"), "/")
291+
l := len(paths)
292+
if l > 0 {
293+
repo.Name = paths[l-1]
294+
}
295+
if l > 1 {
296+
repo.Namespace = paths[l-2]
297+
}
298+
}
299+
240300
// helper function to convert from the gogs issue structure to
241301
// the common issue structure.
242302
func convertIssue(from *issue) *scm.Issue {

0 commit comments

Comments
 (0)