Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkg/github/__toolsnaps__/update_issue_type.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
"description": "Update the type of an existing issue (e.g. 'bug', 'feature').",
"inputSchema": {
"properties": {
"is_suggestion": {
"description": "If true, propose the issue type change instead of applying it. Defaults to false, which applies the change to the issue.",
"type": "boolean"
},
"issue_number": {
"description": "The issue number to update",
"minimum": 1,
Expand Down
65 changes: 65 additions & 0 deletions pkg/github/granular_tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package github

import (
"context"
"encoding/json"
"net/http"
"strings"
"testing"
Expand Down Expand Up @@ -458,6 +459,70 @@ func TestGranularUpdateIssueType(t *testing.T) {
}
}

func TestGranularUpdateIssueTypeSuggest(t *testing.T) {
tests := []struct {
name string
requestArgs map[string]any
expected map[string]any
}{
{
name: "suggest without rationale",
requestArgs: map[string]any{
"owner": "owner",
"repo": "repo",
"issue_number": float64(1),
"issue_type": "bug",
"suggest": true,
},
expected: map[string]any{
"owner": "owner",
"repo": "repo",
"issue_number": float64(1),
"issue_type": "bug",
"suggested": true,
},
},
{
name: "suggest with rationale",
requestArgs: map[string]any{
"owner": "owner",
"repo": "repo",
"issue_number": float64(1),
"issue_type": "feature",
"rationale": " Asks for dark mode support ",
"suggest": true,
},
expected: map[string]any{
"owner": "owner",
"repo": "repo",
"issue_number": float64(1),
"issue_type": "feature",
"rationale": "Asks for dark mode support",
"suggested": true,
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// No HTTP handler registered: any API call would fail the test.
deps := BaseDeps{Client: mustNewGHClient(t, MockHTTPClientWithHandlers(nil))}
serverTool := GranularUpdateIssueType(translations.NullTranslationHelper)
handler := serverTool.Handler(deps)

request := createMCPRequest(tc.requestArgs)
result, err := handler(ContextWithDeps(context.Background(), deps), &request)
require.NoError(t, err)
require.False(t, result.IsError)

textContent := getTextResult(t, result)
var got map[string]any
require.NoError(t, json.Unmarshal([]byte(textContent.Text), &got))
assert.Equal(t, tc.expected, got)
})
}
}

func TestGranularUpdateIssueTypeInvalidRationale(t *testing.T) {
tests := []struct {
name string
Expand Down
27 changes: 27 additions & 0 deletions pkg/github/issues_granular.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,11 @@ func GranularUpdateIssueType(t translations.TranslationHelperFunc) inventory.Ser
"State the concrete signal (e.g. 'Reports a crash when saving' → bug, 'Asks for dark mode support' → feature).",
MaxLength: jsonschema.Ptr(280),
},
"is_suggestion": {
Type: "boolean",
Description: "If true, propose the issue type change instead of applying it. " +
"Defaults to false, which applies the change to the issue.",
},
},
Required: []string{"owner", "repo", "issue_number", "issue_type"},
},
Expand Down Expand Up @@ -542,6 +547,28 @@ func GranularUpdateIssueType(t translations.TranslationHelperFunc) inventory.Ser
if len([]rune(rationale)) > 280 {
return utils.NewToolResultError("parameter rationale must be 280 characters or less"), nil, nil
}
suggest, err := OptionalParam[bool](args, "suggest")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}

if suggest {
suggestion := map[string]any{
"owner": owner,
"repo": repo,
"issue_number": issueNumber,
"issue_type": issueType,
"suggested": true,
}
if rationale != "" {
suggestion["rationale"] = rationale
}
r, err := json.Marshal(suggestion)
if err != nil {
return utils.NewToolResultErrorFromErr("failed to marshal suggestion", err), nil, nil
}
return utils.NewToolResultText(string(r)), nil, nil
}

client, err := deps.GetClient(ctx)
if err != nil {
Expand Down
Loading