diff --git a/api/export_pr.go b/api/export_pr.go index 3c4d14078..e6f0f7221 100644 --- a/api/export_pr.go +++ b/api/export_pr.go @@ -38,7 +38,30 @@ func (pr *PullRequest) ExportData(fields []string) map[string]interface{} { data[f] = pr.HeadRepository case "statusCheckRollup": if n := pr.StatusCheckRollup.Nodes; len(n) > 0 { - data[f] = n[0].Commit.StatusCheckRollup.Contexts.Nodes + checks := make([]interface{}, 0, len(n[0].Commit.StatusCheckRollup.Contexts.Nodes)) + for _, c := range n[0].Commit.StatusCheckRollup.Contexts.Nodes { + if c.TypeName == "CheckRun" { + checks = append(checks, map[string]interface{}{ + "__typename": c.TypeName, + "name": c.Name, + "workflowName": c.CheckSuite.WorkflowRun.Workflow.Name, + "status": c.Status, + "conclusion": c.Conclusion, + "startedAt": c.StartedAt, + "completedAt": c.CompletedAt, + "detailsUrl": c.DetailsURL, + }) + } else { + checks = append(checks, map[string]interface{}{ + "__typename": c.TypeName, + "context": c.Context, + "state": c.State, + "targetUrl": c.TargetURL, + "startedAt": c.CreatedAt, + }) + } + } + data[f] = checks } else { data[f] = nil } diff --git a/api/export_pr_test.go b/api/export_pr_test.go index dde730884..c0be97e4d 100644 --- a/api/export_pr_test.go +++ b/api/export_pr_test.go @@ -140,11 +140,19 @@ func TestPullRequest_ExportData(t *testing.T) { { "__typename": "CheckRun", "name": "mycheck", + "checkSuite": {"workflowRun": {"workflow": {"name": "myworkflow"}}}, "status": "COMPLETED", "conclusion": "SUCCESS", "startedAt": "2020-08-31T15:44:24+02:00", "completedAt": "2020-08-31T15:45:24+02:00", "detailsUrl": "http://example.com/details" + }, + { + "__typename": "StatusContext", + "context": "mycontext", + "state": "SUCCESS", + "createdAt": "2020-08-31T15:44:24+02:00", + "targetUrl": "http://example.com/details" } ] } } } } ] } } @@ -155,11 +163,19 @@ func TestPullRequest_ExportData(t *testing.T) { { "__typename": "CheckRun", "name": "mycheck", + "workflowName": "myworkflow", "status": "COMPLETED", "conclusion": "SUCCESS", "startedAt": "2020-08-31T15:44:24+02:00", "completedAt": "2020-08-31T15:45:24+02:00", "detailsUrl": "http://example.com/details" + }, + { + "__typename": "StatusContext", + "context": "mycontext", + "state": "SUCCESS", + "startedAt": "2020-08-31T15:44:24+02:00", + "targetUrl": "http://example.com/details" } ] } @@ -178,7 +194,14 @@ func TestPullRequest_ExportData(t *testing.T) { enc := json.NewEncoder(&buf) enc.SetIndent("", "\t") require.NoError(t, enc.Encode(exported)) - assert.Equal(t, tt.outputJSON, buf.String()) + + var gotData interface{} + dec = json.NewDecoder(&buf) + require.NoError(t, dec.Decode(&gotData)) + var expectData interface{} + require.NoError(t, json.Unmarshal([]byte(tt.outputJSON), &expectData)) + + assert.Equal(t, expectData, gotData) }) } } diff --git a/api/queries_pr.go b/api/queries_pr.go index 347edd8db..18217a583 100644 --- a/api/queries_pr.go +++ b/api/queries_pr.go @@ -94,16 +94,30 @@ type PullRequest struct { } type CheckContext struct { - TypeName string `json:"__typename"` - Name string `json:"name"` - Context string `json:"context,omitempty"` - State string `json:"state,omitempty"` - Status string `json:"status"` + TypeName string `json:"__typename"` + Name string `json:"name"` + CheckSuite struct { + WorkflowRun struct { + Workflow struct { + Name string `json:"name"` + } `json:"workflow"` + } `json:"workflowRun"` + } `json:"checkSuite"` + // QUEUED IN_PROGRESS COMPLETED WAITING PENDING REQUESTED + Status string `json:"status"` + // ACTION_REQUIRED TIMED_OUT CANCELLED FAILURE SUCCESS NEUTRAL SKIPPED STARTUP_FAILURE STALE Conclusion string `json:"conclusion"` StartedAt time.Time `json:"startedAt"` CompletedAt time.Time `json:"completedAt"` DetailsURL string `json:"detailsUrl"` - TargetURL string `json:"targetUrl,omitempty"` + + /* StatusContext fields */ + + Context string `json:"context"` + // EXPECTED ERROR FAILURE PENDING SUCCESS + State string `json:"state"` + TargetURL string `json:"targetUrl"` + CreatedAt time.Time `json:"createdAt"` } type PRRepository struct { diff --git a/api/query_builder.go b/api/query_builder.go index 977089df6..70c9da6ee 100644 --- a/api/query_builder.go +++ b/api/query_builder.go @@ -141,10 +141,12 @@ func StatusCheckRollupGraphQL(after string) string { ...on StatusContext { context, state, - targetUrl + targetUrl, + createdAt }, ...on CheckRun { name, + checkSuite{workflowRun{workflow{name}}}, status, conclusion, startedAt, diff --git a/go.mod b/go.mod index 731dcda05..d7134eea1 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/fatih/color v1.7.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect @@ -68,6 +69,7 @@ require ( github.com/yuin/goldmark-emoji v1.0.1 // indirect golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) replace golang.org/x/crypto => github.com/cli/crypto v0.0.0-20210929142629-6be313f59b03 diff --git a/go.sum b/go.sum index 7c31d0159..76342fbec 100644 --- a/go.sum +++ b/go.sum @@ -113,8 +113,10 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -125,6 +127,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -499,11 +502,14 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= diff --git a/pkg/cmd/pr/checks/aggregate.go b/pkg/cmd/pr/checks/aggregate.go index e75298cd7..9247082b9 100644 --- a/pkg/cmd/pr/checks/aggregate.go +++ b/pkg/cmd/pr/checks/aggregate.go @@ -86,24 +86,28 @@ func aggregateChecks(pr *api.PullRequest) ([]check, checkCounts, error) { return checks, counts, nil } +// eliminateDuplicates filters a set of checks to only the most recent ones if the set includes repeated runs func eliminateDuplicates(checkContexts []api.CheckContext) []api.CheckContext { - // To return the most recent check, sort in descending order by StartedAt. sort.Slice(checkContexts, func(i, j int) bool { return checkContexts[i].StartedAt.After(checkContexts[j].StartedAt) }) - m := make(map[string]struct{}) + mapChecks := make(map[string]struct{}) + mapContexts := make(map[string]struct{}) unique := make([]api.CheckContext, 0, len(checkContexts)) - // Eliminate duplicates using Name or Context. for _, ctx := range checkContexts { - key := ctx.Name - if key == "" { - key = ctx.Context - } - if _, ok := m[key]; ok { - continue + if ctx.Context != "" { + if _, exists := mapContexts[ctx.Context]; exists { + continue + } + mapContexts[ctx.Context] = struct{}{} + } else { + key := fmt.Sprintf("%s/%s", ctx.Name, ctx.CheckSuite.WorkflowRun.Workflow.Name) + if _, exists := mapChecks[key]; exists { + continue + } + mapChecks[key] = struct{}{} } unique = append(unique, ctx) - m[key] = struct{}{} } return unique