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

Commit33b452d

Browse files
ashwin-antClaude
and
Claude
committed
feat: add UpdateIssueComment tool to edit issue comments
🤖 Generated with [Claude Code](https://claude.ai/code)Co-Authored-By: Claude <noreply@anthropic.com>
1 parent75b3504 commit33b452d

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed

‎pkg/github/issues.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,76 @@ func AddIssueComment(getClient GetClientFn, t translations.TranslationHelperFunc
142142
}
143143
}
144144

145+
// UpdateIssueComment creates a tool to update a comment on an issue.
146+
funcUpdateIssueComment(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
147+
returnmcp.NewTool("update_issue_comment",
148+
mcp.WithDescription(t("TOOL_UPDATE_ISSUE_COMMENT_DESCRIPTION","Update a comment on an issue")),
149+
mcp.WithString("owner",
150+
mcp.Required(),
151+
mcp.Description("Repository owner"),
152+
),
153+
mcp.WithString("repo",
154+
mcp.Required(),
155+
mcp.Description("Repository name"),
156+
),
157+
mcp.WithNumber("commentId",
158+
mcp.Required(),
159+
mcp.Description("Comment ID to update"),
160+
),
161+
mcp.WithString("body",
162+
mcp.Required(),
163+
mcp.Description("The new text for the comment"),
164+
),
165+
),
166+
func(ctx context.Context,request mcp.CallToolRequest) (*mcp.CallToolResult,error) {
167+
owner,err:=requiredParam[string](request,"owner")
168+
iferr!=nil {
169+
returnmcp.NewToolResultError(err.Error()),nil
170+
}
171+
repo,err:=requiredParam[string](request,"repo")
172+
iferr!=nil {
173+
returnmcp.NewToolResultError(err.Error()),nil
174+
}
175+
commentID,err:=RequiredInt(request,"commentId")
176+
iferr!=nil {
177+
returnmcp.NewToolResultError(err.Error()),nil
178+
}
179+
body,err:=requiredParam[string](request,"body")
180+
iferr!=nil {
181+
returnmcp.NewToolResultError(err.Error()),nil
182+
}
183+
184+
comment:=&github.IssueComment{
185+
Body:github.Ptr(body),
186+
}
187+
188+
client,err:=getClient(ctx)
189+
iferr!=nil {
190+
returnnil,fmt.Errorf("failed to get GitHub client: %w",err)
191+
}
192+
updatedComment,resp,err:=client.Issues.EditComment(ctx,owner,repo,int64(commentID),comment)
193+
iferr!=nil {
194+
returnnil,fmt.Errorf("failed to update issue comment: %w",err)
195+
}
196+
deferfunc() {_=resp.Body.Close() }()
197+
198+
ifresp.StatusCode!=http.StatusOK {
199+
body,err:=io.ReadAll(resp.Body)
200+
iferr!=nil {
201+
returnnil,fmt.Errorf("failed to read response body: %w",err)
202+
}
203+
returnmcp.NewToolResultError(fmt.Sprintf("failed to update issue comment: %s",string(body))),nil
204+
}
205+
206+
r,err:=json.Marshal(updatedComment)
207+
iferr!=nil {
208+
returnnil,fmt.Errorf("failed to marshal response: %w",err)
209+
}
210+
211+
returnmcp.NewToolResultText(string(r)),nil
212+
}
213+
}
214+
145215
// SearchIssues creates a tool to search for issues and pull requests.
146216
funcSearchIssues(getClientGetClientFn,t translations.TranslationHelperFunc) (tool mcp.Tool,handler server.ToolHandlerFunc) {
147217
returnmcp.NewTool("search_issues",

‎pkg/github/issues_test.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,3 +1130,139 @@ func Test_GetIssueComments(t *testing.T) {
11301130
})
11311131
}
11321132
}
1133+
1134+
funcTest_UpdateIssueComment(t*testing.T) {
1135+
// Verify tool definition once
1136+
mockClient:=github.NewClient(nil)
1137+
tool,_:=UpdateIssueComment(stubGetClientFn(mockClient),translations.NullTranslationHelper)
1138+
1139+
assert.Equal(t,"update_issue_comment",tool.Name)
1140+
assert.NotEmpty(t,tool.Description)
1141+
assert.Contains(t,tool.InputSchema.Properties,"owner")
1142+
assert.Contains(t,tool.InputSchema.Properties,"repo")
1143+
assert.Contains(t,tool.InputSchema.Properties,"commentId")
1144+
assert.Contains(t,tool.InputSchema.Properties,"body")
1145+
assert.ElementsMatch(t,tool.InputSchema.Required, []string{"owner","repo","commentId","body"})
1146+
1147+
// Setup mock comment for success case
1148+
mockUpdatedComment:=&github.IssueComment{
1149+
ID:github.Ptr(int64(123)),
1150+
Body:github.Ptr("Updated issue comment text here"),
1151+
HTMLURL:github.Ptr("https://github.com/owner/repo/issues/1#issuecomment-123"),
1152+
CreatedAt:&github.Timestamp{Time:time.Now().Add(-1*time.Hour)},
1153+
UpdatedAt:&github.Timestamp{Time:time.Now()},
1154+
User:&github.User{
1155+
Login:github.Ptr("testuser"),
1156+
},
1157+
}
1158+
1159+
tests:= []struct {
1160+
namestring
1161+
mockedClient*http.Client
1162+
requestArgsmap[string]interface{}
1163+
expectErrorbool
1164+
expectedComment*github.IssueComment
1165+
expectedErrMsgstring
1166+
}{
1167+
{
1168+
name:"successful comment update",
1169+
mockedClient:mock.NewMockedHTTPClient(
1170+
mock.WithRequestMatchHandler(
1171+
mock.PatchReposIssuesCommentsByOwnerByRepoByCommentId,
1172+
expectRequestBody(t,map[string]interface{}{
1173+
"body":"Updated issue comment text here",
1174+
}).andThen(
1175+
mockResponse(t,http.StatusOK,mockUpdatedComment),
1176+
),
1177+
),
1178+
),
1179+
requestArgs:map[string]interface{}{
1180+
"owner":"owner",
1181+
"repo":"repo",
1182+
"commentId":float64(123),
1183+
"body":"Updated issue comment text here",
1184+
},
1185+
expectError:false,
1186+
expectedComment:mockUpdatedComment,
1187+
},
1188+
{
1189+
name:"comment update fails - not found",
1190+
mockedClient:mock.NewMockedHTTPClient(
1191+
mock.WithRequestMatchHandler(
1192+
mock.PatchReposIssuesCommentsByOwnerByRepoByCommentId,
1193+
http.HandlerFunc(func(w http.ResponseWriter,_*http.Request) {
1194+
w.WriteHeader(http.StatusNotFound)
1195+
w.Header().Set("Content-Type","application/json")
1196+
_,_=w.Write([]byte(`{"message": "Comment not found"}`))
1197+
}),
1198+
),
1199+
),
1200+
requestArgs:map[string]interface{}{
1201+
"owner":"owner",
1202+
"repo":"repo",
1203+
"commentId":float64(999),
1204+
"body":"This should fail",
1205+
},
1206+
expectError:true,
1207+
expectedErrMsg:"failed to update issue comment",
1208+
},
1209+
{
1210+
name:"comment update fails - validation error",
1211+
mockedClient:mock.NewMockedHTTPClient(
1212+
mock.WithRequestMatchHandler(
1213+
mock.PatchReposIssuesCommentsByOwnerByRepoByCommentId,
1214+
http.HandlerFunc(func(w http.ResponseWriter,_*http.Request) {
1215+
w.WriteHeader(http.StatusUnprocessableEntity)
1216+
w.Header().Set("Content-Type","application/json")
1217+
_,_=w.Write([]byte(`{"message": "Validation Failed"}`))
1218+
}),
1219+
),
1220+
),
1221+
requestArgs:map[string]interface{}{
1222+
"owner":"owner",
1223+
"repo":"repo",
1224+
"commentId":float64(123),
1225+
"body":"Invalid body",
1226+
},
1227+
expectError:true,
1228+
expectedErrMsg:"failed to update issue comment",
1229+
},
1230+
}
1231+
1232+
for_,tc:=rangetests {
1233+
t.Run(tc.name,func(t*testing.T) {
1234+
client:=github.NewClient(tc.mockedClient)
1235+
_,handler:=UpdateIssueComment(stubGetClientFn(client),translations.NullTranslationHelper)
1236+
1237+
request:=createMCPRequest(tc.requestArgs)
1238+
1239+
result,err:=handler(context.Background(),request)
1240+
1241+
iftc.expectError {
1242+
require.Error(t,err)
1243+
assert.Contains(t,err.Error(),tc.expectedErrMsg)
1244+
return
1245+
}
1246+
1247+
require.NoError(t,err)
1248+
assert.NotNil(t,result)
1249+
require.Len(t,result.Content,1)
1250+
1251+
textContent:=getTextResult(t,result)
1252+
1253+
// For non-error cases, check the returned comment
1254+
varreturnedComment github.IssueComment
1255+
err=json.Unmarshal([]byte(textContent.Text),&returnedComment)
1256+
require.NoError(t,err)
1257+
1258+
assert.Equal(t,*tc.expectedComment.ID,*returnedComment.ID)
1259+
assert.Equal(t,*tc.expectedComment.Body,*returnedComment.Body)
1260+
iftc.expectedComment.HTMLURL!=nil {
1261+
assert.Equal(t,*tc.expectedComment.HTMLURL,*returnedComment.HTMLURL)
1262+
}
1263+
iftc.expectedComment.User!=nil&&tc.expectedComment.User.Login!=nil {
1264+
assert.Equal(t,*tc.expectedComment.User.Login,*returnedComment.User.Login)
1265+
}
1266+
})
1267+
}
1268+
}

‎pkg/github/tools.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func InitToolsets(passedToolsets []string, readOnly bool, getClient GetClientFn,
4646
toolsets.NewServerTool(CreateIssue(getClient,t)),
4747
toolsets.NewServerTool(AddIssueComment(getClient,t)),
4848
toolsets.NewServerTool(UpdateIssue(getClient,t)),
49+
toolsets.NewServerTool(UpdateIssueComment(getClient,t)),
4950
)
5051
users:=toolsets.NewToolset("users","GitHub User related tools").
5152
AddReadTools(

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp