Skip to content

Commit bfb759d

Browse files
committed
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
1 parent 55f7b72 commit bfb759d

8 files changed

Lines changed: 92 additions & 20 deletions

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,7 @@ The following sets of tools are available:
12361236
- `owner`: Repository owner (string, required)
12371237
- `pullNumber`: Pull request number (number, required)
12381238
- `repo`: Repository name (string, required)
1239+
- `resolutionReason`: Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid. (string, optional)
12391240
- `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)
12401241

12411242
- **search_pull_requests** - Search pull requests

docs/feature-flags.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ runtime behavior (such as output formatting) won't appear here.
251251

252252
- **resolve_review_thread** - Resolve Review Thread
253253
- **Required OAuth Scopes**: `repo`
254+
- `resolutionReason`: Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid. (string, optional)
254255
- `threadID`: The node ID of the review thread to resolve (e.g., PRRT_kwDOxxx) (string, required)
255256

256257
- **submit_pending_pull_request_review** - Submit Pending Pull Request Review

pkg/github/__toolsnaps__/pull_request_review_write.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
"description": "Repository name",
4848
"type": "string"
4949
},
50+
"resolutionReason": {
51+
"description": "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
52+
"type": "string"
53+
},
5054
"threadId": {
5155
"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.",
5256
"type": "string"

pkg/github/__toolsnaps__/resolve_review_thread.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
"description": "Resolve a review thread on a pull request. Resolving an already-resolved thread is a no-op.",
1010
"inputSchema": {
1111
"properties": {
12+
"resolutionReason": {
13+
"description": "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
14+
"type": "string"
15+
},
1216
"threadID": {
1317
"description": "The node ID of the review thread to resolve (e.g., PRRT_kwDOxxx)",
1418
"type": "string"

pkg/github/granular_tools_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,8 +1738,9 @@ func TestGranularResolveReviewThread(t *testing.T) {
17381738
}
17391739
} `graphql:"resolveReviewThread(input: $input)"`
17401740
}{},
1741-
githubv4.ResolveReviewThreadInput{
1742-
ThreadID: githubv4.ID("PRRT_123"),
1741+
resolveReviewThreadInput{
1742+
ThreadID: githubv4.ID("PRRT_123"),
1743+
ResolutionReason: newGQLStringlike[githubv4.String]("addressed"),
17431744
},
17441745
nil,
17451746
githubv4mock.DataResponse(map[string]any{
@@ -1755,7 +1756,8 @@ func TestGranularResolveReviewThread(t *testing.T) {
17551756
handler := serverTool.Handler(deps)
17561757

17571758
request := createMCPRequest(map[string]any{
1758-
"threadID": "PRRT_123",
1759+
"threadID": "PRRT_123",
1760+
"resolutionReason": "addressed",
17591761
})
17601762
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
17611763
require.NoError(t, err)

pkg/github/pullrequests.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,14 +1760,15 @@ func UpdatePullRequestBranch(t translations.TranslationHelperFunc) inventory.Ser
17601760
}
17611761

17621762
type PullRequestReviewWriteParams struct {
1763-
Method string
1764-
Owner string
1765-
Repo string
1766-
PullNumber int32
1767-
Body string
1768-
Event string
1769-
CommitID *string
1770-
ThreadID string
1763+
Method string
1764+
Owner string
1765+
Repo string
1766+
PullNumber int32
1767+
Body string
1768+
Event string
1769+
CommitID *string
1770+
ThreadID string
1771+
ResolutionReason *string
17711772
}
17721773

17731774
func PullRequestReviewWrite(t translations.TranslationHelperFunc) inventory.ServerTool {
@@ -1811,6 +1812,10 @@ func PullRequestReviewWrite(t translations.TranslationHelperFunc) inventory.Serv
18111812
Type: "string",
18121813
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.",
18131814
},
1815+
"resolutionReason": {
1816+
Type: "string",
1817+
Description: "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
1818+
},
18141819
},
18151820
Required: []string{"method", "owner", "repo", "pullNumber"},
18161821
}
@@ -1858,10 +1863,10 @@ Available methods:
18581863
result, err := DeletePendingPullRequestReview(ctx, client, params)
18591864
return result, nil, err
18601865
case "resolve_thread":
1861-
result, err := ResolveReviewThread(ctx, client, params.ThreadID, true)
1866+
result, err := ResolveReviewThread(ctx, client, params.ThreadID, params.ResolutionReason, true)
18621867
return result, nil, err
18631868
case "unresolve_thread":
1864-
result, err := ResolveReviewThread(ctx, client, params.ThreadID, false)
1869+
result, err := ResolveReviewThread(ctx, client, params.ThreadID, nil, false)
18651870
return result, nil, err
18661871
default:
18671872
return utils.NewToolResultError(fmt.Sprintf("unknown method: %s", params.Method)), nil, nil
@@ -2094,8 +2099,13 @@ func DeletePendingPullRequestReview(ctx context.Context, client *githubv4.Client
20942099
return utils.NewToolResultText("pending pull request review successfully deleted"), nil
20952100
}
20962101

2102+
type resolveReviewThreadInput struct {
2103+
ThreadID githubv4.ID `json:"threadId"`
2104+
ResolutionReason *githubv4.String `json:"resolutionReason,omitempty"`
2105+
}
2106+
20972107
// ResolveReviewThread resolves or unresolves a PR review thread using GraphQL mutations.
2098-
func ResolveReviewThread(ctx context.Context, client *githubv4.Client, threadID string, resolve bool) (*mcp.CallToolResult, error) {
2108+
func ResolveReviewThread(ctx context.Context, client *githubv4.Client, threadID string, resolutionReason *string, resolve bool) (*mcp.CallToolResult, error) {
20992109
if threadID == "" {
21002110
return utils.NewToolResultError("threadId is required for resolve_thread and unresolve_thread methods"), nil
21012111
}
@@ -2110,8 +2120,9 @@ func ResolveReviewThread(ctx context.Context, client *githubv4.Client, threadID
21102120
} `graphql:"resolveReviewThread(input: $input)"`
21112121
}
21122122

2113-
input := githubv4.ResolveReviewThreadInput{
2114-
ThreadID: githubv4.ID(threadID),
2123+
input := resolveReviewThreadInput{
2124+
ThreadID: githubv4.ID(threadID),
2125+
ResolutionReason: newGQLStringlikePtr[githubv4.String](resolutionReason),
21152126
}
21162127

21172128
if err := client.Mutate(ctx, &mutation, input, nil); err != nil {

pkg/github/pullrequests_granular.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,10 @@ func GranularResolveReviewThread(t translations.TranslationHelperFunc) inventory
690690
Type: "string",
691691
Description: "The node ID of the review thread to resolve (e.g., PRRT_kwDOxxx)",
692692
},
693+
"resolutionReason": {
694+
Type: "string",
695+
Description: "Optional reason for resolving a Copilot code review thread: addressed, wont-fix, or invalid.",
696+
},
693697
},
694698
Required: []string{"threadID"},
695699
},
@@ -700,13 +704,21 @@ func GranularResolveReviewThread(t translations.TranslationHelperFunc) inventory
700704
if err != nil {
701705
return utils.NewToolResultError(err.Error()), nil, nil
702706
}
707+
resolutionReason, hasResolutionReason, err := OptionalParamOK[string](args, "resolutionReason")
708+
if err != nil {
709+
return utils.NewToolResultError(err.Error()), nil, nil
710+
}
711+
var resolutionReasonPtr *string
712+
if hasResolutionReason {
713+
resolutionReasonPtr = &resolutionReason
714+
}
703715

704716
gqlClient, err := deps.GetGQLClient(ctx)
705717
if err != nil {
706718
return utils.NewToolResultErrorFromErr("failed to get GitHub GraphQL client", err), nil, nil
707719
}
708720

709-
result, err := ResolveReviewThread(ctx, gqlClient, threadID, true)
721+
result, err := ResolveReviewThread(ctx, gqlClient, threadID, resolutionReasonPtr, true)
710722
return result, nil, err
711723
},
712724
)
@@ -750,7 +762,7 @@ func GranularUnresolveReviewThread(t translations.TranslationHelperFunc) invento
750762
return utils.NewToolResultErrorFromErr("failed to get GitHub GraphQL client", err), nil, nil
751763
}
752764

753-
result, err := ResolveReviewThread(ctx, gqlClient, threadID, false)
765+
result, err := ResolveReviewThread(ctx, gqlClient, threadID, nil, false)
754766
return result, nil, err
755767
},
756768
)

pkg/github/pullrequests_test.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4572,7 +4572,7 @@ func TestResolveReviewThread(t *testing.T) {
45724572
}
45734573
} `graphql:"resolveReviewThread(input: $input)"`
45744574
}{},
4575-
githubv4.ResolveReviewThreadInput{
4575+
resolveReviewThreadInput{
45764576
ThreadID: githubv4.ID("PRRT_kwDOTest123"),
45774577
},
45784578
nil,
@@ -4588,6 +4588,43 @@ func TestResolveReviewThread(t *testing.T) {
45884588
),
45894589
expectedResult: "review thread resolved successfully",
45904590
},
4591+
{
4592+
name: "successful resolve thread with resolution reason",
4593+
requestArgs: map[string]any{
4594+
"method": "resolve_thread",
4595+
"owner": "owner",
4596+
"repo": "repo",
4597+
"pullNumber": float64(42),
4598+
"threadId": "PRRT_kwDOTest123",
4599+
"resolutionReason": "wont-fix",
4600+
},
4601+
mockedClient: githubv4mock.NewMockedHTTPClient(
4602+
githubv4mock.NewMutationMatcher(
4603+
struct {
4604+
ResolveReviewThread struct {
4605+
Thread struct {
4606+
ID githubv4.ID
4607+
IsResolved githubv4.Boolean
4608+
}
4609+
} `graphql:"resolveReviewThread(input: $input)"`
4610+
}{},
4611+
resolveReviewThreadInput{
4612+
ThreadID: githubv4.ID("PRRT_kwDOTest123"),
4613+
ResolutionReason: newGQLStringlike[githubv4.String]("wont-fix"),
4614+
},
4615+
nil,
4616+
githubv4mock.DataResponse(map[string]any{
4617+
"resolveReviewThread": map[string]any{
4618+
"thread": map[string]any{
4619+
"id": "PRRT_kwDOTest123",
4620+
"isResolved": true,
4621+
},
4622+
},
4623+
}),
4624+
),
4625+
),
4626+
expectedResult: "review thread resolved successfully",
4627+
},
45914628
{
45924629
name: "successful unresolve thread",
45934630
requestArgs: map[string]any{
@@ -4692,7 +4729,7 @@ func TestResolveReviewThread(t *testing.T) {
46924729
}
46934730
} `graphql:"resolveReviewThread(input: $input)"`
46944731
}{},
4695-
githubv4.ResolveReviewThreadInput{
4732+
resolveReviewThreadInput{
46964733
ThreadID: githubv4.ID("PRRT_invalid"),
46974734
},
46984735
nil,

0 commit comments

Comments
 (0)