@@ -18,13 +18,24 @@ import (
1818 "github.com/shurcooL/githubv4"
1919)
2020
21+ // issueEditBody is implemented by any type that can serve as the body
22+ // of a PATCH /repos/{owner}/{repo}/issues/{issue_number} request.
23+ type issueEditBody interface {
24+ issueEditBody ()
25+ }
26+
27+ // standardIssueEdit wraps a *github.IssueRequest to satisfy issueEditBody.
28+ type standardIssueEdit struct { * github.IssueRequest }
29+
30+ func (standardIssueEdit ) issueEditBody () {}
31+
2132// issueUpdateTool is a helper to create single-field issue update tools.
2233func issueUpdateTool (
2334 t translations.TranslationHelperFunc ,
2435 name , description , title string ,
2536 extraProps map [string ]* jsonschema.Schema ,
2637 extraRequired []string ,
27- buildRequest func (args map [string ]any ) (* github. IssueRequest , error ),
38+ buildRequest func (args map [string ]any ) (issueEditBody , error ),
2839) inventory.ServerTool {
2940 props := map [string ]* jsonschema.Schema {
3041 "owner" : {
@@ -77,7 +88,7 @@ func issueUpdateTool(
7788 return utils .NewToolResultError (err .Error ()), nil , nil
7889 }
7990
80- issueReq , err := buildRequest (args )
91+ body , err := buildRequest (args )
8192 if err != nil {
8293 return utils .NewToolResultError (err .Error ()), nil , nil
8394 }
@@ -87,7 +98,14 @@ func issueUpdateTool(
8798 return utils .NewToolResultErrorFromErr ("failed to get GitHub client" , err ), nil , nil
8899 }
89100
90- issue , resp , err := client .Issues .Edit (ctx , owner , repo , issueNumber , issueReq )
101+ apiURL := fmt .Sprintf ("repos/%s/%s/issues/%d" , owner , repo , issueNumber )
102+ req , err := client .NewRequest ("PATCH" , apiURL , body )
103+ if err != nil {
104+ return utils .NewToolResultErrorFromErr ("failed to create request" , err ), nil , nil
105+ }
106+
107+ issue := & github.Issue {}
108+ resp , err := client .Do (ctx , req , issue )
91109 if err != nil {
92110 return ghErrors .NewGitHubAPIErrorResponse (ctx , "failed to update issue" , resp , err ), nil , nil
93111 }
@@ -201,12 +219,12 @@ func GranularUpdateIssueTitle(t translations.TranslationHelperFunc) inventory.Se
201219 "title" : {Type : "string" , Description : "The new title for the issue" },
202220 },
203221 []string {"title" },
204- func (args map [string ]any ) (* github. IssueRequest , error ) {
222+ func (args map [string ]any ) (issueEditBody , error ) {
205223 title , err := RequiredParam [string ](args , "title" )
206224 if err != nil {
207225 return nil , err
208226 }
209- return & github.IssueRequest {Title : & title }, nil
227+ return standardIssueEdit { & github.IssueRequest {Title : & title } }, nil
210228 },
211229 )
212230}
@@ -221,12 +239,12 @@ func GranularUpdateIssueBody(t translations.TranslationHelperFunc) inventory.Ser
221239 "body" : {Type : "string" , Description : "The new body content for the issue" },
222240 },
223241 []string {"body" },
224- func (args map [string ]any ) (* github. IssueRequest , error ) {
242+ func (args map [string ]any ) (issueEditBody , error ) {
225243 body , err := RequiredParam [string ](args , "body" )
226244 if err != nil {
227245 return nil , err
228246 }
229- return & github.IssueRequest {Body : & body }, nil
247+ return standardIssueEdit { & github.IssueRequest {Body : & body } }, nil
230248 },
231249 )
232250}
@@ -245,15 +263,15 @@ func GranularUpdateIssueAssignees(t translations.TranslationHelperFunc) inventor
245263 },
246264 },
247265 []string {"assignees" },
248- func (args map [string ]any ) (* github. IssueRequest , error ) {
266+ func (args map [string ]any ) (issueEditBody , error ) {
249267 if _ , ok := args ["assignees" ]; ! ok {
250268 return nil , fmt .Errorf ("missing required parameter: assignees" )
251269 }
252270 assignees , err := OptionalStringArrayParam (args , "assignees" )
253271 if err != nil {
254272 return nil , err
255273 }
256- return & github.IssueRequest {Assignees : & assignees }, nil
274+ return standardIssueEdit { & github.IssueRequest {Assignees : & assignees } }, nil
257275 },
258276 )
259277}
@@ -272,15 +290,15 @@ func GranularUpdateIssueLabels(t translations.TranslationHelperFunc) inventory.S
272290 },
273291 },
274292 []string {"labels" },
275- func (args map [string ]any ) (* github. IssueRequest , error ) {
293+ func (args map [string ]any ) (issueEditBody , error ) {
276294 if _ , ok := args ["labels" ]; ! ok {
277295 return nil , fmt .Errorf ("missing required parameter: labels" )
278296 }
279297 labels , err := OptionalStringArrayParam (args , "labels" )
280298 if err != nil {
281299 return nil , err
282300 }
283- return & github.IssueRequest {Labels : & labels }, nil
301+ return standardIssueEdit { & github.IssueRequest {Labels : & labels } }, nil
284302 },
285303 )
286304}
@@ -299,16 +317,31 @@ func GranularUpdateIssueMilestone(t translations.TranslationHelperFunc) inventor
299317 },
300318 },
301319 []string {"milestone" },
302- func (args map [string ]any ) (* github. IssueRequest , error ) {
320+ func (args map [string ]any ) (issueEditBody , error ) {
303321 milestone , err := RequiredInt (args , "milestone" )
304322 if err != nil {
305323 return nil , err
306324 }
307- return & github.IssueRequest {Milestone : & milestone }, nil
325+ return standardIssueEdit { & github.IssueRequest {Milestone : & milestone } }, nil
308326 },
309327 )
310328}
311329
330+ // issueTypeWithRationale represents the object form of the issue type field,
331+ // allowing a rationale to be sent alongside the type value.
332+ type issueTypeWithRationale struct {
333+ Value string `json:"value"`
334+ Rationale string `json:"rationale"`
335+ }
336+
337+ // issueTypeUpdateRequest is a custom request body for updating an issue type
338+ // with an optional rationale, using the object form that the REST API accepts.
339+ type issueTypeUpdateRequest struct {
340+ Type issueTypeWithRationale `json:"type"`
341+ }
342+
343+ func (* issueTypeUpdateRequest ) issueEditBody () {}
344+
312345// GranularUpdateIssueType creates a tool to update an issue's type.
313346func GranularUpdateIssueType (t translations.TranslationHelperFunc ) inventory.ServerTool {
314347 return issueUpdateTool (t ,
@@ -320,14 +353,29 @@ func GranularUpdateIssueType(t translations.TranslationHelperFunc) inventory.Ser
320353 Type : "string" ,
321354 Description : "The issue type to set" ,
322355 },
356+ "rationale" : {
357+ Type : "string" ,
358+ Description : "One concise sentence explaining what specifically about the issue led you to choose this type. " +
359+ "State the concrete signal (e.g. 'Reports a crash when saving' → bug, 'Asks for dark mode support' → feature)." ,
360+ MaxLength : jsonschema .Ptr (280 ),
361+ },
323362 },
324363 []string {"issue_type" },
325- func (args map [string ]any ) (* github. IssueRequest , error ) {
364+ func (args map [string ]any ) (issueEditBody , error ) {
326365 issueType , err := RequiredParam [string ](args , "issue_type" )
327366 if err != nil {
328367 return nil , err
329368 }
330- return & github.IssueRequest {Type : & issueType }, nil
369+ rationale , _ := OptionalParam [string ](args , "rationale" )
370+ if rationale != "" {
371+ return & issueTypeUpdateRequest {
372+ Type : issueTypeWithRationale {
373+ Value : issueType ,
374+ Rationale : rationale ,
375+ },
376+ }, nil
377+ }
378+ return standardIssueEdit {& github.IssueRequest {Type : & issueType }}, nil
331379 },
332380 )
333381}
@@ -351,7 +399,7 @@ func GranularUpdateIssueState(t translations.TranslationHelperFunc) inventory.Se
351399 },
352400 },
353401 []string {"state" },
354- func (args map [string ]any ) (* github. IssueRequest , error ) {
402+ func (args map [string ]any ) (issueEditBody , error ) {
355403 state , err := RequiredParam [string ](args , "state" )
356404 if err != nil {
357405 return nil , err
@@ -362,7 +410,7 @@ func GranularUpdateIssueState(t translations.TranslationHelperFunc) inventory.Se
362410 if stateReason != "" {
363411 req .StateReason = & stateReason
364412 }
365- return req , nil
413+ return standardIssueEdit { req } , nil
366414 },
367415 )
368416}
0 commit comments