Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ The following sets of tools are available (all are on by default):
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `title`: Issue title (string, required)
- `type`: Type of this issue (string, optional)

- **get_issue** - Get issue details
- `issue_number`: The number of the issue (number, required)
Expand Down Expand Up @@ -600,6 +601,7 @@ The following sets of tools are available (all are on by default):
- `repo`: Repository name (string, required)
- `state`: New state (string, optional)
- `title`: New title (string, optional)
- `type`: New issue type (string, optional)

</details>

Expand Down
4 changes: 4 additions & 0 deletions pkg/github/__toolsnaps__/create_issue.snap
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
"title": {
"description": "Issue title",
"type": "string"
},
"type": {
"description": "Type of this issue",
"type": "string"
}
},
"required": [
Expand Down
4 changes: 4 additions & 0 deletions pkg/github/__toolsnaps__/update_issue.snap
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
"title": {
"description": "New title",
"type": "string"
},
"type": {
"description": "New issue type",
"type": "string"
}
},
"required": [
Expand Down
22 changes: 22 additions & 0 deletions pkg/github/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,9 @@ func CreateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (t
mcp.WithNumber("milestone",
mcp.Description("Milestone number"),
),
mcp.WithString("type",
mcp.Description("Type of this issue"),
),
),
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
owner, err := RequiredParam[string](request, "owner")
Expand Down Expand Up @@ -832,13 +835,20 @@ func CreateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (t
milestoneNum = &milestone
}

// Get optional type
issueType, err := OptionalParam[string](request, "type")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}

// Create the issue request
issueRequest := &github.IssueRequest{
Title: github.Ptr(title),
Body: github.Ptr(body),
Assignees: &assignees,
Labels: &labels,
Milestone: milestoneNum,
Type: &issueType,
}

client, err := getClient(ctx)
Expand Down Expand Up @@ -1129,6 +1139,9 @@ func UpdateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (t
mcp.WithNumber("milestone",
mcp.Description("New milestone number"),
),
mcp.WithString("type",
mcp.Description("New issue type"),
),
),
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
owner, err := RequiredParam[string](request, "owner")
Expand Down Expand Up @@ -1199,6 +1212,15 @@ func UpdateIssue(getClient GetClientFn, t translations.TranslationHelperFunc) (t
issueRequest.Milestone = &milestoneNum
}

// Get issue type
issueType, err := OptionalParam[string](request, "type")
if err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
if issueType != "" {
issueRequest.Type = github.Ptr(issueType)
}

client, err := getClient(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
Expand Down
25 changes: 22 additions & 3 deletions pkg/github/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ func Test_CreateIssue(t *testing.T) {
assert.Contains(t, tool.InputSchema.Properties, "assignees")
assert.Contains(t, tool.InputSchema.Properties, "labels")
assert.Contains(t, tool.InputSchema.Properties, "milestone")
assert.Contains(t, tool.InputSchema.Properties, "type")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "title"})

// Setup mock issue for success case
Expand All @@ -593,6 +594,7 @@ func Test_CreateIssue(t *testing.T) {
Assignees: []*github.User{{Login: github.Ptr("user1")}, {Login: github.Ptr("user2")}},
Labels: []*github.Label{{Name: github.Ptr("bug")}, {Name: github.Ptr("help wanted")}},
Milestone: &github.Milestone{Number: github.Ptr(5)},
Type: &github.IssueType{Name: github.Ptr("Bug")},
}

tests := []struct {
Expand All @@ -614,6 +616,7 @@ func Test_CreateIssue(t *testing.T) {
"labels": []any{"bug", "help wanted"},
"assignees": []any{"user1", "user2"},
"milestone": float64(5),
"type": "Bug",
}).andThen(
mockResponse(t, http.StatusCreated, mockIssue),
),
Expand All @@ -627,6 +630,7 @@ func Test_CreateIssue(t *testing.T) {
"assignees": []any{"user1", "user2"},
"labels": []any{"bug", "help wanted"},
"milestone": float64(5),
"type": "Bug",
},
expectError: false,
expectedIssue: mockIssue,
Expand Down Expand Up @@ -722,6 +726,10 @@ func Test_CreateIssue(t *testing.T) {
assert.Equal(t, *tc.expectedIssue.Body, *returnedIssue.Body)
}

