"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/references"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
api "code.gitea.io/gitea/modules/structs"
return
}
+// FindAndUpdateIssueMentions finds users mentioned in the given content string, and saves them in the database.
+func (issue *Issue) FindAndUpdateIssueMentions(ctx DBContext, doer *User, content string) (mentions []*User, err error) {
+ rawMentions := references.FindAllMentionsMarkdown(content)
+ mentions, err = issue.ResolveMentionsByVisibility(ctx, doer, rawMentions)
+ if err != nil {
+ return nil, fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
+ }
+ if err = UpdateIssueMentions(ctx, issue.ID, mentions); err != nil {
+ return nil, fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
+ }
+ return
+}
+
// ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that
// don't have access to reading it. Teams are expanded into their users, but organizations are ignored.
func (issue *Issue) ResolveMentionsByVisibility(ctx DBContext, doer *User, mentions []string) (users []*User, err error) {
return &actionNotifier{}
}
-func (a *actionNotifier) NotifyNewIssue(issue *models.Issue) {
+func (a *actionNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
if err := issue.LoadPoster(); err != nil {
log.Error("issue.LoadPoster: %v", err)
return
// NotifyCreateIssueComment notifies comment on an issue to notifiers
func (a *actionNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
- issue *models.Issue, comment *models.Comment) {
+ issue *models.Issue, comment *models.Comment, mentions []*models.User) {
act := &models.Action{
ActUserID: doer.ID,
ActUser: doer,
}
}
-func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
+func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest, mentions []*models.User) {
if err := pull.LoadIssue(); err != nil {
log.Error("pull.LoadIssue: %v", err)
return
}
}
-func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
+func (a *actionNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User) {
if err := review.LoadReviewer(); err != nil {
log.Error("LoadReviewer '%d/%d': %v", review.ID, review.ReviewerID, err)
return
NotifyRenameRepository(doer *models.User, repo *models.Repository, oldRepoName string)
NotifyTransferRepository(doer *models.User, repo *models.Repository, oldOwnerName string)
- NotifyNewIssue(*models.Issue)
+ NotifyNewIssue(issue *models.Issue, mentions []*models.User)
NotifyIssueChangeStatus(*models.User, *models.Issue, *models.Comment, bool)
NotifyIssueChangeMilestone(doer *models.User, issue *models.Issue, oldMilestoneID int64)
NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment)
NotifyIssueChangeLabels(doer *models.User, issue *models.Issue,
addedLabels []*models.Label, removedLabels []*models.Label)
- NotifyNewPullRequest(*models.PullRequest)
+ NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User)
NotifyMergePullRequest(*models.PullRequest, *models.User)
NotifyPullRequestSynchronized(doer *models.User, pr *models.PullRequest)
- NotifyPullRequestReview(*models.PullRequest, *models.Review, *models.Comment)
+ NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User)
+ NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User)
NotifyPullRequestChangeTargetBranch(doer *models.User, pr *models.PullRequest, oldBranch string)
NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment)
- NotifyCreateIssueComment(*models.User, *models.Repository,
- *models.Issue, *models.Comment)
+ NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
+ issue *models.Issue, comment *models.Comment, mentions []*models.User)
NotifyUpdateComment(*models.User, *models.Comment, string)
NotifyDeleteComment(*models.User, *models.Comment)
// NotifyCreateIssueComment places a place holder function
func (*NullNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
- issue *models.Issue, comment *models.Comment) {
+ issue *models.Issue, comment *models.Comment, mentions []*models.User) {
}
// NotifyNewIssue places a place holder function
-func (*NullNotifier) NotifyNewIssue(issue *models.Issue) {
+func (*NullNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
}
// NotifyIssueChangeStatus places a place holder function
}
// NotifyNewPullRequest places a place holder function
-func (*NullNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
+func (*NullNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
}
// NotifyPullRequestReview places a place holder function
-func (*NullNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment) {
+func (*NullNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*models.User) {
+}
+
+// NotifyPullRequestCodeComment places a place holder function
+func (*NullNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User) {
}
// NotifyMergePullRequest places a place holder function
}
func (r *indexerNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
- issue *models.Issue, comment *models.Comment) {
+ issue *models.Issue, comment *models.Comment, mentions []*models.User) {
if comment.Type == models.CommentTypeComment {
if issue.Comments == nil {
if err := issue.LoadDiscussComments(); err != nil {
}
}
-func (r *indexerNotifier) NotifyNewIssue(issue *models.Issue) {
+func (r *indexerNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
issue_indexer.UpdateIssueIndexer(issue)
}
-func (r *indexerNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
+func (r *indexerNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
issue_indexer.UpdateIssueIndexer(pr.Issue)
}
}
func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
- issue *models.Issue, comment *models.Comment) {
+ issue *models.Issue, comment *models.Comment, mentions []*models.User) {
var act models.ActionType
if comment.Type == models.CommentTypeClose {
act = models.ActionCloseIssue
act = 0
}
- if err := mailer.MailParticipantsComment(comment, act, issue); err != nil {
+ if err := mailer.MailParticipantsComment(comment, act, issue, mentions); err != nil {
log.Error("MailParticipantsComment: %v", err)
}
}
-func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) {
- if err := mailer.MailParticipants(issue, issue.Poster, models.ActionCreateIssue); err != nil {
+func (m *mailNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
+ if err := mailer.MailParticipants(issue, issue.Poster, models.ActionCreateIssue, mentions); err != nil {
log.Error("MailParticipants: %v", err)
}
}
}
}
- if err := mailer.MailParticipants(issue, doer, actionType); err != nil {
+ if err := mailer.MailParticipants(issue, doer, actionType, nil); err != nil {
log.Error("MailParticipants: %v", err)
}
}
-func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
- if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, models.ActionCreatePullRequest); err != nil {
+func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
+ if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, models.ActionCreatePullRequest, mentions); err != nil {
log.Error("MailParticipants: %v", err)
}
}
-func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment) {
+func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, comment *models.Comment, mentions []*models.User) {
var act models.ActionType
if comment.Type == models.CommentTypeClose {
act = models.ActionCloseIssue
} else if comment.Type == models.CommentTypeComment {
act = models.ActionCommentPull
}
- if err := mailer.MailParticipantsComment(comment, act, pr.Issue); err != nil {
+ if err := mailer.MailParticipantsComment(comment, act, pr.Issue, mentions); err != nil {
log.Error("MailParticipantsComment: %v", err)
}
}
+func (m *mailNotifier) NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User) {
+ if err := mailer.MailMentionsComment(pr, comment, mentions); err != nil {
+ log.Error("MailMentionsComment: %v", err)
+ }
+}
+
func (m *mailNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
// mail only sent to added assignees and not self-assignee
if !removed && doer.ID != assignee.ID && assignee.EmailNotifications() == models.EmailNotificationsEnabled {
return
}
pr.Issue.Content = ""
- if err := mailer.MailParticipants(pr.Issue, doer, models.ActionMergePullRequest); err != nil {
+ if err := mailer.MailParticipants(pr.Issue, doer, models.ActionMergePullRequest, nil); err != nil {
log.Error("MailParticipants: %v", err)
}
}
}
comment.Content = ""
- m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment)
+ m.NotifyCreateIssueComment(doer, comment.Issue.Repo, comment.Issue, comment, nil)
}
func (m *mailNotifier) NotifyNewRelease(rel *models.Release) {
// NotifyCreateIssueComment notifies issue comment related message to notifiers
func NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
- issue *models.Issue, comment *models.Comment) {
+ issue *models.Issue, comment *models.Comment, mentions []*models.User) {
for _, notifier := range notifiers {
- notifier.NotifyCreateIssueComment(doer, repo, issue, comment)
+ notifier.NotifyCreateIssueComment(doer, repo, issue, comment, mentions)
}
}
// NotifyNewIssue notifies new issue to notifiers
-func NotifyNewIssue(issue *models.Issue) {
+func NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
for _, notifier := range notifiers {
- notifier.NotifyNewIssue(issue)
+ notifier.NotifyNewIssue(issue, mentions)
}
}
}
// NotifyNewPullRequest notifies new pull request to notifiers
-func NotifyNewPullRequest(pr *models.PullRequest) {
+func NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
for _, notifier := range notifiers {
- notifier.NotifyNewPullRequest(pr)
+ notifier.NotifyNewPullRequest(pr, mentions)
}
}
}
// NotifyPullRequestReview notifies new pull request review
-func NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
+func NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User) {
for _, notifier := range notifiers {
- notifier.NotifyPullRequestReview(pr, review, comment)
+ notifier.NotifyPullRequestReview(pr, review, comment, mentions)
+ }
+}
+
+// NotifyPullRequestCodeComment notifies new pull request code comment
+func NotifyPullRequestCodeComment(pr *models.PullRequest, comment *models.Comment, mentions []*models.User) {
+ for _, notifier := range notifiers {
+ notifier.NotifyPullRequestCodeComment(pr, comment, mentions)
}
}
}
func (ns *notificationService) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
- issue *models.Issue, comment *models.Comment) {
+ issue *models.Issue, comment *models.Comment, mentions []*models.User) {
var opts = issueNotificationOpts{
IssueID: issue.ID,
NotificationAuthorID: doer.ID,
opts.CommentID = comment.ID
}
_ = ns.issueQueue.Push(opts)
+ for _, mention := range mentions {
+ var opts = issueNotificationOpts{
+ IssueID: issue.ID,
+ NotificationAuthorID: doer.ID,
+ ReceiverID: mention.ID,
+ }
+ if comment != nil {
+ opts.CommentID = comment.ID
+ }
+ _ = ns.issueQueue.Push(opts)
+ }
}
-func (ns *notificationService) NotifyNewIssue(issue *models.Issue) {
+func (ns *notificationService) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
_ = ns.issueQueue.Push(issueNotificationOpts{
IssueID: issue.ID,
NotificationAuthorID: issue.Poster.ID,
})
+ for _, mention := range mentions {
+ _ = ns.issueQueue.Push(issueNotificationOpts{
+ IssueID: issue.ID,
+ NotificationAuthorID: issue.Poster.ID,
+ ReceiverID: mention.ID,
+ })
+ }
}
func (ns *notificationService) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
})
}
-func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest) {
+func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest, mentions []*models.User) {
if err := pr.LoadIssue(); err != nil {
log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
return
IssueID: pr.Issue.ID,
NotificationAuthorID: pr.Issue.PosterID,
})
+ for _, mention := range mentions {
+ _ = ns.issueQueue.Push(issueNotificationOpts{
+ IssueID: pr.Issue.ID,
+ NotificationAuthorID: pr.Issue.PosterID,
+ ReceiverID: mention.ID,
+ })
+ }
}
-func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment) {
+func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment, mentions []*models.User) {
var opts = issueNotificationOpts{
IssueID: pr.Issue.ID,
NotificationAuthorID: r.Reviewer.ID,
opts.CommentID = c.ID
}
_ = ns.issueQueue.Push(opts)
+ for _, mention := range mentions {
+ var opts = issueNotificationOpts{
+ IssueID: pr.Issue.ID,
+ NotificationAuthorID: r.Reviewer.ID,
+ ReceiverID: mention.ID,
+ }
+ if c != nil {
+ opts.CommentID = c.ID
+ }
+ _ = ns.issueQueue.Push(opts)
+ }
+}
+
+func (ns *notificationService) NotifyPullRequestCodeComment(pr *models.PullRequest, c *models.Comment, mentions []*models.User) {
+ for _, mention := range mentions {
+ _ = ns.issueQueue.Push(issueNotificationOpts{
+ IssueID: pr.Issue.ID,
+ NotificationAuthorID: c.Poster.ID,
+ CommentID: c.ID,
+ ReceiverID: mention.ID,
+ })
+ }
}
func (ns *notificationService) NotifyPullRequestPushCommits(doer *models.User, pr *models.PullRequest, comment *models.Comment) {
}
}
-func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue) {
+func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue, mentions []*models.User) {
if err := issue.LoadRepo(); err != nil {
log.Error("issue.LoadRepo: %v", err)
return
}
}
-func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
+func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest, mentions []*models.User) {
if err := pull.LoadIssue(); err != nil {
log.Error("pull.LoadIssue: %v", err)
return
}
func (m *webhookNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
- issue *models.Issue, comment *models.Comment) {
+ issue *models.Issue, comment *models.Comment, mentions []*models.User) {
mode, _ := models.AccessLevel(doer, repo)
var err error
}
}
-func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment) {
+func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review *models.Review, comment *models.Comment, mentions []*models.User) {
var reviewHookType models.HookEventType
switch review.Type {
if err != nil {
return nil, err
}
-
- notification.NotifyCreateIssueComment(doer, repo, issue, comment)
+ mentions, err := issue.FindAndUpdateIssueMentions(models.DefaultDBContext(), doer, comment.Content)
+ if err != nil {
+ return nil, err
+ }
+ notification.NotifyCreateIssueComment(doer, repo, issue, comment, mentions)
return comment, nil
}
}
}
- notification.NotifyNewIssue(issue)
+ mentions, err := issue.FindAndUpdateIssueMentions(models.DefaultDBContext(), issue.Poster, issue.Content)
+ if err != nil {
+ return err
+ }
+
+ notification.NotifyNewIssue(issue, mentions)
return nil
}
package mailer
import (
- "fmt"
-
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/references"
)
// MailParticipantsComment sends new comment emails to repository watchers
// and mentioned people.
-func MailParticipantsComment(c *models.Comment, opType models.ActionType, issue *models.Issue) error {
- return mailParticipantsComment(models.DefaultDBContext(), c, opType, issue)
+func MailParticipantsComment(c *models.Comment, opType models.ActionType, issue *models.Issue, mentions []*models.User) error {
+ return mailParticipantsComment(c, opType, issue, mentions)
}
-func mailParticipantsComment(ctx models.DBContext, c *models.Comment, opType models.ActionType, issue *models.Issue) (err error) {
- rawMentions := references.FindAllMentionsMarkdown(c.Content)
- userMentions, err := issue.ResolveMentionsByVisibility(ctx, c.Poster, rawMentions)
- if err != nil {
- return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", c.IssueID, err)
- }
- if err = models.UpdateIssueMentions(ctx, c.IssueID, userMentions); err != nil {
- return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err)
- }
- mentions := make([]int64, len(userMentions))
- for i, u := range userMentions {
- mentions[i] = u.ID
+func mailParticipantsComment(c *models.Comment, opType models.ActionType, issue *models.Issue, mentions []*models.User) (err error) {
+ mentionedIDs := make([]int64, len(mentions))
+ for i, u := range mentions {
+ mentionedIDs[i] = u.ID
}
if err = mailIssueCommentToParticipants(
&mailCommentContext{
ActionType: opType,
Content: c.Content,
Comment: c,
- }, mentions); err != nil {
+ }, mentionedIDs); err != nil {
log.Error("mailIssueCommentToParticipants: %v", err)
}
return nil
}
+
+// MailMentionsComment sends email to users mentioned in a code comment
+func MailMentionsComment(pr *models.PullRequest, c *models.Comment, mentions []*models.User) (err error) {
+ mentionedIDs := make([]int64, len(mentions))
+ for i, u := range mentions {
+ mentionedIDs[i] = u.ID
+ }
+ visited := make(map[int64]bool, len(mentions)+1)
+ visited[c.Poster.ID] = true
+ if err = mailIssueCommentBatch(
+ &mailCommentContext{
+ Issue: pr.Issue,
+ Doer: c.Poster,
+ ActionType: models.ActionCommentPull,
+ Content: c.Content,
+ Comment: c,
+ }, mentionedIDs, visited, true); err != nil {
+ log.Error("mailIssueCommentBatch: %v", err)
+ }
+ return nil
+}
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/references"
)
func fallbackMailSubject(issue *models.Issue) string {
// Avoid mailing the doer
visited[ctx.Doer.ID] = true
+
+ // =========== Mentions ===========
+ if err = mailIssueCommentBatch(ctx, mentions, visited, true); err != nil {
+ return fmt.Errorf("mailIssueCommentBatch() mentions: %v", err)
+ }
+
// Avoid mailing explicit unwatched
ids, err = models.GetIssueWatchersIDs(ctx.Issue.ID, false)
if err != nil {
return fmt.Errorf("mailIssueCommentBatch(): %v", err)
}
- // =========== Mentions ===========
- if err = mailIssueCommentBatch(ctx, mentions, visited, true); err != nil {
- return fmt.Errorf("mailIssueCommentBatch() mentions: %v", err)
- }
-
return nil
}
// MailParticipants sends new issue thread created emails to repository watchers
// and mentioned people.
-func MailParticipants(issue *models.Issue, doer *models.User, opType models.ActionType) error {
- return mailParticipants(models.DefaultDBContext(), issue, doer, opType)
+func MailParticipants(issue *models.Issue, doer *models.User, opType models.ActionType, mentions []*models.User) error {
+ return mailParticipants(issue, doer, opType, mentions)
}
-func mailParticipants(ctx models.DBContext, issue *models.Issue, doer *models.User, opType models.ActionType) (err error) {
- rawMentions := references.FindAllMentionsMarkdown(issue.Content)
- userMentions, err := issue.ResolveMentionsByVisibility(ctx, doer, rawMentions)
- if err != nil {
- return fmt.Errorf("ResolveMentionsByVisibility [%d]: %v", issue.ID, err)
- }
- if err = models.UpdateIssueMentions(ctx, issue.ID, userMentions); err != nil {
- return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
- }
- mentions := make([]int64, len(userMentions))
- for i, u := range userMentions {
- mentions[i] = u.ID
+func mailParticipants(issue *models.Issue, doer *models.User, opType models.ActionType, mentions []*models.User) (err error) {
+ mentionedIDs := make([]int64, len(mentions))
+ for i, u := range mentions {
+ mentionedIDs[i] = u.ID
}
if err = mailIssueCommentToParticipants(
&mailCommentContext{
ActionType: opType,
Content: issue.Content,
Comment: nil,
- }, mentions); err != nil {
+ }, mentionedIDs); err != nil {
log.Error("mailIssueCommentToParticipants: %v", err)
}
return nil
return err
}
- notification.NotifyNewPullRequest(pr)
+ mentions, err := pull.FindAndUpdateIssueMentions(models.DefaultDBContext(), pull.Poster, pull.Content)
+ if err != nil {
+ return err
+ }
+
+ notification.NotifyNewPullRequest(pr, mentions)
// add first push codes comment
baseGitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
return nil, err
}
- notification.NotifyCreateIssueComment(doer, issue.Repo, issue, comment)
+ mentions, err := issue.FindAndUpdateIssueMentions(models.DefaultDBContext(), doer, comment.Content)
+ if err != nil {
+ return nil, err
+ }
+
+ notification.NotifyCreateIssueComment(doer, issue.Repo, issue, comment, mentions)
return comment, nil
}
return nil, nil, err
}
- notification.NotifyPullRequestReview(pr, review, comm)
+ ctx := models.DefaultDBContext()
+ mentions, err := issue.FindAndUpdateIssueMentions(ctx, doer, comm.Content)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ notification.NotifyPullRequestReview(pr, review, comm, mentions)
+
+ for _, lines := range review.CodeComments {
+ for _, comments := range lines {
+ for _, codeComment := range comments {
+ mentions, err := issue.FindAndUpdateIssueMentions(ctx, doer, codeComment.Content)
+ if err != nil {
+ return nil, nil, err
+ }
+ notification.NotifyPullRequestCodeComment(pr, codeComment, mentions)
+ }
+ }
+ }
return review, comm, nil
}