From 8728c04748e701a383fa488cf9340691b62ee165 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 22 Feb 2026 17:10:04 +0000 Subject: [PATCH] chore: add golangci-lint, bump Go to 1.26, fix all lint issues (#133) ## Summary - Add `.golangci.yml` with linter configuration matching the main gitea repo - Add `lint`, `lint-fix`, `lint-go`, `lint-go-fix`, and `security-check` Makefile targets - Add `tidy` Makefile target (extracts min Go version from `go.mod` for `-compat` flag) - Bump minimum Go version to 1.26 - Update golangci-lint to v2.10.1 - Replace `golang/govulncheck-action` with `make security-check` in CI - Add `make lint` step to CI - Fix all lint issues across the codebase (formatting, `errors.New` vs `fmt.Errorf`, `any` vs `interface{}`, unused returns, stuttering names, Go 1.26 `new(expr)`, etc.) - Remove unused `pkg/ptr` package (inlined by Go 1.26 `new(expr)`) - Remove dead linter exclusions (staticcheck, gocritic, testifylint, dupl) ## Test plan - [x] `make lint` passes - [x] `go test ./...` passes - [x] `make build` succeeds Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/133 Reviewed-by: techknowlogick Co-authored-by: silverwind Co-committed-by: silverwind --- .gitea/workflows/test-pr.yml | 17 +- .golangci.yml | 113 +++++++ Makefile | 33 ++- cmd/cmd.go | 4 +- go.mod | 2 +- main.go | 4 +- operation/actions/actions.go | 2 - operation/actions/logs.go | 31 +- operation/actions/logs_test.go | 2 - operation/actions/runs.go | 109 +++---- operation/actions/secrets.go | 33 ++- operation/actions/variables.go | 72 ++--- operation/issue/issue.go | 50 ++-- operation/label/label.go | 393 ++++++++++++------------- operation/milestone/milestone.go | 34 +-- operation/operation.go | 4 +- operation/pull/pull.go | 140 ++++----- operation/pull/pull_test.go | 10 +- operation/repo/branch.go | 17 +- operation/repo/commit.go | 9 +- operation/repo/file.go | 36 +-- operation/repo/release.go | 36 +-- operation/repo/repo.go | 5 +- operation/repo/tag.go | 23 +- operation/search/search.go | 32 +- operation/timetracking/timetracking.go | 33 ++- operation/wiki/wiki.go | 39 +-- pkg/gitea/gitea.go | 2 +- pkg/gitea/rest.go | 15 +- pkg/gitea/rest_test.go | 2 - pkg/log/log.go | 5 +- pkg/params/params.go | 2 +- pkg/params/params_test.go | 20 +- pkg/ptr/ptr.go | 73 ----- 34 files changed, 727 insertions(+), 675 deletions(-) create mode 100644 .golangci.yml delete mode 100644 pkg/ptr/ptr.go diff --git a/.gitea/workflows/test-pr.yml b/.gitea/workflows/test-pr.yml index 149102b..83879f5 100644 --- a/.gitea/workflows/test-pr.yml +++ b/.gitea/workflows/test-pr.yml @@ -11,16 +11,9 @@ jobs: - uses: actions/setup-go@v5 with: go-version-file: 'go.mod' + - name: lint + run: make lint - name: build - run: | - make build - - govulncheck_job: - runs-on: ubuntu-latest - name: Run govulncheck - steps: - - id: govulncheck - uses: golang/govulncheck-action@v1 - with: - go-version-file: 'go.mod' - go-package: ./... \ No newline at end of file + run: make build + - name: security-check + run: make security-check diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..4d035c7 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,113 @@ +version: "2" +output: + sort-order: + - file +linters: + default: none + enable: + - bidichk + - bodyclose + - depguard + - errcheck + - forbidigo + - gocheckcompilerdirectives + - gocritic + - govet + - ineffassign + - mirror + - modernize + - nakedret + - nilnil + - nolintlint + - perfsprint + - revive + - staticcheck + - testifylint + - unconvert + - unparam + - unused + - usestdlibvars + - usetesting + - wastedassign + settings: + depguard: + rules: + main: + deny: + - pkg: io/ioutil + desc: use os or io instead + - pkg: golang.org/x/exp + desc: it's experimental and unreliable + - pkg: github.com/pkg/errors + desc: use builtin errors package instead + nolintlint: + allow-unused: false + require-explanation: true + require-specific: true + gocritic: + enabled-checks: + - equalFold + disabled-checks: [] + revive: + severity: error + rules: + - name: blank-imports + - name: constant-logical-expr + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: empty-lines + - name: error-return + - name: error-strings + - name: exported + - name: identical-branches + - name: if-return + - name: increment-decrement + - name: modifies-value-receiver + - name: package-comments + - name: redefines-builtin-id + - name: superfluous-else + - name: time-naming + - name: unexported-return + - name: var-declaration + - name: var-naming + disabled: true + staticcheck: + checks: + - all + testifylint: {} + usetesting: + os-temp-dir: true + perfsprint: + concat-loop: false + govet: + enable: + - nilness + - unusedwrite + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - errcheck + - staticcheck + - unparam + path: _test\.go +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +formatters: + enable: + - gofmt + - gofumpt + settings: + gofumpt: + extra-rules: true + exclusions: + generated: lax +run: + timeout: 10m diff --git a/Makefile b/Makefile index 7d5ea25..104291f 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,10 @@ EXECUTABLE := gitea-mcp VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//') LDFLAGS := -X "main.Version=$(VERSION)" +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1 +GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 +GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.2 + .PHONY: help help: ## Print this help message. @echo "Usage: make [target]" @@ -45,8 +49,29 @@ air: ## Install air for hot reload. dev: air ## run the application with hot reload air --build.cmd "make build" --build.bin ./gitea-mcp +.PHONY: lint +lint: lint-go ## lint everything + +.PHONY: lint-fix +lint-fix: lint-go-fix ## lint everything and fix issues + +.PHONY: lint-go +lint-go: ## lint go files + $(GO) run $(GOLANGCI_LINT_PACKAGE) run + +.PHONY: lint-go-fix +lint-go-fix: ## lint go files and fix issues + $(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix + +.PHONY: security-check +security-check: ## run security check + $(GO) run $(GOVULNCHECK_PACKAGE) -show color ./... || true + +.PHONY: tidy +tidy: ## run go mod tidy + $(eval MIN_GO_VERSION := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2)) + $(GO) mod tidy -compat=$(MIN_GO_VERSION) + .PHONY: vendor -vendor: ## tidy and verify module dependencies - @echo 'Tidying and verifying module dependencies...' - go mod tidy - go mod verify +vendor: tidy ## tidy and verify module dependencies + $(GO) mod verify diff --git a/cmd/cmd.go b/cmd/cmd.go index 3ec886f..77fd590 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -99,12 +99,12 @@ func init() { } func Execute() { - defer log.Default().Sync() + defer log.Default().Sync() //nolint:errcheck // best-effort flush if err := operation.Run(); err != nil { if err == context.Canceled { log.Info("Server shutdown due to context cancellation") return } - log.Fatalf("Run Gitea MCP Server Error: %v", err) + log.Fatalf("Run Gitea MCP Server Error: %v", err) //nolint:gocritic // intentional exit after defer } } diff --git a/go.mod b/go.mod index 39686ed..772a1d4 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module gitea.com/gitea/gitea-mcp -go 1.24.0 +go 1.26.0 require ( code.gitea.io/sdk/gitea v0.22.1 diff --git a/main.go b/main.go index 860ee00..fa5c489 100644 --- a/main.go +++ b/main.go @@ -5,9 +5,7 @@ import ( "gitea.com/gitea/gitea-mcp/pkg/flag" ) -var ( - Version = "dev" -) +var Version = "dev" func init() { flag.Version = Version diff --git a/operation/actions/actions.go b/operation/actions/actions.go index ebffe70..3c314cc 100644 --- a/operation/actions/actions.go +++ b/operation/actions/actions.go @@ -6,5 +6,3 @@ import ( // Tool is the registry for all Actions-related MCP tools. var Tool = tool.New() - - diff --git a/operation/actions/logs.go b/operation/actions/logs.go index 188b83a..2dc1d87 100644 --- a/operation/actions/logs.go +++ b/operation/actions/logs.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net/http" "net/url" "os" "path/filepath" @@ -67,7 +68,7 @@ func fetchJobLogBytes(ctx context.Context, owner, repo string, jobID int64) ([]b } lastErr = err var httpErr *gitea.HTTPError - if errors.As(err, &httpErr) && (httpErr.StatusCode == 404 || httpErr.StatusCode == 405) { + if errors.As(err, &httpErr) && (httpErr.StatusCode == http.StatusNotFound || httpErr.StatusCode == http.StatusMethodNotAllowed) { continue } return nil, p, err @@ -109,15 +110,15 @@ func GetRepoActionJobLogPreviewFn(ctx context.Context, req mcp.CallToolRequest) log.Debugf("Called GetRepoActionJobLogPreviewFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } jobIDFloat, ok := req.GetArguments()["job_id"].(float64) if !ok || jobIDFloat <= 0 { - return to.ErrorResult(fmt.Errorf("job_id is required")) + return to.ErrorResult(errors.New("job_id is required")) } tailLinesFloat, _ := req.GetArguments()["tail_lines"].(float64) maxBytesFloat, _ := req.GetArguments()["max_bytes"].(float64) @@ -140,13 +141,13 @@ func GetRepoActionJobLogPreviewFn(ctx context.Context, req mcp.CallToolRequest) limited, truncated := limitBytes(tailed, maxBytes) return to.TextResult(map[string]any{ - "endpoint": usedPath, - "job_id": jobID, - "bytes": len(raw), - "tail_lines": tailLines, - "max_bytes": maxBytes, - "truncated": truncated, - "log": string(limited), + "endpoint": usedPath, + "job_id": jobID, + "bytes": len(raw), + "tail_lines": tailLines, + "max_bytes": maxBytes, + "truncated": truncated, + "log": string(limited), }) } @@ -154,15 +155,15 @@ func DownloadRepoActionJobLogFn(ctx context.Context, req mcp.CallToolRequest) (* log.Debugf("Called DownloadRepoActionJobLogFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } jobIDFloat, ok := req.GetArguments()["job_id"].(float64) if !ok || jobIDFloat <= 0 { - return to.ErrorResult(fmt.Errorf("job_id is required")) + return to.ErrorResult(errors.New("job_id is required")) } outputPath, _ := req.GetArguments()["output_path"].(string) jobID := int64(jobIDFloat) @@ -194,5 +195,3 @@ func DownloadRepoActionJobLogFn(ctx context.Context, req mcp.CallToolRequest) (* "bytes": len(raw), }) } - - diff --git a/operation/actions/logs_test.go b/operation/actions/logs_test.go index 8802149..65a47df 100644 --- a/operation/actions/logs_test.go +++ b/operation/actions/logs_test.go @@ -20,5 +20,3 @@ func TestLimitBytesKeepsTail(t *testing.T) { t.Fatalf("limitBytes tail = %q, want %q", string(out), "6789") } } - - diff --git a/operation/actions/runs.go b/operation/actions/runs.go index 3a397c8..a980b02 100644 --- a/operation/actions/runs.go +++ b/operation/actions/runs.go @@ -4,7 +4,10 @@ import ( "context" "errors" "fmt" + "maps" + "net/http" "net/url" + "strconv" "gitea.com/gitea/gitea-mcp/pkg/gitea" "gitea.com/gitea/gitea-mcp/pkg/log" @@ -125,32 +128,32 @@ func init() { Tool.RegisterRead(server.ServerTool{Tool: ListRepoActionRunJobsTool, Handler: ListRepoActionRunJobsFn}) } -func doJSONWithFallback(ctx context.Context, method string, paths []string, query url.Values, body any, respOut any) (string, int, error) { +func doJSONWithFallback(ctx context.Context, method string, paths []string, query url.Values, body, respOut any) error { var lastErr error for _, p := range paths { - status, err := gitea.DoJSON(ctx, method, p, query, body, respOut) + _, err := gitea.DoJSON(ctx, method, p, query, body, respOut) if err == nil { - return p, status, nil + return nil } lastErr = err var httpErr *gitea.HTTPError - if errors.As(err, &httpErr) && (httpErr.StatusCode == 404 || httpErr.StatusCode == 405) { + if errors.As(err, &httpErr) && (httpErr.StatusCode == http.StatusNotFound || httpErr.StatusCode == http.StatusMethodNotAllowed) { continue } - return p, status, err + return err } - return "", 0, lastErr + return lastErr } func ListRepoActionWorkflowsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called ListRepoActionWorkflowsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -161,11 +164,11 @@ func ListRepoActionWorkflowsFn(ctx context.Context, req mcp.CallToolRequest) (*m pageSize = 50 } query := url.Values{} - query.Set("page", fmt.Sprintf("%d", int(page))) - query.Set("limit", fmt.Sprintf("%d", int(pageSize))) + query.Set("page", strconv.Itoa(int(page))) + query.Set("limit", strconv.Itoa(int(pageSize))) var result any - _, _, err := doJSONWithFallback(ctx, "GET", + err := doJSONWithFallback(ctx, "GET", []string{ fmt.Sprintf("repos/%s/%s/actions/workflows", url.PathEscape(owner), url.PathEscape(repo)), }, @@ -181,19 +184,19 @@ func GetRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) (*mcp log.Debugf("Called GetRepoActionWorkflowFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } workflowID, ok := req.GetArguments()["workflow_id"].(string) if !ok || workflowID == "" { - return to.ErrorResult(fmt.Errorf("workflow_id is required")) + return to.ErrorResult(errors.New("workflow_id is required")) } var result any - _, _, err := doJSONWithFallback(ctx, "GET", + err := doJSONWithFallback(ctx, "GET", []string{ fmt.Sprintf("repos/%s/%s/actions/workflows/%s", url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(workflowID)), }, @@ -209,30 +212,28 @@ func DispatchRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) log.Debugf("Called DispatchRepoActionWorkflowFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } workflowID, ok := req.GetArguments()["workflow_id"].(string) if !ok || workflowID == "" { - return to.ErrorResult(fmt.Errorf("workflow_id is required")) + return to.ErrorResult(errors.New("workflow_id is required")) } ref, ok := req.GetArguments()["ref"].(string) if !ok || ref == "" { - return to.ErrorResult(fmt.Errorf("ref is required")) + return to.ErrorResult(errors.New("ref is required")) } var inputs map[string]any if raw, exists := req.GetArguments()["inputs"]; exists { if m, ok := raw.(map[string]any); ok { inputs = m - } else if m, ok := raw.(map[string]interface{}); ok { + } else if m, ok := raw.(map[string]any); ok { inputs = make(map[string]any, len(m)) - for k, v := range m { - inputs[k] = v - } + maps.Copy(inputs, m) } } @@ -243,7 +244,7 @@ func DispatchRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) body["inputs"] = inputs } - _, _, err := doJSONWithFallback(ctx, "POST", + err := doJSONWithFallback(ctx, "POST", []string{ fmt.Sprintf("repos/%s/%s/actions/workflows/%s/dispatches", url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(workflowID)), fmt.Sprintf("repos/%s/%s/actions/workflows/%s/dispatch", url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(workflowID)), @@ -252,7 +253,7 @@ func DispatchRepoActionWorkflowFn(ctx context.Context, req mcp.CallToolRequest) ) if err != nil { var httpErr *gitea.HTTPError - if errors.As(err, &httpErr) && (httpErr.StatusCode == 404 || httpErr.StatusCode == 405) { + if errors.As(err, &httpErr) && (httpErr.StatusCode == http.StatusNotFound || httpErr.StatusCode == http.StatusMethodNotAllowed) { return to.ErrorResult(fmt.Errorf("workflow dispatch not supported on this Gitea version (endpoint returned %d). Check https://docs.gitea.com/api/1.24/ for available Actions endpoints", httpErr.StatusCode)) } return to.ErrorResult(fmt.Errorf("dispatch action workflow err: %v", err)) @@ -264,11 +265,11 @@ func ListRepoActionRunsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca log.Debugf("Called ListRepoActionRunsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -281,14 +282,14 @@ func ListRepoActionRunsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca statusFilter, _ := req.GetArguments()["status"].(string) query := url.Values{} - query.Set("page", fmt.Sprintf("%d", int(page))) - query.Set("limit", fmt.Sprintf("%d", int(pageSize))) + query.Set("page", strconv.Itoa(int(page))) + query.Set("limit", strconv.Itoa(int(pageSize))) if statusFilter != "" { query.Set("status", statusFilter) } var result any - _, _, err := doJSONWithFallback(ctx, "GET", + err := doJSONWithFallback(ctx, "GET", []string{ fmt.Sprintf("repos/%s/%s/actions/runs", url.PathEscape(owner), url.PathEscape(repo)), }, @@ -304,19 +305,19 @@ func GetRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called GetRepoActionRunFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } runID, ok := req.GetArguments()["run_id"].(float64) if !ok || runID <= 0 { - return to.ErrorResult(fmt.Errorf("run_id is required")) + return to.ErrorResult(errors.New("run_id is required")) } var result any - _, _, err := doJSONWithFallback(ctx, "GET", + err := doJSONWithFallback(ctx, "GET", []string{ fmt.Sprintf("repos/%s/%s/actions/runs/%d", url.PathEscape(owner), url.PathEscape(repo), int64(runID)), }, @@ -332,18 +333,18 @@ func CancelRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.C log.Debugf("Called CancelRepoActionRunFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } runID, ok := req.GetArguments()["run_id"].(float64) if !ok || runID <= 0 { - return to.ErrorResult(fmt.Errorf("run_id is required")) + return to.ErrorResult(errors.New("run_id is required")) } - _, _, err := doJSONWithFallback(ctx, "POST", + err := doJSONWithFallback(ctx, "POST", []string{ fmt.Sprintf("repos/%s/%s/actions/runs/%d/cancel", url.PathEscape(owner), url.PathEscape(repo), int64(runID)), }, @@ -359,18 +360,18 @@ func RerunRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca log.Debugf("Called RerunRepoActionRunFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } runID, ok := req.GetArguments()["run_id"].(float64) if !ok || runID <= 0 { - return to.ErrorResult(fmt.Errorf("run_id is required")) + return to.ErrorResult(errors.New("run_id is required")) } - _, _, err := doJSONWithFallback(ctx, "POST", + err := doJSONWithFallback(ctx, "POST", []string{ fmt.Sprintf("repos/%s/%s/actions/runs/%d/rerun", url.PathEscape(owner), url.PathEscape(repo), int64(runID)), fmt.Sprintf("repos/%s/%s/actions/runs/%d/rerun-failed-jobs", url.PathEscape(owner), url.PathEscape(repo), int64(runID)), @@ -379,7 +380,7 @@ func RerunRepoActionRunFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca ) if err != nil { var httpErr *gitea.HTTPError - if errors.As(err, &httpErr) && (httpErr.StatusCode == 404 || httpErr.StatusCode == 405) { + if errors.As(err, &httpErr) && (httpErr.StatusCode == http.StatusNotFound || httpErr.StatusCode == http.StatusMethodNotAllowed) { return to.ErrorResult(fmt.Errorf("workflow rerun not supported on this Gitea version (endpoint returned %d). Check https://docs.gitea.com/api/1.24/ for available Actions endpoints", httpErr.StatusCode)) } return to.ErrorResult(fmt.Errorf("rerun action run err: %v", err)) @@ -391,11 +392,11 @@ func ListRepoActionJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca log.Debugf("Called ListRepoActionJobsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -408,14 +409,14 @@ func ListRepoActionJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca statusFilter, _ := req.GetArguments()["status"].(string) query := url.Values{} - query.Set("page", fmt.Sprintf("%d", int(page))) - query.Set("limit", fmt.Sprintf("%d", int(pageSize))) + query.Set("page", strconv.Itoa(int(page))) + query.Set("limit", strconv.Itoa(int(pageSize))) if statusFilter != "" { query.Set("status", statusFilter) } var result any - _, _, err := doJSONWithFallback(ctx, "GET", + err := doJSONWithFallback(ctx, "GET", []string{ fmt.Sprintf("repos/%s/%s/actions/jobs", url.PathEscape(owner), url.PathEscape(repo)), }, @@ -431,15 +432,15 @@ func ListRepoActionRunJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp log.Debugf("Called ListRepoActionRunJobsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } runID, ok := req.GetArguments()["run_id"].(float64) if !ok || runID <= 0 { - return to.ErrorResult(fmt.Errorf("run_id is required")) + return to.ErrorResult(errors.New("run_id is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -451,11 +452,11 @@ func ListRepoActionRunJobsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp } query := url.Values{} - query.Set("page", fmt.Sprintf("%d", int(page))) - query.Set("limit", fmt.Sprintf("%d", int(pageSize))) + query.Set("page", strconv.Itoa(int(page))) + query.Set("limit", strconv.Itoa(int(pageSize))) var result any - _, _, err := doJSONWithFallback(ctx, "GET", + err := doJSONWithFallback(ctx, "GET", []string{ fmt.Sprintf("repos/%s/%s/actions/runs/%d/jobs", url.PathEscape(owner), url.PathEscape(repo), int64(runID)), }, diff --git a/operation/actions/secrets.go b/operation/actions/secrets.go index 711b332..9843c78 100644 --- a/operation/actions/secrets.go +++ b/operation/actions/secrets.go @@ -2,6 +2,7 @@ package actions import ( "context" + "errors" "fmt" "net/url" "time" @@ -27,7 +28,7 @@ const ( type secretMeta struct { Name string `json:"name"` Description string `json:"description,omitempty"` - CreatedAt time.Time `json:"created_at,omitempty"` + CreatedAt time.Time `json:"created_at,omitzero"` } var ( @@ -97,11 +98,11 @@ func ListRepoActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp log.Debugf("Called ListRepoActionSecretsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -142,19 +143,19 @@ func UpsertRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mc log.Debugf("Called UpsertRepoActionSecretFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } data, ok := req.GetArguments()["data"].(string) if !ok || data == "" { - return to.ErrorResult(fmt.Errorf("data is required")) + return to.ErrorResult(errors.New("data is required")) } description, _ := req.GetArguments()["description"].(string) @@ -177,15 +178,15 @@ func DeleteRepoActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mc log.Debugf("Called DeleteRepoActionSecretFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } secretName, ok := req.GetArguments()["secretName"].(string) if !ok || secretName == "" { - return to.ErrorResult(fmt.Errorf("secretName is required")) + return to.ErrorResult(errors.New("secretName is required")) } client, err := gitea.ClientFromContext(ctx) @@ -203,7 +204,7 @@ func ListOrgActionSecretsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp. log.Debugf("Called ListOrgActionSecretsFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -244,15 +245,15 @@ func UpsertOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp log.Debugf("Called UpsertOrgActionSecretFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } data, ok := req.GetArguments()["data"].(string) if !ok || data == "" { - return to.ErrorResult(fmt.Errorf("data is required")) + return to.ErrorResult(errors.New("data is required")) } description, _ := req.GetArguments()["description"].(string) @@ -275,11 +276,11 @@ func DeleteOrgActionSecretFn(ctx context.Context, req mcp.CallToolRequest) (*mcp log.Debugf("Called DeleteOrgActionSecretFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } secretName, ok := req.GetArguments()["secretName"].(string) if !ok || secretName == "" { - return to.ErrorResult(fmt.Errorf("secretName is required")) + return to.ErrorResult(errors.New("secretName is required")) } escapedOrg := url.PathEscape(org) diff --git a/operation/actions/variables.go b/operation/actions/variables.go index 98219ec..a7ceb65 100644 --- a/operation/actions/variables.go +++ b/operation/actions/variables.go @@ -2,8 +2,10 @@ package actions import ( "context" + "errors" "fmt" "net/url" + "strconv" "gitea.com/gitea/gitea-mcp/pkg/gitea" "gitea.com/gitea/gitea-mcp/pkg/log" @@ -21,11 +23,11 @@ const ( UpdateRepoActionVariableToolName = "update_repo_action_variable" DeleteRepoActionVariableToolName = "delete_repo_action_variable" - ListOrgActionVariablesToolName = "list_org_action_variables" - GetOrgActionVariableToolName = "get_org_action_variable" - CreateOrgActionVariableToolName = "create_org_action_variable" - UpdateOrgActionVariableToolName = "update_org_action_variable" - DeleteOrgActionVariableToolName = "delete_org_action_variable" + ListOrgActionVariablesToolName = "list_org_action_variables" + GetOrgActionVariableToolName = "get_org_action_variable" + CreateOrgActionVariableToolName = "create_org_action_variable" + UpdateOrgActionVariableToolName = "update_org_action_variable" + DeleteOrgActionVariableToolName = "delete_org_action_variable" ) var ( @@ -131,11 +133,11 @@ func ListRepoActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called ListRepoActionVariablesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -147,8 +149,8 @@ func ListRepoActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*m } query := url.Values{} - query.Set("page", fmt.Sprintf("%d", int(page))) - query.Set("limit", fmt.Sprintf("%d", int(pageSize))) + query.Set("page", strconv.Itoa(int(page))) + query.Set("limit", strconv.Itoa(int(pageSize))) var result any _, err := gitea.DoJSON(ctx, "GET", fmt.Sprintf("repos/%s/%s/actions/variables", url.PathEscape(owner), url.PathEscape(repo)), query, nil, &result) @@ -162,15 +164,15 @@ func GetRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp log.Debugf("Called GetRepoActionVariableFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } client, err := gitea.ClientFromContext(ctx) @@ -188,19 +190,19 @@ func CreateRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (* log.Debugf("Called CreateRepoActionVariableFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } value, ok := req.GetArguments()["value"].(string) if !ok || value == "" { - return to.ErrorResult(fmt.Errorf("value is required")) + return to.ErrorResult(errors.New("value is required")) } client, err := gitea.ClientFromContext(ctx) @@ -218,19 +220,19 @@ func UpdateRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (* log.Debugf("Called UpdateRepoActionVariableFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } value, ok := req.GetArguments()["value"].(string) if !ok || value == "" { - return to.ErrorResult(fmt.Errorf("value is required")) + return to.ErrorResult(errors.New("value is required")) } client, err := gitea.ClientFromContext(ctx) @@ -248,15 +250,15 @@ func DeleteRepoActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (* log.Debugf("Called DeleteRepoActionVariableFn") owner, ok := req.GetArguments()["owner"].(string) if !ok || owner == "" { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok || repo == "" { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } client, err := gitea.ClientFromContext(ctx) @@ -274,7 +276,7 @@ func ListOrgActionVariablesFn(ctx context.Context, req mcp.CallToolRequest) (*mc log.Debugf("Called ListOrgActionVariablesFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } page, _ := req.GetArguments()["page"].(float64) if page <= 0 { @@ -302,11 +304,11 @@ func GetOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*mcp. log.Debugf("Called GetOrgActionVariableFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } client, err := gitea.ClientFromContext(ctx) @@ -324,15 +326,15 @@ func CreateOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called CreateOrgActionVariableFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } value, ok := req.GetArguments()["value"].(string) if !ok || value == "" { - return to.ErrorResult(fmt.Errorf("value is required")) + return to.ErrorResult(errors.New("value is required")) } description, _ := req.GetArguments()["description"].(string) @@ -355,15 +357,15 @@ func UpdateOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called UpdateOrgActionVariableFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } value, ok := req.GetArguments()["value"].(string) if !ok || value == "" { - return to.ErrorResult(fmt.Errorf("value is required")) + return to.ErrorResult(errors.New("value is required")) } description, _ := req.GetArguments()["description"].(string) @@ -385,11 +387,11 @@ func DeleteOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called DeleteOrgActionVariableFn") org, ok := req.GetArguments()["org"].(string) if !ok || org == "" { - return to.ErrorResult(fmt.Errorf("org is required")) + return to.ErrorResult(errors.New("org is required")) } name, ok := req.GetArguments()["name"].(string) if !ok || name == "" { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } _, err := gitea.DoJSON(ctx, "DELETE", fmt.Sprintf("orgs/%s/actions/variables/%s", url.PathEscape(org), url.PathEscape(name)), nil, nil, nil) @@ -398,5 +400,3 @@ func DeleteOrgActionVariableFn(ctx context.Context, req mcp.CallToolRequest) (*m } return to.TextResult(map[string]any{"message": "variable deleted"}) } - - diff --git a/operation/issue/issue.go b/operation/issue/issue.go index 5c7387e..97ecba9 100644 --- a/operation/issue/issue.go +++ b/operation/issue/issue.go @@ -2,12 +2,12 @@ package issue import ( "context" + "errors" "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/ptr" "gitea.com/gitea/gitea-mcp/pkg/to" "gitea.com/gitea/gitea-mcp/pkg/tool" @@ -73,7 +73,7 @@ var ( mcp.WithNumber("index", mcp.Required(), mcp.Description("repository issue index")), mcp.WithString("title", mcp.Description("issue title"), mcp.DefaultString("")), mcp.WithString("body", mcp.Description("issue body content")), - mcp.WithArray("assignees", mcp.Description("usernames to assign to this issue"), mcp.Items(map[string]interface{}{"type": "string"})), + mcp.WithArray("assignees", mcp.Description("usernames to assign to this issue"), mcp.Items(map[string]any{"type": "string"})), mcp.WithNumber("milestone", mcp.Description("milestone number")), mcp.WithString("state", mcp.Description("issue state, one of open, closed, all")), ) @@ -131,11 +131,11 @@ func GetIssueByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called GetIssueByIndexFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -157,11 +157,11 @@ func ListRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called ListIssuesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } state, ok := req.GetArguments()["state"].(string) if !ok { @@ -197,19 +197,19 @@ func CreateIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR log.Debugf("Called CreateIssueFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } title, ok := req.GetArguments()["title"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("title is required")) + return to.ErrorResult(errors.New("title is required")) } body, ok := req.GetArguments()["body"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("body is required")) + return to.ErrorResult(errors.New("body is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -230,11 +230,11 @@ func CreateIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca log.Debugf("Called CreateIssueCommentFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -242,7 +242,7 @@ func CreateIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca } body, ok := req.GetArguments()["body"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("body is required")) + return to.ErrorResult(errors.New("body is required")) } opt := gitea_sdk.CreateIssueCommentOption{ Body: body, @@ -263,11 +263,11 @@ func EditIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes log.Debugf("Called EditIssueFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -282,11 +282,11 @@ func EditIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes } body, ok := req.GetArguments()["body"].(string) if ok { - opt.Body = ptr.To(body) + opt.Body = new(body) } var assignees []string if assigneesArg, exists := req.GetArguments()["assignees"]; exists { - if assigneesSlice, ok := assigneesArg.([]interface{}); ok { + if assigneesSlice, ok := assigneesArg.([]any); ok { for _, assignee := range assigneesSlice { if assigneeStr, ok := assignee.(string); ok { assignees = append(assignees, assigneeStr) @@ -297,11 +297,11 @@ func EditIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes opt.Assignees = assignees milestone, ok := req.GetArguments()["milestone"].(float64) if ok { - opt.Milestone = ptr.To(int64(milestone)) + opt.Milestone = new(int64(milestone)) } state, ok := req.GetArguments()["state"].(string) if ok { - opt.State = ptr.To(gitea_sdk.StateType(state)) + opt.State = new(gitea_sdk.StateType(state)) } client, err := gitea.ClientFromContext(ctx) @@ -320,19 +320,19 @@ func EditIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called EditIssueCommentFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } commentID, ok := req.GetArguments()["commentID"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("comment ID is required")) + return to.ErrorResult(errors.New("comment ID is required")) } body, ok := req.GetArguments()["body"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("body is required")) + return to.ErrorResult(errors.New("body is required")) } opt := gitea_sdk.EditIssueCommentOption{ Body: body, @@ -353,11 +353,11 @@ func GetIssueCommentsByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called GetIssueCommentsByIndexFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { diff --git a/operation/label/label.go b/operation/label/label.go index 2eee6c2..b918c8e 100644 --- a/operation/label/label.go +++ b/operation/label/label.go @@ -2,12 +2,12 @@ package label import ( "context" + "errors" "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/ptr" "gitea.com/gitea/gitea-mcp/pkg/to" "gitea.com/gitea/gitea-mcp/pkg/tool" @@ -28,10 +28,10 @@ const ( ReplaceIssueLabelsToolName = "replace_issue_labels" ClearIssueLabelsToolName = "clear_issue_labels" RemoveIssueLabelToolName = "remove_issue_label" - ListOrgLabelsToolName = "list_org_labels" - CreateOrgLabelToolName = "create_org_label" - EditOrgLabelToolName = "edit_org_label" - DeleteOrgLabelToolName = "delete_org_label" + ListOrgLabelsToolName = "list_org_labels" + CreateOrgLabelToolName = "create_org_label" + EditOrgLabelToolName = "edit_org_label" + DeleteOrgLabelToolName = "delete_org_label" ) var ( @@ -87,7 +87,7 @@ var ( mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")), mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")), mcp.WithNumber("index", mcp.Required(), mcp.Description("issue index")), - mcp.WithArray("labels", mcp.Required(), mcp.Description("array of label IDs to add"), mcp.Items(map[string]interface{}{"type": "number"})), + mcp.WithArray("labels", mcp.Required(), mcp.Description("array of label IDs to add"), mcp.Items(map[string]any{"type": "number"})), ) ReplaceIssueLabelsTool = mcp.NewTool( @@ -96,7 +96,7 @@ var ( mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")), mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")), mcp.WithNumber("index", mcp.Required(), mcp.Description("issue index")), - mcp.WithArray("labels", mcp.Required(), mcp.Description("array of label IDs to replace with"), mcp.Items(map[string]interface{}{"type": "number"})), + mcp.WithArray("labels", mcp.Required(), mcp.Description("array of label IDs to replace with"), mcp.Items(map[string]any{"type": "number"})), ) ClearIssueLabelsTool = mcp.NewTool( @@ -116,42 +116,41 @@ var ( mcp.WithNumber("label_id", mcp.Required(), mcp.Description("label ID to remove")), ) - ListOrgLabelsTool = mcp.NewTool( - ListOrgLabelsToolName, - mcp.WithDescription("Lists labels defined at organization level"), - mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), - mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(1)), - mcp.WithNumber("pageSize", mcp.Description("page size"), mcp.DefaultNumber(100)), - ) + ListOrgLabelsTool = mcp.NewTool( + ListOrgLabelsToolName, + mcp.WithDescription("Lists labels defined at organization level"), + mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), + mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(1)), + mcp.WithNumber("pageSize", mcp.Description("page size"), mcp.DefaultNumber(100)), + ) - CreateOrgLabelTool = mcp.NewTool( - CreateOrgLabelToolName, - mcp.WithDescription("Creates a new label for an organization"), - mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), - mcp.WithString("name", mcp.Required(), mcp.Description("label name")), - mcp.WithString("color", mcp.Required(), mcp.Description("label color (hex code, e.g., #RRGGBB)")), - mcp.WithString("description", mcp.Description("label description")), - mcp.WithBoolean("exclusive", mcp.Description("whether the label is exclusive"), mcp.DefaultBool(false)), - ) + CreateOrgLabelTool = mcp.NewTool( + CreateOrgLabelToolName, + mcp.WithDescription("Creates a new label for an organization"), + mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), + mcp.WithString("name", mcp.Required(), mcp.Description("label name")), + mcp.WithString("color", mcp.Required(), mcp.Description("label color (hex code, e.g., #RRGGBB)")), + mcp.WithString("description", mcp.Description("label description")), + mcp.WithBoolean("exclusive", mcp.Description("whether the label is exclusive"), mcp.DefaultBool(false)), + ) - EditOrgLabelTool = mcp.NewTool( - EditOrgLabelToolName, - mcp.WithDescription("Edits an existing organization label"), - mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), - mcp.WithNumber("id", mcp.Required(), mcp.Description("label ID")), - mcp.WithString("name", mcp.Description("new label name")), - mcp.WithString("color", mcp.Description("new label color (hex code, e.g., #RRGGBB)")), - mcp.WithString("description", mcp.Description("new label description")), - mcp.WithBoolean("exclusive", mcp.Description("whether the label is exclusive")), - ) - - DeleteOrgLabelTool = mcp.NewTool( - DeleteOrgLabelToolName, - mcp.WithDescription("Deletes an organization label by ID"), - mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), - mcp.WithNumber("id", mcp.Required(), mcp.Description("label ID")), - ) + EditOrgLabelTool = mcp.NewTool( + EditOrgLabelToolName, + mcp.WithDescription("Edits an existing organization label"), + mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), + mcp.WithNumber("id", mcp.Required(), mcp.Description("label ID")), + mcp.WithString("name", mcp.Description("new label name")), + mcp.WithString("color", mcp.Description("new label color (hex code, e.g., #RRGGBB)")), + mcp.WithString("description", mcp.Description("new label description")), + mcp.WithBoolean("exclusive", mcp.Description("whether the label is exclusive")), + ) + DeleteOrgLabelTool = mcp.NewTool( + DeleteOrgLabelToolName, + mcp.WithDescription("Deletes an organization label by ID"), + mcp.WithString("org", mcp.Required(), mcp.Description("organization name")), + mcp.WithNumber("id", mcp.Required(), mcp.Description("label ID")), + ) ) func init() { @@ -191,33 +190,33 @@ func init() { Tool: RemoveIssueLabelTool, Handler: RemoveIssueLabelFn, }) - Tool.RegisterRead(server.ServerTool{ - Tool: ListOrgLabelsTool, - Handler: ListOrgLabelsFn, - }) - Tool.RegisterWrite(server.ServerTool{ - Tool: CreateOrgLabelTool, - Handler: CreateOrgLabelFn, - }) - Tool.RegisterWrite(server.ServerTool{ - Tool: EditOrgLabelTool, - Handler: EditOrgLabelFn, - }) - Tool.RegisterWrite(server.ServerTool{ - Tool: DeleteOrgLabelTool, - Handler: DeleteOrgLabelFn, - }) + Tool.RegisterRead(server.ServerTool{ + Tool: ListOrgLabelsTool, + Handler: ListOrgLabelsFn, + }) + Tool.RegisterWrite(server.ServerTool{ + Tool: CreateOrgLabelTool, + Handler: CreateOrgLabelFn, + }) + Tool.RegisterWrite(server.ServerTool{ + Tool: EditOrgLabelTool, + Handler: EditOrgLabelFn, + }) + Tool.RegisterWrite(server.ServerTool{ + Tool: DeleteOrgLabelTool, + Handler: DeleteOrgLabelFn, + }) } func ListRepoLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called ListRepoLabelsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, ok := req.GetArguments()["page"].(float64) if !ok { @@ -249,15 +248,15 @@ func GetRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool log.Debugf("Called GetRepoLabelFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } id, ok := req.GetArguments()["id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("label ID is required")) + return to.ErrorResult(errors.New("label ID is required")) } client, err := gitea.ClientFromContext(ctx) @@ -275,19 +274,19 @@ func CreateRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called CreateRepoLabelFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } name, ok := req.GetArguments()["name"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("name is required")) + return to.ErrorResult(errors.New("name is required")) } color, ok := req.GetArguments()["color"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("color is required")) + return to.ErrorResult(errors.New("color is required")) } description, _ := req.GetArguments()["description"].(string) // Optional @@ -312,26 +311,26 @@ func EditRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called EditRepoLabelFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } id, ok := req.GetArguments()["id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("label ID is required")) + return to.ErrorResult(errors.New("label ID is required")) } opt := gitea_sdk.EditLabelOption{} if name, ok := req.GetArguments()["name"].(string); ok { - opt.Name = ptr.To(name) + opt.Name = new(name) } if color, ok := req.GetArguments()["color"].(string); ok { - opt.Color = ptr.To(color) + opt.Color = new(color) } if description, ok := req.GetArguments()["description"].(string); ok { - opt.Description = ptr.To(description) + opt.Description = new(description) } client, err := gitea.ClientFromContext(ctx) @@ -349,15 +348,15 @@ func DeleteRepoLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called DeleteRepoLabelFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } id, ok := req.GetArguments()["id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("label ID is required")) + return to.ErrorResult(errors.New("label ID is required")) } client, err := gitea.ClientFromContext(ctx) @@ -375,26 +374,26 @@ func AddIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called AddIssueLabelsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { return to.ErrorResult(err) } - labelsRaw, ok := req.GetArguments()["labels"].([]interface{}) + labelsRaw, ok := req.GetArguments()["labels"].([]any) if !ok { - return to.ErrorResult(fmt.Errorf("labels (array of IDs) is required")) + return to.ErrorResult(errors.New("labels (array of IDs) is required")) } var labels []int64 for _, l := range labelsRaw { if labelID, ok := l.(float64); ok { labels = append(labels, int64(labelID)) } else { - return to.ErrorResult(fmt.Errorf("invalid label ID in labels array")) + return to.ErrorResult(errors.New("invalid label ID in labels array")) } } @@ -417,26 +416,26 @@ func ReplaceIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca log.Debugf("Called ReplaceIssueLabelsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { return to.ErrorResult(err) } - labelsRaw, ok := req.GetArguments()["labels"].([]interface{}) + labelsRaw, ok := req.GetArguments()["labels"].([]any) if !ok { - return to.ErrorResult(fmt.Errorf("labels (array of IDs) is required")) + return to.ErrorResult(errors.New("labels (array of IDs) is required")) } var labels []int64 for _, l := range labelsRaw { if labelID, ok := l.(float64); ok { labels = append(labels, int64(labelID)) } else { - return to.ErrorResult(fmt.Errorf("invalid label ID in labels array")) + return to.ErrorResult(errors.New("invalid label ID in labels array")) } } @@ -459,11 +458,11 @@ func ClearIssueLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called ClearIssueLabelsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -485,11 +484,11 @@ func RemoveIssueLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called RemoveIssueLabelFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -497,7 +496,7 @@ func RemoveIssueLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call } labelID, ok := req.GetArguments()["label_id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("label ID is required")) + return to.ErrorResult(errors.New("label ID is required")) } client, err := gitea.ClientFromContext(ctx) @@ -512,126 +511,126 @@ func RemoveIssueLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call } func ListOrgLabelsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - log.Debugf("Called ListOrgLabelsFn") - org, ok := req.GetArguments()["org"].(string) - if !ok { - return to.ErrorResult(fmt.Errorf("org is required")) - } - page, ok := req.GetArguments()["page"].(float64) - if !ok { - page = 1 - } - pageSize, ok := req.GetArguments()["pageSize"].(float64) - if !ok { - pageSize = 100 - } + log.Debugf("Called ListOrgLabelsFn") + org, ok := req.GetArguments()["org"].(string) + if !ok { + return to.ErrorResult(errors.New("org is required")) + } + page, ok := req.GetArguments()["page"].(float64) + if !ok { + page = 1 + } + pageSize, ok := req.GetArguments()["pageSize"].(float64) + if !ok { + pageSize = 100 + } - opt := gitea_sdk.ListOrgLabelsOptions{ - ListOptions: gitea_sdk.ListOptions{ - Page: int(page), - PageSize: int(pageSize), - }, - } - client, err := gitea.ClientFromContext(ctx) - if err != nil { - return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) - } - labels, _, err := client.ListOrgLabels(org, opt) - if err != nil { - return to.ErrorResult(fmt.Errorf("list %v/labels err: %v", org, err)) - } - return to.TextResult(labels) + opt := gitea_sdk.ListOrgLabelsOptions{ + ListOptions: gitea_sdk.ListOptions{ + Page: int(page), + PageSize: int(pageSize), + }, + } + client, err := gitea.ClientFromContext(ctx) + if err != nil { + return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) + } + labels, _, err := client.ListOrgLabels(org, opt) + if err != nil { + return to.ErrorResult(fmt.Errorf("list %v/labels err: %v", org, err)) + } + return to.TextResult(labels) } func CreateOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - log.Debugf("Called CreateOrgLabelFn") - org, ok := req.GetArguments()["org"].(string) - if !ok { - return to.ErrorResult(fmt.Errorf("org is required")) - } - name, ok := req.GetArguments()["name"].(string) - if !ok { - return to.ErrorResult(fmt.Errorf("name is required")) - } - color, ok := req.GetArguments()["color"].(string) - if !ok { - return to.ErrorResult(fmt.Errorf("color is required")) - } - description, _ := req.GetArguments()["description"].(string) - exclusive, _ := req.GetArguments()["exclusive"].(bool) + log.Debugf("Called CreateOrgLabelFn") + org, ok := req.GetArguments()["org"].(string) + if !ok { + return to.ErrorResult(errors.New("org is required")) + } + name, ok := req.GetArguments()["name"].(string) + if !ok { + return to.ErrorResult(errors.New("name is required")) + } + color, ok := req.GetArguments()["color"].(string) + if !ok { + return to.ErrorResult(errors.New("color is required")) + } + description, _ := req.GetArguments()["description"].(string) + exclusive, _ := req.GetArguments()["exclusive"].(bool) - opt := gitea_sdk.CreateOrgLabelOption{ - Name: name, - Color: color, - Description: description, - Exclusive: exclusive, - } + opt := gitea_sdk.CreateOrgLabelOption{ + Name: name, + Color: color, + Description: description, + Exclusive: exclusive, + } - client, err := gitea.ClientFromContext(ctx) - if err != nil { - return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) - } - label, _, err := client.CreateOrgLabel(org, opt) - if err != nil { - return to.ErrorResult(fmt.Errorf("create %v/labels err: %v", org, err)) - } - return to.TextResult(label) + client, err := gitea.ClientFromContext(ctx) + if err != nil { + return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) + } + label, _, err := client.CreateOrgLabel(org, opt) + if err != nil { + return to.ErrorResult(fmt.Errorf("create %v/labels err: %v", org, err)) + } + return to.TextResult(label) } func EditOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - log.Debugf("Called EditOrgLabelFn") - org, ok := req.GetArguments()["org"].(string) - if !ok { - return to.ErrorResult(fmt.Errorf("org is required")) - } - id, ok := req.GetArguments()["id"].(float64) - if !ok { - return to.ErrorResult(fmt.Errorf("label ID is required")) - } + log.Debugf("Called EditOrgLabelFn") + org, ok := req.GetArguments()["org"].(string) + if !ok { + return to.ErrorResult(errors.New("org is required")) + } + id, ok := req.GetArguments()["id"].(float64) + if !ok { + return to.ErrorResult(errors.New("label ID is required")) + } - opt := gitea_sdk.EditOrgLabelOption{} - if name, ok := req.GetArguments()["name"].(string); ok { - opt.Name = ptr.To(name) - } - if color, ok := req.GetArguments()["color"].(string); ok { - opt.Color = ptr.To(color) - } - if description, ok := req.GetArguments()["description"].(string); ok { - opt.Description = ptr.To(description) - } - if exclusive, ok := req.GetArguments()["exclusive"].(bool); ok { - opt.Exclusive = ptr.To(exclusive) - } + opt := gitea_sdk.EditOrgLabelOption{} + if name, ok := req.GetArguments()["name"].(string); ok { + opt.Name = new(name) + } + if color, ok := req.GetArguments()["color"].(string); ok { + opt.Color = new(color) + } + if description, ok := req.GetArguments()["description"].(string); ok { + opt.Description = new(description) + } + if exclusive, ok := req.GetArguments()["exclusive"].(bool); ok { + opt.Exclusive = new(exclusive) + } - client, err := gitea.ClientFromContext(ctx) - if err != nil { - return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) - } - label, _, err := client.EditOrgLabel(org, int64(id), opt) - if err != nil { - return to.ErrorResult(fmt.Errorf("edit %v/labels/%v err: %v", org, int64(id), err)) - } - return to.TextResult(label) + client, err := gitea.ClientFromContext(ctx) + if err != nil { + return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) + } + label, _, err := client.EditOrgLabel(org, int64(id), opt) + if err != nil { + return to.ErrorResult(fmt.Errorf("edit %v/labels/%v err: %v", org, int64(id), err)) + } + return to.TextResult(label) } func DeleteOrgLabelFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - log.Debugf("Called DeleteOrgLabelFn") - org, ok := req.GetArguments()["org"].(string) - if !ok { - return to.ErrorResult(fmt.Errorf("org is required")) - } - id, ok := req.GetArguments()["id"].(float64) - if !ok { - return to.ErrorResult(fmt.Errorf("label ID is required")) - } + log.Debugf("Called DeleteOrgLabelFn") + org, ok := req.GetArguments()["org"].(string) + if !ok { + return to.ErrorResult(errors.New("org is required")) + } + id, ok := req.GetArguments()["id"].(float64) + if !ok { + return to.ErrorResult(errors.New("label ID is required")) + } - client, err := gitea.ClientFromContext(ctx) - if err != nil { - return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) - } - _, err = client.DeleteOrgLabel(org, int64(id)) - if err != nil { - return to.ErrorResult(fmt.Errorf("delete %v/labels/%v err: %v", org, int64(id), err)) - } - return to.TextResult("Label deleted successfully") -} \ No newline at end of file + client, err := gitea.ClientFromContext(ctx) + if err != nil { + return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) + } + _, err = client.DeleteOrgLabel(org, int64(id)) + if err != nil { + return to.ErrorResult(fmt.Errorf("delete %v/labels/%v err: %v", org, int64(id), err)) + } + return to.TextResult("Label deleted successfully") +} diff --git a/operation/milestone/milestone.go b/operation/milestone/milestone.go index ca49ab8..05ef9eb 100644 --- a/operation/milestone/milestone.go +++ b/operation/milestone/milestone.go @@ -2,11 +2,11 @@ package milestone import ( "context" + "errors" "fmt" "gitea.com/gitea/gitea-mcp/pkg/gitea" "gitea.com/gitea/gitea-mcp/pkg/log" - "gitea.com/gitea/gitea-mcp/pkg/ptr" "gitea.com/gitea/gitea-mcp/pkg/to" "gitea.com/gitea/gitea-mcp/pkg/tool" @@ -103,15 +103,15 @@ func GetMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool log.Debugf("Called GetMilestoneFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } id, ok := req.GetArguments()["id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("id is required")) + return to.ErrorResult(errors.New("id is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -129,11 +129,11 @@ func ListMilestonesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called ListMilestonesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } state, ok := req.GetArguments()["state"].(string) if !ok { @@ -174,15 +174,15 @@ func CreateMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called CreateMilestoneFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } title, ok := req.GetArguments()["title"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("title is required")) + return to.ErrorResult(errors.New("title is required")) } opt := gitea_sdk.CreateMilestoneOption{ @@ -210,15 +210,15 @@ func EditMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called EditMilestoneFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } id, ok := req.GetArguments()["id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("id is required")) + return to.ErrorResult(errors.New("id is required")) } opt := gitea_sdk.EditMilestoneOption{} @@ -229,11 +229,11 @@ func EditMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo } description, ok := req.GetArguments()["description"].(string) if ok { - opt.Description = ptr.To(description) + opt.Description = new(description) } state, ok := req.GetArguments()["state"].(string) if ok { - opt.State = ptr.To(gitea_sdk.StateType(state)) + opt.State = new(gitea_sdk.StateType(state)) } client, err := gitea.ClientFromContext(ctx) @@ -252,15 +252,15 @@ func DeleteMilestoneFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called DeleteMilestoneFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } id, ok := req.GetArguments()["id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("id is required")) + return to.ErrorResult(errors.New("id is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { diff --git a/operation/operation.go b/operation/operation.go index 1171392..e893d2b 100644 --- a/operation/operation.go +++ b/operation/operation.go @@ -10,14 +10,14 @@ import ( "syscall" "time" + "gitea.com/gitea/gitea-mcp/operation/actions" "gitea.com/gitea/gitea-mcp/operation/issue" "gitea.com/gitea/gitea-mcp/operation/label" "gitea.com/gitea/gitea-mcp/operation/milestone" - "gitea.com/gitea/gitea-mcp/operation/timetracking" - "gitea.com/gitea/gitea-mcp/operation/actions" "gitea.com/gitea/gitea-mcp/operation/pull" "gitea.com/gitea/gitea-mcp/operation/repo" "gitea.com/gitea/gitea-mcp/operation/search" + "gitea.com/gitea/gitea-mcp/operation/timetracking" "gitea.com/gitea/gitea-mcp/operation/user" "gitea.com/gitea/gitea-mcp/operation/version" "gitea.com/gitea/gitea-mcp/operation/wiki" diff --git a/operation/pull/pull.go b/operation/pull/pull.go index 188de9f..54a1daf 100644 --- a/operation/pull/pull.go +++ b/operation/pull/pull.go @@ -2,12 +2,12 @@ package pull import ( "context" + "errors" "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/ptr" "gitea.com/gitea/gitea-mcp/pkg/to" "gitea.com/gitea/gitea-mcp/pkg/tool" @@ -83,8 +83,8 @@ var ( mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")), mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")), mcp.WithNumber("index", mcp.Required(), mcp.Description("pull request index")), - mcp.WithArray("reviewers", mcp.Description("list of reviewer usernames"), mcp.Items(map[string]interface{}{"type": "string"})), - mcp.WithArray("team_reviewers", mcp.Description("list of team reviewer names"), mcp.Items(map[string]interface{}{"type": "string"})), + mcp.WithArray("reviewers", mcp.Description("list of reviewer usernames"), mcp.Items(map[string]any{"type": "string"})), + mcp.WithArray("team_reviewers", mcp.Description("list of team reviewer names"), mcp.Items(map[string]any{"type": "string"})), ) DeletePullRequestReviewerTool = mcp.NewTool( @@ -93,8 +93,8 @@ var ( mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")), mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")), mcp.WithNumber("index", mcp.Required(), mcp.Description("pull request index")), - mcp.WithArray("reviewers", mcp.Description("list of reviewer usernames to remove"), mcp.Items(map[string]interface{}{"type": "string"})), - mcp.WithArray("team_reviewers", mcp.Description("list of team reviewer names to remove"), mcp.Items(map[string]interface{}{"type": "string"})), + mcp.WithArray("reviewers", mcp.Description("list of reviewer usernames to remove"), mcp.Items(map[string]any{"type": "string"})), + mcp.WithArray("team_reviewers", mcp.Description("list of team reviewer names to remove"), mcp.Items(map[string]any{"type": "string"})), ) ListPullRequestReviewsTool = mcp.NewTool( @@ -134,13 +134,13 @@ var ( mcp.WithString("state", mcp.Description("review state"), mcp.Enum("APPROVED", "REQUEST_CHANGES", "COMMENT", "PENDING")), mcp.WithString("body", mcp.Description("review body/comment")), mcp.WithString("commit_id", mcp.Description("commit SHA to review")), - mcp.WithArray("comments", mcp.Description("inline review comments (objects with path, body, old_line_num, new_line_num)"), mcp.Items(map[string]interface{}{ + mcp.WithArray("comments", mcp.Description("inline review comments (objects with path, body, old_line_num, new_line_num)"), mcp.Items(map[string]any{ "type": "object", - "properties": map[string]interface{}{ - "path": map[string]interface{}{"type": "string", "description": "file path to comment on"}, - "body": map[string]interface{}{"type": "string", "description": "comment body"}, - "old_line_num": map[string]interface{}{"type": "number", "description": "line number in the old file (for deletions/changes)"}, - "new_line_num": map[string]interface{}{"type": "number", "description": "line number in the new file (for additions/changes)"}, + "properties": map[string]any{ + "path": map[string]any{"type": "string", "description": "file path to comment on"}, + "body": map[string]any{"type": "string", "description": "comment body"}, + "old_line_num": map[string]any{"type": "number", "description": "line number in the old file (for deletions/changes)"}, + "new_line_num": map[string]any{"type": "number", "description": "line number in the new file (for additions/changes)"}, }, })), ) @@ -196,7 +196,7 @@ var ( mcp.WithString("body", mcp.Description("pull request body content")), mcp.WithString("base", mcp.Description("pull request base branch")), mcp.WithString("assignee", mcp.Description("username to assign")), - mcp.WithArray("assignees", mcp.Description("usernames to assign"), mcp.Items(map[string]interface{}{"type": "string"})), + mcp.WithArray("assignees", mcp.Description("usernames to assign"), mcp.Items(map[string]any{"type": "string"})), mcp.WithNumber("milestone", mcp.Description("milestone number")), mcp.WithString("state", mcp.Description("pull request state"), mcp.Enum("open", "closed")), mcp.WithBoolean("allow_maintainer_edit", mcp.Description("allow maintainer to edit the pull request")), @@ -270,11 +270,11 @@ func GetPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp log.Debugf("Called GetPullRequestByIndexFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -296,11 +296,11 @@ func GetPullRequestDiffFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca log.Debugf("Called GetPullRequestDiffFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -319,7 +319,7 @@ func GetPullRequestDiffFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v diff err: %v", owner, repo, index, err)) } - result := map[string]interface{}{ + result := map[string]any{ "diff": string(diffBytes), "binary": binary, "index": index, @@ -333,11 +333,11 @@ func ListRepoPullRequestsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp. log.Debugf("Called ListRepoPullRequests") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } state, _ := req.GetArguments()["state"].(string) sort, ok := req.GetArguments()["sort"].(string) @@ -378,27 +378,27 @@ func CreatePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal log.Debugf("Called CreatePullRequestFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } title, ok := req.GetArguments()["title"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("title is required")) + return to.ErrorResult(errors.New("title is required")) } body, ok := req.GetArguments()["body"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("body is required")) + return to.ErrorResult(errors.New("body is required")) } head, ok := req.GetArguments()["head"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("head is required")) + return to.ErrorResult(errors.New("head is required")) } base, ok := req.GetArguments()["base"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("base is required")) + return to.ErrorResult(errors.New("base is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -421,11 +421,11 @@ func CreatePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( log.Debugf("Called CreatePullRequestReviewerFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -434,7 +434,7 @@ func CreatePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( var reviewers []string if reviewersArg, exists := req.GetArguments()["reviewers"]; exists { - if reviewersSlice, ok := reviewersArg.([]interface{}); ok { + if reviewersSlice, ok := reviewersArg.([]any); ok { for _, reviewer := range reviewersSlice { if reviewerStr, ok := reviewer.(string); ok { reviewers = append(reviewers, reviewerStr) @@ -445,7 +445,7 @@ func CreatePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( var teamReviewers []string if teamReviewersArg, exists := req.GetArguments()["team_reviewers"]; exists { - if teamReviewersSlice, ok := teamReviewersArg.([]interface{}); ok { + if teamReviewersSlice, ok := teamReviewersArg.([]any); ok { for _, teamReviewer := range teamReviewersSlice { if teamReviewerStr, ok := teamReviewer.(string); ok { teamReviewers = append(teamReviewers, teamReviewerStr) @@ -468,7 +468,7 @@ func CreatePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( } // Return a success message instead of the Response object which contains non-serializable functions - successMsg := map[string]interface{}{ + successMsg := map[string]any{ "message": "Successfully created review requests", "reviewers": reviewers, "team_reviewers": teamReviewers, @@ -483,11 +483,11 @@ func DeletePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( log.Debugf("Called DeletePullRequestReviewerFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -496,7 +496,7 @@ func DeletePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( var reviewers []string if reviewersArg, exists := req.GetArguments()["reviewers"]; exists { - if reviewersSlice, ok := reviewersArg.([]interface{}); ok { + if reviewersSlice, ok := reviewersArg.([]any); ok { for _, reviewer := range reviewersSlice { if reviewerStr, ok := reviewer.(string); ok { reviewers = append(reviewers, reviewerStr) @@ -507,7 +507,7 @@ func DeletePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( var teamReviewers []string if teamReviewersArg, exists := req.GetArguments()["team_reviewers"]; exists { - if teamReviewersSlice, ok := teamReviewersArg.([]interface{}); ok { + if teamReviewersSlice, ok := teamReviewersArg.([]any); ok { for _, teamReviewer := range teamReviewersSlice { if teamReviewerStr, ok := teamReviewer.(string); ok { teamReviewers = append(teamReviewers, teamReviewerStr) @@ -529,7 +529,7 @@ func DeletePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) ( return to.ErrorResult(fmt.Errorf("delete review requests for %v/%v/pr/%v err: %v", owner, repo, index, err)) } - successMsg := map[string]interface{}{ + successMsg := map[string]any{ "message": "Successfully deleted review requests", "reviewers": reviewers, "team_reviewers": teamReviewers, @@ -544,11 +544,11 @@ func ListPullRequestReviewsFn(ctx context.Context, req mcp.CallToolRequest) (*mc log.Debugf("Called ListPullRequestReviewsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -585,11 +585,11 @@ func GetPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp. log.Debugf("Called GetPullRequestReviewFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -597,7 +597,7 @@ func GetPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*mcp. } reviewID, ok := req.GetArguments()["review_id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("review_id is required")) + return to.ErrorResult(errors.New("review_id is required")) } client, err := gitea.ClientFromContext(ctx) @@ -617,11 +617,11 @@ func ListPullRequestReviewCommentsFn(ctx context.Context, req mcp.CallToolReques log.Debugf("Called ListPullRequestReviewCommentsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -629,7 +629,7 @@ func ListPullRequestReviewCommentsFn(ctx context.Context, req mcp.CallToolReques } reviewID, ok := req.GetArguments()["review_id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("review_id is required")) + return to.ErrorResult(errors.New("review_id is required")) } client, err := gitea.ClientFromContext(ctx) @@ -649,11 +649,11 @@ func CreatePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called CreatePullRequestReviewFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -674,9 +674,9 @@ func CreatePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m // Parse inline comments if commentsArg, exists := req.GetArguments()["comments"]; exists { - if commentsSlice, ok := commentsArg.([]interface{}); ok { + if commentsSlice, ok := commentsArg.([]any); ok { for _, comment := range commentsSlice { - if commentMap, ok := comment.(map[string]interface{}); ok { + if commentMap, ok := comment.(map[string]any); ok { reviewComment := gitea_sdk.CreatePullReviewComment{} if path, ok := commentMap["path"].(string); ok { reviewComment.Path = path @@ -713,11 +713,11 @@ func SubmitPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called SubmitPullRequestReviewFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -725,11 +725,11 @@ func SubmitPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m } reviewID, ok := req.GetArguments()["review_id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("review_id is required")) + return to.ErrorResult(errors.New("review_id is required")) } state, ok := req.GetArguments()["state"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("state is required")) + return to.ErrorResult(errors.New("state is required")) } opt := gitea_sdk.SubmitPullReviewOptions{ @@ -756,11 +756,11 @@ func DeletePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m log.Debugf("Called DeletePullRequestReviewFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -768,7 +768,7 @@ func DeletePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m } reviewID, ok := req.GetArguments()["review_id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("review_id is required")) + return to.ErrorResult(errors.New("review_id is required")) } client, err := gitea.ClientFromContext(ctx) @@ -781,7 +781,7 @@ func DeletePullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (*m return to.ErrorResult(fmt.Errorf("delete review %v for %v/%v/pr/%v err: %v", int64(reviewID), owner, repo, index, err)) } - successMsg := map[string]interface{}{ + successMsg := map[string]any{ "message": "Successfully deleted review", "review_id": int64(reviewID), "pr_index": index, @@ -795,11 +795,11 @@ func DismissPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (* log.Debugf("Called DismissPullRequestReviewFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -807,7 +807,7 @@ func DismissPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (* } reviewID, ok := req.GetArguments()["review_id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("review_id is required")) + return to.ErrorResult(errors.New("review_id is required")) } opt := gitea_sdk.DismissPullReviewOptions{} @@ -825,7 +825,7 @@ func DismissPullRequestReviewFn(ctx context.Context, req mcp.CallToolRequest) (* return to.ErrorResult(fmt.Errorf("dismiss review %v for %v/%v/pr/%v err: %v", int64(reviewID), owner, repo, index, err)) } - successMsg := map[string]interface{}{ + successMsg := map[string]any{ "message": "Successfully dismissed review", "review_id": int64(reviewID), "pr_index": index, @@ -839,15 +839,15 @@ func MergePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called MergePullRequestFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, ok := req.GetArguments()["index"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("index is required")) + return to.ErrorResult(errors.New("index is required")) } mergeStyle := "merge" @@ -889,7 +889,7 @@ func MergePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call return to.ErrorResult(fmt.Errorf("merge %v/%v/pr/%v returned merged=false", owner, repo, int64(index))) } - successMsg := map[string]interface{}{ + successMsg := map[string]any{ "merged": merged, "pr_index": int64(index), "repository": fmt.Sprintf("%s/%s", owner, repo), @@ -904,15 +904,15 @@ func EditPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called EditPullRequestFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, ok := req.GetArguments()["index"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("index is required")) + return to.ErrorResult(errors.New("index is required")) } opt := gitea_sdk.EditPullRequestOption{} @@ -921,7 +921,7 @@ func EditPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT opt.Title = title } if body, ok := req.GetArguments()["body"].(string); ok { - opt.Body = ptr.To(body) + opt.Body = new(body) } if base, ok := req.GetArguments()["base"].(string); ok { opt.Base = base @@ -930,7 +930,7 @@ func EditPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT opt.Assignee = assignee } if assigneesArg, exists := req.GetArguments()["assignees"]; exists { - if assigneesSlice, ok := assigneesArg.([]interface{}); ok { + if assigneesSlice, ok := assigneesArg.([]any); ok { var assignees []string for _, a := range assigneesSlice { if s, ok := a.(string); ok { @@ -944,10 +944,10 @@ func EditPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT opt.Milestone = int64(milestone) } if state, ok := req.GetArguments()["state"].(string); ok { - opt.State = ptr.To(gitea_sdk.StateType(state)) + opt.State = new(gitea_sdk.StateType(state)) } if allowMaintainerEdit, ok := req.GetArguments()["allow_maintainer_edit"].(bool); ok { - opt.AllowMaintainerEdit = ptr.To(allowMaintainerEdit) + opt.AllowMaintainerEdit = new(allowMaintainerEdit) } client, err := gitea.ClientFromContext(ctx) diff --git a/operation/pull/pull_test.go b/operation/pull/pull_test.go index aaca693..86f97ee 100644 --- a/operation/pull/pull_test.go +++ b/operation/pull/pull_test.go @@ -21,10 +21,10 @@ func TestEditPullRequestFn(t *testing.T) { ) var ( - mu sync.Mutex - gotMethod string - gotPath string - gotBody map[string]any + mu sync.Mutex + gotMethod string + gotPath string + gotBody map[string]any ) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -44,7 +44,7 @@ func TestEditPullRequestFn(t *testing.T) { gotBody = body mu.Unlock() w.Header().Set("Content-Type", "application/json") - _, _ = w.Write([]byte(fmt.Sprintf(`{"number":%d,"title":"%s","state":"open"}`, index, body["title"]))) + _, _ = w.Write(fmt.Appendf(nil, `{"number":%d,"title":"%s","state":"open"}`, index, body["title"])) default: http.NotFound(w, r) } diff --git a/operation/repo/branch.go b/operation/repo/branch.go index 1680915..e4dac5b 100644 --- a/operation/repo/branch.go +++ b/operation/repo/branch.go @@ -2,6 +2,7 @@ package repo import ( "context" + "errors" "fmt" "gitea.com/gitea/gitea-mcp/pkg/gitea" @@ -64,15 +65,15 @@ func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool log.Debugf("Called CreateBranchFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } branch, ok := req.GetArguments()["branch"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("branch is required")) + return to.ErrorResult(errors.New("branch is required")) } oldBranch, _ := req.GetArguments()["old_branch"].(string) @@ -95,15 +96,15 @@ func DeleteBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool log.Debugf("Called DeleteBranchFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } branch, ok := req.GetArguments()["branch"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("branch is required")) + return to.ErrorResult(errors.New("branch is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -121,11 +122,11 @@ func ListBranchesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool log.Debugf("Called ListBranchesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } opt := gitea_sdk.ListRepoBranchesOptions{ ListOptions: gitea_sdk.ListOptions{ diff --git a/operation/repo/commit.go b/operation/repo/commit.go index 1aa61e5..77fab4b 100644 --- a/operation/repo/commit.go +++ b/operation/repo/commit.go @@ -2,6 +2,7 @@ package repo import ( "context" + "errors" "fmt" "gitea.com/gitea/gitea-mcp/pkg/gitea" @@ -39,19 +40,19 @@ func ListRepoCommitsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called ListRepoCommitsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, ok := req.GetArguments()["page"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("page is required")) + return to.ErrorResult(errors.New("page is required")) } pageSize, ok := req.GetArguments()["page_size"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("page_size is required")) + return to.ErrorResult(errors.New("page_size is required")) } sha, _ := req.GetArguments()["sha"].(string) path, _ := req.GetArguments()["path"].(string) diff --git a/operation/repo/file.go b/operation/repo/file.go index 01465df..623678f 100644 --- a/operation/repo/file.go +++ b/operation/repo/file.go @@ -6,6 +6,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "gitea.com/gitea/gitea-mcp/pkg/gitea" @@ -113,16 +114,16 @@ func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called GetFileFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } ref, _ := req.GetArguments()["ref"].(string) filePath, ok := req.GetArguments()["filePath"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("filePath is required")) + return to.ErrorResult(errors.New("filePath is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -151,7 +152,6 @@ func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo LineNumber: line, Content: scanner.Text(), }) - } if err := scanner.Err(); err != nil { return to.ErrorResult(fmt.Errorf("scan content err: %v", err)) @@ -177,16 +177,16 @@ func GetDirContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called GetDirContentFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } ref, _ := req.GetArguments()["ref"].(string) filePath, ok := req.GetArguments()["filePath"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("filePath is required")) + return to.ErrorResult(errors.New("filePath is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -203,15 +203,15 @@ func CreateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe log.Debugf("Called CreateFileFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } filePath, ok := req.GetArguments()["filePath"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("filePath is required")) + return to.ErrorResult(errors.New("filePath is required")) } content, _ := req.GetArguments()["content"].(string) message, _ := req.GetArguments()["message"].(string) @@ -239,19 +239,19 @@ func UpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe log.Debugf("Called UpdateFileFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } filePath, ok := req.GetArguments()["filePath"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("filePath is required")) + return to.ErrorResult(errors.New("filePath is required")) } sha, ok := req.GetArguments()["sha"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("sha is required")) + return to.ErrorResult(errors.New("sha is required")) } content, _ := req.GetArguments()["content"].(string) message, _ := req.GetArguments()["message"].(string) @@ -280,21 +280,21 @@ func DeleteFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe log.Debugf("Called DeleteFileFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } filePath, ok := req.GetArguments()["filePath"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("filePath is required")) + return to.ErrorResult(errors.New("filePath is required")) } message, _ := req.GetArguments()["message"].(string) branchName, _ := req.GetArguments()["branch_name"].(string) sha, ok := req.GetArguments()["sha"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("sha is required")) + return to.ErrorResult(errors.New("sha is required")) } opt := gitea_sdk.DeleteFileOptions{ FileOptions: gitea_sdk.FileOptions{ diff --git a/operation/repo/release.go b/operation/repo/release.go index 7bdf4b5..04631f0 100644 --- a/operation/repo/release.go +++ b/operation/repo/release.go @@ -2,12 +2,12 @@ package repo import ( "context" + "errors" "fmt" "time" "gitea.com/gitea/gitea-mcp/pkg/gitea" "gitea.com/gitea/gitea-mcp/pkg/log" - "gitea.com/gitea/gitea-mcp/pkg/ptr" "gitea.com/gitea/gitea-mcp/pkg/to" gitea_sdk "code.gitea.io/sdk/gitea" @@ -112,23 +112,23 @@ func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called CreateReleasesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } tagName, ok := req.GetArguments()["tag_name"].(string) if !ok { - return nil, fmt.Errorf("tag_name is required") + return nil, errors.New("tag_name is required") } target, ok := req.GetArguments()["target"].(string) if !ok { - return nil, fmt.Errorf("target is required") + return nil, errors.New("target is required") } title, ok := req.GetArguments()["title"].(string) if !ok { - return nil, fmt.Errorf("title is required") + return nil, errors.New("title is required") } isDraft, _ := req.GetArguments()["is_draft"].(bool) isPreRelease, _ := req.GetArguments()["is_pre_release"].(bool) @@ -157,15 +157,15 @@ func DeleteReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called DeleteReleaseFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } id, ok := req.GetArguments()["id"].(float64) if !ok { - return nil, fmt.Errorf("id is required") + return nil, errors.New("id is required") } client, err := gitea.ClientFromContext(ctx) @@ -184,15 +184,15 @@ func GetReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe log.Debugf("Called GetReleaseFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } id, ok := req.GetArguments()["id"].(float64) if !ok { - return nil, fmt.Errorf("id is required") + return nil, errors.New("id is required") } client, err := gitea.ClientFromContext(ctx) @@ -211,11 +211,11 @@ func GetLatestReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called GetLatestReleaseFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } client, err := gitea.ClientFromContext(ctx) @@ -234,21 +234,21 @@ func ListReleasesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool log.Debugf("Called ListReleasesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } var pIsDraft *bool isDraft, ok := req.GetArguments()["is_draft"].(bool) if ok { - pIsDraft = ptr.To(isDraft) + pIsDraft = new(isDraft) } var pIsPreRelease *bool isPreRelease, ok := req.GetArguments()["is_pre_release"].(bool) if ok { - pIsPreRelease = ptr.To(isPreRelease) + pIsPreRelease = new(isPreRelease) } page, _ := req.GetArguments()["page"].(float64) pageSize, _ := req.GetArguments()["pageSize"].(float64) diff --git a/operation/repo/repo.go b/operation/repo/repo.go index 76b202c..d7a191f 100644 --- a/operation/repo/repo.go +++ b/operation/repo/repo.go @@ -7,7 +7,6 @@ import ( "gitea.com/gitea/gitea-mcp/pkg/gitea" "gitea.com/gitea/gitea-mcp/pkg/log" - "gitea.com/gitea/gitea-mcp/pkg/ptr" "gitea.com/gitea/gitea-mcp/pkg/to" "gitea.com/gitea/gitea-mcp/pkg/tool" @@ -166,12 +165,12 @@ func ForkRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu return to.ErrorResult(errors.New("repository name is required")) } organization, ok := req.GetArguments()["organization"].(string) - organizationPtr := ptr.To(organization) + organizationPtr := new(organization) if !ok || organization == "" { organizationPtr = nil } name, ok := req.GetArguments()["name"].(string) - namePtr := ptr.To(name) + namePtr := new(name) if !ok || name == "" { namePtr = nil } diff --git a/operation/repo/tag.go b/operation/repo/tag.go index 02fcb7a..4f792e1 100644 --- a/operation/repo/tag.go +++ b/operation/repo/tag.go @@ -2,6 +2,7 @@ package repo import ( "context" + "errors" "fmt" "gitea.com/gitea/gitea-mcp/pkg/gitea" @@ -89,15 +90,15 @@ func CreateTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes log.Debugf("Called CreateTagFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } tagName, ok := req.GetArguments()["tag_name"].(string) if !ok { - return nil, fmt.Errorf("tag_name is required") + return nil, errors.New("tag_name is required") } target, _ := req.GetArguments()["target"].(string) message, _ := req.GetArguments()["message"].(string) @@ -122,15 +123,15 @@ func DeleteTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRes log.Debugf("Called DeleteTagFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } tagName, ok := req.GetArguments()["tag_name"].(string) if !ok { - return nil, fmt.Errorf("tag_name is required") + return nil, errors.New("tag_name is required") } client, err := gitea.ClientFromContext(ctx) @@ -149,15 +150,15 @@ func GetTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult log.Debugf("Called GetTagFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } tagName, ok := req.GetArguments()["tag_name"].(string) if !ok { - return nil, fmt.Errorf("tag_name is required") + return nil, errors.New("tag_name is required") } client, err := gitea.ClientFromContext(ctx) @@ -176,11 +177,11 @@ func ListTagsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu log.Debugf("Called ListTagsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return nil, fmt.Errorf("owner is required") + return nil, errors.New("owner is required") } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return nil, fmt.Errorf("repo is required") + return nil, errors.New("repo is required") } page, _ := req.GetArguments()["page"].(float64) pageSize, _ := req.GetArguments()["pageSize"].(float64) diff --git a/operation/search/search.go b/operation/search/search.go index c18d252..3dee452 100644 --- a/operation/search/search.go +++ b/operation/search/search.go @@ -2,11 +2,11 @@ package search import ( "context" + "errors" "fmt" "gitea.com/gitea/gitea-mcp/pkg/gitea" "gitea.com/gitea/gitea-mcp/pkg/log" - "gitea.com/gitea/gitea-mcp/pkg/ptr" "gitea.com/gitea/gitea-mcp/pkg/to" "gitea.com/gitea/gitea-mcp/pkg/tool" @@ -61,23 +61,23 @@ var ( func init() { Tool.RegisterRead(server.ServerTool{ Tool: SearchUsersTool, - Handler: SearchUsersFn, + Handler: UsersFn, }) Tool.RegisterRead(server.ServerTool{ Tool: SearOrgTeamsTool, - Handler: SearchOrgTeamsFn, + Handler: OrgTeamsFn, }) Tool.RegisterRead(server.ServerTool{ Tool: SearchReposTool, - Handler: SearchReposFn, + Handler: ReposFn, }) } -func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - log.Debugf("Called SearchUsersFn") +func UsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + log.Debugf("Called UsersFn") keyword, ok := req.GetArguments()["keyword"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("keyword is required")) + return to.ErrorResult(errors.New("keyword is required")) } page, ok := req.GetArguments()["page"].(float64) if !ok { @@ -105,15 +105,15 @@ func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR return to.TextResult(users) } -func SearchOrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - log.Debugf("Called SearchOrgTeamsFn") +func OrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + log.Debugf("Called OrgTeamsFn") org, ok := req.GetArguments()["org"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("organization is required")) + return to.ErrorResult(errors.New("organization is required")) } query, ok := req.GetArguments()["query"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("query is required")) + return to.ErrorResult(errors.New("query is required")) } includeDescription, _ := req.GetArguments()["includeDescription"].(bool) page, ok := req.GetArguments()["page"].(float64) @@ -143,11 +143,11 @@ func SearchOrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo return to.TextResult(teams) } -func SearchReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { - log.Debugf("Called SearchReposFn") +func ReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + log.Debugf("Called ReposFn") keyword, ok := req.GetArguments()["keyword"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("keyword is required")) + return to.ErrorResult(errors.New("keyword is required")) } keywordIsTopic, _ := req.GetArguments()["keywordIsTopic"].(bool) keywordInDescription, _ := req.GetArguments()["keywordInDescription"].(bool) @@ -155,12 +155,12 @@ func SearchReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR var pIsPrivate *bool isPrivate, ok := req.GetArguments()["isPrivate"].(bool) if ok { - pIsPrivate = ptr.To(isPrivate) + pIsPrivate = new(isPrivate) } var pIsArchived *bool isArchived, ok := req.GetArguments()["isArchived"].(bool) if ok { - pIsArchived = ptr.To(isArchived) + pIsArchived = new(isArchived) } sort, _ := req.GetArguments()["sort"].(string) order, _ := req.GetArguments()["order"].(string) diff --git a/operation/timetracking/timetracking.go b/operation/timetracking/timetracking.go index 0f6d169..38c797a 100644 --- a/operation/timetracking/timetracking.go +++ b/operation/timetracking/timetracking.go @@ -3,6 +3,7 @@ package timetracking import ( "context" + "errors" "fmt" gitea_sdk "code.gitea.io/sdk/gitea" @@ -129,11 +130,11 @@ func StartStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called StartStopwatchFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -154,11 +155,11 @@ func StopStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called StopStopwatchFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -179,11 +180,11 @@ func DeleteStopwatchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT log.Debugf("Called DeleteStopwatchFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -222,11 +223,11 @@ func ListTrackedTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called ListTrackedTimesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -264,11 +265,11 @@ func AddTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called AddTrackedTimeFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") if err != nil { @@ -277,7 +278,7 @@ func AddTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo timeSeconds, ok := req.GetArguments()["time"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("time is required")) + return to.ErrorResult(errors.New("time is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -296,11 +297,11 @@ func DeleteTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal log.Debugf("Called DeleteTrackedTimeFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } index, err := params.GetIndex(req.GetArguments(), "index") @@ -309,7 +310,7 @@ func DeleteTrackedTimeFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal } id, ok := req.GetArguments()["id"].(float64) if !ok { - return to.ErrorResult(fmt.Errorf("id is required")) + return to.ErrorResult(errors.New("id is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { @@ -326,11 +327,11 @@ func ListRepoTimesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called ListRepoTimesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } page, ok := req.GetArguments()["page"].(float64) diff --git a/operation/wiki/wiki.go b/operation/wiki/wiki.go index 13aeb13..c0bf9e8 100644 --- a/operation/wiki/wiki.go +++ b/operation/wiki/wiki.go @@ -2,6 +2,7 @@ package wiki import ( "context" + "errors" "fmt" "net/url" @@ -110,11 +111,11 @@ func ListWikiPagesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToo log.Debugf("Called ListWikiPagesFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } // Use direct HTTP request because SDK does not support yet wikis @@ -131,15 +132,15 @@ func GetWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR log.Debugf("Called GetWikiPageFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } pageName, ok := req.GetArguments()["pageName"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("pageName is required")) + return to.ErrorResult(errors.New("pageName is required")) } var result any @@ -155,15 +156,15 @@ func GetWikiRevisionsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call log.Debugf("Called GetWikiRevisionsFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } pageName, ok := req.GetArguments()["pageName"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("pageName is required")) + return to.ErrorResult(errors.New("pageName is required")) } var result any @@ -179,19 +180,19 @@ func CreateWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called CreateWikiPageFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } title, ok := req.GetArguments()["title"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("title is required")) + return to.ErrorResult(errors.New("title is required")) } contentBase64, ok := req.GetArguments()["content_base64"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("content_base64 is required")) + return to.ErrorResult(errors.New("content_base64 is required")) } message, _ := req.GetArguments()["message"].(string) @@ -218,19 +219,19 @@ func UpdateWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called UpdateWikiPageFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } pageName, ok := req.GetArguments()["pageName"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("pageName is required")) + return to.ErrorResult(errors.New("pageName is required")) } contentBase64, ok := req.GetArguments()["content_base64"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("content_base64 is required")) + return to.ErrorResult(errors.New("content_base64 is required")) } requestBody := map[string]string{ @@ -264,15 +265,15 @@ func DeleteWikiPageFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo log.Debugf("Called DeleteWikiPageFn") owner, ok := req.GetArguments()["owner"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("owner is required")) + return to.ErrorResult(errors.New("owner is required")) } repo, ok := req.GetArguments()["repo"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("repo is required")) + return to.ErrorResult(errors.New("repo is required")) } pageName, ok := req.GetArguments()["pageName"].(string) if !ok { - return to.ErrorResult(fmt.Errorf("pageName is required")) + return to.ErrorResult(errors.New("pageName is required")) } _, err := gitea.DoJSON(ctx, "DELETE", fmt.Sprintf("repos/%s/%s/wiki/page/%s", url.QueryEscape(owner), url.QueryEscape(repo), url.QueryEscape(pageName)), nil, nil, nil) diff --git a/pkg/gitea/gitea.go b/pkg/gitea/gitea.go index 1b7bc9c..3f3a4d7 100644 --- a/pkg/gitea/gitea.go +++ b/pkg/gitea/gitea.go @@ -34,7 +34,7 @@ func NewClient(token string) (*gitea.Client, error) { } // Set user agent for the client - client.SetUserAgent(fmt.Sprintf("gitea-mcp-server/%s", flag.Version)) + client.SetUserAgent("gitea-mcp-server/" + flag.Version) return client, nil } diff --git a/pkg/gitea/rest.go b/pkg/gitea/rest.go index fa69e9a..982dfef 100644 --- a/pkg/gitea/rest.go +++ b/pkg/gitea/rest.go @@ -5,6 +5,7 @@ import ( "context" "crypto/tls" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -40,7 +41,7 @@ func tokenFromContext(ctx context.Context) string { func newRESTHTTPClient() *http.Client { transport := http.DefaultTransport.(*http.Transport).Clone() if flag.Insecure { - transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec // user-requested insecure mode } return &http.Client{ Transport: transport, @@ -51,7 +52,7 @@ func newRESTHTTPClient() *http.Client { func buildAPIURL(path string, query url.Values) (string, error) { host := strings.TrimRight(flag.Host, "/") if host == "" { - return "", fmt.Errorf("gitea host is empty") + return "", errors.New("gitea host is empty") } p := strings.TrimLeft(path, "/") u, err := url.Parse(fmt.Sprintf("%s/api/v1/%s", host, p)) @@ -66,7 +67,7 @@ func buildAPIURL(path string, query url.Values) (string, error) { // DoJSON performs an API request and decodes a JSON response into respOut (if non-nil). // It returns the HTTP status code. -func DoJSON(ctx context.Context, method, path string, query url.Values, body any, respOut any) (int, error) { +func DoJSON(ctx context.Context, method, path string, query url.Values, body, respOut any) (int, error) { var bodyReader io.Reader if body != nil { b, err := json.Marshal(body) @@ -87,7 +88,7 @@ func DoJSON(ctx context.Context, method, path string, query url.Values, body any token := tokenFromContext(ctx) if token != "" { - req.Header.Set("Authorization", fmt.Sprintf("token %s", token)) + req.Header.Set("Authorization", "token "+token) } req.Header.Set("Accept", "application/json") if body != nil { @@ -107,7 +108,7 @@ func DoJSON(ctx context.Context, method, path string, query url.Values, body any } if respOut == nil { - io.Copy(io.Discard, resp.Body) // best-effort + _, _ = io.Copy(io.Discard, resp.Body) // best-effort return resp.StatusCode, nil } @@ -140,7 +141,7 @@ func DoBytes(ctx context.Context, method, path string, query url.Values, body an token := tokenFromContext(ctx) if token != "" { - req.Header.Set("Authorization", fmt.Sprintf("token %s", token)) + req.Header.Set("Authorization", "token "+token) } if accept != "" { req.Header.Set("Accept", accept) @@ -171,5 +172,3 @@ func DoBytes(ctx context.Context, method, path string, query url.Values, body an return respBytes, resp.StatusCode, nil } - - diff --git a/pkg/gitea/rest_test.go b/pkg/gitea/rest_test.go index 579cc34..4d3d841 100644 --- a/pkg/gitea/rest_test.go +++ b/pkg/gitea/rest_test.go @@ -28,5 +28,3 @@ func TestTokenFromContext(t *testing.T) { } }) } - - diff --git a/pkg/log/log.go b/pkg/log/log.go index f0be5cd..caeb4bb 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -1,7 +1,6 @@ package log import ( - "fmt" "os" "sync" "time" @@ -35,14 +34,14 @@ func Default() *zap.Logger { home = os.TempDir() } - logDir := fmt.Sprintf("%s/.gitea-mcp", home) + logDir := home + "/.gitea-mcp" if err := os.MkdirAll(logDir, 0o700); err != nil { // Fallback to temp directory if creation fails logDir = os.TempDir() } wss = append(wss, zapcore.AddSync(&lumberjack.Logger{ - Filename: fmt.Sprintf("%s/gitea-mcp.log", logDir), + Filename: logDir + "/gitea-mcp.log", MaxSize: 100, MaxBackups: 10, MaxAge: 30, diff --git a/pkg/params/params.go b/pkg/params/params.go index 6afdafc..3f6275e 100644 --- a/pkg/params/params.go +++ b/pkg/params/params.go @@ -9,7 +9,7 @@ import ( // It accepts both numeric (float64 from JSON) and string representations. // This provides better UX for LLM callers that may naturally use strings // for identifiers like issue/PR numbers. -func GetIndex(args map[string]interface{}, key string) (int64, error) { +func GetIndex(args map[string]any, key string) (int64, error) { val, exists := args[key] if !exists { return 0, fmt.Errorf("%s is required", key) diff --git a/pkg/params/params_test.go b/pkg/params/params_test.go index 3077691..f951cc4 100644 --- a/pkg/params/params_test.go +++ b/pkg/params/params_test.go @@ -8,7 +8,7 @@ import ( func TestGetIndex(t *testing.T) { tests := []struct { name string - args map[string]interface{} + args map[string]any key string wantIndex int64 wantErr bool @@ -16,63 +16,63 @@ func TestGetIndex(t *testing.T) { }{ { name: "valid float64", - args: map[string]interface{}{"index": float64(123)}, + args: map[string]any{"index": float64(123)}, key: "index", wantIndex: 123, wantErr: false, }, { name: "valid string", - args: map[string]interface{}{"index": "456"}, + args: map[string]any{"index": "456"}, key: "index", wantIndex: 456, wantErr: false, }, { name: "valid string with large number", - args: map[string]interface{}{"index": "999999"}, + args: map[string]any{"index": "999999"}, key: "index", wantIndex: 999999, wantErr: false, }, { name: "missing parameter", - args: map[string]interface{}{}, + args: map[string]any{}, key: "index", wantErr: true, errMsg: "index is required", }, { name: "invalid string (not a number)", - args: map[string]interface{}{"index": "abc"}, + args: map[string]any{"index": "abc"}, key: "index", wantErr: true, errMsg: "must be a valid integer", }, { name: "invalid string (decimal)", - args: map[string]interface{}{"index": "12.34"}, + args: map[string]any{"index": "12.34"}, key: "index", wantErr: true, errMsg: "must be a valid integer", }, { name: "invalid type (bool)", - args: map[string]interface{}{"index": true}, + args: map[string]any{"index": true}, key: "index", wantErr: true, errMsg: "must be a number or numeric string", }, { name: "invalid type (map)", - args: map[string]interface{}{"index": map[string]string{"foo": "bar"}}, + args: map[string]any{"index": map[string]string{"foo": "bar"}}, key: "index", wantErr: true, errMsg: "must be a number or numeric string", }, { name: "custom key name", - args: map[string]interface{}{"pr_index": "789"}, + args: map[string]any{"pr_index": "789"}, key: "pr_index", wantIndex: 789, wantErr: false, diff --git a/pkg/ptr/ptr.go b/pkg/ptr/ptr.go deleted file mode 100644 index 659ed3b..0000000 --- a/pkg/ptr/ptr.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright 2023 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ptr - -import ( - "fmt" - "reflect" -) - -// AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when, -// for example, an API struct is handled by plugins which need to distinguish -// "no plugin accepted this spec" from "this spec is empty". -// -// This function is only valid for structs and pointers to structs. Any other -// type will cause a panic. Passing a typed nil pointer will return true. -func AllPtrFieldsNil(obj interface{}) bool { - v := reflect.ValueOf(obj) - if !v.IsValid() { - panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj)) - } - if v.Kind() == reflect.Ptr { - if v.IsNil() { - return true - } - v = v.Elem() - } - for i := 0; i < v.NumField(); i++ { - if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() { - return false - } - } - return true -} - -// To returns a pointer to the given value. -func To[T any](v T) *T { - return &v -} - -// Deref dereferences ptr and returns the value it points to if no nil, or else -// returns def. -func Deref[T any](ptr *T, def T) T { - if ptr != nil { - return *ptr - } - return def -} - -// Equal returns true if both arguments are nil or both arguments -// dereference to the same value. -func Equal[T comparable](a, b *T) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -}