Commit 8f8101d7 authored by Robert Speicher's avatar Robert Speicher

Merge branch '42-approval-notifications' into 'master'

Send notification email when MR is approved

Closes #42.

See merge request !484
parents dbc1991b 328655e0
...@@ -7,6 +7,7 @@ v 8.9.0 (unreleased) ...@@ -7,6 +7,7 @@ v 8.9.0 (unreleased)
- Forbid MR authors from approving their own MRs - Forbid MR authors from approving their own MRs
- Instrument instance methods of Gitlab::InsecureKeyFingerprint class - Instrument instance methods of Gitlab::InsecureKeyFingerprint class
- Add API endpoint for Merge Request Approvals !449 - Add API endpoint for Merge Request Approvals !449
- Send notification email when merge request is approved
- Distribute RepositoryUpdateMirror jobs in time and add exclusive lease on them by project_id - Distribute RepositoryUpdateMirror jobs in time and add exclusive lease on them by project_id
- [Elastic] Move ES settings to application settings - [Elastic] Move ES settings to application settings
- Disable mirror flag for projects without import_url - Disable mirror flag for projects without import_url
......
...@@ -42,6 +42,13 @@ module Emails ...@@ -42,6 +42,13 @@ module Emails
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id)) mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id))
end end
def approved_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
setup_merge_request_mail(merge_request_id, recipient_id)
@approved_by_users = @merge_request.approved_by_users.map(&:name)
mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id))
end
private private
def setup_merge_request_mail(merge_request_id, recipient_id) def setup_merge_request_mail(merge_request_id, recipient_id)
......
...@@ -8,6 +8,7 @@ module MergeRequests ...@@ -8,6 +8,7 @@ module MergeRequests
mark_pending_todos_as_done(merge_request) mark_pending_todos_as_done(merge_request)
if merge_request.approvals_left.zero? if merge_request.approvals_left.zero?
notification_service.approve_mr(merge_request, current_user)
execute_hooks(merge_request, 'approved') execute_hooks(merge_request, 'approved')
end end
end end
......
...@@ -115,6 +115,10 @@ class NotificationService ...@@ -115,6 +115,10 @@ class NotificationService
) )
end end
def approve_mr(merge_request, current_user)
approve_mr_email(merge_request, merge_request.target_project, current_user)
end
# Notify new user with email after creation # Notify new user with email after creation
def new_user(user, token = nil) def new_user(user, token = nil)
# Don't email omniauth created users # Don't email omniauth created users
...@@ -477,6 +481,14 @@ class NotificationService ...@@ -477,6 +481,14 @@ class NotificationService
end end
end end
def approve_mr_email(merge_request, project, current_user)
recipients = build_recipients(merge_request, project, current_user)
recipients.each do |recipient|
mailer.approved_merge_request_email(recipient.id, merge_request.id, current_user.id).deliver_later
end
end
def build_recipients(target, project, current_user, action: nil, previous_assignee: nil) def build_recipients(target, project, current_user, action: nil, previous_assignee: nil)
recipients = target.participants(current_user) recipients = target.participants(current_user)
recipients = add_project_watchers(recipients, project) recipients = add_project_watchers(recipients, project)
......
%p
= "Merge Request #{@merge_request.to_reference} was approved by #{@approved_by_users.to_sentence}"
= "Merge Request #{@merge_request.to_reference} was approved by #{@approved_by_users.to_sentence}"
Merge Request url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)}
= merge_path_description(@merge_request, 'to')
Author: #{@merge_request.author_name}
Assignee: #{@merge_request.assignee_name}
...@@ -366,6 +366,46 @@ describe Notify do ...@@ -366,6 +366,46 @@ describe Notify do
end end
end end
describe 'that are approved' do
let(:last_approver) { create(:user) }
subject { Notify.approved_merge_request_email(recipient.id, merge_request.id, last_approver.id) }
before do
merge_request.approvals.create(user: merge_request.assignee)
merge_request.approvals.create(user: last_approver)
end
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request }
end
it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like 'an unsubscribeable thread'
it 'is sent as the last approver' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(last_approver.name)
expect(sender.address).to eq(gitlab_sender)
end
it 'has the correct subject' do
is_expected.to have_subject /#{merge_request.title} \(#{merge_request.to_reference}\)/
end
it 'contains the new status' do
is_expected.to have_body_text /approved/i
end
it 'contains a link to the merge request' do
is_expected.to have_body_text /#{namespace_project_merge_request_path project.namespace, project, merge_request}/
end
it 'contains the names of all of the approvers' do
is_expected.to have_body_text /#{merge_request.assignee.name}/
is_expected.to have_body_text /#{last_approver.name}/
end
end
describe 'that are merged' do describe 'that are merged' do
subject { Notify.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) } subject { Notify.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) }
......
...@@ -47,15 +47,36 @@ describe MergeRequests::ApprovalService, services: true do ...@@ -47,15 +47,36 @@ describe MergeRequests::ApprovalService, services: true do
service.execute(merge_request) service.execute(merge_request)
end end
it 'does not send an email' do
expect(merge_request).to receive(:approvals_left).and_return(5)
expect(service).not_to receive(:notification_service)
service.execute(merge_request)
end
end end
context 'with required approvals' do context 'with required approvals' do
it 'fires a webhook' do let(:notification_service) { NotificationService.new }
before do
expect(merge_request).to receive(:approvals_left).and_return(0) expect(merge_request).to receive(:approvals_left).and_return(0)
allow(service).to receive(:notification_service).and_return(notification_service)
allow(service).to receive(:execute_hooks)
allow(notification_service).to receive(:approve_mr)
end
it 'fires a webhook' do
expect(service).to receive(:execute_hooks).with(merge_request, 'approved') expect(service).to receive(:execute_hooks).with(merge_request, 'approved')
service.execute(merge_request) service.execute(merge_request)
end end
it 'sends an email' do
expect(notification_service).to receive(:approve_mr).with(merge_request, user)
service.execute(merge_request)
end
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment