-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpulls.go
More file actions
355 lines (310 loc) · 15.4 KB
/
pulls.go
File metadata and controls
355 lines (310 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
package forge
import (
"context"
"iter"
"net/url"
"strconv"
core "dappco.re/go/core"
"dappco.re/go/core/forge/types"
)
// PullService handles pull request operations within a repository.
//
// Usage:
//
// f := forge.NewForge("https://forge.lthn.ai", "token")
// _, err := f.Pulls.ListAll(ctx, forge.Params{"owner": "core", "repo": "go-forge"})
type PullService struct {
Resource[types.PullRequest, types.CreatePullRequestOption, types.EditPullRequestOption]
}
// PullListOptions controls filtering for repository pull request listings.
//
// Usage:
//
// opts := forge.PullListOptions{State: "open", Labels: []int64{1, 2}}
type PullListOptions struct {
State string
Sort string
Milestone int64
Labels []int64
Poster string
}
// String returns a safe summary of the pull request list filters.
func (o PullListOptions) String() string {
return optionString("forge.PullListOptions",
"state", o.State,
"sort", o.Sort,
"milestone", o.Milestone,
"labels", o.Labels,
"poster", o.Poster,
)
}
// GoString returns a safe Go-syntax summary of the pull request list filters.
func (o PullListOptions) GoString() string { return o.String() }
func (o PullListOptions) addQuery(values url.Values) {
if o.State != "" {
values.Set("state", o.State)
}
if o.Sort != "" {
values.Set("sort", o.Sort)
}
if o.Milestone != 0 {
values.Set("milestone", strconv.FormatInt(o.Milestone, 10))
}
for _, label := range o.Labels {
if label != 0 {
values.Add("labels", strconv.FormatInt(label, 10))
}
}
if o.Poster != "" {
values.Set("poster", o.Poster)
}
}
func newPullService(c *Client) *PullService {
return &PullService{
Resource: *NewResource[types.PullRequest, types.CreatePullRequestOption, types.EditPullRequestOption](
c, "/api/v1/repos/{owner}/{repo}/pulls/{index}",
),
}
}
// ListPullRequests returns all pull requests in a repository.
func (s *PullService) ListPullRequests(ctx context.Context, owner, repo string, filters ...PullListOptions) ([]types.PullRequest, error) {
return s.listAll(ctx, owner, repo, filters...)
}
// IterPullRequests returns an iterator over all pull requests in a repository.
func (s *PullService) IterPullRequests(ctx context.Context, owner, repo string, filters ...PullListOptions) iter.Seq2[types.PullRequest, error] {
return s.listIter(ctx, owner, repo, filters...)
}
// CreatePullRequest creates a pull request in a repository.
func (s *PullService) CreatePullRequest(ctx context.Context, owner, repo string, opts *types.CreatePullRequestOption) (*types.PullRequest, error) {
var out types.PullRequest
if err := s.client.Post(ctx, ResolvePath("/api/v1/repos/{owner}/{repo}/pulls", pathParams("owner", owner, "repo", repo)), opts, &out); err != nil {
return nil, err
}
return &out, nil
}
// Merge merges a pull request. Method is one of "merge", "rebase", "rebase-merge", "squash", "fast-forward-only", "manually-merged".
func (s *PullService) Merge(ctx context.Context, owner, repo string, index int64, method string) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/merge", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
body := map[string]string{"Do": method}
return s.client.Post(ctx, path, body, nil)
}
// CancelScheduledAutoMerge cancels the scheduled auto merge for a pull request.
func (s *PullService) CancelScheduledAutoMerge(ctx context.Context, owner, repo string, index int64) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/merge", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return s.client.Delete(ctx, path)
}
// Update updates a pull request branch with the base branch.
func (s *PullService) Update(ctx context.Context, owner, repo string, index int64) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/update", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return s.client.Post(ctx, path, nil, nil)
}
// GetDiffOrPatch returns a pull request diff or patch as raw bytes.
func (s *PullService) GetDiffOrPatch(ctx context.Context, owner, repo string, index int64, diffType string) ([]byte, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}.{diffType}", pathParams("owner", owner, "repo", repo, "index", int64String(index), "diffType", diffType))
return s.client.GetRaw(ctx, path)
}
// ListCommits returns all commits for a pull request.
func (s *PullService) ListCommits(ctx context.Context, owner, repo string, index int64) ([]types.Commit, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/commits", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return ListAll[types.Commit](ctx, s.client, path, nil)
}
// IterCommits returns an iterator over all commits for a pull request.
func (s *PullService) IterCommits(ctx context.Context, owner, repo string, index int64) iter.Seq2[types.Commit, error] {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/commits", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return ListIter[types.Commit](ctx, s.client, path, nil)
}
// ListReviews returns all reviews on a pull request.
func (s *PullService) ListReviews(ctx context.Context, owner, repo string, index int64) ([]types.PullReview, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return ListAll[types.PullReview](ctx, s.client, path, nil)
}
// IterReviews returns an iterator over all reviews on a pull request.
func (s *PullService) IterReviews(ctx context.Context, owner, repo string, index int64) iter.Seq2[types.PullReview, error] {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return ListIter[types.PullReview](ctx, s.client, path, nil)
}
// ListFiles returns all changed files on a pull request.
func (s *PullService) ListFiles(ctx context.Context, owner, repo string, index int64) ([]types.ChangedFile, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/files", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return ListAll[types.ChangedFile](ctx, s.client, path, nil)
}
// IterFiles returns an iterator over all changed files on a pull request.
func (s *PullService) IterFiles(ctx context.Context, owner, repo string, index int64) iter.Seq2[types.ChangedFile, error] {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/files", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return ListIter[types.ChangedFile](ctx, s.client, path, nil)
}
// GetByBaseHead returns a pull request for a given base and head branch pair.
func (s *PullService) GetByBaseHead(ctx context.Context, owner, repo, base, head string) (*types.PullRequest, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{base}/{head}", pathParams(
"owner", owner,
"repo", repo,
"base", base,
"head", head,
))
var out types.PullRequest
if err := s.client.Get(ctx, path, &out); err != nil {
return nil, err
}
return &out, nil
}
// ListReviewers returns all users who can be requested to review a pull request.
func (s *PullService) ListReviewers(ctx context.Context, owner, repo string) ([]types.User, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/reviewers", pathParams("owner", owner, "repo", repo))
return ListAll[types.User](ctx, s.client, path, nil)
}
// IterReviewers returns an iterator over all users who can be requested to review a pull request.
func (s *PullService) IterReviewers(ctx context.Context, owner, repo string) iter.Seq2[types.User, error] {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/reviewers", pathParams("owner", owner, "repo", repo))
return ListIter[types.User](ctx, s.client, path, nil)
}
// RequestReviewers creates review requests for a pull request.
func (s *PullService) RequestReviewers(ctx context.Context, owner, repo string, index int64, opts *types.PullReviewRequestOptions) ([]types.PullReview, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/requested_reviewers", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
var out []types.PullReview
if err := s.client.Post(ctx, path, opts, &out); err != nil {
return nil, err
}
return out, nil
}
// CancelReviewRequests cancels review requests for a pull request.
func (s *PullService) CancelReviewRequests(ctx context.Context, owner, repo string, index int64, opts *types.PullReviewRequestOptions) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/requested_reviewers", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
return s.client.DeleteWithBody(ctx, path, opts)
}
// SubmitReview creates a new review on a pull request.
func (s *PullService) SubmitReview(ctx context.Context, owner, repo string, index int64, review *types.SubmitPullReviewOptions) (*types.PullReview, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews", pathParams("owner", owner, "repo", repo, "index", int64String(index)))
var out types.PullReview
if err := s.client.Post(ctx, path, review, &out); err != nil {
return nil, err
}
return &out, nil
}
// GetReview returns a single pull request review.
func (s *PullService) GetReview(ctx context.Context, owner, repo string, index, reviewID int64) (*types.PullReview, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID)))
var out types.PullReview
if err := s.client.Get(ctx, path, &out); err != nil {
return nil, err
}
return &out, nil
}
// DeleteReview deletes a pull request review.
func (s *PullService) DeleteReview(ctx context.Context, owner, repo string, index, reviewID int64) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID)))
return s.client.Delete(ctx, path)
}
func (s *PullService) listPage(ctx context.Context, owner, repo string, opts ListOptions, filters ...PullListOptions) (*PagedResult[types.PullRequest], error) {
if opts.Page < 1 {
opts.Page = 1
}
if opts.Limit < 1 {
opts.Limit = defaultPageLimit
}
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls", pathParams("owner", owner, "repo", repo))
u, err := url.Parse(path)
if err != nil {
return nil, core.E("PullService.listPage", "forge: parse path", err)
}
values := u.Query()
values.Set("page", strconv.Itoa(opts.Page))
values.Set("limit", strconv.Itoa(opts.Limit))
for _, filter := range filters {
filter.addQuery(values)
}
u.RawQuery = values.Encode()
var items []types.PullRequest
resp, err := s.client.doJSON(ctx, "GET", u.String(), nil, &items)
if err != nil {
return nil, err
}
totalCount, _ := strconv.Atoi(resp.Header.Get("X-Total-Count"))
return &PagedResult[types.PullRequest]{
Items: items,
TotalCount: totalCount,
Page: opts.Page,
HasMore: (totalCount > 0 && (opts.Page-1)*opts.Limit+len(items) < totalCount) ||
(totalCount == 0 && len(items) >= opts.Limit),
}, nil
}
func (s *PullService) listAll(ctx context.Context, owner, repo string, filters ...PullListOptions) ([]types.PullRequest, error) {
var all []types.PullRequest
page := 1
for {
result, err := s.listPage(ctx, owner, repo, ListOptions{Page: page, Limit: defaultPageLimit}, filters...)
if err != nil {
return nil, err
}
all = append(all, result.Items...)
if !result.HasMore {
break
}
page++
}
return all, nil
}
func (s *PullService) listIter(ctx context.Context, owner, repo string, filters ...PullListOptions) iter.Seq2[types.PullRequest, error] {
return func(yield func(types.PullRequest, error) bool) {
page := 1
for {
result, err := s.listPage(ctx, owner, repo, ListOptions{Page: page, Limit: defaultPageLimit}, filters...)
if err != nil {
yield(*new(types.PullRequest), err)
return
}
for _, item := range result.Items {
if !yield(item, nil) {
return
}
}
if !result.HasMore {
break
}
page++
}
}
}
// ListReviewComments returns all comments on a pull request review.
func (s *PullService) ListReviewComments(ctx context.Context, owner, repo string, index, reviewID int64) ([]types.PullReviewComment, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID)))
return ListAll[types.PullReviewComment](ctx, s.client, path, nil)
}
// IterReviewComments returns an iterator over all comments on a pull request review.
func (s *PullService) IterReviewComments(ctx context.Context, owner, repo string, index, reviewID int64) iter.Seq2[types.PullReviewComment, error] {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID)))
return ListIter[types.PullReviewComment](ctx, s.client, path, nil)
}
// GetReviewComment returns a single comment on a pull request review.
func (s *PullService) GetReviewComment(ctx context.Context, owner, repo string, index, reviewID, commentID int64) (*types.PullReviewComment, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments/{comment}", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID), "comment", int64String(commentID)))
var out types.PullReviewComment
if err := s.client.Get(ctx, path, &out); err != nil {
return nil, err
}
return &out, nil
}
// CreateReviewComment creates a new comment on a pull request review.
func (s *PullService) CreateReviewComment(ctx context.Context, owner, repo string, index, reviewID int64, opts *types.CreatePullReviewCommentOptions) (*types.PullReviewComment, error) {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID)))
var out types.PullReviewComment
if err := s.client.Post(ctx, path, opts, &out); err != nil {
return nil, err
}
return &out, nil
}
// DeleteReviewComment deletes a comment on a pull request review.
func (s *PullService) DeleteReviewComment(ctx context.Context, owner, repo string, index, reviewID, commentID int64) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments/{comment}", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID), "comment", int64String(commentID)))
return s.client.Delete(ctx, path)
}
// DismissReview dismisses a pull request review.
func (s *PullService) DismissReview(ctx context.Context, owner, repo string, index, reviewID int64, msg string) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/dismissals", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID)))
body := map[string]string{"message": msg}
return s.client.Post(ctx, path, body, nil)
}
// UndismissReview undismisses a pull request review.
func (s *PullService) UndismissReview(ctx context.Context, owner, repo string, index, reviewID int64) error {
path := ResolvePath("/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/undismissals", pathParams("owner", owner, "repo", repo, "index", int64String(index), "id", int64String(reviewID)))
return s.client.Post(ctx, path, nil, nil)
}