pr checks: avoid deduplicating same-named checks under different workflows (#5919)
This commit is contained in:
parent
1037917d67
commit
dea1af1227
7 changed files with 96 additions and 22 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
2
go.mod
2
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
|
||||
|
|
|
|||
12
go.sum
12
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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue