- errorlint: fmt.Errorf %v→%w across all handlers (errors now wrap the underlying SDK/HTTP error for errors.Is/As); errors.Is for context.Canceled in cmd - staticcheck quickfixes: Fprintf over WriteString(Sprintf), tagged switches, omit inferred 'any'; QF1001 resolved by hoisting hex checks into isHex predicates (normalizeColor, validateSHA) - govet: reflect.Ptr → reflect.Pointer in pkg/ptr - errcheck: explicit '_ =' for fs.Parse (ExitOnError) and deferred zap Sync - repair four test assertions the autofix broke (it dropped the 're.Code != X' half of combined type-assert checks, inverting the test); all errors.As sites use 'var re *resource.ResourceError' golangci-lint: 0 issues. staticcheck, vet, tests: clean.
125 lines
3.7 KiB
Go
125 lines
3.7 KiB
Go
package org
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"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"
|
|
)
|
|
|
|
const (
|
|
ListOrgMembersToolName = "list_org_members"
|
|
CheckOrgMembershipToolName = "check_org_membership"
|
|
RemoveOrgMemberToolName = "remove_org_member"
|
|
)
|
|
|
|
var (
|
|
ListOrgMembersTool = mcp.NewTool(
|
|
ListOrgMembersToolName,
|
|
mcp.WithDescription("List members of an organization"),
|
|
mcp.WithString("org", mcp.Required(), mcp.Description(params.Org)),
|
|
mcp.WithNumber("page", mcp.Required(), mcp.Description(params.Page), mcp.DefaultNumber(1), mcp.Min(1)),
|
|
mcp.WithNumber("limit", mcp.Required(), mcp.Description(params.Limit), mcp.DefaultNumber(100), mcp.Min(1)),
|
|
)
|
|
|
|
CheckOrgMembershipTool = mcp.NewTool(
|
|
CheckOrgMembershipToolName,
|
|
mcp.WithDescription("Check if a user is a member of an organization"),
|
|
mcp.WithString("org", mcp.Required(), mcp.Description(params.Org)),
|
|
mcp.WithString("user", mcp.Required(), mcp.Description(params.User)),
|
|
)
|
|
|
|
RemoveOrgMemberTool = mcp.NewTool(
|
|
RemoveOrgMemberToolName,
|
|
mcp.WithDescription("Remove a member from an organization"),
|
|
mcp.WithString("org", mcp.Required(), mcp.Description(params.Org)),
|
|
mcp.WithString("user", mcp.Required(), mcp.Description(params.User)),
|
|
)
|
|
)
|
|
|
|
func ListOrgMembersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called ListOrgMembersFn")
|
|
orgName, ok := req.GetArguments()["org"].(string)
|
|
if !ok {
|
|
return to.ErrorResult(errors.New("organization name is required"))
|
|
}
|
|
page, ok := req.GetArguments()["page"].(float64)
|
|
if !ok {
|
|
page = 1
|
|
}
|
|
limit, ok := req.GetArguments()["limit"].(float64)
|
|
if !ok {
|
|
limit = 100
|
|
}
|
|
|
|
opt := forgejo_sdk.ListOrgMembershipOption{
|
|
ListOptions: forgejo_sdk.ListOptions{
|
|
Page: int(page),
|
|
PageSize: int(limit),
|
|
},
|
|
}
|
|
client, err := forgejo.Client(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
members, _, err := client.ListOrgMembership(orgName, opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list org members err: %w", err))
|
|
}
|
|
return to.TextResult(members)
|
|
}
|
|
|
|
func CheckOrgMembershipFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called CheckOrgMembershipFn")
|
|
orgName, ok := req.GetArguments()["org"].(string)
|
|
if !ok {
|
|
return to.ErrorResult(errors.New("organization name is required"))
|
|
}
|
|
user, ok := req.GetArguments()["user"].(string)
|
|
if !ok {
|
|
return to.ErrorResult(errors.New("username is required"))
|
|
}
|
|
|
|
client, err := forgejo.Client(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
isMember, _, err := client.CheckOrgMembership(orgName, user)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("check org membership err: %w", err))
|
|
}
|
|
return to.TextResult(map[string]interface{}{
|
|
"org": orgName,
|
|
"user": user,
|
|
"is_member": isMember,
|
|
})
|
|
}
|
|
|
|
func RemoveOrgMemberFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called RemoveOrgMemberFn")
|
|
orgName, ok := req.GetArguments()["org"].(string)
|
|
if !ok {
|
|
return to.ErrorResult(errors.New("organization name is required"))
|
|
}
|
|
user, ok := req.GetArguments()["user"].(string)
|
|
if !ok {
|
|
return to.ErrorResult(errors.New("username is required"))
|
|
}
|
|
|
|
client, err := forgejo.Client(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
_, err = client.DeleteOrgMembership(orgName, user)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("remove org member err: %w", err))
|
|
}
|
|
return to.TextResult(fmt.Sprintf("User '%s' removed from organization '%s'", user, orgName))
|
|
}
|