Update all import paths from forgejo-sdk/forgejo/v2 to v3. No breaking API changes affect this codebase; build and tests pass.
563 lines
20 KiB
Go
563 lines
20 KiB
Go
package issue
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"codeberg.org/goern/forgejo-mcp/v2/operation/params"
|
|
"codeberg.org/goern/forgejo-mcp/v2/pkg/forgejo"
|
|
"codeberg.org/goern/forgejo-mcp/v2/pkg/log"
|
|
"codeberg.org/goern/forgejo-mcp/v2/pkg/to"
|
|
|
|
forgejo_sdk "codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v3"
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
"github.com/mark3labs/mcp-go/server"
|
|
)
|
|
|
|
const (
|
|
GetIssueByIndexToolName = "get_issue_by_index"
|
|
ListRepoIssuesToolName = "list_repo_issues"
|
|
CreateIssueToolName = "create_issue"
|
|
CreateIssueCommentToolName = "create_issue_comment"
|
|
UpdateIssueToolName = "update_issue"
|
|
AddIssueLabelsToolName = "add_issue_labels"
|
|
RemoveIssueLabelsToolName = "remove_issue_labels"
|
|
IssueStateChangeToolName = "issue_state_change"
|
|
ListIssueCommentsToolName = "list_issue_comments"
|
|
GetIssueCommentToolName = "get_issue_comment"
|
|
EditIssueCommentToolName = "edit_issue_comment"
|
|
DeleteIssueCommentToolName = "delete_issue_comment"
|
|
ListRepoMilestonesToolName = "list_repo_milestones"
|
|
ListRepoLabelsToolName = "list_repo_labels"
|
|
)
|
|
|
|
var (
|
|
GetIssueByIndexTool = mcp.NewTool(
|
|
GetIssueByIndexToolName,
|
|
mcp.WithDescription("Get issue by index"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("index", mcp.Required(), mcp.Description(params.IssueIndex)),
|
|
)
|
|
|
|
ListRepoIssuesTool = mcp.NewTool(
|
|
ListRepoIssuesToolName,
|
|
mcp.WithDescription("List repo issues"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithString("state", mcp.Description("State (open|closed|all)"), mcp.DefaultString("open")),
|
|
mcp.WithString("type", mcp.Description("Type (issues|pulls)")),
|
|
mcp.WithString("milestones", mcp.Description("Milestone names/IDs (comma-separated)")),
|
|
mcp.WithString("labels", mcp.Description("Labels (comma-separated)")),
|
|
mcp.WithNumber("page", mcp.Description(params.Page), mcp.DefaultNumber(1)),
|
|
mcp.WithNumber("limit", mcp.Description(params.Limit), mcp.DefaultNumber(20)),
|
|
)
|
|
|
|
CreateIssueTool = mcp.NewTool(
|
|
CreateIssueToolName,
|
|
mcp.WithDescription("Create issue"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithString("title", mcp.Required(), mcp.Description(params.Title)),
|
|
mcp.WithString("body", mcp.Description(params.Body)),
|
|
)
|
|
|
|
CreateIssueCommentTool = mcp.NewTool(
|
|
CreateIssueCommentToolName,
|
|
mcp.WithDescription("Create issue comment"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("index", mcp.Required(), mcp.Description(params.Index)),
|
|
mcp.WithString("body", mcp.Required(), mcp.Description(params.Body)),
|
|
)
|
|
|
|
UpdateIssueTool = mcp.NewTool(
|
|
UpdateIssueToolName,
|
|
mcp.WithDescription("Update issue"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("index", mcp.Required(), mcp.Description(params.IssueIndex)),
|
|
mcp.WithString("title", mcp.Description(params.Title)),
|
|
mcp.WithString("body", mcp.Description(params.Body)),
|
|
mcp.WithString("assignee", mcp.Description("Assignee username")),
|
|
mcp.WithString("milestone", mcp.Description(params.Milestone)),
|
|
)
|
|
|
|
AddIssueLabelsTools = mcp.NewTool(
|
|
AddIssueLabelsToolName,
|
|
mcp.WithDescription("Add labels to issue"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("index", mcp.Required(), mcp.Description(params.IssueIndex)),
|
|
mcp.WithString("labels", mcp.Required(), mcp.Description("Labels to add (comma-separated)")),
|
|
)
|
|
|
|
RemoveIssueLabelsTools = mcp.NewTool(
|
|
RemoveIssueLabelsToolName,
|
|
mcp.WithDescription("Remove labels from issue"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("index", mcp.Required(), mcp.Description(params.IssueIndex)),
|
|
mcp.WithString("labels", mcp.Required(), mcp.Description("Labels to remove (comma-separated label IDs)")),
|
|
)
|
|
|
|
IssueStateChangeTool = mcp.NewTool(
|
|
IssueStateChangeToolName,
|
|
mcp.WithDescription("Change issue state"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("index", mcp.Required(), mcp.Description(params.IssueIndex)),
|
|
mcp.WithString("state", mcp.Required(), mcp.Description("State (open|closed)")),
|
|
)
|
|
|
|
ListIssueCommentsTool = mcp.NewTool(
|
|
ListIssueCommentsToolName,
|
|
mcp.WithDescription("List issue/PR comments"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("index", mcp.Required(), mcp.Description(params.Index)),
|
|
mcp.WithString("since", mcp.Description(params.Since)),
|
|
mcp.WithString("before", mcp.Description(params.Before)),
|
|
mcp.WithNumber("page", mcp.Description(params.Page), mcp.DefaultNumber(1)),
|
|
mcp.WithNumber("limit", mcp.Description(params.Limit), mcp.DefaultNumber(20)),
|
|
)
|
|
|
|
GetIssueCommentTool = mcp.NewTool(
|
|
GetIssueCommentToolName,
|
|
mcp.WithDescription("Get comment by ID"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("comment_id", mcp.Required(), mcp.Description(params.CommentID)),
|
|
)
|
|
|
|
EditIssueCommentTool = mcp.NewTool(
|
|
EditIssueCommentToolName,
|
|
mcp.WithDescription("Edit issue/PR comment"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("comment_id", mcp.Required(), mcp.Description(params.CommentID)),
|
|
mcp.WithString("body", mcp.Required(), mcp.Description(params.Body)),
|
|
)
|
|
|
|
DeleteIssueCommentTool = mcp.NewTool(
|
|
DeleteIssueCommentToolName,
|
|
mcp.WithDescription("Delete issue/PR comment"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("comment_id", mcp.Required(), mcp.Description(params.CommentID)),
|
|
)
|
|
|
|
ListRepoMilestonesTool = mcp.NewTool(
|
|
ListRepoMilestonesToolName,
|
|
mcp.WithDescription("List repository milestones"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("page", mcp.Description(params.Page), mcp.DefaultNumber(1)),
|
|
mcp.WithNumber("limit", mcp.Description(params.Limit), mcp.DefaultNumber(100)),
|
|
mcp.WithString("state", mcp.Description("Milestone state (open|closed|all)"), mcp.DefaultString("open")),
|
|
)
|
|
|
|
ListRepoLabelsTool = mcp.NewTool(
|
|
ListRepoLabelsToolName,
|
|
mcp.WithDescription("List repository labels"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)),
|
|
mcp.WithNumber("page", mcp.Description(params.Page), mcp.DefaultNumber(1)),
|
|
mcp.WithNumber("limit", mcp.Description(params.Limit), mcp.DefaultNumber(100)),
|
|
)
|
|
)
|
|
|
|
func RegisterTool(s *server.MCPServer) {
|
|
s.AddTool(GetIssueByIndexTool, GetIssueByIndexFn)
|
|
s.AddTool(ListRepoIssuesTool, ListRepoIssuesFn)
|
|
s.AddTool(CreateIssueTool, CreateIssueFn)
|
|
s.AddTool(CreateIssueCommentTool, CreateIssueCommentFn)
|
|
s.AddTool(UpdateIssueTool, UpdateIssueFn)
|
|
s.AddTool(AddIssueLabelsTools, AddIssueLabelsFn)
|
|
s.AddTool(RemoveIssueLabelsTools, RemoveIssueLabelsFn)
|
|
s.AddTool(IssueStateChangeTool, IssueStateChangeFn)
|
|
s.AddTool(ListIssueCommentsTool, ListIssueCommentsFn)
|
|
s.AddTool(GetIssueCommentTool, GetIssueCommentFn)
|
|
s.AddTool(EditIssueCommentTool, EditIssueCommentFn)
|
|
s.AddTool(DeleteIssueCommentTool, DeleteIssueCommentFn)
|
|
s.AddTool(ListRepoMilestonesTool, ListRepoMilestonesFn)
|
|
s.AddTool(ListRepoLabelsTool, ListRepoLabelsFn)
|
|
}
|
|
|
|
func GetIssueByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called GetIssueByIndexFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
index, _ := to.Float64(req.GetArguments()["index"])
|
|
|
|
issue, _, err := forgejo.Client().GetIssue(owner, repo, int64(index))
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get issue err: %v", err))
|
|
}
|
|
return to.TextResult(issue)
|
|
}
|
|
|
|
func ListRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called ListRepoIssuesFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
state, ok := req.GetArguments()["state"].(string)
|
|
if !ok {
|
|
state = "open"
|
|
}
|
|
issueType, _ := req.GetArguments()["type"].(string)
|
|
milestones, _ := req.GetArguments()["milestones"].(string)
|
|
labels, _ := req.GetArguments()["labels"].(string)
|
|
page, _ := to.Float64(req.GetArguments()["page"])
|
|
if page == 0 {
|
|
page = 1
|
|
}
|
|
limit, _ := to.Float64(req.GetArguments()["limit"])
|
|
if limit == 0 {
|
|
limit = 20
|
|
}
|
|
|
|
// Create ListIssueOption according to the Forgejo API
|
|
opt := forgejo_sdk.ListIssueOption{
|
|
// State is correctly set directly
|
|
State: forgejo_sdk.StateType(state),
|
|
// ListOptions maps directly
|
|
ListOptions: forgejo_sdk.ListOptions{
|
|
Page: int(page),
|
|
PageSize: int(limit),
|
|
},
|
|
}
|
|
|
|
// Set issue type if provided (convert to string parameters)
|
|
if issueType != "" {
|
|
// Note: Using optional parameters since IssueType is not directly assignable
|
|
}
|
|
|
|
// Set milestones if provided
|
|
if milestones != "" {
|
|
opt.Milestones = strings.Split(milestones, ",")
|
|
}
|
|
|
|
// Set labels if provided
|
|
if labels != "" {
|
|
opt.Labels = strings.Split(labels, ",")
|
|
}
|
|
|
|
issues, _, err := forgejo.Client().ListRepoIssues(owner, repo, opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get issues list err: %v", err))
|
|
}
|
|
return to.TextResult(issues)
|
|
}
|
|
|
|
func CreateIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called CreateIssueFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
title, _ := req.GetArguments()["title"].(string)
|
|
body, _ := req.GetArguments()["body"].(string)
|
|
|
|
opt := forgejo_sdk.CreateIssueOption{
|
|
Title: title,
|
|
Body: body,
|
|
}
|
|
issue, _, err := forgejo.Client().CreateIssue(owner, repo, opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("create issue err: %v", err))
|
|
}
|
|
return to.TextResult(issue)
|
|
}
|
|
|
|
func CreateIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called CreateIssueCommentFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
index, _ := to.Float64(req.GetArguments()["index"])
|
|
body, _ := req.GetArguments()["body"].(string)
|
|
|
|
opt := forgejo_sdk.CreateIssueCommentOption{
|
|
Body: body,
|
|
}
|
|
comment, _, err := forgejo.Client().CreateIssueComment(owner, repo, int64(index), opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("create issue comment err: %v", err))
|
|
}
|
|
return to.TextResult(comment)
|
|
}
|
|
|
|
func UpdateIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called UpdateIssueFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
index, _ := to.Float64(req.GetArguments()["index"])
|
|
title, _ := req.GetArguments()["title"].(string)
|
|
body, _ := req.GetArguments()["body"].(string)
|
|
// assignee is not supported in the current SDK
|
|
milestone, _ := req.GetArguments()["milestone"].(string)
|
|
|
|
opt := forgejo_sdk.EditIssueOption{}
|
|
|
|
// Only set fields that were provided
|
|
if title != "" {
|
|
opt.Title = title
|
|
}
|
|
if body != "" {
|
|
opt.Body = &body
|
|
}
|
|
// Note: Assignee field doesn't exist in EditIssueOption
|
|
// Using collaborators field would require changes to the API
|
|
if milestone != "" {
|
|
milestoneID, err := strconv.ParseInt(milestone, 10, 64)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("invalid milestone ID: %v", err))
|
|
}
|
|
opt.Milestone = &milestoneID
|
|
}
|
|
|
|
issue, _, err := forgejo.Client().EditIssue(owner, repo, int64(index), opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("update issue err: %v", err))
|
|
}
|
|
return to.TextResult(issue)
|
|
}
|
|
|
|
func AddIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called AddIssueLabelsFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
index, _ := to.Float64(req.GetArguments()["index"])
|
|
labels, _ := req.GetArguments()["labels"].(string)
|
|
|
|
// Get the ID for each label
|
|
// Since we can't directly use label names, we need to fetch the IDs first
|
|
// This modified approach treats the labels as numeric IDs
|
|
labelIDs := []int64{}
|
|
|
|
for _, labelStr := range strings.Split(labels, ",") {
|
|
labelStr = strings.TrimSpace(labelStr)
|
|
labelID, err := strconv.ParseInt(labelStr, 10, 64)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("invalid label ID '%s': %v - labels must be numeric IDs", labelStr, err))
|
|
}
|
|
labelIDs = append(labelIDs, labelID)
|
|
}
|
|
|
|
// Create IssueLabelsOption with numeric IDs
|
|
opt := forgejo_sdk.IssueLabelsOption{
|
|
Labels: labelIDs,
|
|
}
|
|
|
|
_, _, err := forgejo.Client().AddIssueLabels(owner, repo, int64(index), opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("add issue labels err: %v", err))
|
|
}
|
|
|
|
// Fetch the updated issue to return it with the new labels
|
|
issue, _, err := forgejo.Client().GetIssue(owner, repo, int64(index))
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get updated issue err: %v", err))
|
|
}
|
|
return to.TextResult(issue)
|
|
}
|
|
|
|
func RemoveIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called RemoveIssueLabelsFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
index, _ := to.Float64(req.GetArguments()["index"])
|
|
labels, _ := req.GetArguments()["labels"].(string)
|
|
|
|
for _, labelStr := range strings.Split(labels, ",") {
|
|
labelStr = strings.TrimSpace(labelStr)
|
|
labelID, err := strconv.ParseInt(labelStr, 10, 64)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("invalid label ID '%s': %v - labels must be numeric IDs", labelStr, err))
|
|
}
|
|
_, err = forgejo.Client().DeleteIssueLabel(owner, repo, int64(index), labelID)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("remove issue label err: %v", err))
|
|
}
|
|
}
|
|
|
|
// Fetch the updated issue to return it with the updated labels
|
|
issue, _, err := forgejo.Client().GetIssue(owner, repo, int64(index))
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get updated issue err: %v", err))
|
|
}
|
|
return to.TextResult(issue)
|
|
}
|
|
|
|
func IssueStateChangeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called IssueStateChangeFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
index, _ := to.Float64(req.GetArguments()["index"])
|
|
state, _ := req.GetArguments()["state"].(string)
|
|
|
|
if state != "open" && state != "closed" {
|
|
return to.ErrorResult(fmt.Errorf("invalid state: %s, must be 'open' or 'closed'", state))
|
|
}
|
|
|
|
// Convert string to StateType and create pointer
|
|
stateType := forgejo_sdk.StateType(state)
|
|
|
|
opt := forgejo_sdk.EditIssueOption{
|
|
State: &stateType,
|
|
}
|
|
|
|
issue, _, err := forgejo.Client().EditIssue(owner, repo, int64(index), opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("change issue state err: %v", err))
|
|
}
|
|
return to.TextResult(issue)
|
|
}
|
|
|
|
func ListIssueCommentsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called ListIssueCommentsFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
index, _ := to.Float64(req.GetArguments()["index"])
|
|
since, _ := req.GetArguments()["since"].(string)
|
|
before, _ := req.GetArguments()["before"].(string)
|
|
page, _ := to.Float64(req.GetArguments()["page"])
|
|
if page == 0 {
|
|
page = 1
|
|
}
|
|
limit, _ := to.Float64(req.GetArguments()["limit"])
|
|
if limit == 0 {
|
|
limit = 20
|
|
}
|
|
|
|
opt := forgejo_sdk.ListIssueCommentOptions{
|
|
ListOptions: forgejo_sdk.ListOptions{
|
|
Page: int(page),
|
|
PageSize: int(limit),
|
|
},
|
|
}
|
|
|
|
// Set time filters if provided
|
|
if since != "" {
|
|
sinceTime, err := time.Parse(time.RFC3339, since)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("invalid since time format (expected RFC3339): %v", err))
|
|
}
|
|
opt.Since = sinceTime
|
|
}
|
|
if before != "" {
|
|
beforeTime, err := time.Parse(time.RFC3339, before)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("invalid before time format (expected RFC3339): %v", err))
|
|
}
|
|
opt.Before = beforeTime
|
|
}
|
|
|
|
comments, _, err := forgejo.Client().ListIssueComments(owner, repo, int64(index), opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list issue comments err: %v", err))
|
|
}
|
|
return to.TextResult(comments)
|
|
}
|
|
|
|
func GetIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called GetIssueCommentFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
commentID, _ := to.Float64(req.GetArguments()["comment_id"])
|
|
|
|
comment, _, err := forgejo.Client().GetIssueComment(owner, repo, int64(commentID))
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get issue comment err: %v", err))
|
|
}
|
|
return to.TextResult(comment)
|
|
}
|
|
|
|
func EditIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called EditIssueCommentFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
commentID, _ := to.Float64(req.GetArguments()["comment_id"])
|
|
body, _ := req.GetArguments()["body"].(string)
|
|
|
|
opt := forgejo_sdk.EditIssueCommentOption{
|
|
Body: body,
|
|
}
|
|
comment, _, err := forgejo.Client().EditIssueComment(owner, repo, int64(commentID), opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("edit issue comment err: %v", err))
|
|
}
|
|
return to.TextResult(comment)
|
|
}
|
|
|
|
func DeleteIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called DeleteIssueCommentFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
commentID, _ := to.Float64(req.GetArguments()["comment_id"])
|
|
|
|
_, err := forgejo.Client().DeleteIssueComment(owner, repo, int64(commentID))
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("delete issue comment err: %v", err))
|
|
}
|
|
return to.TextResult("Delete comment success")
|
|
}
|
|
func ListRepoMilestonesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called ListRepoMilestonesFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
state, ok := req.GetArguments()["state"].(string)
|
|
if !ok || state == "" {
|
|
state = "open"
|
|
}
|
|
page, _ := to.Float64(req.GetArguments()["page"])
|
|
if page == 0 {
|
|
page = 1
|
|
}
|
|
limit, _ := to.Float64(req.GetArguments()["limit"])
|
|
if limit == 0 {
|
|
limit = 100
|
|
}
|
|
|
|
opt := forgejo_sdk.ListMilestoneOption{
|
|
ListOptions: forgejo_sdk.ListOptions{
|
|
Page: int(page),
|
|
PageSize: int(limit),
|
|
},
|
|
State: forgejo_sdk.StateType(state),
|
|
}
|
|
|
|
milestones, _, err := forgejo.Client().ListRepoMilestones(owner, repo, opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list repo milestones err: %v", err))
|
|
}
|
|
return to.TextResult(milestones)
|
|
}
|
|
|
|
func ListRepoLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called ListRepoLabelsFn")
|
|
owner, _ := req.GetArguments()["owner"].(string)
|
|
repo, _ := req.GetArguments()["repo"].(string)
|
|
page, _ := to.Float64(req.GetArguments()["page"])
|
|
if page == 0 {
|
|
page = 1
|
|
}
|
|
limit, _ := to.Float64(req.GetArguments()["limit"])
|
|
if limit == 0 {
|
|
limit = 100
|
|
}
|
|
|
|
opt := forgejo_sdk.ListLabelsOptions{
|
|
ListOptions: forgejo_sdk.ListOptions{
|
|
Page: int(page),
|
|
PageSize: int(limit),
|
|
},
|
|
}
|
|
|
|
labels, _, err := forgejo.Client().ListRepoLabels(owner, repo, opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list repo labels err: %v", err))
|
|
}
|
|
return to.TextResult(labels)
|
|
}
|