Files
teai/internal/workflow/giteaapi.go
chenyunda218 5583a00bb5 internal/workflow + cli:gitea.py 工作流命令 Go 化(#6)
- internal/workflow:Client 介面+判定語義(最後留言、作者/審核者跟進、
  assignee 交集、最久未更新優先),含假 client 單元測試
- internal/workflow/giteaapi.go:以 internal/gitea(#5)實作 Client
- internal/cli:註冊 whoami/orgs/members/mine/pulls/next;全域選項允許
  出現在命令之後;結束碼 0/2/3
- 與 gitea.py 交叉驗證:next/mine/pulls/members(--has-work) 拾取一致
- 依 #5 分支 feature/issue5-gitea-client 為基底
2026-09-10 08:39:35 +08:00

125 lines
3.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// giteaapi.go — 以 internal/gitea 的 HTTP 用戶端實作 workflow.Client。
//
// 端點與查詢參數對照 gitea.py:清單一律帶 limit 分頁(ListAll 固定 50);
// issues 端點帶 type=issues(排除 PR)與 state=open;pulls 帶 state=open。
package workflow
import (
"context"
"errors"
"net/url"
"strconv"
"gitea.alterminal.com/alterminal/teai/internal/gitea"
)
// errNoUsername 表示 /user 回應中找不到帳號名(伺服端回應異常)。
var errNoUsername = errors.New("gitea: GET /user: response has no username")
// APIClient 是 Client 介面的 HTTP 實作,包裝 internal/gitea.Client。
type APIClient struct {
Client *gitea.Client
}
// 確認 APIClient 實作 Client 介面(編譯期檢查)。
var _ Client = (*APIClient)(nil)
func (a *APIClient) CurrentUser() (string, error) {
var u User
if err := a.Client.GetJSON(context.Background(), "/user", &u); err != nil {
return "", err
}
name := u.Name()
if name == "" {
return "", errNoUsername
}
return name, nil
}
func (a *APIClient) ListOrgs() ([]string, error) {
var orgs []Org
if err := a.Client.ListAll(context.Background(), "/user/orgs", gitea.ListOptions{}, &orgs); err != nil {
return nil, err
}
names := make([]string, 0, len(orgs))
for _, o := range orgs {
if n := o.Account(); n != "" {
names = append(names, n)
}
}
return names, nil
}
func (a *APIClient) ListTeams(org string) ([]Team, error) {
var teams []Team
path := "/orgs/" + url.PathEscape(org) + "/teams"
if err := a.Client.ListAll(context.Background(), path, gitea.ListOptions{}, &teams); err != nil {
return nil, err
}
return teams, nil
}
func (a *APIClient) ListTeamMembers(teamID int64) ([]string, error) {
var users []User
path := "/teams/" + strconv.FormatInt(teamID, 10) + "/members"
if err := a.Client.ListAll(context.Background(), path, gitea.ListOptions{}, &users); err != nil {
return nil, err
}
names := make([]string, 0, len(users))
for i := range users {
if n := users[i].Name(); n != "" {
names = append(names, n)
}
}
return names, nil
}
func (a *APIClient) ListOrgRepos(org string) ([]Repo, error) {
var repos []Repo
path := "/orgs/" + url.PathEscape(org) + "/repos"
if err := a.Client.ListAll(context.Background(), path, gitea.ListOptions{}, &repos); err != nil {
return nil, err
}
return repos, nil
}
func (a *APIClient) ListIssues(owner, repo string) ([]Issue, error) {
var issues []Issue
path := "/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(repo) + "/issues"
opts := gitea.ListOptions{Extra: url.Values{
"type": {"issues"},
"state": {"open"},
}}
if err := a.Client.ListAll(context.Background(), path, opts, &issues); err != nil {
return nil, err
}
// /issues 也會回傳 PR(帶 pull_request 欄位);一律排除。
out := make([]Issue, 0, len(issues))
for i := range issues {
if issues[i].PullRequest == nil {
out = append(out, issues[i])
}
}
return out, nil
}
func (a *APIClient) ListPulls(owner, repo string) ([]PullRequest, error) {
var pulls []PullRequest
path := "/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(repo) + "/pulls"
opts := gitea.ListOptions{Extra: url.Values{"state": {"open"}}}
if err := a.Client.ListAll(context.Background(), path, opts, &pulls); err != nil {
return nil, err
}
return pulls, nil
}
func (a *APIClient) ListComments(owner, repo string, number int64) ([]Comment, error) {
var comments []Comment
path := "/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(repo) +
"/issues/" + strconv.FormatInt(number, 10) + "/comments"
if err := a.Client.ListAll(context.Background(), path, gitea.ListOptions{}, &comments); err != nil {
return nil, err
}
return comments, nil
}