cli/pkg/forge/prs.go

110 lines
3.3 KiB
Go
Raw Normal View History

package forge
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
forgejo "codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2"
"github.com/host-uk/core/pkg/log"
)
// MergePullRequest merges a pull request with the given method ("squash", "rebase", "merge").
func (c *Client) MergePullRequest(owner, repo string, index int64, method string) error {
style := forgejo.MergeStyleMerge
switch method {
case "squash":
style = forgejo.MergeStyleSquash
case "rebase":
style = forgejo.MergeStyleRebase
}
merged, _, err := c.api.MergePullRequest(owner, repo, index, forgejo.MergePullRequestOption{
Style: style,
DeleteBranchAfterMerge: true,
})
if err != nil {
return log.E("forge.MergePullRequest", "failed to merge pull request", err)
}
if !merged {
return fmt.Errorf("forge.MergePullRequest: merge returned false for %s/%s#%d", owner, repo, index)
}
return nil
}
// SetPRDraft sets or clears the draft status on a pull request.
// The Forgejo SDK v2.2.0 doesn't expose the draft field on EditPullRequestOption,
// so we use a raw HTTP PATCH request.
func (c *Client) SetPRDraft(owner, repo string, index int64, draft bool) error {
payload := map[string]bool{"draft": draft}
body, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("forge.SetPRDraft: marshal: %w", err)
}
url := fmt.Sprintf("%s/api/v1/repos/%s/%s/pulls/%d", c.url, owner, repo, index)
req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(body))
if err != nil {
return fmt.Errorf("forge.SetPRDraft: create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "token "+c.token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return log.E("forge.SetPRDraft", "failed to update draft status", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("forge.SetPRDraft: unexpected status %d", resp.StatusCode)
}
return nil
}
// ListPRReviews returns all reviews for a pull request.
func (c *Client) ListPRReviews(owner, repo string, index int64) ([]*forgejo.PullReview, error) {
var all []*forgejo.PullReview
page := 1
for {
reviews, resp, err := c.api.ListPullReviews(owner, repo, index, forgejo.ListPullReviewsOptions{
ListOptions: forgejo.ListOptions{Page: page, PageSize: 50},
})
if err != nil {
return nil, log.E("forge.ListPRReviews", "failed to list reviews", err)
}
all = append(all, reviews...)
if resp == nil || page >= resp.LastPage {
break
}
page++
}
return all, nil
}
// GetCombinedStatus returns the combined commit status for a ref (SHA or branch).
func (c *Client) GetCombinedStatus(owner, repo string, ref string) (*forgejo.CombinedStatus, error) {
status, _, err := c.api.GetCombinedStatus(owner, repo, ref)
if err != nil {
return nil, log.E("forge.GetCombinedStatus", "failed to get combined status", err)
}
return status, nil
}
// DismissReview dismisses a pull request review by ID.
func (c *Client) DismissReview(owner, repo string, index, reviewID int64, message string) error {
_, err := c.api.DismissPullReview(owner, repo, index, reviewID, forgejo.DismissPullReviewOptions{
Message: message,
})
if err != nil {
return log.E("forge.DismissReview", "failed to dismiss review", err)
}
return nil
}