forked from adamm/autogits
159 lines
3.2 KiB
Go
159 lines
3.2 KiB
Go
package common
|
|
|
|
import (
|
|
"regexp"
|
|
"slices"
|
|
"strings"
|
|
|
|
"src.opensuse.org/autogits/common/gitea-generated/models"
|
|
)
|
|
|
|
type PRReviews struct {
|
|
reviews []*models.PullReview
|
|
reviewers []string
|
|
comments []*models.TimelineComment
|
|
}
|
|
|
|
func FetchGiteaReviews(rf GiteaReviewTimelineFetcher, reviewers []string, org, repo string, no int64) (*PRReviews, error) {
|
|
timeline, err := rf.GetTimeline(org, repo, no)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rawReviews, err := rf.GetPullRequestReviews(org, repo, no)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
reviews := make([]*models.PullReview, 0, 10)
|
|
var comments []*models.TimelineComment
|
|
|
|
for idx, item := range timeline {
|
|
if item.Type == TimelineCommentType_Review {
|
|
for _, r := range rawReviews {
|
|
if r.ID == item.ReviewID {
|
|
reviews = append(reviews, r)
|
|
break
|
|
}
|
|
}
|
|
} else if item.Type == TimelineCommentType_Comment {
|
|
comments = append(comments, item)
|
|
} else if item.Type == TimelineCommentType_PushPull {
|
|
timeline = timeline[0:idx]
|
|
break
|
|
} else {
|
|
LogDebug("Unhandled timeline type:", item.Type)
|
|
}
|
|
}
|
|
|
|
return &PRReviews{
|
|
reviews: reviews,
|
|
reviewers: reviewers,
|
|
comments: comments,
|
|
}, nil
|
|
}
|
|
|
|
const ManualMergeOK = "^merge\\s+ok(\\W|$)"
|
|
|
|
var merge_ok_regex *regexp.Regexp = regexp.MustCompile(ManualMergeOK)
|
|
|
|
func bodyCommandManualMergeOK(body string) bool {
|
|
lines := SplitLines(body)
|
|
for _, line := range lines {
|
|
if merge_ok_regex.MatchString(strings.ToLower(line)) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r *PRReviews) IsManualMergeOK() bool {
|
|
for _, c := range r.comments {
|
|
if c.Updated != c.Created {
|
|
continue
|
|
}
|
|
if slices.Contains(r.reviewers, c.User.UserName) {
|
|
if bodyCommandManualMergeOK(c.Body) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, c := range r.reviews {
|
|
if c.Updated != c.Submitted {
|
|
continue
|
|
}
|
|
if slices.Contains(r.reviewers, c.User.UserName) {
|
|
if bodyCommandManualMergeOK(c.Body) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (r *PRReviews) IsApproved() bool {
|
|
goodReview := true
|
|
|
|
for _, reviewer := range r.reviewers {
|
|
goodReview = false
|
|
for _, review := range r.reviews {
|
|
if review.User.UserName == reviewer && review.State == ReviewStateApproved && !review.Stale && !review.Dismissed {
|
|
LogDebug(" -- found review: ", review.User.UserName)
|
|
goodReview = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !goodReview {
|
|
break
|
|
}
|
|
}
|
|
|
|
return goodReview
|
|
}
|
|
|
|
func (r *PRReviews) HasPendingReviewBy(reviewer string) bool {
|
|
if !slices.Contains(r.reviewers, reviewer) {
|
|
return false
|
|
}
|
|
|
|
isPending := false
|
|
for _, r := range r.reviews {
|
|
if r.User.UserName == reviewer && !r.Stale {
|
|
switch r.State {
|
|
case ReviewStateApproved:
|
|
fallthrough
|
|
case ReviewStateRequestChanges:
|
|
return false
|
|
case ReviewStateRequestReview:
|
|
fallthrough
|
|
case ReviewStatePending:
|
|
isPending = true
|
|
}
|
|
}
|
|
}
|
|
|
|
return isPending
|
|
}
|
|
|
|
func (r *PRReviews) IsReviewedBy(reviewer string) bool {
|
|
if !slices.Contains(r.reviewers, reviewer) {
|
|
return false
|
|
}
|
|
|
|
for _, r := range r.reviews {
|
|
if r.User.UserName == reviewer && !r.Stale {
|
|
switch r.State {
|
|
case ReviewStateApproved:
|
|
return true
|
|
case ReviewStateRequestChanges:
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|