fix(issue): include owner and repo in dependency request bodies #4

Merged
gronod merged 1 commits from fix/issue-meta-body into main 2026-09-15 16:24:10 +01:00
2 changed files with 34 additions and 26 deletions
+24 -24
View File
@@ -3,6 +3,8 @@ package issue
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"net/url"
"gitea.com/gitea/gitea-mcp/pkg/gitea" "gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/params" "gitea.com/gitea/gitea-mcp/pkg/params"
@@ -12,6 +14,14 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp" "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) { func listIssueBlocksFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
owner, repo, index, err := issueRef(args) owner, repo, index, err := issueRef(args)
if err != nil { if err != nil {
@@ -49,21 +59,16 @@ func setIssueBlockingFn(ctx context.Context, args map[string]any, block bool) (*
if err != nil { if err != nil {
return to.ErrorResult(err) return to.ErrorResult(err)
} }
client, err := gitea.ClientFromContext(ctx) method := http.MethodPost
if err != nil { if !block {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) method = http.MethodDelete
} }
meta := gitea_sdk.IssueMeta{Index: blocked} var issue gitea_sdk.Issue
var issue *gitea_sdk.Issue path := fmt.Sprintf("repos/%s/%s/issues/%d/blocks", url.PathEscape(owner), url.PathEscape(repo), index)
if block { if _, err := gitea.DoJSON(ctx, method, path, nil, issueMeta{Index: blocked, Owner: owner, Repo: repo}, &issue); err != nil {
issue, _, err = client.Issues.CreateIssueBlocking(ctx, owner, repo, index, meta)
} else {
issue, _, err = client.Issues.RemoveIssueBlocking(ctx, owner, repo, index, meta)
}
if err != nil {
return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/blocks err: %v", owner, repo, index, err)) return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/blocks err: %v", owner, repo, index, err))
} }
return to.TextResult(slimIssue(issue)) return to.TextResult(slimIssue(&issue))
} }
func listIssueDependenciesFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) { func listIssueDependenciesFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
@@ -103,21 +108,16 @@ func setIssueDependencyFn(ctx context.Context, args map[string]any, add bool) (*
if err != nil { if err != nil {
return to.ErrorResult(err) return to.ErrorResult(err)
} }
client, err := gitea.ClientFromContext(ctx) method := http.MethodPost
if err != nil { if !add {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) method = http.MethodDelete
} }
meta := gitea_sdk.IssueMeta{Index: blocking} var issue gitea_sdk.Issue
var issue *gitea_sdk.Issue path := fmt.Sprintf("repos/%s/%s/issues/%d/dependencies", url.PathEscape(owner), url.PathEscape(repo), index)
if add { if _, err := gitea.DoJSON(ctx, method, path, nil, issueMeta{Index: blocking, Owner: owner, Repo: repo}, &issue); err != nil {
issue, _, err = client.Issues.CreateIssueDependency(ctx, owner, repo, index, meta)
} else {
issue, _, err = client.Issues.RemoveIssueDependency(ctx, owner, repo, index, meta)
}
if err != nil {
return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err)) return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err))
} }
return to.TextResult(slimIssue(issue)) return to.TextResult(slimIssue(&issue))
} }
func issueRef(args map[string]any) (owner, repo string, index int64, err error) { func issueRef(args map[string]any) (owner, repo string, index int64, err error) {
+10 -2
View File
@@ -135,8 +135,16 @@ func Test_issueBlocking(t *testing.T) {
if tt.wantQuery != "" && gotQuery != tt.wantQuery { if tt.wantQuery != "" && gotQuery != tt.wantQuery {
t.Fatalf("query = %s, want %s", gotQuery, tt.wantQuery) t.Fatalf("query = %s, want %s", gotQuery, tt.wantQuery)
} }
if tt.wantIndex != 0 && gotBody["index"] != tt.wantIndex { if tt.wantIndex != 0 {
t.Fatalf("body index = %v, want %v", gotBody["index"], tt.wantIndex) if gotBody["index"] != tt.wantIndex {
t.Fatalf("body index = %v, want %v", gotBody["index"], tt.wantIndex)
}
if gotBody["owner"] != owner {
t.Fatalf("body owner = %v, want %s", gotBody["owner"], owner)
}
if gotBody["repo"] != repo {
t.Fatalf("body repo = %v, want %s", gotBody["repo"], repo)
}
} }
body := res.Content[0].(*mcp.TextContent).Text body := res.Content[0].(*mcp.TextContent).Text
if !strings.Contains(body, `"number":7`) && !strings.Contains(body, `"number": 7`) { if !strings.Contains(body, `"number":7`) && !strings.Contains(body, `"number": 7`) {