diff --git a/pkg/cmd/run/shared/shared.go b/pkg/cmd/run/shared/shared.go index a755ce93c..cd9d481b8 100644 --- a/pkg/cmd/run/shared/shared.go +++ b/pkg/cmd/run/shared/shared.go @@ -4,6 +4,7 @@ import ( "archive/zip" "errors" "fmt" + "net/http" "net/url" "reflect" "strings" @@ -424,19 +425,31 @@ func preloadWorkflowNames(client *api.Client, repo ghrepo.Interface, runs []Run) } type JobsPayload struct { - Jobs []Job + TotalCount int `json:"total_count"` + Jobs []Job } func GetJobs(client *api.Client, repo ghrepo.Interface, run *Run) ([]Job, error) { if run.Jobs != nil { return run.Jobs, nil } - var result JobsPayload - if err := client.REST(repo.RepoHost(), "GET", run.JobsURL, nil, &result); err != nil { - return nil, err + + query := url.Values{} + query.Set("per_page", "100") + jobsPath := fmt.Sprintf("%s?%s", run.JobsURL, query.Encode()) + + for jobsPath != "" { + var resp JobsPayload + var err error + jobsPath, err = client.RESTWithNext(repo.RepoHost(), http.MethodGet, jobsPath, nil, &resp) + if err != nil { + run.Jobs = nil + return nil, err + } + + run.Jobs = append(run.Jobs, resp.Jobs...) } - run.Jobs = result.Jobs - return result.Jobs, nil + return run.Jobs, nil } func GetJob(client *api.Client, repo ghrepo.Interface, jobID string) (*Job, error) { diff --git a/pkg/cmd/run/shared/test.go b/pkg/cmd/run/shared/test.go index 0e37572e3..e44debaa4 100644 --- a/pkg/cmd/run/shared/test.go +++ b/pkg/cmd/run/shared/test.go @@ -5,6 +5,7 @@ import ( "time" workflowShared "github.com/cli/cli/v2/pkg/cmd/workflow/shared" + "github.com/cli/cli/v2/pkg/iostreams" ) var TestRunStartTime, _ = time.Parse("2006-01-02 15:04:05", "2021-02-23 04:51:00") @@ -122,3 +123,20 @@ var TestWorkflow workflowShared.Workflow = workflowShared.Workflow{ Name: "CI", ID: 123, } + +type TestExporter struct { + fields []string + writeHandler func(io *iostreams.IOStreams, data interface{}) error +} + +func MakeTestExporter(fields []string, wh func(io *iostreams.IOStreams, data interface{}) error) *TestExporter { + return &TestExporter{fields: fields, writeHandler: wh} +} + +func (t *TestExporter) Fields() []string { + return t.fields +} + +func (t *TestExporter) Write(io *iostreams.IOStreams, data interface{}) error { + return t.writeHandler(io, data) +} diff --git a/pkg/cmd/run/view/view_test.go b/pkg/cmd/run/view/view_test.go index 3d4fc4cf0..36d563eee 100644 --- a/pkg/cmd/run/view/view_test.go +++ b/pkg/cmd/run/view/view_test.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "net/url" "testing" "time" @@ -1242,6 +1243,42 @@ func TestViewRun(t *testing.T) { }, wantOut: "\nX trunk CI ยท 123\nTriggered via push about 59 minutes ago\n\nX This run likely failed because of a workflow file issue.\n\nFor more information, see: https://github.com/runs/123\n", }, + { + name: "Fetches all of a run's jobs with --json flag", + opts: &ViewOptions{ + RunID: "3", + Exporter: shared.MakeTestExporter( + []string{"jobs"}, + func(io *iostreams.IOStreams, data interface{}) error { + run, ok := data.(*shared.Run) + if !ok { + return fmt.Errorf("expected data type *shared.Run") + } + fmt.Fprintf(io.Out, "fetched %d jobs\n", len(run.Jobs)) + return nil + }, + ), + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/3"), + httpmock.JSONResponse(shared.SuccessfulRun)) + reg.Register( + httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"), + httpmock.JSONResponse(shared.TestWorkflow)) + reg.Register( + httpmock.QueryMatcher("GET", "runs/3/jobs", url.Values{"per_page": []string{"100"}}), + httpmock.WithHeader( + httpmock.StringResponse(`{"jobs":[{},{},{}]}`), + "Link", + `; rel="next", ; rel="last"`), + ) + reg.Register( + httpmock.REST("GET", "runs/3/jobs"), + httpmock.StringResponse(`{"jobs":[{},{}]}`)) + }, + wantOut: "fetched 5 jobs\n", + }, } for _, tt := range tests {