feat(pull-requests): expose review resolution reason
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8bf69b12-5131-4382-8c81-8ed1c88fb211
This commit is contained in:
@@ -1236,6 +1236,7 @@ The following sets of tools are available:
|
||||
- `owner`: Repository owner (string, required)
|
||||
- `pullNumber`: Pull request number (number, required)
|
||||
- `repo`: Repository name (string, required)
|
||||
- `resolutionReason`: Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid. (string, optional)
|
||||
- `threadId`: The node ID of the review thread (e.g., PRRT_kwDOxxx). Required for resolve_thread and unresolve_thread methods. Get thread IDs from pull_request_read with method get_review_comments. (string, optional)
|
||||
|
||||
- **search_pull_requests** - Search pull requests
|
||||
|
||||
@@ -251,6 +251,7 @@ runtime behavior (such as output formatting) won't appear here.
|
||||
|
||||
- **resolve_review_thread** - Resolve Review Thread
|
||||
- **Required OAuth Scopes**: `repo`
|
||||
- `resolutionReason`: Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid. (string, optional)
|
||||
- `threadID`: The node ID of the review thread to resolve (e.g., PRRT_kwDOxxx) (string, required)
|
||||
|
||||
- **submit_pending_pull_request_review** - Submit Pending Pull Request Review
|
||||
|
||||
@@ -47,6 +47,10 @@
|
||||
"description": "Repository name",
|
||||
"type": "string"
|
||||
},
|
||||
"resolutionReason": {
|
||||
"description": "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
|
||||
"type": "string"
|
||||
},
|
||||
"threadId": {
|
||||
"description": "The node ID of the review thread (e.g., PRRT_kwDOxxx). Required for resolve_thread and unresolve_thread methods. Get thread IDs from pull_request_read with method get_review_comments.",
|
||||
"type": "string"
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
"description": "Resolve a review thread on a pull request. Resolving an already-resolved thread is a no-op.",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"resolutionReason": {
|
||||
"description": "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
|
||||
"type": "string"
|
||||
},
|
||||
"threadID": {
|
||||
"description": "The node ID of the review thread to resolve (e.g., PRRT_kwDOxxx)",
|
||||
"type": "string"
|
||||
|
||||
@@ -1738,8 +1738,9 @@ func TestGranularResolveReviewThread(t *testing.T) {
|
||||
}
|
||||
} `graphql:"resolveReviewThread(input: $input)"`
|
||||
}{},
|
||||
githubv4.ResolveReviewThreadInput{
|
||||
ThreadID: githubv4.ID("PRRT_123"),
|
||||
resolveReviewThreadInput{
|
||||
ThreadID: githubv4.ID("PRRT_123"),
|
||||
ResolutionReason: newGQLStringlike[githubv4.String]("addressed"),
|
||||
},
|
||||
nil,
|
||||
githubv4mock.DataResponse(map[string]any{
|
||||
@@ -1755,7 +1756,8 @@ func TestGranularResolveReviewThread(t *testing.T) {
|
||||
handler := serverTool.Handler(deps)
|
||||
|
||||
request := createMCPRequest(map[string]any{
|
||||
"threadID": "PRRT_123",
|
||||
"threadID": "PRRT_123",
|
||||
"resolutionReason": "addressed",
|
||||
})
|
||||
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
|
||||
require.NoError(t, err)
|
||||
|
||||
+24
-13
@@ -1760,14 +1760,15 @@ func UpdatePullRequestBranch(t translations.TranslationHelperFunc) inventory.Ser
|
||||
}
|
||||
|
||||
type PullRequestReviewWriteParams struct {
|
||||
Method string
|
||||
Owner string
|
||||
Repo string
|
||||
PullNumber int32
|
||||
Body string
|
||||
Event string
|
||||
CommitID *string
|
||||
ThreadID string
|
||||
Method string
|
||||
Owner string
|
||||
Repo string
|
||||
PullNumber int32
|
||||
Body string
|
||||
Event string
|
||||
CommitID *string
|
||||
ThreadID string
|
||||
ResolutionReason *string
|
||||
}
|
||||
|
||||
func PullRequestReviewWrite(t translations.TranslationHelperFunc) inventory.ServerTool {
|
||||
@@ -1811,6 +1812,10 @@ func PullRequestReviewWrite(t translations.TranslationHelperFunc) inventory.Serv
|
||||
Type: "string",
|
||||
Description: "The node ID of the review thread (e.g., PRRT_kwDOxxx). Required for resolve_thread and unresolve_thread methods. Get thread IDs from pull_request_read with method get_review_comments.",
|
||||
},
|
||||
"resolutionReason": {
|
||||
Type: "string",
|
||||
Description: "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
|
||||
},
|
||||
},
|
||||
Required: []string{"method", "owner", "repo", "pullNumber"},
|
||||
}
|
||||
@@ -1858,10 +1863,10 @@ Available methods:
|
||||
result, err := DeletePendingPullRequestReview(ctx, client, params)
|
||||
return result, nil, err
|
||||
case "resolve_thread":
|
||||
result, err := ResolveReviewThread(ctx, client, params.ThreadID, true)
|
||||
result, err := ResolveReviewThread(ctx, client, params.ThreadID, params.ResolutionReason, true)
|
||||
return result, nil, err
|
||||
case "unresolve_thread":
|
||||
result, err := ResolveReviewThread(ctx, client, params.ThreadID, false)
|
||||
result, err := ResolveReviewThread(ctx, client, params.ThreadID, nil, false)
|
||||
return result, nil, err
|
||||
default:
|
||||
return utils.NewToolResultError(fmt.Sprintf("unknown method: %s", params.Method)), nil, nil
|
||||
@@ -2094,8 +2099,13 @@ func DeletePendingPullRequestReview(ctx context.Context, client *githubv4.Client
|
||||
return utils.NewToolResultText("pending pull request review successfully deleted"), nil
|
||||
}
|
||||
|
||||
type resolveReviewThreadInput struct {
|
||||
ThreadID githubv4.ID `json:"threadId"`
|
||||
ResolutionReason *githubv4.String `json:"resolutionReason,omitempty"`
|
||||
}
|
||||
|
||||
// ResolveReviewThread resolves or unresolves a PR review thread using GraphQL mutations.
|
||||
func ResolveReviewThread(ctx context.Context, client *githubv4.Client, threadID string, resolve bool) (*mcp.CallToolResult, error) {
|
||||
func ResolveReviewThread(ctx context.Context, client *githubv4.Client, threadID string, resolutionReason *string, resolve bool) (*mcp.CallToolResult, error) {
|
||||
if threadID == "" {
|
||||
return utils.NewToolResultError("threadId is required for resolve_thread and unresolve_thread methods"), nil
|
||||
}
|
||||
@@ -2110,8 +2120,9 @@ func ResolveReviewThread(ctx context.Context, client *githubv4.Client, threadID
|
||||
} `graphql:"resolveReviewThread(input: $input)"`
|
||||
}
|
||||
|
||||
input := githubv4.ResolveReviewThreadInput{
|
||||
ThreadID: githubv4.ID(threadID),
|
||||
input := resolveReviewThreadInput{
|
||||
ThreadID: githubv4.ID(threadID),
|
||||
ResolutionReason: newGQLStringlikePtr[githubv4.String](resolutionReason),
|
||||
}
|
||||
|
||||
if err := client.Mutate(ctx, &mutation, input, nil); err != nil {
|
||||
|
||||
@@ -690,6 +690,10 @@ func GranularResolveReviewThread(t translations.TranslationHelperFunc) inventory
|
||||
Type: "string",
|
||||
Description: "The node ID of the review thread to resolve (e.g., PRRT_kwDOxxx)",
|
||||
},
|
||||
"resolutionReason": {
|
||||
Type: "string",
|
||||
Description: "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
|
||||
},
|
||||
},
|
||||
Required: []string{"threadID"},
|
||||
},
|
||||
@@ -700,13 +704,21 @@ func GranularResolveReviewThread(t translations.TranslationHelperFunc) inventory
|
||||
if err != nil {
|
||||
return utils.NewToolResultError(err.Error()), nil, nil
|
||||
}
|
||||
resolutionReason, hasResolutionReason, err := OptionalParamOK[string](args, "resolutionReason")
|
||||
if err != nil {
|
||||
return utils.NewToolResultError(err.Error()), nil, nil
|
||||
}
|
||||
var resolutionReasonPtr *string
|
||||
if hasResolutionReason {
|
||||
resolutionReasonPtr = &resolutionReason
|
||||
}
|
||||
|
||||
gqlClient, err := deps.GetGQLClient(ctx)
|
||||
if err != nil {
|
||||
return utils.NewToolResultErrorFromErr("failed to get GitHub GraphQL client", err), nil, nil
|
||||
}
|
||||
|
||||
result, err := ResolveReviewThread(ctx, gqlClient, threadID, true)
|
||||
result, err := ResolveReviewThread(ctx, gqlClient, threadID, resolutionReasonPtr, true)
|
||||
return result, nil, err
|
||||
},
|
||||
)
|
||||
@@ -750,7 +762,7 @@ func GranularUnresolveReviewThread(t translations.TranslationHelperFunc) invento
|
||||
return utils.NewToolResultErrorFromErr("failed to get GitHub GraphQL client", err), nil, nil
|
||||
}
|
||||
|
||||
result, err := ResolveReviewThread(ctx, gqlClient, threadID, false)
|
||||
result, err := ResolveReviewThread(ctx, gqlClient, threadID, nil, false)
|
||||
return result, nil, err
|
||||
},
|
||||
)
|
||||
|
||||
@@ -4572,7 +4572,7 @@ func TestResolveReviewThread(t *testing.T) {
|
||||
}
|
||||
} `graphql:"resolveReviewThread(input: $input)"`
|
||||
}{},
|
||||
githubv4.ResolveReviewThreadInput{
|
||||
resolveReviewThreadInput{
|
||||
ThreadID: githubv4.ID("PRRT_kwDOTest123"),
|
||||
},
|
||||
nil,
|
||||
@@ -4588,6 +4588,43 @@ func TestResolveReviewThread(t *testing.T) {
|
||||
),
|
||||
expectedResult: "review thread resolved successfully",
|
||||
},
|
||||
{
|
||||
name: "successful resolve thread with resolution reason",
|
||||
requestArgs: map[string]any{
|
||||
"method": "resolve_thread",
|
||||
"owner": "owner",
|
||||
"repo": "repo",
|
||||
"pullNumber": float64(42),
|
||||
"threadId": "PRRT_kwDOTest123",
|
||||
"resolutionReason": "wont-fix",
|
||||
},
|
||||
mockedClient: githubv4mock.NewMockedHTTPClient(
|
||||
githubv4mock.NewMutationMatcher(
|
||||
struct {
|
||||
ResolveReviewThread struct {
|
||||
Thread struct {
|
||||
ID githubv4.ID
|
||||
IsResolved githubv4.Boolean
|
||||
}
|
||||
} `graphql:"resolveReviewThread(input: $input)"`
|
||||
}{},
|
||||
resolveReviewThreadInput{
|
||||
ThreadID: githubv4.ID("PRRT_kwDOTest123"),
|
||||
ResolutionReason: newGQLStringlike[githubv4.String]("wont-fix"),
|
||||
},
|
||||
nil,
|
||||
githubv4mock.DataResponse(map[string]any{
|
||||
"resolveReviewThread": map[string]any{
|
||||
"thread": map[string]any{
|
||||
"id": "PRRT_kwDOTest123",
|
||||
"isResolved": true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
),
|
||||
expectedResult: "review thread resolved successfully",
|
||||
},
|
||||
{
|
||||
name: "successful unresolve thread",
|
||||
requestArgs: map[string]any{
|
||||
@@ -4692,7 +4729,7 @@ func TestResolveReviewThread(t *testing.T) {
|
||||
}
|
||||
} `graphql:"resolveReviewThread(input: $input)"`
|
||||
}{},
|
||||
githubv4.ResolveReviewThreadInput{
|
||||
resolveReviewThreadInput{
|
||||
ThreadID: githubv4.ID("PRRT_invalid"),
|
||||
},
|
||||
nil,
|
||||
|
||||
Reference in New Issue
Block a user