package gitclient import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/url" "time" ) type giteaClient struct { baseURL string token string httpClient *http.Client } func NewClient(baseURL, token string) GitClient { return &giteaClient{ baseURL: baseURL, token: token, httpClient: &http.Client{Timeout: 30 * time.Second}, } } func (c *giteaClient) doRequest(method, path string, body interface{}) ([]byte, error) { u := c.baseURL + "/api/v1" + path var bodyReader io.Reader if body != nil { data, err := json.Marshal(body) if err != nil { return nil, fmt.Errorf("marshaling body: %w", err) } bodyReader = bytes.NewReader(data) } req, err := http.NewRequest(method, u, bodyReader) if err != nil { return nil, fmt.Errorf("creating request: %w", err) } req.Header.Set("Authorization", "token "+c.token) if body != nil { req.Header.Set("Content-Type", "application/json") } resp, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("executing request: %w", err) } defer resp.Body.Close() data, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("reading response: %w", err) } if resp.StatusCode >= 400 { return nil, fmt.Errorf("gitea API error (%d): %s", resp.StatusCode, string(data)) } return data, nil } func (c *giteaClient) ListRepositories(owner string) ([]Repository, error) { data, err := c.doRequest("GET", "/repos/search?limit=50&owner="+url.QueryEscape(owner), nil) if err != nil { return nil, err } var result struct { Data []Repository `json:"data"` } if err := json.Unmarshal(data, &result); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } return result.Data, nil } func (c *giteaClient) CreateRepository(owner, name, description string, private bool) (*Repository, error) { body := map[string]interface{}{ "name": name, "description": description, "private": private, } data, err := c.doRequest("POST", "/user/repos", body) if err != nil { return nil, err } var repo Repository if err := json.Unmarshal(data, &repo); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } return &repo, nil } func (c *giteaClient) GetRepository(owner, name string) (*Repository, error) { data, err := c.doRequest("GET", "/repos/"+url.PathEscape(owner)+"/"+url.PathEscape(name), nil) if err != nil { return nil, err } var repo Repository if err := json.Unmarshal(data, &repo); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } return &repo, nil } func (c *giteaClient) ListBranches(owner, repo string) ([]Branch, error) { data, err := c.doRequest("GET", "/repos/"+url.PathEscape(owner)+"/"+url.PathEscape(repo)+"/branches", nil) if err != nil { return nil, err } var branches []Branch if err := json.Unmarshal(data, &branches); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } return branches, nil } func (c *giteaClient) GetBranch(owner, repo, branch string) (*Branch, error) { data, err := c.doRequest("GET", "/repos/"+url.PathEscape(owner)+"/"+url.PathEscape(repo)+"/branches/"+url.PathEscape(branch), nil) if err != nil { return nil, err } var b Branch if err := json.Unmarshal(data, &b); err != nil { return nil, fmt.Errorf("parsing response: %w", err) } return &b, nil }