package gitea import ( "context" "encoding/json" "fmt" "net/url" ) type Repo struct { Name string `json:"name"` FullName string `json:"full_name"` DefaultBranch string `json:"default_branch"` Description string `json:"description"` Private bool `json:"private"` CloneURL string `json:"clone_url"` HTMLURL string `json:"html_url"` Template bool `json:"template"` } type TreeEntry struct { Path string `json:"path"` Type string `json:"type"` // "blob" or "tree" SHA string `json:"sha"` Size int64 `json:"size"` URL string `json:"url"` } type Tree struct { SHA string `json:"sha"` URL string `json:"url"` Tree []TreeEntry `json:"tree"` Truncated bool `json:"truncated"` } func (c *Client) GetTree(ctx context.Context, owner, repo, ref string, recursive bool) (*Tree, error) { path := fmt.Sprintf("/api/v1/repos/%s/%s/git/trees/%s", owner, repo, url.PathEscape(ref)) if recursive { path += "?recursive=1" } body, status, err := c.GetJSON(ctx, path) if err != nil { return nil, err } if err := MapStatus(status, body); err != nil { return nil, err } var t Tree if err := json.Unmarshal(body, &t); err != nil { return nil, err } return &t, nil } type Release struct { ID int64 `json:"id"` TagName string `json:"tag_name"` Name string `json:"name"` Body string `json:"body"` Draft bool `json:"draft"` Prerelease bool `json:"prerelease"` HTMLURL string `json:"html_url"` CreatedAt string `json:"created_at"` } type CreateReleaseArgs struct { TagName string `json:"tag_name"` Name string `json:"name,omitempty"` Body string `json:"body,omitempty"` Draft bool `json:"draft,omitempty"` Prerelease bool `json:"prerelease,omitempty"` // Target branch or commit SHA for tag creation. Empty = repo default branch. Target string `json:"target_commitish,omitempty"` } func (c *Client) CreateRelease(ctx context.Context, owner, repo string, args CreateReleaseArgs) (*Release, error) { path := fmt.Sprintf("/api/v1/repos/%s/%s/releases", owner, repo) body, err := json.Marshal(args) if err != nil { return nil, err } resp, status, err := c.PostJSON(ctx, path, body) if err != nil { return nil, err } if err := MapStatus(status, resp); err != nil { return nil, err } var r Release if err := json.Unmarshal(resp, &r); err != nil { return nil, err } return &r, nil } func (c *Client) DeleteRepo(ctx context.Context, owner, repo string) error { path := fmt.Sprintf("/api/v1/repos/%s/%s", owner, repo) resp, status, err := c.DeleteJSON(ctx, path) if err != nil { return err } if status == 204 { return nil } return MapStatus(status, resp) } func (c *Client) UpdateTopics(ctx context.Context, owner, repo string, topics []string) error { path := fmt.Sprintf("/api/v1/repos/%s/%s/topics", owner, repo) body, err := json.Marshal(map[string][]string{"topics": topics}) if err != nil { return err } resp, status, err := c.PutJSON(ctx, path, body) if err != nil { return err } if status == 204 { return nil } return MapStatus(status, resp) } func (c *Client) ListRepos(ctx context.Context, owner string, page, limit int) ([]Repo, error) { if page < 1 { page = 1 } if limit < 1 { limit = 30 } path := fmt.Sprintf("/api/v1/users/%s/repos?page=%d&limit=%d", owner, page, limit) body, status, err := c.GetJSON(ctx, path) if err != nil { return nil, err } if err := MapStatus(status, body); err != nil { return nil, err } var repos []Repo if err := json.Unmarshal(body, &repos); err != nil { return nil, err } return repos, nil } type repoSearchEnvelope struct { Data []Repo `json:"data"` OK bool `json:"ok"` } func (c *Client) SearchRepos(ctx context.Context, q, owner string, page, limit int) ([]Repo, error) { if page < 1 { page = 1 } if limit < 1 { limit = 30 } path := fmt.Sprintf("/api/v1/repos/search?q=%s&page=%d&limit=%d", url.QueryEscape(q), page, limit) if owner != "" { path += "&owner=" + url.QueryEscape(owner) } body, status, err := c.GetJSON(ctx, path) if err != nil { return nil, err } if err := MapStatus(status, body); err != nil { return nil, err } var env repoSearchEnvelope if err := json.Unmarshal(body, &env); err != nil { return nil, err } return env.Data, nil } type CreateRepoArgs struct { Name string `json:"name"` Description string `json:"description,omitempty"` Private bool `json:"private,omitempty"` AutoInit bool `json:"auto_init,omitempty"` DefaultBranch string `json:"default_branch,omitempty"` // Org, when non-empty, creates the repo under the named organisation. // Uses POST /api/v1/orgs/{org}/repos instead of /api/v1/user/repos. Org string `json:"-"` } func (c *Client) CreateRepo(ctx context.Context, args CreateRepoArgs) (*Repo, error) { var path string if args.Org != "" { path = fmt.Sprintf("/api/v1/orgs/%s/repos", args.Org) } else { path = "/api/v1/user/repos" } body, err := json.Marshal(args) if err != nil { return nil, err } resp, status, err := c.PostJSON(ctx, path, body) if err != nil { return nil, err } if err := MapStatus(status, resp); err != nil { return nil, err } var r Repo if err := json.Unmarshal(resp, &r); err != nil { return nil, err } return &r, nil } // UpdateRepoArgs uses pointers so omitempty can distinguish "not set" from false/zero. type UpdateRepoArgs struct { Description *string `json:"description,omitempty"` Private *bool `json:"private,omitempty"` Website *string `json:"website,omitempty"` DefaultBranch *string `json:"default_branch,omitempty"` Archived *bool `json:"archived,omitempty"` Template *bool `json:"template,omitempty"` } func (c *Client) UpdateRepo(ctx context.Context, owner, name string, args UpdateRepoArgs) (*Repo, error) { path := fmt.Sprintf("/api/v1/repos/%s/%s", owner, name) body, err := json.Marshal(args) if err != nil { return nil, err } resp, status, err := c.PatchJSON(ctx, path, body) if err != nil { return nil, err } if err := MapStatus(status, resp); err != nil { return nil, err } var r Repo if err := json.Unmarshal(resp, &r); err != nil { return nil, err } return &r, nil } func (c *Client) GetRepo(ctx context.Context, owner, name string) (*Repo, error) { path := fmt.Sprintf("/api/v1/repos/%s/%s", owner, name) body, status, err := c.GetJSON(ctx, path) if err != nil { return nil, err } if err := MapStatus(status, body); err != nil { return nil, err } var r Repo if err := json.Unmarshal(body, &r); err != nil { return nil, err } return &r, nil }