Files
gitea-mcp-server/mcp/operation/repo/status.go
T

139 lines
3.9 KiB
Go

package repo
import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/errors"
"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_sdk "code.gitea.io/sdk/gitea"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
const (
CreateCommitStatusToolName = "create_commit_status"
)
var (
CreateCommitStatusTool = mcp.NewTool(
CreateCommitStatusToolName,
mcp.WithDescription("Create a commit status check for a repository. Adds a new status context to a commit without overwriting existing statuses."),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("sha", mcp.Required(), mcp.Description("commit SHA (full 40-character SHA or short SHA)")),
mcp.WithString("state", mcp.Required(), mcp.Description("status state: pending, success, error, or failure")),
mcp.WithString("target_url", mcp.Description("URL with more details about the status (e.g., review environment link like https://review.lumbridgecorp.com)")),
mcp.WithString("context", mcp.Description("status context identifier (e.g., 'ci/metal', 'ci/cloud-1', 'continuous-integration/jenkins')"), mcp.DefaultString("default")),
mcp.WithString("description", mcp.Description("short description of the status")),
)
)
func init() {
Tool.RegisterWrite(server.ServerTool{
Tool: CreateCommitStatusTool,
Handler: CreateCommitStatusFn,
})
}
// CreateCommitStatusFn creates a status check for a commit
func CreateCommitStatusFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateCommitStatusFn")
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)
}
sha, err := params.GetString(args, "sha")
if err != nil {
return to.ErrorResult(err)
}
state, err := params.GetString(args, "state")
if err != nil {
return to.ErrorResult(err)
}
statusState, err := parseStatusState(state)
if err != nil {
return to.ErrorResult(fmt.Errorf("invalid state '%s': must be one of pending, success, failure, error", state))
}
targetURL, _ := args["target_url"].(string)
context, _ := args["context"].(string)
description, _ := args["description"].(string)
// Use default context if not provided
if context == "" {
context = "default"
}
opt := gitea_sdk.CreateStatusOption{
State: statusState,
TargetURL: targetURL,
Context: context,
Description: description,
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
status, _, err := client.CreateStatus(owner, repo, sha, opt)
if err != nil {
translatedErr := errors.TranslateError(err, map[string]string{
"operation": "CreateCommitStatus",
"owner": owner,
"repo": repo,
"sha": sha,
"state": state,
"context": context,
})
return to.ErrorResult(translatedErr)
}
return to.TextResult(slimStatus(status))
}
// parseStatusState converts a string state to gitea_sdk.StatusState
func parseStatusState(state string) (gitea_sdk.StatusState, error) {
switch state {
case "pending":
return gitea_sdk.StatusPending, nil
case "success":
return gitea_sdk.StatusSuccess, nil
case "failure":
return gitea_sdk.StatusFailure, nil
case "error":
return gitea_sdk.StatusError, nil
default:
return "", fmt.Errorf("invalid state: %s", state)
}
}
// slimStatus creates a slimmed down representation of a commit status
func slimStatus(s *gitea_sdk.Status) map[string]any {
if s == nil {
return nil
}
return map[string]any{
"id": s.ID,
"state": s.State,
"target_url": s.TargetURL,
"context": s.Context,
"description": s.Description,
}
}