if tc.expectedIssue.Type != nil {
assert.Equal(t, *tc.expectedIssue.Type.Name, *returnedIssue.Type.Name)
}

// Check assignees if expected
if len(tc.expectedIssue.Assignees) > 0 {
assert.Equal(t, len(tc.expectedIssue.Assignees), len(returnedIssue.Assignees))
Expand Down Expand Up @@ -1066,6 +1074,7 @@ func Test_UpdateIssue(t *testing.T) {
assert.Contains(t, tool.InputSchema.Properties, "labels")
assert.Contains(t, tool.InputSchema.Properties, "assignees")
assert.Contains(t, tool.InputSchema.Properties, "milestone")
assert.Contains(t, tool.InputSchema.Properties, "type")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "issue_number"})

// Setup mock issue for success case
Expand All @@ -1078,6 +1087,7 @@ func Test_UpdateIssue(t *testing.T) {
Assignees: []*github.User{{Login: github.Ptr("assignee1")}, {Login: github.Ptr("assignee2")}},
Labels: []*github.Label{{Name: github.Ptr("bug")}, {Name: github.Ptr("priority")}},
Milestone: &github.Milestone{Number: github.Ptr(5)},
Type: &github.IssueType{Name: github.Ptr("Bug")},
}

tests := []struct {
Expand All @@ -1100,6 +1110,7 @@ func Test_UpdateIssue(t *testing.T) {
"labels": []any{"bug", "priority"},
"assignees": []any{"assignee1", "assignee2"},
"milestone": float64(5),
"type": "Bug",
}).andThen(
mockResponse(t, http.StatusOK, mockIssue),
),
Expand All @@ -1115,6 +1126,7 @@ func Test_UpdateIssue(t *testing.T) {
"labels": []any{"bug", "priority"},
"assignees": []any{"assignee1", "assignee2"},
"milestone": float64(5),
"type": "Bug",
},
expectError: false,
expectedIssue: mockIssue,
Expand All @@ -1126,24 +1138,27 @@ func Test_UpdateIssue(t *testing.T) {
mock.PatchReposIssuesByOwnerByRepoByIssueNumber,
mockResponse(t, http.StatusOK, &github.Issue{
Number: github.Ptr(123),
Title: github.Ptr("Only Title Updated"),
Title: github.Ptr("Updated Issue Title"),
HTMLURL: github.Ptr("https://github.com/owner/repo/issues/123"),
State: github.Ptr("open"),
Type: &github.IssueType{Name: github.Ptr("Feature")},
}),
),
),
requestArgs: map[string]interface{}{
"owner": "owner",
"repo": "repo",
"issue_number": float64(123),
"title": "Only Title Updated",
"title": "Updated Issue Title",
"type": "Feature",
},
expectError: false,
expectedIssue: &github.Issue{
Number: github.Ptr(123),
Title: github.Ptr("Only Title Updated"),
Title: github.Ptr("Updated Issue Title"),
HTMLURL: github.Ptr("https://github.com/owner/repo/issues/123"),
State: github.Ptr("open"),
Type: &github.IssueType{Name: github.Ptr("Feature")},
},
},
{
Expand Down Expand Up @@ -1232,6 +1247,10 @@ func Test_UpdateIssue(t *testing.T) {
assert.Equal(t, *tc.expectedIssue.Body, *returnedIssue.Body)
}

if tc.expectedIssue.Type != nil {
assert.Equal(t, *tc.expectedIssue.Type.Name, *returnedIssue.Type.Name)
}

// Check assignees if expected
if len(tc.expectedIssue.Assignees) > 0 {
assert.Len(t, returnedIssue.Assignees, len(tc.expectedIssue.Assignees))
Expand Down
Loading