diff --git a/pkg/cmd/run/shared/shared.go b/pkg/cmd/run/shared/shared.go index a755ce93c..9fcdb5df3 100644 --- a/pkg/cmd/run/shared/shared.go +++ b/pkg/cmd/run/shared/shared.go @@ -424,7 +424,8 @@ 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) { @@ -432,10 +433,23 @@ func GetJobs(client *api.Client, repo ghrepo.Interface, run *Run) ([]Job, error) return run.Jobs, nil } var result JobsPayload - if err := client.REST(repo.RepoHost(), "GET", run.JobsURL, nil, &result); err != nil { - return nil, err + perPage := 100 + v := url.Values{} + v.Set("per_page", fmt.Sprintf("%d", perPage)) + + // Fetch all the pages until total fetched jobs == result.TotalCount + maxPages := 10 + for p := 1; p < maxPages; p++ { + v.Set("page", fmt.Sprintf("%d", p)) + jobsPath := fmt.Sprintf("%s?%s", run.JobsURL, v.Encode()) + if err := client.REST(repo.RepoHost(), "GET", jobsPath, nil, &result); err != nil { + return run.Jobs, err + } + run.Jobs = append(run.Jobs, result.Jobs...) + if len(run.Jobs) >= result.TotalCount { + break + } } - run.Jobs = result.Jobs return result.Jobs, nil } 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..e2a2a2456 100644 --- a/pkg/cmd/run/view/view_test.go +++ b/pkg/cmd/run/view/view_test.go @@ -1242,6 +1242,51 @@ 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) { + jobs := []shared.Job{} + for i := 0; i < 115; i++ { + jobs = append(jobs, shared.Job{ + ID: int64(i), + Name: fmt.Sprintf("job %d", i), + }) + } + + limit := 100 + firstPage := jobs[:limit] + secondPage := jobs[limit:] + + 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.REST("GET", "runs/3/jobs"), + httpmock.JSONResponse(shared.JobsPayload{TotalCount: len(jobs), Jobs: firstPage})) + // /runs/:runID/jobs endpoint should be called once more to fetch the remaining jobs + reg.Register( + httpmock.REST("GET", "runs/3/jobs"), + httpmock.JSONResponse(shared.JobsPayload{TotalCount: len(jobs), Jobs: secondPage})) + }, + wantOut: "fetched 115 jobs\n", + }, } for _, tt := range tests {