Commit 9e616459e068f2ba65f90016a09387a192fe4cfc
1 parent
11d52a15
Exists in
master
and in
4 other branches
add watchers to email recipients list. Add emails for close/merge MR
Showing
5 changed files
with
196 additions
and
27 deletions
Show diff stats
app/observers/merge_request_observer.rb
| @@ -7,6 +7,12 @@ class MergeRequestObserver < BaseObserver | @@ -7,6 +7,12 @@ class MergeRequestObserver < BaseObserver | ||
| 7 | 7 | ||
| 8 | def after_close(merge_request, transition) | 8 | def after_close(merge_request, transition) |
| 9 | Note.create_status_change_note(merge_request, current_user, merge_request.state) | 9 | Note.create_status_change_note(merge_request, current_user, merge_request.state) |
| 10 | + | ||
| 11 | + notification.close_mr(merge_request, current_user) | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + def after_merge(merge_request, transition) | ||
| 15 | + notification.merge_mr(merge_request, current_user) | ||
| 10 | end | 16 | end |
| 11 | 17 | ||
| 12 | def after_reopen(merge_request, transition) | 18 | def after_reopen(merge_request, transition) |
app/services/notification_service.rb
| @@ -17,7 +17,21 @@ class NotificationService | @@ -17,7 +17,21 @@ class NotificationService | ||
| 17 | end | 17 | end |
| 18 | end | 18 | end |
| 19 | 19 | ||
| 20 | - # TODO: When we close an issue we should send next emails: | 20 | + # When create an issue we should send next emails: |
| 21 | + # | ||
| 22 | + # * issue assignee if his notification level is not Disabled | ||
| 23 | + # * project team members with notification level higher then Participating | ||
| 24 | + # | ||
| 25 | + def new_issue(issue, current_user) | ||
| 26 | + recipients = reject_muted_users([issue.assignee]) | ||
| 27 | + recipients = recipients.concat(project_watchers(issue.project)).uniq | ||
| 28 | + | ||
| 29 | + recipients.each do |recipient| | ||
| 30 | + Notify.delay.new_issue_email(recipient.id, issue.id) | ||
| 31 | + end | ||
| 32 | + end | ||
| 33 | + | ||
| 34 | + # When we close an issue we should send next emails: | ||
| 21 | # | 35 | # |
| 22 | # * issue author if his notification level is not Disabled | 36 | # * issue author if his notification level is not Disabled |
| 23 | # * issue assignee if his notification level is not Disabled | 37 | # * issue assignee if his notification level is not Disabled |
| @@ -26,6 +40,9 @@ class NotificationService | @@ -26,6 +40,9 @@ class NotificationService | ||
| 26 | def close_issue(issue, current_user) | 40 | def close_issue(issue, current_user) |
| 27 | recipients = reject_muted_users([issue.author, issue.assignee]) | 41 | recipients = reject_muted_users([issue.author, issue.assignee]) |
| 28 | 42 | ||
| 43 | + # Add watchers to email list | ||
| 44 | + recipients = recipients.concat(project_watchers(issue.project)).uniq | ||
| 45 | + | ||
| 29 | # Dont send email to me when I close an issue | 46 | # Dont send email to me when I close an issue |
| 30 | recipients.delete(current_user) | 47 | recipients.delete(current_user) |
| 31 | 48 | ||
| @@ -43,30 +60,17 @@ class NotificationService | @@ -43,30 +60,17 @@ class NotificationService | ||
| 43 | reassign_email(issue, current_user, 'reassigned_issue_email') | 60 | reassign_email(issue, current_user, 'reassigned_issue_email') |
| 44 | end | 61 | end |
| 45 | 62 | ||
| 46 | - # When create an issue we should send next emails: | ||
| 47 | - # | ||
| 48 | - # * issue assignee if his notification level is not Disabled | ||
| 49 | - # | ||
| 50 | - def new_issue(issue, current_user) | ||
| 51 | - | ||
| 52 | - if issue.assignee && issue.assignee != current_user | ||
| 53 | - # skip if assignee notification disabled | ||
| 54 | - return true if issue.assignee.notification.disabled? | ||
| 55 | - | ||
| 56 | - Notify.delay.new_issue_email(issue.id) | ||
| 57 | - end | ||
| 58 | - end | ||
| 59 | 63 | ||
| 60 | # When create a merge request we should send next emails: | 64 | # When create a merge request we should send next emails: |
| 61 | # | 65 | # |
| 62 | # * mr assignee if his notification level is not Disabled | 66 | # * mr assignee if his notification level is not Disabled |
| 63 | # | 67 | # |
| 64 | def new_merge_request(merge_request, current_user) | 68 | def new_merge_request(merge_request, current_user) |
| 65 | - if merge_request.assignee && merge_request.assignee != current_user | ||
| 66 | - # skip if assignee notification disabled | ||
| 67 | - return true if merge_request.assignee.notification.disabled? | 69 | + recipients = reject_muted_users([merge_request.assignee]) |
| 70 | + recipients = recipients.concat(project_watchers(merge_request.project)).uniq | ||
| 68 | 71 | ||
| 69 | - Notify.delay.new_merge_request_email(merge_request.id) | 72 | + recipients.each do |recipient| |
| 73 | + Notify.delay.new_merge_request_email(recipient.id, merge_request.id) | ||
| 70 | end | 74 | end |
| 71 | end | 75 | end |
| 72 | 76 | ||
| @@ -79,6 +83,36 @@ class NotificationService | @@ -79,6 +83,36 @@ class NotificationService | ||
| 79 | reassign_email(merge_request, current_user, 'reassigned_merge_request_email') | 83 | reassign_email(merge_request, current_user, 'reassigned_merge_request_email') |
| 80 | end | 84 | end |
| 81 | 85 | ||
| 86 | + # When we close a merge request we should send next emails: | ||
| 87 | + # | ||
| 88 | + # * merge_request author if his notification level is not Disabled | ||
| 89 | + # * merge_request assignee if his notification level is not Disabled | ||
| 90 | + # * project team members with notification level higher then Participating | ||
| 91 | + # | ||
| 92 | + def close_mr(merge_request) | ||
| 93 | + recipients = reject_muted_users([merge_request.author, merge_request.assignee]) | ||
| 94 | + recipients = recipients.concat(project_watchers(merge_request.project)).uniq | ||
| 95 | + | ||
| 96 | + recipients.each do |recipient| | ||
| 97 | + Notify.delay.closed_merge_request_email(recipient.id, merge_request.id) | ||
| 98 | + end | ||
| 99 | + end | ||
| 100 | + | ||
| 101 | + # When we merge a merge request we should send next emails: | ||
| 102 | + # | ||
| 103 | + # * merge_request author if his notification level is not Disabled | ||
| 104 | + # * merge_request assignee if his notification level is not Disabled | ||
| 105 | + # * project team members with notification level higher then Participating | ||
| 106 | + # | ||
| 107 | + def merge_mr(merge_request) | ||
| 108 | + recipients = reject_muted_users([merge_request.author, merge_request.assignee]) | ||
| 109 | + recipients = recipients.concat(project_watchers(merge_request.project)).uniq | ||
| 110 | + | ||
| 111 | + recipients.each do |recipient| | ||
| 112 | + Notify.delay.merged_merge_request_email(recipient.id, merge_request.id) | ||
| 113 | + end | ||
| 114 | + end | ||
| 115 | + | ||
| 82 | # Notify new user with email after creation | 116 | # Notify new user with email after creation |
| 83 | def new_user(user) | 117 | def new_user(user) |
| 84 | # Dont email omniauth created users | 118 | # Dont email omniauth created users |
| @@ -119,6 +153,11 @@ class NotificationService | @@ -119,6 +153,11 @@ class NotificationService | ||
| 119 | 153 | ||
| 120 | protected | 154 | protected |
| 121 | 155 | ||
| 156 | + # Get project users with WATCH notification level | ||
| 157 | + def project_watchers(project) | ||
| 158 | + project.users.where(notification_level: Notification::N_WATCH) | ||
| 159 | + end | ||
| 160 | + | ||
| 122 | # Remove users with disabled notifications from array | 161 | # Remove users with disabled notifications from array |
| 123 | # Also remove duplications and nil recipients | 162 | # Also remove duplications and nil recipients |
| 124 | def reject_muted_users(users) | 163 | def reject_muted_users(users) |
| @@ -130,6 +169,9 @@ class NotificationService | @@ -130,6 +169,9 @@ class NotificationService | ||
| 130 | def reassign_email(target, current_user, method) | 169 | def reassign_email(target, current_user, method) |
| 131 | recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) | 170 | recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) |
| 132 | 171 | ||
| 172 | + # Add watchers to email list | ||
| 173 | + recipients = recipients.concat(project_watchers(target.project)) | ||
| 174 | + | ||
| 133 | # reject users with disabled notifications | 175 | # reject users with disabled notifications |
| 134 | recipients = reject_muted_users(recipients) | 176 | recipients = reject_muted_users(recipients) |
| 135 | 177 |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +%p | ||
| 2 | + = "Merge Request #{@merge_request.id} was closed" | ||
| 3 | +%p | ||
| 4 | + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) | ||
| 5 | +%p | ||
| 6 | + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | ||
| 7 | +%p | ||
| 8 | + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} | ||
| 9 | + |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +%p | ||
| 2 | + = "Merge Request #{@merge_request.id} was merged" | ||
| 3 | +%p | ||
| 4 | + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) | ||
| 5 | +%p | ||
| 6 | + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | ||
| 7 | +%p | ||
| 8 | + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} | ||
| 9 | + |
spec/services/notification_service_spec.rb
| @@ -23,6 +23,10 @@ describe NotificationService do | @@ -23,6 +23,10 @@ describe NotificationService do | ||
| 23 | describe 'Issues' do | 23 | describe 'Issues' do |
| 24 | let(:issue) { create :issue, assignee: create(:user) } | 24 | let(:issue) { create :issue, assignee: create(:user) } |
| 25 | 25 | ||
| 26 | + before do | ||
| 27 | + build_team(issue.project) | ||
| 28 | + end | ||
| 29 | + | ||
| 26 | describe :new_issue do | 30 | describe :new_issue do |
| 27 | it 'should sent email to issue assignee' do | 31 | it 'should sent email to issue assignee' do |
| 28 | Notify.should_receive(:new_issue_email).with(issue.id) | 32 | Notify.should_receive(:new_issue_email).with(issue.id) |
| @@ -31,16 +35,41 @@ describe NotificationService do | @@ -31,16 +35,41 @@ describe NotificationService do | ||
| 31 | end | 35 | end |
| 32 | 36 | ||
| 33 | describe :reassigned_issue do | 37 | describe :reassigned_issue do |
| 34 | - it 'should sent email to issue old assignee and new issue assignee' do | ||
| 35 | - Notify.should_receive(:reassigned_issue_email) | ||
| 36 | - notification.reassigned_issue(issue, issue.author) | 38 | + it 'should email new assignee' do |
| 39 | + should_email(issue.assignee_id) | ||
| 40 | + should_email(@u_watcher.id) | ||
| 41 | + should_not_email(@u_participating.id) | ||
| 42 | + should_not_email(@u_disabled.id) | ||
| 43 | + | ||
| 44 | + notification.reassigned_issue(issue, @u_disabled) | ||
| 45 | + end | ||
| 46 | + | ||
| 47 | + def should_email(user_id) | ||
| 48 | + Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) | ||
| 49 | + end | ||
| 50 | + | ||
| 51 | + def should_not_email(user_id) | ||
| 52 | + Notify.should_not_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) | ||
| 37 | end | 53 | end |
| 38 | end | 54 | end |
| 39 | 55 | ||
| 40 | describe :close_issue do | 56 | describe :close_issue do |
| 41 | it 'should sent email to issue assignee and issue author' do | 57 | it 'should sent email to issue assignee and issue author' do |
| 42 | - Notify.should_receive(:issue_status_changed_email) | ||
| 43 | - notification.close_issue(issue, issue.author) | 58 | + should_email(issue.assignee_id) |
| 59 | + should_email(issue.author_id) | ||
| 60 | + should_email(@u_watcher.id) | ||
| 61 | + should_not_email(@u_participating.id) | ||
| 62 | + should_not_email(@u_disabled.id) | ||
| 63 | + | ||
| 64 | + notification.close_issue(issue, @u_disabled) | ||
| 65 | + end | ||
| 66 | + | ||
| 67 | + def should_email(user_id) | ||
| 68 | + Notify.should_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) | ||
| 69 | + end | ||
| 70 | + | ||
| 71 | + def should_not_email(user_id) | ||
| 72 | + Notify.should_not_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) | ||
| 44 | end | 73 | end |
| 45 | end | 74 | end |
| 46 | end | 75 | end |
| @@ -48,16 +77,90 @@ describe NotificationService do | @@ -48,16 +77,90 @@ describe NotificationService do | ||
| 48 | describe 'Merge Requests' do | 77 | describe 'Merge Requests' do |
| 49 | let(:merge_request) { create :merge_request, assignee: create(:user) } | 78 | let(:merge_request) { create :merge_request, assignee: create(:user) } |
| 50 | 79 | ||
| 80 | + before do | ||
| 81 | + build_team(merge_request.project) | ||
| 82 | + end | ||
| 83 | + | ||
| 51 | describe :new_merge_request do | 84 | describe :new_merge_request do |
| 52 | - it 'should send email to merge_request assignee' do | 85 | + it do |
| 86 | + should_email(merge_request.assignee_id) | ||
| 87 | + should_email(@u_watcher.id) | ||
| 88 | + should_not_email(@u_participating.id) | ||
| 89 | + should_not_email(@u_disabled.id) | ||
| 90 | + notification.new_merge_request(merge_request, @u_disabled) | ||
| 91 | + end | ||
| 92 | + | ||
| 93 | + def should_email(user_id) | ||
| 53 | Notify.should_receive(:new_merge_request_email).with(merge_request.id) | 94 | Notify.should_receive(:new_merge_request_email).with(merge_request.id) |
| 54 | - notification.new_merge_request(merge_request, merge_request.author) | ||
| 55 | end | 95 | end |
| 56 | 96 | ||
| 57 | - it 'should not send email to merge_request assignee if he is current_user' do | 97 | + def should_not_email(user_id) |
| 58 | Notify.should_not_receive(:new_merge_request_email).with(merge_request.id) | 98 | Notify.should_not_receive(:new_merge_request_email).with(merge_request.id) |
| 59 | - notification.new_merge_request(merge_request, merge_request.assignee) | ||
| 60 | end | 99 | end |
| 61 | end | 100 | end |
| 101 | + | ||
| 102 | + describe :reassigned_merge_request do | ||
| 103 | + it do | ||
| 104 | + should_email(merge_request.assignee_id) | ||
| 105 | + should_email(@u_watcher.id) | ||
| 106 | + should_not_email(@u_participating.id) | ||
| 107 | + should_not_email(@u_disabled.id) | ||
| 108 | + notification.reassigned_merge_request(merge_request, merge_request.author) | ||
| 109 | + end | ||
| 110 | + | ||
| 111 | + def should_email(user_id) | ||
| 112 | + Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) | ||
| 113 | + end | ||
| 114 | + | ||
| 115 | + def should_not_email(user_id) | ||
| 116 | + Notify.should_not_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) | ||
| 117 | + end | ||
| 118 | + end | ||
| 119 | + | ||
| 120 | + describe :closed_merge_request do | ||
| 121 | + it do | ||
| 122 | + should_email(merge_request.assignee_id) | ||
| 123 | + should_email(@u_watcher.id) | ||
| 124 | + should_not_email(@u_participating.id) | ||
| 125 | + should_not_email(@u_disabled.id) | ||
| 126 | + notification.close_mr(merge_request) | ||
| 127 | + end | ||
| 128 | + | ||
| 129 | + def should_email(user_id) | ||
| 130 | + Notify.should_receive(:closed_merge_request_email).with(user_id, merge_request.id) | ||
| 131 | + end | ||
| 132 | + | ||
| 133 | + def should_not_email(user_id) | ||
| 134 | + Notify.should_not_receive(:closed_merge_request_email).with(user_id, merge_request.id) | ||
| 135 | + end | ||
| 136 | + end | ||
| 137 | + | ||
| 138 | + describe :merged_merge_request do | ||
| 139 | + it do | ||
| 140 | + should_email(merge_request.assignee_id) | ||
| 141 | + should_email(@u_watcher.id) | ||
| 142 | + should_not_email(@u_participating.id) | ||
| 143 | + should_not_email(@u_disabled.id) | ||
| 144 | + notification.merge_mr(merge_request) | ||
| 145 | + end | ||
| 146 | + | ||
| 147 | + def should_email(user_id) | ||
| 148 | + Notify.should_receive(:merged_merge_request_email).with(user_id, merge_request.id) | ||
| 149 | + end | ||
| 150 | + | ||
| 151 | + def should_not_email(user_id) | ||
| 152 | + Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id) | ||
| 153 | + end | ||
| 154 | + end | ||
| 155 | + end | ||
| 156 | + | ||
| 157 | + def build_team(project) | ||
| 158 | + @u_watcher = create(:user, notification_level: Notification::N_WATCH) | ||
| 159 | + @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING) | ||
| 160 | + @u_disabled = create(:user, notification_level: Notification::N_DISABLED) | ||
| 161 | + | ||
| 162 | + project.team << [@u_watcher, :master] | ||
| 163 | + project.team << [@u_participating, :master] | ||
| 164 | + project.team << [@u_disabled, :master] | ||
| 62 | end | 165 | end |
| 63 | end | 166 | end |