mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
refactor: add services layer on the Gitea Go SDK (#1125)
- `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>
This commit is contained in:
1 parent
faea86cd94
commit
12e415a7a7
80 files changed
+9512
No files matched your search
@@ -0,0 +1,160 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
gitea "gitea.dev/sdk"
|
||||
"gitea.dev/tea/internal/transport"
|
||||
)
|
||||
|
||||
// Organization is the public command representation of a Gitea organization.
|
||||
type Organization struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
FullName string `json:"full_name"`
|
||||
Description string `json:"description"`
|
||||
Website string `json:"website"`
|
||||
Location string `json:"location"`
|
||||
Visibility string `json:"visibility"`
|
||||
RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"`
|
||||
}
|
||||
|
||||
// organization returns the ID of owner when it is an organization; a missing organization
|
||||
// means a user owns the namespace.
|
||||
func organization(ctx context.Context, client *transport.Client, owner string) (id int64, isOrg bool, err error) {
|
||||
org, _, err := call(ctx, client, func(ctx context.Context, c *gitea.Client) (*gitea.Organization, *gitea.Response, error) {
|
||||
return c.Organizations.GetOrg(ctx, owner)
|
||||
})
|
||||
if failure, ok := errors.AsType[*transport.APIError](err); ok && failure.Status == http.StatusNotFound {
|
||||
return 0, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
if org.ID < 1 {
|
||||
return 0, false, fmt.Errorf("cannot verify the identity of organization %s", owner)
|
||||
}
|
||||
return org.ID, true, nil
|
||||
}
|
||||
|
||||
// OrganizationOptions permits explicit empty and false preference updates.
|
||||
type OrganizationOptions struct {
|
||||
Name *string `json:"username,omitempty"`
|
||||
FullName *string `json:"full_name,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Website *string `json:"website,omitempty"`
|
||||
Location *string `json:"location,omitempty"`
|
||||
Visibility *string `json:"visibility,omitempty"`
|
||||
RepoAdminChangeTeamAccess *bool `json:"repo_admin_change_team_access,omitempty"`
|
||||
}
|
||||
|
||||
// Organizations implements instance-scoped organization workflows.
|
||||
type Organizations struct{ Client *transport.Client }
|
||||
|
||||
// List selects public organizations, your organizations, or a named user's organizations.
|
||||
// It reports whether more organizations follow the selected page.
|
||||
func (s Organizations) List(ctx context.Context, mine bool, username string, limit, page int) ([]Organization, bool, error) {
|
||||
orgs, more, err := listWindow(limit, page, func(limit, page int) ([]*gitea.Organization, http.Header, error) {
|
||||
orgs, resp, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Organization, *gitea.Response, error) {
|
||||
opts := gitea.ListOrgsOptions{ListOptions: listOptions(limit, page)}
|
||||
switch {
|
||||
case mine:
|
||||
return c.Organizations.ListMyOrgs(ctx, opts)
|
||||
case username != "":
|
||||
return c.Organizations.ListUserOrgs(ctx, username, opts)
|
||||
}
|
||||
return c.Organizations.ListOrgs(ctx, opts)
|
||||
})
|
||||
return orgs, headerOf(resp), err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return convertAll(orgs, organizationFrom), more, nil
|
||||
}
|
||||
|
||||
// View retrieves a named organization.
|
||||
func (s Organizations) View(ctx context.Context, name string) (Organization, error) {
|
||||
org, _, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) (*gitea.Organization, *gitea.Response, error) {
|
||||
return c.Organizations.GetOrg(ctx, name)
|
||||
})
|
||||
if err != nil {
|
||||
return Organization{}, err
|
||||
}
|
||||
return organizationFrom(org), nil
|
||||
}
|
||||
|
||||
// Create creates an organization owned by the selected account.
|
||||
func (s Organizations) Create(ctx context.Context, opts OrganizationOptions) (Organization, error) {
|
||||
org, _, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) (*gitea.Organization, *gitea.Response, error) {
|
||||
return c.Organizations.CreateOrg(ctx, gitea.CreateOrgOption{
|
||||
Name: deref(opts.Name), FullName: deref(opts.FullName), Description: deref(opts.Description),
|
||||
Website: deref(opts.Website), Location: deref(opts.Location), Visibility: gitea.VisibleType(deref(opts.Visibility)),
|
||||
RepoAdminChangeTeamAccess: deref(opts.RepoAdminChangeTeamAccess),
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
return Organization{}, err
|
||||
}
|
||||
return organizationFrom(org), nil
|
||||
}
|
||||
|
||||
// Edit changes only supplied organization preferences.
|
||||
func (s Organizations) Edit(ctx context.Context, name string, opts OrganizationOptions) (Organization, error) {
|
||||
var org gitea.Organization
|
||||
// TODO(sdk): EditOrgOption needs pointer fields so omitted preferences stay unchanged, and EditOrg should return the organization.
|
||||
if err := sendJSON(ctx, s.Client, http.MethodPatch, "orgs/"+url.PathEscape(name), opts, &org); err != nil {
|
||||
return Organization{}, err
|
||||
}
|
||||
return organizationFrom(&org), nil
|
||||
}
|
||||
|
||||
// Delete deletes the named organization.
|
||||
func (s Organizations) Delete(ctx context.Context, name string) error {
|
||||
return do(ctx, s.Client, func(ctx context.Context, c *gitea.Client) (*gitea.Response, error) {
|
||||
return c.Organizations.DeleteOrg(ctx, name)
|
||||
})
|
||||
}
|
||||
|
||||
// OrganizationMember identifies a member without exposing private profile fields.
|
||||
type OrganizationMember struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
FullName string `json:"full_name"`
|
||||
}
|
||||
|
||||
// Members lists visible members in an organization.
|
||||
func (s Organizations) Members(ctx context.Context, name string, public bool, limit, page int) ([]OrganizationMember, error) {
|
||||
users, _, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.User, *gitea.Response, error) {
|
||||
opts := gitea.ListOrgMembershipOption{ListOptions: listOptions(limit, page)}
|
||||
if public {
|
||||
return c.Organizations.ListPublicOrgMembership(ctx, name, opts)
|
||||
}
|
||||
return c.Organizations.ListOrgMembership(ctx, name, opts)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertAll(users, memberFrom), nil
|
||||
}
|
||||
|
||||
// RemoveMember removes an organization member and their organization access.
|
||||
func (s Organizations) RemoveMember(ctx context.Context, name, username string) error {
|
||||
return do(ctx, s.Client, func(ctx context.Context, c *gitea.Client) (*gitea.Response, error) {
|
||||
return c.Organizations.DeleteOrgMembership(ctx, name, username)
|
||||
})
|
||||
}
|
||||
|
||||
// SetMemberPublic changes public visibility of an existing membership.
|
||||
func (s Organizations) SetMemberPublic(ctx context.Context, name, username string, public bool) error {
|
||||
return do(ctx, s.Client, func(ctx context.Context, c *gitea.Client) (*gitea.Response, error) {
|
||||
return c.Organizations.SetPublicOrgMembership(ctx, name, username, public)
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user