diff --git a/common/timeline.go b/common/timeline.go index 77cc2bb..fd7a50f 100644 --- a/common/timeline.go +++ b/common/timeline.go @@ -22,8 +22,6 @@ func FetchTimelineSinceLastPush(gitea GiteaTimelineFetcher, headSha, org, repo s return nil, err } - idx := len(timeline) - 1 - //{"is_force_push":true,"commit_ids":["36e43509be1b13a1a8fc63a4361405de04cc621ab16935f88968c46193221bb6","732246a48fbc6bac9df16c0b0ca23ce0f6fbabd9990795863b6d1f0ef3f242c8"]} type PullPushData struct { IsForcePush bool `json:"is_force_push"` @@ -31,8 +29,7 @@ func FetchTimelineSinceLastPush(gitea GiteaTimelineFetcher, headSha, org, repo s } // trim timeline to last push update or last time review request was requested - for ; idx > 0; idx-- { - e := timeline[idx] + for i, e := range timeline { if e.Type == TimelineCommentType_PushPull { var push PullPushData if err := json.Unmarshal([]byte(e.Body), &push); err != nil { @@ -40,12 +37,11 @@ func FetchTimelineSinceLastPush(gitea GiteaTimelineFetcher, headSha, org, repo s } if slices.Contains(push.CommitIds, headSha) { - break + return timeline[0:i], nil } } } - timeline = timeline[idx:] return timeline, nil } @@ -55,17 +51,13 @@ func FetchTimelineSinceReviewRequestOrPush(gitea GiteaTimelineFetcher, groupName return nil, err } - idx := len(timeline) - 1 - // trim timeline to last push update or last time review request was requested - for ; idx > 0; idx-- { - e := timeline[idx] + for i, e := range timeline { if e.Type == TimelineCommentType_ReviewRequested && e.Assignee != nil && e.Assignee.UserName == groupName { // review request is cut-off for reviews too - break + return timeline[0:i], nil } } - timeline = timeline[idx:] return timeline, nil } diff --git a/group-review/main.go b/group-review/main.go index b8b78e8..6ed4e18 100644 --- a/group-review/main.go +++ b/group-review/main.go @@ -28,8 +28,9 @@ func InitRegex(groupName string) { func ParseReviewLine(reviewText string) (bool, string) { line := strings.TrimSpace(reviewText) - glen := len(groupName) - if len(line) < glen || line[0:glen] != groupName { + groupTextName := "@" + groupName + glen := len(groupTextName) + if len(line) < glen || line[0:glen] != groupTextName { return false, line } @@ -99,23 +100,22 @@ var commentStrings = []string{ "change_time_estimate", }*/ -func FindAcceptableReviewInTimeline(user string, timeline []*models.TimelineComment, reviews []*models.PullReview) *models.PullReview { - var good_review *models.PullReview - +func FindAcceptableReviewInTimeline(user string, timeline []*models.TimelineComment, reviews []*models.PullReview) *models.TimelineComment { for _, t := range timeline { - if t.Type == common.TimelineCommentType_Review && t.User != nil && t.User.UserName == user && t.Created == t.Updated { - for _, r := range reviews { - if r.ID == t.ReviewID && (ReviewAccepted(r.Body) || ReviewRejected(r.Body)) { - good_review = r - break - } + if t.Type == common.TimelineCommentType_Comment && t.User.UserName == user && t.Created == t.Updated { + if ReviewAccepted(t.Body) || ReviewRejected(t.Body) { + return t } - } else if (t.Type == common.TimelineCommentType_DismissReview || t.Type == common.TimelineCommentType_ReviewRequested) && t.Assignee != nil && t.Assignee.UserName == user { - good_review = nil } } - return good_review + return nil +} + +func UnrequestReviews(gitea common.Gitea, org, repo string, id int64, users []string) { + if err := gitea.UnrequestReview(org, repo, id, users...); err != nil { + common.LogError("Can't remove reviewrs after a review:", err) + } } func ProcessNotifications(notification *models.NotificationThread, gitea common.Gitea) { @@ -204,9 +204,10 @@ func ProcessNotifications(notification *models.NotificationThread, gitea common. for _, reviewer := range requestReviewers { if review := FindAcceptableReviewInTimeline(reviewer, timeline, reviews); review != nil { - if review.State == common.ReviewStateApproved && ReviewAccepted(review.Body) { + if ReviewAccepted(review.Body) { if !common.IsDryRun { gitea.AddReviewComment(pr, common.ReviewStateApproved, "Signed off by: "+reviewer) + UnrequestReviews(gitea, org, repo, id, requestReviewers) if !common.IsDryRun { if err := gitea.SetNotificationRead(notification.ID); err != nil { common.LogDebug(" Cannot set notification as read", err) @@ -214,11 +215,12 @@ func ProcessNotifications(notification *models.NotificationThread, gitea common. } } common.LogInfo(" -> approved by", reviewer) - common.LogInfo(" review at", review.Submitted) + common.LogInfo(" review at", review.Created) return - } else if review.State == common.ReviewStateRequestChanges && ReviewRejected(review.Body) { + } else if ReviewRejected(review.Body) { if !common.IsDryRun { - gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Request changes. See review by: "+reviewer) + gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Changes requested. See review by: "+reviewer) + UnrequestReviews(gitea, org, repo, id, requestReviewers) if err := gitea.SetNotificationRead(notification.ID); err != nil { common.LogDebug(" Cannot set notification as read", err) } @@ -243,6 +245,20 @@ func ProcessNotifications(notification *models.NotificationThread, gitea common. } else { common.LogDebug(" Not requesting additional reviewers") } + + // add a helpful comment, if not yet added + found_help_comment := false + for _, t := range timeline { + if t.Type == common.TimelineCommentType_Comment && t.User != nil && t.User.UserName == groupName { + found_help_comment = true + break + } + } + + if !found_help_comment && !common.IsDryRun { + helpComment := fmt.Sprintln("Review by", groupName, "represents a group of reviewers:", strings.Join(requestReviewers, ", "), ". To review as part of this group, create a comment with contents @"+groupName+": LGTM on a separate line to accept a review. To request changes, write @"+groupName+": followed by reason for rejection. Do not use reviews to review as a group. Editing a comment invalidates that comment.") + gitea.AddComment(pr, helpComment) + } } func PeriodReviewCheck(gitea common.Gitea) {