Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/github/__toolsnaps__/pull_request_read.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"type": "string"
},
"method": {
"description": "Action to specify what pull request data needs to be retrieved from GitHub. \nPossible options: \n 1. get - Get details of a specific pull request.\n 2. get_diff - Get the diff of a pull request.\n 3. get_status - Get combined commit status of a head commit in a pull request.\n 4. get_files - Get the list of files changed in a pull request. Use with pagination parameters to control the number of results returned.\n 5. get_review_comments - Get review threads on a pull request. Each thread contains logically grouped review comments made on the same code location during pull request reviews. Returns threads with metadata (isResolved, isOutdated, isCollapsed) and their associated comments. Use cursor-based pagination (perPage, after) to control results.\n 6. get_reviews - Get the reviews on a pull request. When asked for review comments, use get_review_comments method. Use with pagination parameters to control the number of results returned.\n 7. get_comments - Get comments on a pull request. Use this if user doesn't specifically want review comments. Use with pagination parameters to control the number of results returned.\n 8. get_check_runs - Get check runs for the head commit of a pull request. Check runs are the individual CI/CD jobs and checks that run on the PR.\n",
"description": "Action to specify what pull request data needs to be retrieved from GitHub. \nPossible options: \n 1. get - Get details of a specific pull request.\n 2. get_diff - Get the diff of a pull request.\n 3. get_status - Get combined commit status of a head commit in a pull request.\n 4. get_files - Get the list of files changed in a pull request. Use with pagination parameters to control the number of results returned.\n 5. get_review_comments - Get review threads on a pull request. Each thread contains logically grouped review comments made on the same code location during pull request reviews. Returns threads with metadata (isResolved, isOutdated, isCollapsed) and their associated comments. Review comments include structured code suggestions when available, including Copilot-generated \"Suggest\" changesets (via thread partial) and human-authored suggestion code blocks in the comment body. Use cursor-based pagination (perPage, after) to control results.\n 6. get_reviews - Get the reviews on a pull request. When asked for review comments, use get_review_comments method. Use with pagination parameters to control the number of results returned.\n 7. get_comments - Get comments on a pull request. Use this if user doesn't specifically want review comments. Use with pagination parameters to control the number of results returned.\n 8. get_check_runs - Get check runs for the head commit of a pull request. Check runs are the individual CI/CD jobs and checks that run on the PR.\n",
"enum": [
"get",
"get_diff",
Expand Down
15 changes: 8 additions & 7 deletions pkg/github/minimal_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1567,13 +1567,14 @@ type MinimalPageInfo struct {

// MinimalReviewComment is the trimmed output type for PR review comment objects.
type MinimalReviewComment struct {
Body string `json:"body,omitempty"`
Path string `json:"path"`
Line *int `json:"line,omitempty"`
Author string `json:"author,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
HTMLURL string `json:"html_url"`
Body string `json:"body,omitempty"`
Path string `json:"path"`
Line *int `json:"line,omitempty"`
Author string `json:"author,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
HTMLURL string `json:"html_url"`
Suggestions []MinimalReviewSuggestion `json:"suggestions,omitempty"`
}

// MinimalReviewThread is the trimmed output type for PR review thread objects.
Expand Down
10 changes: 8 additions & 2 deletions pkg/github/pullrequests.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Possible options:
2. get_diff - Get the diff of a pull request.
3. get_status - Get combined commit status of a head commit in a pull request.
4. get_files - Get the list of files changed in a pull request. Use with pagination parameters to control the number of results returned.
5. get_review_comments - Get review threads on a pull request. Each thread contains logically grouped review comments made on the same code location during pull request reviews. Returns threads with metadata (isResolved, isOutdated, isCollapsed) and their associated comments. Use cursor-based pagination (perPage, after) to control results.
5. get_review_comments - Get review threads on a pull request. Each thread contains logically grouped review comments made on the same code location during pull request reviews. Returns threads with metadata (isResolved, isOutdated, isCollapsed) and their associated comments. Review comments include structured code suggestions when available, including Copilot-generated "Suggest" changesets (via thread partial) and human-authored suggestion code blocks in the comment body. Use cursor-based pagination (perPage, after) to control results.
6. get_reviews - Get the reviews on a pull request. When asked for review comments, use get_review_comments method. Use with pagination parameters to control the number of results returned.
7. get_comments - Get comments on a pull request. Use this if user doesn't specifically want review comments. Use with pagination parameters to control the number of results returned.
8. get_check_runs - Get check runs for the head commit of a pull request. Check runs are the individual CI/CD jobs and checks that run on the PR.
Expand Down Expand Up @@ -482,7 +482,13 @@ func GetPullRequestReviewComments(ctx context.Context, gqlClient *githubv4.Clien
}
}

return MarshalledTextResult(convertToMinimalReviewThreadsResponse(query)), nil
response := convertToMinimalReviewThreadsResponse(query)

if client, err := deps.GetClient(ctx); err == nil {
enrichReviewThreadsWithSuggestions(ctx, client, owner, repo, pullNumber, response.ReviewThreads)
}

return MarshalledTextResult(response), nil
}

func GetPullRequestReviews(ctx context.Context, client *github.Client, deps ToolDependencies, owner, repo string, pullNumber int, pagination PaginationParams) (*mcp.CallToolResult, error) {
Expand Down
98 changes: 98 additions & 0 deletions pkg/github/pullrequests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"

Expand Down Expand Up @@ -2056,6 +2057,103 @@ func Test_GetPullRequestComments(t *testing.T) {
}
}

func Test_GetPullRequestCommentsWithSuggestions(t *testing.T) {
t.Parallel()

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/owner/repo/pull/42/threads/1964378741", r.URL.Path)
_, _ = w.Write([]byte(automatedSuggestionHTMLFixture))
}))
defer server.Close()

