feat(gitea): pull-request create/list/get/merge endpoints

This commit is contained in:
2026-08-29 16:11:58 -05:00
parent c251cd6a98
commit 5b35e8cd84
3 changed files with 278 additions and 6 deletions
+116
View File
@@ -0,0 +1,116 @@
package gitea
import (
"context"
"net/url"
"strconv"
)
// Pull request states.
const (
PRStateOpen = "open"
PRStateClosed = "closed"
PRStateAll = "all"
)
// Merge styles (Gitea's closed set; empty means "merge").
const (
MergeMerge = "merge"
MergeRebase = "rebase"
MergeRebaseMerge = "rebase-merge"
MergeSquash = "squash"
MergeFastForward = "fast-forward"
)
// PRBranch is one end of a pull request.
type PRBranch struct {
Ref string `json:"ref"`
SHA string `json:"sha"`
Repo *Repo `json:"repo"`
}
// PullRequest is the PR projection (read shape).
type PullRequest struct {
Number int64 `json:"number"`
Title string `json:"title"`
Body string `json:"body"`
State string `json:"state"` // open|closed
User *User `json:"user"`
Base *PRBranch `json:"base"`
Head *PRBranch `json:"head"`
Mergeable bool `json:"mergeable"`
Merged bool `json:"merged"`
MergedAt string `json:"merged_at"`
HTMLURL string `json:"html_url"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// PRParams is the PR-create write shape. Head may be "branch" (same
// repo) or "owner:branch" (fork syntax); the server resolves both.
type PRParams struct {
Title string `json:"title"`
Body string `json:"body"`
Base string `json:"base"`
Head string `json:"head"`
}
// MergeParams is the merge write shape. Do is one of the Merge*
// constants (empty means "merge"); Title and Message are optional merge
// commit fields.
type MergeParams struct {
Do string
Title string
Message string
}
type mergeWrite struct {
Do string `json:"Do"`
MergeTitle string `json:"MergeTitleField,omitempty"`
MergeMessage string `json:"MergeMessageField,omitempty"`
}
// CreatePullRequest opens a PR and returns it.
func (c *Client) CreatePullRequest(ctx context.Context, owner, repo string, p PRParams) (*PullRequest, error) {
var out PullRequest
path := "/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(repo) + "/pulls"
if err := c.do(ctx, "POST", path, nil, p, &out); err != nil {
return nil, err
}
return &out, nil
}
// ListPullRequests lists PRs filtered by state (PRStateOpen is the
// server default; PRStateAll lifts it).
func (c *Client) ListPullRequests(ctx context.Context, owner, repo, state string) ([]PullRequest, error) {
var out []PullRequest
var query url.Values
if state != "" {
query = url.Values{"state": []string{state}}
}
path := "/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(repo) + "/pulls"
if err := c.do(ctx, "GET", path, query, nil, &out); err != nil {
return nil, err
}
return out, nil
}
// GetPullRequest fetches one PR by number.
func (c *Client) GetPullRequest(ctx context.Context, owner, repo string, number int64) (*PullRequest, error) {
var out PullRequest
path := "/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(repo) + "/pulls/" + strconv.FormatInt(number, 10)
if err := c.do(ctx, "GET", path, nil, nil, &out); err != nil {
return nil, err
}
return &out, nil
}
// MergePullRequest merges an open PR. Re-merging or merging a closed PR
// maps to ErrValidation (http 409).
func (c *Client) MergePullRequest(ctx context.Context, owner, repo string, number int64, p MergeParams) error {
if p.Do == "" {
p.Do = MergeMerge
}
path := "/repos/" + url.PathEscape(owner) + "/" + url.PathEscape(repo) + "/pulls/" + strconv.FormatInt(number, 10) + "/merge"
return c.do(ctx, "POST", path, nil, mergeWrite{Do: p.Do, MergeTitle: p.Title, MergeMessage: p.Message}, nil)
}