add --required flag to gh pr checks (#5648)
This commit is contained in:
parent
537dcb2739
commit
e5b37ee661
11 changed files with 552 additions and 262 deletions
|
|
@ -67,19 +67,7 @@ type PullRequest struct {
|
|||
Nodes []PullRequestCommit
|
||||
}
|
||||
StatusCheckRollup struct {
|
||||
Nodes []struct {
|
||||
Commit struct {
|
||||
StatusCheckRollup struct {
|
||||
Contexts struct {
|
||||
Nodes []CheckContext
|
||||
PageInfo struct {
|
||||
HasNextPage bool
|
||||
EndCursor string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Nodes []StatusCheckRollupNode
|
||||
}
|
||||
|
||||
Assignees Assignees
|
||||
|
|
@ -93,9 +81,30 @@ type PullRequest struct {
|
|||
ReviewRequests ReviewRequests
|
||||
}
|
||||
|
||||
type StatusCheckRollupNode struct {
|
||||
Commit StatusCheckRollupCommit
|
||||
}
|
||||
|
||||
type StatusCheckRollupCommit struct {
|
||||
StatusCheckRollup CommitStatusCheckRollup
|
||||
}
|
||||
|
||||
type CommitStatusCheckRollup struct {
|
||||
Contexts CheckContexts
|
||||
}
|
||||
|
||||
type CheckContexts struct {
|
||||
Nodes []CheckContext
|
||||
PageInfo struct {
|
||||
HasNextPage bool
|
||||
EndCursor string
|
||||
}
|
||||
}
|
||||
|
||||
type CheckContext struct {
|
||||
TypeName string `json:"__typename"`
|
||||
Name string `json:"name"`
|
||||
IsRequired bool `json:"isRequired"`
|
||||
CheckSuite struct {
|
||||
WorkflowRun struct {
|
||||
Workflow struct {
|
||||
|
|
|
|||
|
|
@ -164,6 +164,45 @@ func StatusCheckRollupGraphQL(after string) string {
|
|||
}`), afterClause)
|
||||
}
|
||||
|
||||
func RequiredStatusCheckRollupGraphQL(prID, after string) string {
|
||||
var afterClause string
|
||||
if after != "" {
|
||||
afterClause = ",after:" + after
|
||||
}
|
||||
return fmt.Sprintf(shortenQuery(`
|
||||
statusCheckRollup: commits(last: 1) {
|
||||
nodes {
|
||||
commit {
|
||||
statusCheckRollup {
|
||||
contexts(first:100%[1]s) {
|
||||
nodes {
|
||||
__typename
|
||||
...on StatusContext {
|
||||
context,
|
||||
state,
|
||||
targetUrl,
|
||||
createdAt,
|
||||
isRequired(pullRequestId: %[2]s)
|
||||
},
|
||||
...on CheckRun {
|
||||
name,
|
||||
checkSuite{workflowRun{workflow{name}}},
|
||||
status,
|
||||
conclusion,
|
||||
startedAt,
|
||||
completedAt,
|
||||
detailsUrl,
|
||||
isRequired(pullRequestId: %[2]s)
|
||||
}
|
||||
},
|
||||
pageInfo{hasNextPage,endCursor}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`), afterClause, prID)
|
||||
}
|
||||
|
||||
var IssueFields = []string{
|
||||
"assignees",
|
||||
"author",
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ type checkCounts struct {
|
|||
Skipping int
|
||||
}
|
||||
|
||||
func aggregateChecks(pr *api.PullRequest) ([]check, checkCounts, error) {
|
||||
func aggregateChecks(pr *api.PullRequest, requiredChecks bool) ([]check, checkCounts, error) {
|
||||
checks := []check{}
|
||||
counts := checkCounts{}
|
||||
|
||||
|
|
@ -39,6 +39,10 @@ func aggregateChecks(pr *api.PullRequest) ([]check, checkCounts, error) {
|
|||
|
||||
checkContexts := pr.StatusCheckRollup.Nodes[0].Commit.StatusCheckRollup.Contexts.Nodes
|
||||
for _, c := range eliminateDuplicates(checkContexts) {
|
||||
if requiredChecks && !c.IsRequired {
|
||||
continue
|
||||
}
|
||||
|
||||
state := c.State
|
||||
if state == "" {
|
||||
if c.Status == "COMPLETED" {
|
||||
|
|
@ -83,6 +87,10 @@ func aggregateChecks(pr *api.PullRequest) ([]check, checkCounts, error) {
|
|||
checks = append(checks, item)
|
||||
}
|
||||
|
||||
if len(checks) == 0 && requiredChecks {
|
||||
return checks, counts, fmt.Errorf("no required checks reported on the '%s' branch", pr.HeadRefName)
|
||||
}
|
||||
|
||||
return checks, counts, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package checks
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
|
|
@ -18,8 +19,9 @@ import (
|
|||
const defaultInterval time.Duration = 10 * time.Second
|
||||
|
||||
type ChecksOptions struct {
|
||||
IO *iostreams.IOStreams
|
||||
Browser browser.Browser
|
||||
HttpClient func() (*http.Client, error)
|
||||
IO *iostreams.IOStreams
|
||||
Browser browser.Browser
|
||||
|
||||
Finder shared.PRFinder
|
||||
|
||||
|
|
@ -27,14 +29,16 @@ type ChecksOptions struct {
|
|||
WebMode bool
|
||||
Interval time.Duration
|
||||
Watch bool
|
||||
Required bool
|
||||
}
|
||||
|
||||
func NewCmdChecks(f *cmdutil.Factory, runF func(*ChecksOptions) error) *cobra.Command {
|
||||
var interval int
|
||||
opts := &ChecksOptions{
|
||||
IO: f.IOStreams,
|
||||
Browser: f.Browser,
|
||||
Interval: defaultInterval,
|
||||
HttpClient: f.HttpClient,
|
||||
IO: f.IOStreams,
|
||||
Browser: f.Browser,
|
||||
Interval: defaultInterval,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
|
|
@ -82,6 +86,7 @@ func NewCmdChecks(f *cmdutil.Factory, runF func(*ChecksOptions) error) *cobra.Co
|
|||
cmd.Flags().BoolVarP(&opts.WebMode, "web", "w", false, "Open the web browser to show details about checks")
|
||||
cmd.Flags().BoolVarP(&opts.Watch, "watch", "", false, "Watch checks until they finish")
|
||||
cmd.Flags().IntVarP(&interval, "interval", "i", 10, "Refresh interval in seconds when using `--watch` flag")
|
||||
cmd.Flags().BoolVar(&opts.Required, "required", false, "Only show checks that are required")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -111,6 +116,22 @@ func checksRun(opts *ChecksOptions) error {
|
|||
return checksRunWebMode(opts)
|
||||
}
|
||||
|
||||
findOptions := shared.FindOptions{
|
||||
Selector: opts.SelectorArg,
|
||||
Fields: []string{"number", "headRefName"},
|
||||
}
|
||||
|
||||
var pr *api.PullRequest
|
||||
pr, repo, findErr := opts.Finder.Find(findOptions)
|
||||
if findErr != nil {
|
||||
return findErr
|
||||
}
|
||||
|
||||
client, clientErr := opts.HttpClient()
|
||||
if clientErr != nil {
|
||||
return clientErr
|
||||
}
|
||||
|
||||
if opts.Watch {
|
||||
opts.IO.StartAlternateScreenBuffer()
|
||||
} else {
|
||||
|
|
@ -127,19 +148,14 @@ func checksRun(opts *ChecksOptions) error {
|
|||
|
||||
// Do not return err until we can StopAlternateScreenBuffer()
|
||||
var err error
|
||||
for {
|
||||
findOptions := shared.FindOptions{
|
||||
Selector: opts.SelectorArg,
|
||||
Fields: []string{"number", "headRefName", "statusCheckRollup"},
|
||||
}
|
||||
|
||||
var pr *api.PullRequest
|
||||
pr, _, err = opts.Finder.Find(findOptions)
|
||||
for {
|
||||
err = populateStatusChecks(client, repo, pr)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
checks, counts, err = aggregateChecks(pr)
|
||||
checks, counts, err = aggregateChecks(pr, opts.Required)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
|
@ -183,3 +199,63 @@ func checksRun(opts *ChecksOptions) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateStatusChecks(client *http.Client, repo ghrepo.Interface, pr *api.PullRequest) error {
|
||||
apiClient := api.NewClientFromHTTP(client)
|
||||
|
||||
type response struct {
|
||||
Node *api.PullRequest
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
query PullRequestStatusChecks($id: ID!, $endCursor: String!) {
|
||||
node(id: $id) {
|
||||
...on PullRequest {
|
||||
%s
|
||||
}
|
||||
}
|
||||
}`, api.RequiredStatusCheckRollupGraphQL("$id", "$endCursor"))
|
||||
|
||||
variables := map[string]interface{}{
|
||||
"id": pr.ID,
|
||||
}
|
||||
|
||||
statusCheckRollup := api.CheckContexts{}
|
||||
endCursor := ""
|
||||
|
||||
for {
|
||||
variables["endCursor"] = endCursor
|
||||
var resp response
|
||||
err := apiClient.GraphQL(repo.RepoHost(), query, variables, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.Node.StatusCheckRollup.Nodes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := resp.Node.StatusCheckRollup.Nodes[0].Commit.StatusCheckRollup.Contexts
|
||||
statusCheckRollup.Nodes = append(
|
||||
statusCheckRollup.Nodes,
|
||||
result.Nodes...,
|
||||
)
|
||||
|
||||
if !result.PageInfo.HasNextPage {
|
||||
break
|
||||
}
|
||||
endCursor = result.PageInfo.EndCursor
|
||||
}
|
||||
|
||||
statusCheckRollup.PageInfo.HasNextPage = false
|
||||
|
||||
pr.StatusCheckRollup.Nodes = []api.StatusCheckRollupNode{{
|
||||
Commit: api.StatusCheckRollupCommit{
|
||||
StatusCheckRollup: api.CommitStatusCheckRollup{
|
||||
Contexts: statusCheckRollup,
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ package checks
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -15,10 +13,10 @@ import (
|
|||
"github.com/cli/cli/v2/internal/run"
|
||||
"github.com/cli/cli/v2/pkg/cmd/pr/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewCmdChecks(t *testing.T) {
|
||||
|
|
@ -64,6 +62,14 @@ func TestNewCmdChecks(t *testing.T) {
|
|||
cli: "--interval 5",
|
||||
wantsError: "cannot use `--interval` flag without `--watch` flag",
|
||||
},
|
||||
{
|
||||
name: "required flag",
|
||||
cli: "--required",
|
||||
wants: ChecksOptions{
|
||||
Required: true,
|
||||
Interval: time.Duration(10000000000),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -95,107 +101,198 @@ func TestNewCmdChecks(t *testing.T) {
|
|||
assert.Equal(t, tt.wants.SelectorArg, gotOpts.SelectorArg)
|
||||
assert.Equal(t, tt.wants.Watch, gotOpts.Watch)
|
||||
assert.Equal(t, tt.wants.Interval, gotOpts.Interval)
|
||||
assert.Equal(t, tt.wants.Required, gotOpts.Required)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_checksRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
prJSON string
|
||||
tty bool
|
||||
watch bool
|
||||
wantOut string
|
||||
wantErr string
|
||||
name string
|
||||
tty bool
|
||||
watch bool
|
||||
required bool
|
||||
httpStubs func(*httpmock.Registry)
|
||||
wantOut string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "no commits",
|
||||
prJSON: `{ "number": 123 }`,
|
||||
tty: true,
|
||||
name: "no commits",
|
||||
tty: true,
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.StringResponse(`{"data":{"node":{}}}`),
|
||||
)
|
||||
},
|
||||
wantOut: "",
|
||||
wantErr: "no commit found on the pull request",
|
||||
},
|
||||
{
|
||||
name: "no checks",
|
||||
prJSON: `{ "number": 123, "statusCheckRollup": { "nodes": [{"commit": {"oid": "abc"}}]}, "headRefName": "master" }`,
|
||||
tty: true,
|
||||
name: "no checks",
|
||||
tty: true,
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.StringResponse(`{"data":{"node":{"statusCheckRollup":{"nodes":[{"commit":{"oid": "abc"}}]}}}}`),
|
||||
)
|
||||
},
|
||||
wantOut: "",
|
||||
wantErr: "no checks reported on the 'master' branch",
|
||||
wantErr: "no checks reported on the 'trunk' branch",
|
||||
},
|
||||
{
|
||||
name: "some failing",
|
||||
fixture: "./fixtures/someFailing.json",
|
||||
tty: true,
|
||||
name: "some failing",
|
||||
tty: true,
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/someFailing.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "Some checks were not successful\n1 failing, 1 successful, 0 skipped, and 1 pending checks\n\nX sad tests 1m26s sweet link\n✓ cool tests 1m26s sweet link\n* slow tests 1m26s sweet link\n",
|
||||
wantErr: "SilentError",
|
||||
},
|
||||
{
|
||||
name: "some pending",
|
||||
fixture: "./fixtures/somePending.json",
|
||||
tty: true,
|
||||
name: "some pending",
|
||||
tty: true,
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/somePending.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "Some checks are still pending\n0 failing, 2 successful, 0 skipped, and 1 pending checks\n\n✓ cool tests 1m26s sweet link\n✓ rad tests 1m26s sweet link\n* slow tests 1m26s sweet link\n",
|
||||
wantErr: "SilentError",
|
||||
},
|
||||
{
|
||||
name: "all passing",
|
||||
fixture: "./fixtures/allPassing.json",
|
||||
tty: true,
|
||||
name: "all passing",
|
||||
tty: true,
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/allPassing.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "All checks were successful\n0 failing, 3 successful, 0 skipped, and 0 pending checks\n\n✓ awesome tests 1m26s sweet link\n✓ cool tests 1m26s sweet link\n✓ rad tests 1m26s sweet link\n",
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "watch all passing",
|
||||
fixture: "./fixtures/allPassing.json",
|
||||
tty: true,
|
||||
watch: true,
|
||||
name: "watch all passing",
|
||||
tty: true,
|
||||
watch: true,
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/allPassing.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "\x1b[?1049hAll checks were successful\n0 failing, 3 successful, 0 skipped, and 0 pending checks\n\n✓ awesome tests 1m26s sweet link\n✓ cool tests 1m26s sweet link\n✓ rad tests 1m26s sweet link\n\x1b[?1049lAll checks were successful\n0 failing, 3 successful, 0 skipped, and 0 pending checks\n\n✓ awesome tests 1m26s sweet link\n✓ cool tests 1m26s sweet link\n✓ rad tests 1m26s sweet link\n",
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "with statuses",
|
||||
fixture: "./fixtures/withStatuses.json",
|
||||
tty: true,
|
||||
name: "with statuses",
|
||||
tty: true,
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/withStatuses.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "Some checks were not successful\n1 failing, 2 successful, 0 skipped, and 0 pending checks\n\nX a status sweet link\n✓ cool tests 1m26s sweet link\n✓ rad tests 1m26s sweet link\n",
|
||||
wantErr: "SilentError",
|
||||
},
|
||||
{
|
||||
name: "no checks",
|
||||
prJSON: `{ "number": 123, "statusCheckRollup": { "nodes": [{"commit": {"oid": "abc"}}]}, "headRefName": "master" }`,
|
||||
name: "no checks",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.StringResponse(`{"data":{"node":{"statusCheckRollup":{"nodes":[{"commit":{"oid": "abc"}}]}}}}`),
|
||||
)
|
||||
},
|
||||
wantOut: "",
|
||||
wantErr: "no checks reported on the 'master' branch",
|
||||
wantErr: "no checks reported on the 'trunk' branch",
|
||||
},
|
||||
{
|
||||
name: "some failing",
|
||||
fixture: "./fixtures/someFailing.json",
|
||||
name: "some failing",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/someFailing.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "sad tests\tfail\t1m26s\tsweet link\ncool tests\tpass\t1m26s\tsweet link\nslow tests\tpending\t1m26s\tsweet link\n",
|
||||
wantErr: "SilentError",
|
||||
},
|
||||
{
|
||||
name: "some pending",
|
||||
fixture: "./fixtures/somePending.json",
|
||||
name: "some pending",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/somePending.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "cool tests\tpass\t1m26s\tsweet link\nrad tests\tpass\t1m26s\tsweet link\nslow tests\tpending\t1m26s\tsweet link\n",
|
||||
wantErr: "SilentError",
|
||||
},
|
||||
{
|
||||
name: "all passing",
|
||||
fixture: "./fixtures/allPassing.json",
|
||||
name: "all passing",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/allPassing.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "awesome tests\tpass\t1m26s\tsweet link\ncool tests\tpass\t1m26s\tsweet link\nrad tests\tpass\t1m26s\tsweet link\n",
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "with statuses",
|
||||
fixture: "./fixtures/withStatuses.json",
|
||||
name: "with statuses",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/withStatuses.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "a status\tfail\t0\tsweet link\ncool tests\tpass\t1m26s\tsweet link\nrad tests\tpass\t1m26s\tsweet link\n",
|
||||
wantErr: "SilentError",
|
||||
},
|
||||
{
|
||||
name: "some skipped",
|
||||
fixture: "./fixtures/someSkipping.json",
|
||||
name: "some skipped",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/someSkipping.json"),
|
||||
)
|
||||
},
|
||||
tty: true,
|
||||
wantOut: "All checks were successful\n0 failing, 1 successful, 2 skipped, and 0 pending checks\n\n✓ cool tests 1m26s sweet link\n- rad tests 1m26s sweet link\n- skip tests 1m26s sweet link\n",
|
||||
wantErr: "",
|
||||
},
|
||||
{
|
||||
name: "only required",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/onlyRequired.json"),
|
||||
)
|
||||
},
|
||||
tty: true,
|
||||
wantOut: "All checks were successful\n0 failing, 1 successful, 0 skipped, and 0 pending checks\n\n✓ cool tests 1m26s sweet link\n",
|
||||
wantErr: "",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "no required checks",
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query PullRequestStatusChecks\b`),
|
||||
httpmock.FileResponse("./fixtures/someSkipping.json"),
|
||||
)
|
||||
},
|
||||
wantOut: "",
|
||||
wantErr: "no required checks reported on the 'trunk' branch",
|
||||
required: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
@ -204,24 +301,22 @@ func Test_checksRun(t *testing.T) {
|
|||
ios.SetStdoutTTY(tt.tty)
|
||||
ios.SetAlternateScreenBufferEnabled(tt.tty)
|
||||
|
||||
var response *api.PullRequest
|
||||
var jsonReader io.Reader
|
||||
if tt.fixture != "" {
|
||||
ff, err := os.Open(tt.fixture)
|
||||
require.NoError(t, err)
|
||||
defer ff.Close()
|
||||
jsonReader = ff
|
||||
} else {
|
||||
jsonReader = bytes.NewBufferString(tt.prJSON)
|
||||
reg := &httpmock.Registry{}
|
||||
defer reg.Verify(t)
|
||||
if tt.httpStubs != nil {
|
||||
tt.httpStubs(reg)
|
||||
}
|
||||
dec := json.NewDecoder(jsonReader)
|
||||
require.NoError(t, dec.Decode(&response))
|
||||
|
||||
response := &api.PullRequest{Number: 123, HeadRefName: "trunk"}
|
||||
opts := &ChecksOptions{
|
||||
HttpClient: func() (*http.Client, error) {
|
||||
return &http.Client{Transport: reg}, nil
|
||||
},
|
||||
IO: ios,
|
||||
SelectorArg: "123",
|
||||
Finder: shared.NewMockFinder("123", response, ghrepo.New("OWNER", "REPO")),
|
||||
Watch: tt.watch,
|
||||
Required: tt.required,
|
||||
}
|
||||
|
||||
err := checksRun(opts)
|
||||
|
|
|
|||
|
|
@ -1,42 +1,45 @@
|
|||
{
|
||||
"number": 123,
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "awesome tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
{
|
||||
"data": {
|
||||
"node": {
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "awesome tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
48
pkg/cmd/pr/checks/fixtures/onlyRequired.json
Normal file
48
pkg/cmd/pr/checks/fixtures/onlyRequired.json
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"data": {
|
||||
"node": {
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link",
|
||||
"isRequired": true
|
||||
},
|
||||
{
|
||||
"conclusion": "SKIPPED",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link",
|
||||
"isRequired": false
|
||||
},
|
||||
{
|
||||
"conclusion": "SKIPPED",
|
||||
"status": "COMPLETED",
|
||||
"name": "skip tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link",
|
||||
"isRequired": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +1,45 @@
|
|||
{
|
||||
"number": 123,
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "FAILURE",
|
||||
"status": "COMPLETED",
|
||||
"name": "sad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "",
|
||||
"status": "IN_PROGRESS",
|
||||
"name": "slow tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
{
|
||||
"data": {
|
||||
"node": {
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "FAILURE",
|
||||
"status": "COMPLETED",
|
||||
"name": "sad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "",
|
||||
"status": "IN_PROGRESS",
|
||||
"name": "slow tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,45 @@
|
|||
{
|
||||
"number": 123,
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "",
|
||||
"status": "IN_PROGRESS",
|
||||
"name": "slow tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
{
|
||||
"data": {
|
||||
"node": {
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "",
|
||||
"status": "IN_PROGRESS",
|
||||
"name": "slow tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,45 @@
|
|||
{
|
||||
"number": 123,
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SKIPPED",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SKIPPED",
|
||||
"status": "COMPLETED",
|
||||
"name": "skip tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
{
|
||||
"data": {
|
||||
"node": {
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SKIPPED",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SKIPPED",
|
||||
"status": "COMPLETED",
|
||||
"name": "skip tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,42 @@
|
|||
{
|
||||
"number": 123,
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"state": "FAILURE",
|
||||
"name": "a status",
|
||||
"targetUrl": "sweet link"
|
||||
{
|
||||
"data": {
|
||||
"node": {
|
||||
"statusCheckRollup": {
|
||||
"nodes": [
|
||||
{
|
||||
"commit": {
|
||||
"oid": "abc",
|
||||
"statusCheckRollup": {
|
||||
"contexts": {
|
||||
"nodes": [
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "cool tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"conclusion": "SUCCESS",
|
||||
"status": "COMPLETED",
|
||||
"name": "rad tests",
|
||||
"completedAt": "2020-08-27T19:00:12Z",
|
||||
"startedAt": "2020-08-27T18:58:46Z",
|
||||
"detailsUrl": "sweet link"
|
||||
},
|
||||
{
|
||||
"state": "FAILURE",
|
||||
"name": "a status",
|
||||
"targetUrl": "sweet link"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue