mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
- `internal/services`: typed Gitea workflows built on `gitea.dev/sdk`, independent of CLI flags and terminal I/O: issues, pull requests, reviews, comments, labels, milestones, releases and assets, repositories, branches, wiki, Actions (workflows, runs, jobs, logs, artifacts, secrets, variables), organizations, teams, webhooks, notifications, SSH keys, tracked time, admin users, search and status. - SDK types are mapped to tea's own output types, so `--json` stays a stable contract. Requests the SDK cannot express yet (e.g. pull list filters, multi-status run lists, org label archiving) go through small raw helpers, each marked `TODO(sdk)` with the missing SDK piece. - Targets Gitea 28 or newer: no version or API-schema probing. List helpers fill pages capped by `MAX_RESPONSE_ITEMS`. Nothing imports this package yet. Reviewed-on: https://gitea.com/gitea/tea/pulls/1125 Reviewed-by: TheFox0x7 <95654+thefox0x7@noreply.gitea.com>
74 lines
2.1 KiB
Go
74 lines
2.1 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package services
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
|
|
"gitea.dev/tea/internal/transport"
|
|
)
|
|
|
|
var errInvalidJSON = errors.New("Gitea returned an invalid JSON response")
|
|
|
|
// getJSON decodes a raw GET response into out.
|
|
func getJSON(ctx context.Context, client *transport.Client, endpoint string, out any) error {
|
|
_, err := rawJSON(ctx, client, http.MethodGet, endpoint, nil, out)
|
|
return err
|
|
}
|
|
|
|
// sendJSON sends payload as a JSON body, or no body when it is nil, and decodes the response
|
|
// into out unless out is nil.
|
|
func sendJSON(ctx context.Context, client *transport.Client, method, endpoint string, payload, out any) error {
|
|
var body io.Reader
|
|
if payload != nil {
|
|
data, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
body = bytes.NewReader(data)
|
|
}
|
|
_, err := rawJSON(ctx, client, method, endpoint, body, out)
|
|
return err
|
|
}
|
|
|
|
// rawWindow is listWindow over a raw JSON collection endpoint; it sets limit and page on query.
|
|
func rawWindow[T any](ctx context.Context, client *transport.Client, endpoint string, query url.Values, limit, page int) ([]T, bool, error) {
|
|
if query == nil {
|
|
query = url.Values{}
|
|
}
|
|
return listWindow(limit, page, func(limit, page int) ([]T, http.Header, error) {
|
|
query.Set("limit", strconv.Itoa(limit))
|
|
query.Set("page", strconv.Itoa(page))
|
|
var response []T
|
|
headers, err := rawJSON(ctx, client, http.MethodGet, endpoint+"?"+query.Encode(), nil, &response)
|
|
return response, headers, err
|
|
})
|
|
}
|
|
|
|
func rawJSON(ctx context.Context, client *transport.Client, method, endpoint string, body io.Reader, out any) (http.Header, error) {
|
|
resp, err := client.Do(ctx, method, endpoint, body, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if out == nil || resp.StatusCode == http.StatusNoContent {
|
|
_, err = io.Copy(io.Discard, resp.Body)
|
|
return resp.Header, err
|
|
}
|
|
if err := json.NewDecoder(resp.Body).Decode(out); err != nil {
|
|
if ctx.Err() != nil {
|
|
return nil, ctx.Err()
|
|
}
|
|
return nil, errInvalidJSON
|
|
}
|
|
return resp.Header, nil
|
|
}
|