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
47 changes: 37 additions & 10 deletions pkg/github/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -1002,21 +1003,47 @@ func isSafeRefContent(ctx context.Context, cache *lockdown.RepoAccessCache, repo
return safe
}

type issueCommentMinimized struct {
Reason string `json:"reason"`
}

type issueCommentResponse struct {
github.IssueComment
Minimized *issueCommentMinimized `json:"minimized,omitempty"`
}

func listIssueComments(ctx context.Context, client *github.Client, owner string, repo string, issueNumber int, pagination PaginationParams) ([]issueCommentResponse, *github.Response, error) {
query := url.Values{}
if pagination.Page > 0 {
query.Set("page", strconv.Itoa(pagination.Page))
}
if pagination.PerPage > 0 {
query.Set("per_page", strconv.Itoa(pagination.PerPage))
}

apiURL := fmt.Sprintf("repos/%s/%s/issues/%d/comments", owner, repo, issueNumber)
if encoded := query.Encode(); encoded != "" {
apiURL += "?" + encoded
}
req, err := client.NewRequest(ctx, http.MethodGet, apiURL, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", "application/vnd.github+json")

var comments []issueCommentResponse
resp, err := client.Do(req, &comments)
return comments, resp, err
}

func GetIssueComments(ctx context.Context, client *github.Client, deps ToolDependencies, owner string, repo string, issueNumber int, pagination PaginationParams) (*mcp.CallToolResult, error) {
cache, err := deps.GetRepoAccessCache(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get repo access cache: %w", err)
}
flags := deps.GetFlags(ctx)

opts := &github.IssueListCommentsOptions{
ListOptions: github.ListOptions{
Page: pagination.Page,
PerPage: pagination.PerPage,
},
}

comments, resp, err := client.Issues.ListComments(ctx, owner, repo, issueNumber, opts)
comments, resp, err := listIssueComments(ctx, client, owner, repo, issueNumber, pagination)
if err != nil {
return nil, fmt.Errorf("failed to get issue comments: %w", err)
}
Expand All @@ -1033,7 +1060,7 @@ func GetIssueComments(ctx context.Context, client *github.Client, deps ToolDepen
if cache == nil {
return nil, fmt.Errorf("lockdown cache is not configured")
}
filteredComments := make([]*github.IssueComment, 0, len(comments))
filteredComments := make([]issueCommentResponse, 0, len(comments))
for _, comment := range comments {
user := comment.User
if user == nil {
Expand All @@ -1056,7 +1083,7 @@ func GetIssueComments(ctx context.Context, client *github.Client, deps ToolDepen

minimalComments := make([]MinimalIssueComment, 0, len(comments))
for _, comment := range comments {
minimalComments = append(minimalComments, convertToMinimalIssueComment(comment))
minimalComments = append(minimalComments, convertToMinimalIssueCommentWithMinimized(&comment.IssueComment, comment.Minimized))
}

return MarshalledTextResult(minimalComments), nil
Expand Down
37 changes: 37 additions & 0 deletions pkg/github/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5483,6 +5483,43 @@ func Test_GetIssueComments(t *testing.T) {
}
}

func TestGetIssueCommentsIncludesMinimizedReason(t *testing.T) {
serverTool := IssueRead(translations.NullTranslationHelper)
client := mustNewGHClient(t, MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
GetReposIssuesCommentsByOwnerByRepoByIssueNumber: mockResponse(t, http.StatusOK, []map[string]any{
{
"id": 123,
"body": "This comment is marked as spam",
"user": map[string]any{"login": "user1"},
"minimized": map[string]any{
"reason": "spam",
},
},
}),
}))
deps := BaseDeps{
Client: client,
RepoAccessCache: stubRepoAccessCache(nil, 15*time.Minute),
Flags: stubFeatureFlags(nil),
}
handler := serverTool.Handler(deps)
request := createMCPRequest(map[string]any{
"method": "get_comments",
"owner": "owner",
"repo": "repo",
"issue_number": float64(42),
})

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

var comments []MinimalIssueComment
require.NoError(t, json.Unmarshal([]byte(getTextResult(t, result).Text), &comments))
require.Len(t, comments, 1)
assert.Equal(t, "spam", comments[0].MinimizedReason)
}

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

Expand Down
8 changes: 8 additions & 0 deletions pkg/github/minimal_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ type MinimalIssueComment struct {
User *MinimalUser `json:"user,omitempty"`
AuthorAssociation string `json:"author_association,omitempty"`
Reactions *MinimalReactions `json:"reactions,omitempty"`
MinimizedReason string `json:"minimized_reason,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
}
Expand Down Expand Up @@ -1013,13 +1014,20 @@ func convertToMinimalIssuesResponseWithoutFieldValues(fragment issueQueryFragmen
}

func convertToMinimalIssueComment(comment *github.IssueComment) MinimalIssueComment {
return convertToMinimalIssueCommentWithMinimized(comment, nil)
}

func convertToMinimalIssueCommentWithMinimized(comment *github.IssueComment, minimized *issueCommentMinimized) MinimalIssueComment {
m := MinimalIssueComment{
ID: comment.GetID(),
Body: sanitize.Content(comment.GetBody()),
HTMLURL: comment.GetHTMLURL(),
User: convertToMinimalUser(comment.GetUser()),
AuthorAssociation: comment.GetAuthorAssociation(),
}
if minimized != nil {
m.MinimizedReason = minimized.Reason
}

if comment.CreatedAt != nil {
m.CreatedAt = comment.CreatedAt.Format(time.RFC3339)
Expand Down