Use the same ListOptions local as the other list helpers instead of embedding gitea_sdk.ListOptions in the composite literal.
182 lines
6.1 KiB
Go
182 lines
6.1 KiB
Go
package issue
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
|
|
|
gitea_sdk "gitea.dev/sdk"
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
)
|
|
|
|
// issueMeta carries owner/repo in the body; the SDK's IssueMeta only has Index
|
|
// and Gitea resolves the body repo from those fields.
|
|
type issueMeta struct {
|
|
Index int64 `json:"index"`
|
|
Owner string `json:"owner"`
|
|
Repo string `json:"repo"`
|
|
}
|
|
|
|
func listIssueBlocksFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
|
owner, repo, index, err := issueRef(args)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
page, pageSize := params.GetPagination(args, 30)
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
listOpt := gitea_sdk.ListOptions{Page: page, PageSize: pageSize}
|
|
issues, _, err := client.Issues.ListIssueBlocks(ctx, owner, repo, index, gitea_sdk.ListIssueBlocksOptions{
|
|
ListOptions: listOpt,
|
|
})
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list %v/%v/issue/%v/blocks err: %v", owner, repo, index, err))
|
|
}
|
|
return to.TextResult(slimIssues(issues))
|
|
}
|
|
|
|
func blockIssueFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
|
return setIssueBlockingFn(ctx, args, true)
|
|
}
|
|
|
|
func unblockIssueFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
|
return setIssueBlockingFn(ctx, args, false)
|
|
}
|
|
|
|
func setIssueBlockingFn(ctx context.Context, args map[string]any, block bool) (*mcp.CallToolResult, error) {
|
|
owner, repo, index, err := issueRef(args)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
blocked, err := params.GetIndex(args, "blocked_issue")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
blockedOwner, blockedRepo := relatedIssueRepo(args, "blocked_owner", "blocked_repo", owner, repo)
|
|
method := http.MethodPost
|
|
if !block {
|
|
method = http.MethodDelete
|
|
}
|
|
var issue gitea_sdk.Issue
|
|
path := fmt.Sprintf("repos/%s/%s/issues/%d/blocks", url.PathEscape(owner), url.PathEscape(repo), index)
|
|
if _, err := gitea.DoJSON(ctx, method, path, nil, issueMeta{Index: blocked, Owner: blockedOwner, Repo: blockedRepo}, &issue); err != nil {
|
|
return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/blocks err: %v", owner, repo, index, err))
|
|
}
|
|
return to.TextResult(slimIssue(&issue))
|
|
}
|
|
|
|
func listIssueDependenciesFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
|
owner, repo, index, err := issueRef(args)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
page, pageSize := params.GetPagination(args, 30)
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
listOpt := gitea_sdk.ListOptions{Page: page, PageSize: pageSize}
|
|
issues, _, err := client.Issues.ListIssueDependencies(ctx, owner, repo, index, gitea_sdk.ListIssueDependenciesOptions{
|
|
ListOptions: listOpt,
|
|
})
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err))
|
|
}
|
|
return to.TextResult(slimIssues(issues))
|
|
}
|
|
|
|
func addIssueDependencyFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
|
return setIssueDependencyFn(ctx, args, true)
|
|
}
|
|
|
|
func removeIssueDependencyFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
|
return setIssueDependencyFn(ctx, args, false)
|
|
}
|
|
|
|
func setIssueDependencyFn(ctx context.Context, args map[string]any, add bool) (*mcp.CallToolResult, error) {
|
|
owner, repo, index, err := issueRef(args)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
blocking, err := params.GetIndex(args, "blocking_issue")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
blockingOwner, blockingRepo := relatedIssueRepo(args, "blocking_owner", "blocking_repo", owner, repo)
|
|
method := http.MethodPost
|
|
if !add {
|
|
method = http.MethodDelete
|
|
}
|
|
var issue gitea_sdk.Issue
|
|
path := fmt.Sprintf("repos/%s/%s/issues/%d/dependencies", url.PathEscape(owner), url.PathEscape(repo), index)
|
|
if _, err := gitea.DoJSON(ctx, method, path, nil, issueMeta{Index: blocking, Owner: blockingOwner, Repo: blockingRepo}, &issue); err != nil {
|
|
return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err))
|
|
}
|
|
return to.TextResult(slimIssue(&issue))
|
|
}
|
|
|
|
func checkIssueBlockedFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
|
owner, repo, index, err := issueRef(args)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
page, pageSize := params.GetPagination(args, 30)
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
listOpt := gitea_sdk.ListOptions{Page: page, PageSize: pageSize}
|
|
issues, _, err := client.Issues.ListIssueDependencies(ctx, owner, repo, index, gitea_sdk.ListIssueDependenciesOptions{
|
|
ListOptions: listOpt,
|
|
})
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err))
|
|
}
|
|
openBlockers := make([]map[string]any, 0)
|
|
for _, issue := range issues {
|
|
if issue == nil {
|
|
continue
|
|
}
|
|
if issue.State == gitea_sdk.StateOpen || issue.State == "" {
|
|
openBlockers = append(openBlockers, slimIssue(issue))
|
|
}
|
|
}
|
|
return to.TextResult(map[string]any{
|
|
"blocked": len(openBlockers) > 0,
|
|
"total_dependencies": len(issues),
|
|
"open_blockers": len(openBlockers),
|
|
"blockers": slimIssues(issues),
|
|
"open": openBlockers,
|
|
})
|
|
}
|
|
|
|
func relatedIssueRepo(args map[string]any, ownerKey, repoKey, owner, repo string) (string, string) {
|
|
if o := params.GetOptionalString(args, ownerKey, ""); o != "" {
|
|
owner = o
|
|
}
|
|
if r := params.GetOptionalString(args, repoKey, ""); r != "" {
|
|
repo = r
|
|
}
|
|
return owner, repo
|
|
}
|
|
|
|
func issueRef(args map[string]any) (owner, repo string, index int64, err error) {
|
|
if owner, err = params.GetString(args, "owner"); err != nil {
|
|
return "", "", 0, err
|
|
}
|
|
if repo, err = params.GetString(args, "repo"); err != nil {
|
|
return "", "", 0, err
|
|
}
|
|
if index, err = params.GetIndex(args, "issue_number"); err != nil {
|
|
return "", "", 0, err
|
|
}
|
|
return owner, repo, index, nil
|
|
}
|