Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit75b3504

Browse files
ashwin-antclaude
andcommitted
feat: add UpdatePullRequestComment tool to edit PR review comments
🤖 Generated with [Claude Code](https://claude.ai/code)Co-Authored-By: Claude <noreply@anthropic.com>
1 parent495c0cb commit75b3504

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed

‎pkg/github/pullrequests.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,76 @@ func CreatePullRequestReview(getClient GetClientFn, t translations.TranslationHe
10731073
}
10741074
}
10751075

1076+
// UpdatePullRequestComment creates a tool to update a review comment on a pull request.
1077+
funcUpdatePullRequestComment(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
1078+
returnmcp.NewTool("update_pull_request_comment",
1079+
mcp.WithDescription(t("TOOL_UPDATE_PULL_REQUEST_COMMENT_DESCRIPTION","Update a review comment on a pull request")),
1080+
mcp.WithString("owner",
1081+
mcp.Required(),
1082+
mcp.Description("Repository owner"),
1083+
),
1084+
mcp.WithString("repo",
1085+
mcp.Required(),
1086+
mcp.Description("Repository name"),
1087+
),
1088+
mcp.WithNumber("commentId",
1089+
mcp.Required(),
1090+
mcp.Description("Comment ID to update"),
1091+
),
1092+
mcp.WithString("body",
1093+
mcp.Required(),
1094+
mcp.Description("The new text for the comment"),
1095+
),
1096+
),
1097+
func(ctx context.Context,request mcp.CallToolRequest) (*mcp.CallToolResult,error) {
1098+
owner,err:=requiredParam[string](request,"owner")
1099+
iferr!=nil {
1100+
returnmcp.NewToolResultError(err.Error()),nil
1101+
}
1102+
repo,err:=requiredParam[string](request,"repo")
1103+
iferr!=nil {
1104+
returnmcp.NewToolResultError(err.Error()),nil
1105+
}
1106+
commentID,err:=RequiredInt(request,"commentId")
1107+
iferr!=nil {
1108+
returnmcp.NewToolResultError(err.Error()),nil
1109+
}
1110+
body,err:=requiredParam[string](request,"body")
1111+
iferr!=nil {
1112+
returnmcp.NewToolResultError(err.Error()),nil
1113+
}
1114+
1115+
comment:=&github.PullRequestComment{
1116+
Body:github.Ptr(body),
1117+
}
1118+
1119+
client,err:=getClient(ctx)
1120+
iferr!=nil {
1121+
returnnil,fmt.Errorf("failed to get GitHub client: %w",err)
1122+
}
1123+
updatedComment,resp,err:=client.PullRequests.EditComment(ctx,owner,repo,int64(commentID),comment)
1124+
iferr!=nil {
1125+
returnnil,fmt.Errorf("failed to update pull request comment: %w",err)
1126+
}
1127+
deferfunc() {_=resp.Body.Close() }()
1128+
1129+
ifresp.StatusCode!=http.StatusOK {
1130+
body,err:=io.ReadAll(resp.Body)
1131+
iferr!=nil {
1132+
returnnil,fmt.Errorf("failed to read response body: %w",err)
1133+
}
1134+
returnmcp.NewToolResultError(fmt.Sprintf("failed to update pull request comment: %s",string(body))),nil
1135+
}
1136+
1137+
r,err:=json.Marshal(updatedComment)
1138+
iferr!=nil {
1139+
returnnil,fmt.Errorf("failed to marshal response: %w",err)
1140+
}
1141+
1142+
returnmcp.NewToolResultText(string(r)),nil
1143+
}
1144+
}
1145+
10761146
// CreatePullRequest creates a tool to create a new pull request.
10771147
funcCreatePullRequest(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
10781148
returnmcp.NewTool("create_pull_request",

‎pkg/github/pullrequests_test.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,3 +1916,139 @@ func Test_AddPullRequestReviewComment(t *testing.T) {
19161916
})
19171917
}
19181918
}
1919+
1920+
funcTest_UpdatePullRequestComment(t*testing.T) {
1921+
// Verify tool definition once
1922+
mockClient:=github.NewClient(nil)
1923+
tool,_:=UpdatePullRequestComment(stubGetClientFn(mockClient),translations.NullTranslationHelper)
1924+
1925+
assert.Equal(t,"update_pull_request_comment",tool.Name)
1926+
assert.NotEmpty(t,tool.Description)
1927+
assert.Contains(t,tool.InputSchema.Properties,"owner")
1928+
assert.Contains(t,tool.InputSchema.Properties,"repo")
1929+
assert.Contains(t,tool.InputSchema.Properties,"commentId")
1930+
assert.Contains(t,tool.InputSchema.Properties,"body")
1931+
assert.ElementsMatch(t,tool.InputSchema.Required, []string{"owner","repo","commentId","body"})
1932+
1933+
// Setup mock comment for success case
1934+
mockUpdatedComment:=&github.PullRequestComment{
1935+
ID:github.Ptr(int64(456)),
1936+
Body:github.Ptr("Updated comment text here"),
1937+
HTMLURL:github.Ptr("https://github.com/owner/repo/pull/1#discussion_r456"),
1938+
Path:github.Ptr("file1.txt"),
1939+
UpdatedAt:&github.Timestamp{Time:time.Now()},
1940+
User:&github.User{
1941+
Login:github.Ptr("testuser"),
1942+
},
1943+
}
1944+
1945+
tests:= []struct {
1946+
namestring
1947+
mockedClient*http.Client
1948+
requestArgsmap[string]interface{}
1949+
expectErrorbool
1950+
expectedComment*github.PullRequestComment
1951+
expectedErrMsgstring
1952+
}{
1953+
{
1954+
name:"successful comment update",
1955+
mockedClient:mock.NewMockedHTTPClient(
1956+
mock.WithRequestMatchHandler(
1957+
mock.PatchReposPullsCommentsByOwnerByRepoByCommentId,
1958+
expectRequestBody(t,map[string]interface{}{
1959+
"body":"Updated comment text here",
1960+
}).andThen(
1961+
mockResponse(t,http.StatusOK,mockUpdatedComment),
1962+
),
1963+
),
1964+
),
1965+
requestArgs:map[string]interface{}{
1966+
"owner":"owner",
1967+
"repo":"repo",
1968+
"commentId":float64(456),
1969+
"body":"Updated comment text here",
1970+
},
1971+
expectError:false,
1972+
expectedComment:mockUpdatedComment,
1973+
},
1974+
{
1975+
name:"comment update fails - not found",
1976+
mockedClient:mock.NewMockedHTTPClient(
1977+
mock.WithRequestMatchHandler(
1978+
mock.PatchReposPullsCommentsByOwnerByRepoByCommentId,
1979+
http.HandlerFunc(func(w http.ResponseWriter,_*http.Request) {
1980+
w.WriteHeader(http.StatusNotFound)
1981+
w.Header().Set("Content-Type","application/json")
1982+
_,_=w.Write([]byte(`{"message": "Comment not found"}`))
1983+
}),
1984+
),
1985+
),
1986+
requestArgs:map[string]interface{}{
1987+
"owner":"owner",
1988+
"repo":"repo",
1989+
"commentId":float64(999),
1990+
"body":"This should fail",
1991+
},
1992+
expectError:true,
1993+
expectedErrMsg:"failed to update pull request comment",
1994+
},
1995+
{
1996+
name:"comment update fails - validation error",
1997+
mockedClient:mock.NewMockedHTTPClient(
1998+
mock.WithRequestMatchHandler(
1999+
mock.PatchReposPullsCommentsByOwnerByRepoByCommentId,
2000+
http.HandlerFunc(func(w http.ResponseWriter,_*http.Request) {
2001+
w.WriteHeader(http.StatusUnprocessableEntity)
2002+
w.Header().Set("Content-Type","application/json")
2003+
_,_=w.Write([]byte(`{"message": "Validation Failed"}`))
2004+
}),
2005+
),
2006+
),
2007+
requestArgs:map[string]interface{}{
2008+
"owner":"owner",
2009+
"repo":"repo",
2010+
"commentId":float64(456),
2011+
"body":"Invalid body",// Changed this to a non-empty string
2012+
},
2013+
expectError:true,
2014+
expectedErrMsg:"failed to update pull request comment",
2015+
},
2016+
}
2017+
2018+
for_,tc:=rangetests {
2019+
t.Run(tc.name,func(t*testing.T) {
2020+
client:=github.NewClient(tc.mockedClient)
2021+
_,handler:=UpdatePullRequestComment(stubGetClientFn(client),translations.NullTranslationHelper)
2022+
2023+
request:=createMCPRequest(tc.requestArgs)
2024+
2025+
result,err:=handler(context.Background(),request)
2026+
2027+
iftc.expectError {
2028+
require.Error(t,err)
2029+
assert.Contains(t,err.Error(),tc.expectedErrMsg)
2030+
return
2031+
}
2032+
2033+
require.NoError(t,err)
2034+
assert.NotNil(t,result)
2035+
require.Len(t,result.Content,1)
2036+
2037+
textContent:=getTextResult(t,result)
2038+
2039+
// For non-error cases, check the returned comment
2040+
varreturnedComment github.PullRequestComment
2041+
err=json.Unmarshal([]byte(textContent.Text),&returnedComment)
2042+
require.NoError(t,err)
2043+
2044+
assert.Equal(t,*tc.expectedComment.ID,*returnedComment.ID)
2045+
assert.Equal(t,*tc.expectedComment.Body,*returnedComment.Body)
2046+
iftc.expectedComment.Path!=nil {
2047+
assert.Equal(t,*tc.expectedComment.Path,*returnedComment.Path)
2048+
}
2049+
iftc.expectedComment.HTMLURL!=nil {
2050+
assert.Equal(t,*tc.expectedComment.HTMLURL,*returnedComment.HTMLURL)
2051+
}
2052+
})
2053+
}
2054+
}

‎pkg/github/tools.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func InitToolsets(passedToolsets []string, readOnly bool, getClient GetClientFn,
6767
toolsets.NewServerTool(CreatePullRequest(getClient,t)),
6868
toolsets.NewServerTool(UpdatePullRequest(getClient,t)),
6969
toolsets.NewServerTool(AddPullRequestReviewComment(getClient,t)),
70+
toolsets.NewServerTool(UpdatePullRequestComment(getClient,t)),
7071
)
7172
codeSecurity:=toolsets.NewToolset("code_security","Code security related tools, such as GitHub Code Scanning").
7273
AddReadTools(

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp