257 lines
7.5 KiB
Go
257 lines
7.5 KiB
Go
package mirror
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
|
"gitea.com/gitea/gitea-mcp/pkg/log"
|
|
"gitea.com/gitea/gitea-mcp/pkg/params"
|
|
"gitea.com/gitea/gitea-mcp/pkg/to"
|
|
"gitea.com/gitea/gitea-mcp/pkg/tool"
|
|
|
|
gitea_sdk "code.gitea.io/sdk/gitea"
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
"github.com/mark3labs/mcp-go/server"
|
|
)
|
|
|
|
const (
|
|
ListPushMirrorsToolName = "list_push_mirrors"
|
|
GetPushMirrorToolName = "get_push_mirror"
|
|
CreatePushMirrorToolName = "create_push_mirror"
|
|
DeletePushMirrorToolName = "delete_push_mirror"
|
|
SyncMirrorToolName = "sync_mirror"
|
|
)
|
|
|
|
var Tool = tool.New()
|
|
|
|
var (
|
|
ListPushMirrorsTool = mcp.NewTool(
|
|
ListPushMirrorsToolName,
|
|
mcp.WithDescription("List push mirrors for a repository"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
|
)
|
|
|
|
GetPushMirrorTool = mcp.NewTool(
|
|
GetPushMirrorToolName,
|
|
mcp.WithDescription("Get a specific push mirror by remote name"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
|
mcp.WithString("remote_name", mcp.Required(), mcp.Description("Remote name")),
|
|
)
|
|
|
|
CreatePushMirrorTool = mcp.NewTool(
|
|
CreatePushMirrorToolName,
|
|
mcp.WithDescription("Create a push mirror for a repository"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
|
mcp.WithString("remote_name", mcp.Required(), mcp.Description("Remote name")),
|
|
mcp.WithString("remote_addr", mcp.Required(), mcp.Description("Remote address (git URL)")),
|
|
mcp.WithString("sync_interval", mcp.Description("Sync interval (e.g. 8h30m0s)")),
|
|
mcp.WithBoolean("sync_on_commit", mcp.Description("Sync on commit"), mcp.DefaultBool(false)),
|
|
)
|
|
|
|
DeletePushMirrorTool = mcp.NewTool(
|
|
DeletePushMirrorToolName,
|
|
mcp.WithDescription("Delete a push mirror"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
|
mcp.WithString("remote_name", mcp.Required(), mcp.Description("Remote name")),
|
|
)
|
|
|
|
SyncMirrorTool = mcp.NewTool(
|
|
SyncMirrorToolName,
|
|
mcp.WithDescription("Trigger immediate sync for a mirror repository"),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
|
)
|
|
)
|
|
|
|
func init() {
|
|
Tool.RegisterRead(server.ServerTool{
|
|
Tool: ListPushMirrorsTool,
|
|
Handler: listPushMirrorsFn,
|
|
})
|
|
Tool.RegisterRead(server.ServerTool{
|
|
Tool: GetPushMirrorTool,
|
|
Handler: getPushMirrorFn,
|
|
})
|
|
Tool.RegisterWrite(server.ServerTool{
|
|
Tool: CreatePushMirrorTool,
|
|
Handler: createPushMirrorFn,
|
|
})
|
|
Tool.RegisterWrite(server.ServerTool{
|
|
Tool: DeletePushMirrorTool,
|
|
Handler: deletePushMirrorFn,
|
|
})
|
|
Tool.RegisterWrite(server.ServerTool{
|
|
Tool: SyncMirrorTool,
|
|
Handler: syncMirrorFn,
|
|
})
|
|
}
|
|
|
|
func listPushMirrorsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("[Mirror] Called listPushMirrorsFn")
|
|
args := req.GetArguments()
|
|
owner, err := params.GetString(args, "owner")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
repo, err := params.GetString(args, "repo")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
|
|
mirrors, _, err := client.ListPushMirrors(owner, repo, gitea_sdk.ListOptions{})
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list push mirrors err: %v", err))
|
|
}
|
|
|
|
return to.TextResult(slimMirrors(mirrors))
|
|
}
|
|
|
|
func getPushMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("[Mirror] Called getPushMirrorFn")
|
|
args := req.GetArguments()
|
|
owner, err := params.GetString(args, "owner")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
repo, err := params.GetString(args, "repo")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
remoteName, err := params.GetString(args, "remote_name")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
|
|
mirror, _, err := client.GetPushMirrorByRemoteName(owner, repo, remoteName)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get push mirror err: %v", err))
|
|
}
|
|
|
|
return to.TextResult(slimMirror(mirror))
|
|
}
|
|
|
|
func createPushMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("[Mirror] Called createPushMirrorFn")
|
|
args := req.GetArguments()
|
|
owner, err := params.GetString(args, "owner")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
repo, err := params.GetString(args, "repo")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
remoteAddr, err := params.GetString(args, "remote_addr")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
syncInterval, _ := args["sync_interval"].(string)
|
|
syncOnCommit, _ := args["sync_on_commit"].(bool)
|
|
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
|
|
opt := gitea_sdk.CreatePushMirrorOption{
|
|
RemoteAddress: remoteAddr,
|
|
Interval: syncInterval,
|
|
SyncONCommit: syncOnCommit,
|
|
}
|
|
|
|
mirror, _, err := client.PushMirrors(owner, repo, opt)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("create push mirror err: %v", err))
|
|
}
|
|
|
|
return to.TextResult(slimMirror(mirror))
|
|
}
|
|
|
|
func deletePushMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("[Mirror] Called deletePushMirrorFn")
|
|
args := req.GetArguments()
|
|
owner, err := params.GetString(args, "owner")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
repo, err := params.GetString(args, "repo")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
remoteName, err := params.GetString(args, "remote_name")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
|
|
_, err = client.DeletePushMirror(owner, repo, remoteName)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("delete push mirror err: %v", err))
|
|
}
|
|
|
|
return to.TextResult("Push mirror deleted successfully")
|
|
}
|
|
|
|
func syncMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("[Mirror] Called syncMirrorFn")
|
|
args := req.GetArguments()
|
|
owner, err := params.GetString(args, "owner")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
repo, err := params.GetString(args, "repo")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
|
|
_, err = client.MirrorSync(owner, repo)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("sync mirror err: %v", err))
|
|
}
|
|
|
|
return to.TextResult("Mirror sync triggered successfully")
|
|
}
|
|
|
|
func slimMirrors(mirrors []*gitea_sdk.PushMirrorResponse) []map[string]interface{} {
|
|
result := make([]map[string]interface{}, len(mirrors))
|
|
for i, m := range mirrors {
|
|
result[i] = slimMirror(m)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func slimMirror(m *gitea_sdk.PushMirrorResponse) map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"remote_name": m.RemoteName,
|
|
"remote_addr": m.RemoteAddress,
|
|
"interval": m.Interval,
|
|
"sync_on_commit": m.SyncONCommit,
|
|
"last_update": m.LastUpdate,
|
|
"last_error": m.LastError,
|
|
}
|
|
}
|