@@ -335,6 +335,84 @@ func TestGranularUpdateIssueLabels(t *testing.T) {
335335 }
336336}
337337
338+ func TestGranularUpdateIssueLabelsSuggest (t * testing.T ) {
339+ tests := []struct {
340+ name string
341+ requestArgs map [string ]any
342+ expectedReq map [string ]any
343+ }{
344+ {
345+ name : "single label suggested without rationale" ,
346+ requestArgs : map [string ]any {
347+ "owner" : "owner" ,
348+ "repo" : "repo" ,
349+ "issue_number" : float64 (1 ),
350+ "labels" : []any {
351+ map [string ]any {"name" : "bug" , "is_suggestion" : true },
352+ },
353+ },
354+ expectedReq : map [string ]any {
355+ "labels" : []any {
356+ map [string ]any {"name" : "bug" , "suggest" : true },
357+ },
358+ },
359+ },
360+ {
361+ name : "suggested label with rationale" ,
362+ requestArgs : map [string ]any {
363+ "owner" : "owner" ,
364+ "repo" : "repo" ,
365+ "issue_number" : float64 (1 ),
366+ "labels" : []any {
367+ map [string ]any {"name" : "frontend" , "rationale" : "Mentions the UI button" , "is_suggestion" : true },
368+ },
369+ },
370+ expectedReq : map [string ]any {
371+ "labels" : []any {
372+ map [string ]any {"name" : "frontend" , "rationale" : "Mentions the UI button" , "suggest" : true },
373+ },
374+ },
375+ },
376+ {
377+ name : "mix of plain, applied-with-rationale, and suggested labels" ,
378+ requestArgs : map [string ]any {
379+ "owner" : "owner" ,
380+ "repo" : "repo" ,
381+ "issue_number" : float64 (1 ),
382+ "labels" : []any {
383+ "triage" ,
384+ map [string ]any {"name" : "bug" , "rationale" : "Reports a crash when saving" },
385+ map [string ]any {"name" : "needs-design" , "is_suggestion" : true },
386+ },
387+ },
388+ expectedReq : map [string ]any {
389+ "labels" : []any {
390+ "triage" ,
391+ map [string ]any {"name" : "bug" , "rationale" : "Reports a crash when saving" },
392+ map [string ]any {"name" : "needs-design" , "suggest" : true },
393+ },
394+ },
395+ },
396+ }
397+
398+ for _ , tc := range tests {
399+ t .Run (tc .name , func (t * testing.T ) {
400+ client := mustNewGHClient (t , MockHTTPClientWithHandlers (map [string ]http.HandlerFunc {
401+ PatchReposIssuesByOwnerByRepoByIssueNumber : expectRequestBody (t , tc .expectedReq ).
402+ andThen (mockResponse (t , http .StatusOK , & gogithub.Issue {Number : gogithub .Ptr (1 )})),
403+ }))
404+ deps := BaseDeps {Client : client }
405+ serverTool := GranularUpdateIssueLabels (translations .NullTranslationHelper )
406+ handler := serverTool .Handler (deps )
407+
408+ request := createMCPRequest (tc .requestArgs )
409+ result , err := handler (ContextWithDeps (context .Background (), deps ), & request )
410+ require .NoError (t , err )
411+ assert .False (t , result .IsError )
412+ })
413+ }
414+ }
415+
338416func TestGranularUpdateIssueLabelsInvalidRationale (t * testing.T ) {
339417 tests := []struct {
340418 name string
@@ -1307,4 +1385,97 @@ func TestGranularSetIssueFields(t *testing.T) {
13071385 textContent := getTextResult (t , result )
13081386 assert .Contains (t , textContent .Text , "field rationale must be 280 characters or less" )
13091387 })
1388+
1389+ t .Run ("successful set with suggest flag" , func (t * testing.T ) {
1390+ suggestTrue := githubv4 .Boolean (true )
1391+ matchers := []githubv4mock.Matcher {
1392+ githubv4mock .NewQueryMatcher (
1393+ struct {
1394+ Repository struct {
1395+ Issue struct {
1396+ ID githubv4.ID
1397+ } `graphql:"issue(number: $issueNumber)"`
1398+ } `graphql:"repository(owner: $owner, name: $repo)"`
1399+ }{},
1400+ map [string ]any {
1401+ "owner" : githubv4 .String ("owner" ),
1402+ "repo" : githubv4 .String ("repo" ),
1403+ "issueNumber" : githubv4 .Int (5 ),
1404+ },
1405+ githubv4mock .DataResponse (map [string ]any {
1406+ "repository" : map [string ]any {
1407+ "issue" : map [string ]any {"id" : "ISSUE_123" },
1408+ },
1409+ }),
1410+ ),
1411+ githubv4mock .NewMutationMatcher (
1412+ struct {
1413+ SetIssueFieldValue struct {
1414+ Issue struct {
1415+ ID githubv4.ID
1416+ Number githubv4.Int
1417+ URL githubv4.String
1418+ }
1419+ IssueFieldValues []struct {
1420+ TextValue struct {
1421+ Value string
1422+ } `graphql:"... on IssueFieldTextValue"`
1423+ SingleSelectValue struct {
1424+ Name string
1425+ } `graphql:"... on IssueFieldSingleSelectValue"`
1426+ DateValue struct {
1427+ Value string
1428+ } `graphql:"... on IssueFieldDateValue"`
1429+ NumberValue struct {
1430+ Value float64
1431+ } `graphql:"... on IssueFieldNumberValue"`
1432+ }
1433+ } `graphql:"setIssueFieldValue(input: $input)"`
1434+ }{},
1435+ SetIssueFieldValueInput {
1436+ IssueID : githubv4 .ID ("ISSUE_123" ),
1437+ IssueFields : []IssueFieldCreateOrUpdateInput {
1438+ {
1439+ FieldID : githubv4 .ID ("FIELD_1" ),
1440+ TextValue : githubv4 .NewString (githubv4 .String ("hello" )),
1441+ Rationale : githubv4 .NewString (githubv4 .String ("Reflects the reported severity" )),
1442+ Suggest : & suggestTrue ,
1443+ },
1444+ },
1445+ },
1446+ nil ,
1447+ githubv4mock .DataResponse (map [string ]any {
1448+ "setIssueFieldValue" : map [string ]any {
1449+ "issue" : map [string ]any {
1450+ "id" : "ISSUE_123" ,
1451+ "number" : 5 ,
1452+ "url" : "https://github.com/owner/repo/issues/5" ,
1453+ },
1454+ },
1455+ }),
1456+ ),
1457+ }
1458+
1459+ gqlClient := githubv4 .NewClient (githubv4mock .NewMockedHTTPClient (matchers ... ))
1460+ deps := BaseDeps {GQLClient : gqlClient }
1461+ serverTool := GranularSetIssueFields (translations .NullTranslationHelper )
1462+ handler := serverTool .Handler (deps )
1463+
1464+ request := createMCPRequest (map [string ]any {
1465+ "owner" : "owner" ,
1466+ "repo" : "repo" ,
1467+ "issue_number" : float64 (5 ),
1468+ "fields" : []any {
1469+ map [string ]any {
1470+ "field_id" : "FIELD_1" ,
1471+ "text_value" : "hello" ,
1472+ "rationale" : "Reflects the reported severity" ,
1473+ "is_suggestion" : true ,
1474+ },
1475+ },
1476+ })
1477+ result , err := handler (ContextWithDeps (context .Background (), deps ), & request )
1478+ require .NoError (t , err )
1479+ assert .False (t , result .IsError )
1480+ })
13101481}
0 commit comments