Merge pull request #5069 from hirasawayuki/fix-pr-checks-cmd
Fix duplicates check results returned by `gh pr checks`
This commit is contained in:
commit
3a088e4df5
3 changed files with 253 additions and 14 deletions
|
|
@ -80,18 +80,7 @@ type PullRequest struct {
|
|||
Commit struct {
|
||||
StatusCheckRollup struct {
|
||||
Contexts struct {
|
||||
Nodes []struct {
|
||||
TypeName string `json:"__typename"`
|
||||
Name string `json:"name"`
|
||||
Context string `json:"context,omitempty"`
|
||||
State string `json:"state,omitempty"`
|
||||
Status string `json:"status"`
|
||||
Conclusion string `json:"conclusion"`
|
||||
StartedAt time.Time `json:"startedAt"`
|
||||
CompletedAt time.Time `json:"completedAt"`
|
||||
DetailsURL string `json:"detailsUrl"`
|
||||
TargetURL string `json:"targetUrl,omitempty"`
|
||||
}
|
||||
Nodes []CheckContext
|
||||
PageInfo struct {
|
||||
HasNextPage bool
|
||||
EndCursor string
|
||||
|
|
@ -113,6 +102,19 @@ type PullRequest struct {
|
|||
ReviewRequests ReviewRequests
|
||||
}
|
||||
|
||||
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"`
|
||||
Conclusion string `json:"conclusion"`
|
||||
StartedAt time.Time `json:"startedAt"`
|
||||
CompletedAt time.Time `json:"completedAt"`
|
||||
DetailsURL string `json:"detailsUrl"`
|
||||
TargetURL string `json:"targetUrl,omitempty"`
|
||||
}
|
||||
|
||||
type PRRepository struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmd/pr/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
|
|
@ -41,7 +42,7 @@ func NewCmdChecks(f *cmdutil.Factory, runF func(*ChecksOptions) error) *cobra.Co
|
|||
Show CI status for a single pull request.
|
||||
|
||||
Without an argument, the pull request that belongs to the current branch
|
||||
is selected.
|
||||
is selected.
|
||||
`),
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -118,7 +119,8 @@ func checksRun(opts *ChecksOptions) error {
|
|||
|
||||
outputs := []output{}
|
||||
|
||||
for _, c := range pr.StatusCheckRollup.Nodes[0].Commit.StatusCheckRollup.Contexts.Nodes {
|
||||
checkContexts := pr.StatusCheckRollup.Nodes[0].Commit.StatusCheckRollup.Contexts.Nodes
|
||||
for _, c := range eliminateDuplicates(checkContexts) {
|
||||
mark := "✓"
|
||||
bucket := "pass"
|
||||
state := c.State
|
||||
|
|
@ -245,3 +247,26 @@ func checksRun(opts *ChecksOptions) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
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{})
|
||||
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
|
||||
}
|
||||
unique = append(unique, ctx)
|
||||
m[key] = struct{}{}
|
||||
}
|
||||
|
||||
return unique
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import (
|
|||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
|
|
@ -239,3 +241,213 @@ func TestChecksRun_web(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEliminateDupulicates(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
checkContexts []api.CheckContext
|
||||
want []api.CheckContext
|
||||
}{
|
||||
{
|
||||
name: "duplicate CheckRun (lint)",
|
||||
checkContexts: []api.CheckContext{
|
||||
{
|
||||
TypeName: "CheckRun",
|
||||
Name: "build (ubuntu-latest)",
|
||||
Status: "COMPLETED",
|
||||
Conclusion: "SUCCESS",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "https://github.com/cli/cli/runs/1",
|
||||
},
|
||||
{
|
||||
TypeName: "CheckRun",
|
||||
Name: "lint",
|
||||
Status: "COMPLETED",
|
||||
Conclusion: "FAILURE",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "https://github.com/cli/cli/runs/2",
|
||||
},
|
||||
{
|
||||
TypeName: "CheckRun",
|
||||
Name: "lint",
|
||||
Status: "COMPLETED",
|
||||
Conclusion: "SUCCESS",
|
||||
StartedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
CompletedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
DetailsURL: "https://github.com/cli/cli/runs/3",
|
||||
},
|
||||
},
|
||||
want: []api.CheckContext{
|
||||
{
|
||||
TypeName: "CheckRun",
|
||||
Name: "lint",
|
||||
Status: "COMPLETED",
|
||||
Conclusion: "SUCCESS",
|
||||
StartedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
CompletedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
DetailsURL: "https://github.com/cli/cli/runs/3",
|
||||
},
|
||||
{
|
||||
TypeName: "CheckRun",
|
||||
Name: "build (ubuntu-latest)",
|
||||
Status: "COMPLETED",
|
||||
Conclusion: "SUCCESS",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "https://github.com/cli/cli/runs/1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "duplicate StatusContext (Windows GPU)",
|
||||
checkContexts: []api.CheckContext{
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Windows GPU",
|
||||
State: "FAILURE",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/2",
|
||||
},
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Windows GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
CompletedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/3",
|
||||
},
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Linux GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/1",
|
||||
},
|
||||
},
|
||||
want: []api.CheckContext{
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Windows GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
CompletedAt: time.Date(2022, 2, 2, 2, 2, 2, 2, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/3",
|
||||
},
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Linux GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unique CheckContext",
|
||||
checkContexts: []api.CheckContext{
|
||||
{
|
||||
TypeName: "CheckRun",
|
||||
Name: "build (ubuntu-latest)",
|
||||
Status: "COMPLETED",
|
||||
Conclusion: "SUCCESS",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "https://github.com/cli/cli/runs/1",
|
||||
},
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Windows GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/2",
|
||||
},
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Linux GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/3",
|
||||
},
|
||||
},
|
||||
want: []api.CheckContext{
|
||||
{
|
||||
TypeName: "CheckRun",
|
||||
Name: "build (ubuntu-latest)",
|
||||
Status: "COMPLETED",
|
||||
Conclusion: "SUCCESS",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "https://github.com/cli/cli/runs/1",
|
||||
},
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Windows GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/2",
|
||||
},
|
||||
{
|
||||
TypeName: "StatusContext",
|
||||
Name: "",
|
||||
Context: "Linux GPU",
|
||||
State: "SUCCESS",
|
||||
Status: "",
|
||||
Conclusion: "",
|
||||
StartedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
CompletedAt: time.Date(2022, 1, 1, 1, 1, 1, 1, time.UTC),
|
||||
DetailsURL: "",
|
||||
TargetURL: "https://github.com/cli/cli/3",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := eliminateDuplicates(tt.checkContexts)
|
||||
if !reflect.DeepEqual(tt.want, got) {
|
||||
t.Errorf("got eliminateDuplicates %+v, want %+v\n", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue