Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
ec67616 to
94af699
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR adds a new tool called find_closing_pull_requests that leverages GitHub's GraphQL API to find pull requests that closed specific issues using the closedByPullRequestsReferences field. This functionality helps identify code changes that resolved similar issues.
Key changes:
- Added
FindClosingPullRequeststool with advanced GraphQL parameters including pagination, filtering, and ordering options - Implemented helper functions
OptionalIntArrayParamandRequiredIntArrayParamfor handling integer array parameters - Added comprehensive test coverage for the new functionality
Reviewed Changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/github/tools.go | Added the new tool to the default toolset group |
| pkg/github/server.go | Added helper functions for handling integer array parameters |
| pkg/github/issues.go | Implemented the core FindClosingPullRequests tool with GraphQL queries |
| pkg/github/server_test.go | Added unit tests for the new integer array parameter functions |
| pkg/github/find_closing_prs_integration_test.go | Added integration tests for the new tool |
| e2e/e2e_test.go | Added comprehensive end-to-end tests covering various scenarios |
| README.md | Updated documentation with the new tool's parameters |
Comments suppressed due to low confidence (2)
e2e/e2e_test.go:1737
- The JSON field name
closingPullRequestsdoesn't match the actual field nameclosing_pull_requestsused in the response structure. This should beclosing_pull_requeststo match the API response format.
} `json:"closingPullRequests"`
e2e/e2e_test.go:1738
- The JSON field name
totalCountdoesn't match the actual field nametotal_countused in the response structure. This should betotal_countto match the API response format.
TotalCount int `json:"totalCount"`
| variables := map[string]any{ | ||
| "owner": githubv4.String(owner), | ||
| "repo": githubv4.String(repo), | ||
| "number": githubv4.Int(issueNumber), // #nosec G115 - issueNumber validated to be positive |
There was a problem hiding this comment.
The comment references validation that doesn't exist. The function only checks if issueNumber < 0 but doesn't validate it to be positive (greater than 0). Consider adding proper validation or updating the comment to be accurate.
| } | ||
|
|
||
| // Validate issue number (basic bounds check) | ||
| if issueNumber < 0 { |
There was a problem hiding this comment.
Issue number validation should check for both negative values and zero, as GitHub issue numbers start from 1. Consider changing the condition to issueNumber <= 0 for more accurate validation.
| if issueNumber < 0 { | |
| if issueNumber <= 0 { |
| variables["last"] = githubv4.Int(params.Last) // #nosec G115 - params.Last validated to be positive | ||
| variables["first"] = (*githubv4.Int)(nil) | ||
| } else { | ||
| variables["first"] = githubv4.Int(params.First) // #nosec G115 - params.First validated to be positive |
There was a problem hiding this comment.
The comments claim validation that doesn't match the actual validation logic. The validation only checks if values are non-negative, not positive. Update the comments to reflect the actual validation or improve the validation to match the comments.
| variables["first"] = githubv4.Int(params.First) // #nosec G115 - params.First validated to be positive | |
| "number": githubv4.Int(issueNumber), // #nosec G115 - issueNumber validated to be non-negative | |
| } | |
| if params.Last != 0 { | |
| variables["last"] = githubv4.Int(params.Last) // #nosec G115 - params.Last validated to be non-negative | |
| variables["first"] = (*githubv4.Int)(nil) | |
| } else { | |
| variables["first"] = githubv4.Int(params.First) // #nosec G115 - params.First validated to be non-negative |
| variables["last"] = githubv4.Int(params.Last) // #nosec G115 - params.Last validated to be positive | ||
| variables["first"] = (*githubv4.Int)(nil) | ||
| } else { | ||
| variables["first"] = githubv4.Int(params.First) // #nosec G115 - params.First validated to be positive |
There was a problem hiding this comment.
The comments claim validation that doesn't match the actual validation logic. The validation only checks if values are non-negative, not positive. Update the comments to reflect the actual validation or improve the validation to match the comments.
| variables["first"] = githubv4.Int(params.First) // #nosec G115 - params.First validated to be positive | |
| "number": githubv4.Int(issueNumber), // #nosec G115 - issueNumber validated to be non-negative | |
| } | |
| if params.Last != 0 { | |
| variables["last"] = githubv4.Int(params.Last) // #nosec G115 - params.Last validated to be non-negative | |
| variables["first"] = (*githubv4.Int)(nil) | |
| } else { | |
| variables["first"] = githubv4.Int(params.First) // #nosec G115 - params.First validated to be non-negative |
There was a problem hiding this comment.
Thank you @lumaxis for adding this new tool!
I'd like to suggest some small changes:
- Issue number should be positive (as mentioned in your comments). So you should use issueNumber <=0 as the invalid range. This should resolve the 4 copilot review comments about issueNumber validation
- We have existing GQL pagination parameter parsing helpers. You can find an example usage in ListDiscussions in ./pkg/github/discussions.go. This should resolve the 4 copilot review comments about nosec G115.
A few other items to better fit into existing patterns:
- testing, mocking, toolsnaps: details in comment
- Error tool results: For errors from the GitHub REST/GraphQL clients we use
NewGitHubAPIErrorResponse/NewGitHubGraphQLErrorResponse. More info can be found in ./docs/error-handling.md
And finally, a more subjective comment: I think the tool should be named get_issue_pull_requests and take a single issue number instead of an array of them. This mirrors get_issue_comments, makes it simpler/easier for models to use.
| ) | ||
|
|
||
| // TestFindClosingPullRequestsIntegration tests the FindClosingPullRequests tool with real GitHub API calls | ||
| func TestFindClosingPullRequestsIntegration(t *testing.T) { |
There was a problem hiding this comment.
Integration tests are better placed in the ./e2e/ directory.
Alternatively/additionally, you should add a unit test to ./pkg/github/issues_test.go, naming it Test_FindClosingPullRequests and mock the github clients to prevent breaking tests should any live data change. Test_FindClosingPullRequestsshould also include a toolsnaps.Test (e.g Test_CreateIssue) and you can generate/update toolsnaps when running tests by using:
UPDATE_TOOLSNAPS=true go test ./...
More info: https://github.com/github/github-mcp-server/blob/main/docs/testing.md
| mcp.WithString("after", | ||
| mcp.Description("Cursor for forward pagination (use with first/limit)"), | ||
| ), | ||
| mcp.WithString("before", | ||
| mcp.Description("Cursor for backward pagination (use with last)"), | ||
| ), | ||
| mcp.WithNumber("last", | ||
| mcp.Description(fmt.Sprintf( | ||
| "Number of results from end for backward pagination (max: %d)", | ||
| MaxGraphQLPageSize, | ||
| )), | ||
| ), |
There was a problem hiding this comment.
We have existing GQL pagination parameter parsing helpers: WithCursorPagination, OptionalCursorPaginationParams in ./pkg/github/server.go. You can find an example usage in ListDiscussions in ./pkg/github/discussions.go. Instead of limit/after/before/last, we keep it simple by just using perPage/after.
This will also resolve many of the Copilot review comments about pagination param validation logic.
This PR adds a new tool that uses
closedByPullRequestsReferencesonIssueto specifically find PRs in a repo that closed the specified issues. We'd like to use this to find code changes that solved similar issues to a given new issue.