restClient, err := github.NewClient(github.WithHTTPClient(server.Client()), github.WithEnterpriseURLs(server.URL+"/", server.URL+"/"))
require.NoError(t, err)

gqlHTTPClient := githubv4mock.NewMockedHTTPClient(
githubv4mock.NewQueryMatcher(
reviewThreadsQuery{},
map[string]any{
"owner": githubv4.String("owner"),
"repo": githubv4.String("repo"),
"prNum": githubv4.Int(42),
"first": githubv4.Int(30),
"commentsPerThread": githubv4.Int(100),
"after": (*githubv4.String)(nil),
},
githubv4mock.DataResponse(map[string]any{
"repository": map[string]any{
"pullRequest": map[string]any{
"reviewThreads": map[string]any{
"nodes": []map[string]any{
{
"id": "PRRT_kwDORGz4i851Fgp1",
"isResolved": false,
"isOutdated": false,
"isCollapsed": false,
"comments": map[string]any{
"totalCount": 1,
"nodes": []map[string]any{
{
"id": "PRRC_kwDORGz4i86v72Xc",
"body": "Consider adding validation.",
"path": "glmocr/cli.py",
"line": 10,
"author": map[string]any{
"login": "copilot-pull-request-reviewer",
},
"createdAt": "2024-01-01T12:00:00Z",
"updatedAt": "2024-01-01T12:00:00Z",
"url": "https://github.com/owner/repo/pull/42#discussion_r101",
},
},
},
},
},
"pageInfo": map[string]any{
"hasNextPage": false,
"hasPreviousPage": false,
"startCursor": "cursor1",
"endCursor": "cursor2",
},
"totalCount": 1,
},
},
},
}),
),
)

serverTool := PullRequestRead(translations.NullTranslationHelper)
deps := BaseDeps{
Client: restClient,
GQLClient: githubv4.NewClient(gqlHTTPClient),
}
handler := serverTool.Handler(deps)

request := createMCPRequest(map[string]any{
"method": "get_review_comments",
"owner": "owner",
"repo": "repo",
"pullNumber": float64(42),
})

result, err := handler(ContextWithDeps(context.Background(), deps), &request)
require.NoError(t, err)
require.False(t, result.IsError)

textContent := getTextResult(t, result)
var response MinimalReviewThreadsResponse
require.NoError(t, json.Unmarshal([]byte(textContent.Text), &response))
require.Len(t, response.ReviewThreads, 1)
require.Len(t, response.ReviewThreads[0].Comments, 1)

suggestions := response.ReviewThreads[0].Comments[0].Suggestions
require.Len(t, suggestions, 1)
assert.Equal(t, suggestionSourceAutomated, suggestions[0].Source)
assert.Equal(t, "glmocr/cli.py", suggestions[0].Path)
assert.Contains(t, suggestions[0].Suggestion, "import re")
}

func Test_GetPullRequestReviews(t *testing.T) {
// Verify tool definition once
serverTool := PullRequestRead(translations.NullTranslationHelper)
Expand Down
Loading