@@ -388,19 +388,32 @@ func GetPullRequestCheckRuns(ctx context.Context, client *github.Client, owner,
388388 return utils .NewToolResultText (string (r )), nil
389389}
390390
391- func GetPullRequestReviewers (ctx context.Context , client * github.Client , owner , repo string , pullNumber int ) (* mcp.CallToolResult , error ) {
392- reviewers , resp , err := client .PullRequests .ListReviewers (ctx , owner , repo , pullNumber )
393- if err != nil {
394- return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to get pull request reviewers" , resp , err ), nil
395- }
391+ // closeStatusResponse closes the response body and, for any non-200 status,
392+ // returns a tool error result. It returns (nil, nil) when the response is OK so
393+ // the caller can proceed. Closing the body synchronously here (rather than via a
394+ // deferred closure over a reused resp variable) avoids leaking earlier response
395+ // bodies when several API calls are made in sequence.
396+ func closeStatusResponse (ctx context.Context , resp * github.Response , message string ) (* mcp.CallToolResult , error ) {
396397 defer func () { _ = resp .Body .Close () }()
397398
398399 if resp .StatusCode != http .StatusOK {
399400 body , err := io .ReadAll (resp .Body )
400401 if err != nil {
401402 return nil , fmt .Errorf ("failed to read response body: %w" , err )
402403 }
403- return ghErrors .NewGitHubAPIStatusErrorResponse (ctx , "failed to get pull request reviewers" , resp , body ), nil
404+ return ghErrors .NewGitHubAPIStatusErrorResponse (ctx , message , resp , body ), nil
405+ }
406+
407+ return nil , nil
408+ }
409+
410+ func GetPullRequestReviewers (ctx context.Context , client * github.Client , owner , repo string , pullNumber int ) (* mcp.CallToolResult , error ) {
411+ reviewers , resp , err := client .PullRequests .ListReviewers (ctx , owner , repo , pullNumber )
412+ if err != nil {
413+ return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to get pull request reviewers" , resp , err ), nil
414+ }
415+ if errResult , err := closeStatusResponse (ctx , resp , "failed to get pull request reviewers" ); err != nil || errResult != nil {
416+ return errResult , err
404417 }
405418
406419 result := MinimalPRReviewers {}
@@ -431,62 +444,65 @@ func GetPullRequestStatusChecks(ctx context.Context, client *github.Client, owne
431444 if err != nil {
432445 return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to get pull request" , resp , err ), nil
433446 }
434- defer func () { _ = resp .Body .Close () }()
435-
436- if resp .StatusCode != http .StatusOK {
437- body , err := io .ReadAll (resp .Body )
438- if err != nil {
439- return nil , fmt .Errorf ("failed to read response body: %w" , err )
440- }
441- return ghErrors .NewGitHubAPIStatusErrorResponse (ctx , "failed to get pull request" , resp , body ), nil
447+ if errResult , err := closeStatusResponse (ctx , resp , "failed to get pull request" ); err != nil || errResult != nil {
448+ return errResult , err
442449 }
443450
444451 sha := pr .GetHead ().GetSHA ()
445452
446- combinedStatus , resp , err := client .Repositories .GetCombinedStatus (ctx , owner , repo , sha , nil )
447- if err != nil {
448- return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to get combined status" , resp , err ), nil
449- }
450- defer func () { _ = resp .Body .Close () }()
453+ result := MinimalStatusChecks {}
451454
452- if resp .StatusCode != http .StatusOK {
453- body , err := io .ReadAll (resp .Body )
455+ // Page through the combined commit statuses so the unified view is complete
456+ // rather than limited to the first page.
457+ statusOpts := & github.ListOptions {PerPage : 100 }
458+ for {
459+ combinedStatus , resp , err := client .Repositories .GetCombinedStatus (ctx , owner , repo , sha , statusOpts )
454460 if err != nil {
455- return nil , fmt .Errorf ("failed to read response body: %w" , err )
461+ return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to get combined status" , resp , err ), nil
462+ }
463+ if errResult , err := closeStatusResponse (ctx , resp , "failed to get combined status" ); err != nil || errResult != nil {
464+ return errResult , err
456465 }
457- return ghErrors .NewGitHubAPIStatusErrorResponse (ctx , "failed to get combined status" , resp , body ), nil
458- }
459466
460- checkRuns , resp , err := client .Checks .ListCheckRunsForRef (ctx , owner , repo , sha , nil )
461- if err != nil {
462- return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to get check runs" , resp , err ), nil
463- }
464- defer func () { _ = resp .Body .Close () }()
467+ // The combined state is identical across pages; capture it once.
468+ if result .CombinedState == "" {
469+ result .CombinedState = combinedStatus .GetState ()
470+ }
465471
466- if resp .StatusCode != http .StatusOK {
467- body , err := io .ReadAll (resp .Body )
468- if err != nil {
469- return nil , fmt .Errorf ("failed to read response body: %w" , err )
472+ for _ , s := range combinedStatus .Statuses {
473+ result .Statuses = append (result .Statuses , MinimalCommitStatus {
474+ State : s .GetState (),
475+ Context : s .GetContext (),
476+ Description : s .GetDescription (),
477+ TargetURL : s .GetTargetURL (),
478+ })
470479 }
471- return ghErrors .NewGitHubAPIStatusErrorResponse (ctx , "failed to get check runs" , resp , body ), nil
472- }
473480
474- result := MinimalStatusChecks {
475- CombinedState : combinedStatus .GetState (),
481+ if resp .NextPage == 0 {
482+ break
483+ }
484+ statusOpts .Page = resp .NextPage
476485 }
477486
478- for _ , s := range combinedStatus .Statuses {
479- ms := MinimalCommitStatus {
480- State : s .GetState (),
481- Context : s .GetContext (),
482- Description : s .GetDescription (),
483- TargetURL : s .GetTargetURL (),
487+ // Page through the check runs for the same reason.
488+ checkOpts := & github.ListCheckRunsOptions {ListOptions : github.ListOptions {PerPage : 100 }}
489+ for {
490+ checkRuns , resp , err := client .Checks .ListCheckRunsForRef (ctx , owner , repo , sha , checkOpts )
491+ if err != nil {
492+ return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to get check runs" , resp , err ), nil
493+ }
494+ if errResult , err := closeStatusResponse (ctx , resp , "failed to get check runs" ); err != nil || errResult != nil {
495+ return errResult , err
484496 }
485- result .Statuses = append (result .Statuses , ms )
486- }
487497
488- for _ , cr := range checkRuns .CheckRuns {
489- result .CheckRuns = append (result .CheckRuns , convertToMinimalCheckRun (cr ))
498+ for _ , cr := range checkRuns .CheckRuns {
499+ result .CheckRuns = append (result .CheckRuns , convertToMinimalCheckRun (cr ))
500+ }
501+
502+ if resp .NextPage == 0 {
503+ break
504+ }
505+ checkOpts .Page = resp .NextPage
490506 }
491507
492508 result .TotalCount = len (result .Statuses ) + len (result .CheckRuns )
0 commit comments