From 2ecffd1b7a0a83862e711edc66c3477ec98e70fd Mon Sep 17 00:00:00 2001 From: Mathias Bergqvist Date: Mon, 4 May 2026 21:26:03 +0200 Subject: [PATCH] feat(gitea): base http client with token auth --- internal/gitea/client.go | 69 +++++++++++++++++++++++++++++++++++ internal/gitea/client_test.go | 29 +++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 internal/gitea/client.go create mode 100644 internal/gitea/client_test.go diff --git a/internal/gitea/client.go b/internal/gitea/client.go new file mode 100644 index 0000000..864ce3e --- /dev/null +++ b/internal/gitea/client.go @@ -0,0 +1,69 @@ +package gitea + +import ( + "bytes" + "context" + "io" + "net/http" + "time" +) + +type Client struct { + baseURL string + token string + hc *http.Client +} + +func NewClient(baseURL, token string) *Client { + return &Client{ + baseURL: baseURL, + token: token, + hc: &http.Client{Timeout: 30 * time.Second}, + } +} + +func (c *Client) do(ctx context.Context, method, path string, body []byte) ([]byte, int, error) { + var reader io.Reader + if body != nil { + reader = bytes.NewReader(body) + } + req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, reader) + if err != nil { + return nil, 0, err + } + if c.token != "" { + req.Header.Set("Authorization", "token "+c.token) + } + if body != nil { + req.Header.Set("Content-Type", "application/json") + } + req.Header.Set("Accept", "application/json") + + resp, err := c.hc.Do(req) + if err != nil { + return nil, 0, err + } + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + return b, resp.StatusCode, err +} + +func (c *Client) GetJSON(ctx context.Context, path string) ([]byte, int, error) { + return c.do(ctx, http.MethodGet, path, nil) +} + +func (c *Client) PostJSON(ctx context.Context, path string, body []byte) ([]byte, int, error) { + return c.do(ctx, http.MethodPost, path, body) +} + +func (c *Client) PatchJSON(ctx context.Context, path string, body []byte) ([]byte, int, error) { + return c.do(ctx, http.MethodPatch, path, body) +} + +func (c *Client) PutJSON(ctx context.Context, path string, body []byte) ([]byte, int, error) { + return c.do(ctx, http.MethodPut, path, body) +} + +func (c *Client) DeleteJSON(ctx context.Context, path string) ([]byte, int, error) { + return c.do(ctx, http.MethodDelete, path, nil) +} diff --git a/internal/gitea/client_test.go b/internal/gitea/client_test.go new file mode 100644 index 0000000..cdeb976 --- /dev/null +++ b/internal/gitea/client_test.go @@ -0,0 +1,29 @@ +package gitea_test + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "gitea.d-ma.be/mathias/gitea-mcp/internal/gitea" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestClientGetsTokenInHeader(t *testing.T) { + var gotAuth string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotAuth = r.Header.Get("Authorization") + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"ok":true}`)) + })) + defer srv.Close() + + c := gitea.NewClient(srv.URL, "test-token") + body, status, err := c.GetJSON(context.Background(), "/api/v1/user") + require.NoError(t, err) + assert.Equal(t, 200, status) + assert.Contains(t, string(body), `"ok":true`) + assert.Equal(t, "token test-token", gotAuth) +}