Commit 74b50363 authored by Douwe Maan's avatar Douwe Maan

Merge branch '40226-refactor-the-issuable-s-webhooks-data-architecture' into 'master'

Refactor the way we pass `old associations` to issuable's update services

Closes #40226

See merge request gitlab-org/gitlab-ce!15542
parents 25a3a183 ba62143a
...@@ -255,8 +255,10 @@ module Issuable ...@@ -255,8 +255,10 @@ module Issuable
participants(user).include?(user) participants(user).include?(user)
end end
def to_hook_data(user, old_labels: [], old_assignees: [], old_total_time_spent: nil) def to_hook_data(user, old_associations: {})
changes = previous_changes changes = previous_changes
old_labels = old_associations.fetch(:labels, [])
old_assignees = old_associations.fetch(:assignees, [])
if old_labels != labels if old_labels != labels
changes[:labels] = [old_labels.map(&:hook_attrs), labels.map(&:hook_attrs)] changes[:labels] = [old_labels.map(&:hook_attrs), labels.map(&:hook_attrs)]
...@@ -270,8 +272,12 @@ module Issuable ...@@ -270,8 +272,12 @@ module Issuable
end end
end end
if old_total_time_spent != total_time_spent if self.respond_to?(:total_time_spent)
changes[:total_time_spent] = [old_total_time_spent, total_time_spent] old_total_time_spent = old_associations.fetch(:total_time_spent, nil)
if old_total_time_spent != total_time_spent
changes[:total_time_spent] = [old_total_time_spent, total_time_spent]
end
end end
Gitlab::HookData::IssuableBuilder.new(self).build(user: user, changes: changes) Gitlab::HookData::IssuableBuilder.new(self).build(user: user, changes: changes)
......
...@@ -169,10 +169,7 @@ class IssuableBaseService < BaseService ...@@ -169,10 +169,7 @@ class IssuableBaseService < BaseService
change_todo(issuable) change_todo(issuable)
toggle_award(issuable) toggle_award(issuable)
filter_params(issuable) filter_params(issuable)
old_labels = issuable.labels.to_a old_associations = associations_before_update(issuable)
old_mentioned_users = issuable.mentioned_users.to_a
old_assignees = issuable.assignees.to_a
old_total_time_spent = issuable.total_time_spent
label_ids = process_label_ids(params, existing_label_ids: issuable.label_ids) label_ids = process_label_ids(params, existing_label_ids: issuable.label_ids)
params[:label_ids] = label_ids if labels_changing?(issuable.label_ids, label_ids) params[:label_ids] = label_ids if labels_changing?(issuable.label_ids, label_ids)
...@@ -193,18 +190,13 @@ class IssuableBaseService < BaseService ...@@ -193,18 +190,13 @@ class IssuableBaseService < BaseService
if issuable.with_transaction_returning_status { issuable.save } if issuable.with_transaction_returning_status { issuable.save }
# We do not touch as it will affect a update on updated_at field # We do not touch as it will affect a update on updated_at field
ActiveRecord::Base.no_touching do ActiveRecord::Base.no_touching do
Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels) Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_associations[:labels])
end end
handle_changes( handle_changes(issuable, old_associations: old_associations)
issuable,
old_labels: old_labels,
old_mentioned_users: old_mentioned_users,
old_assignees: old_assignees
)
new_assignees = issuable.assignees.to_a new_assignees = issuable.assignees.to_a
affected_assignees = (old_assignees + new_assignees) - (old_assignees & new_assignees) affected_assignees = (old_associations[:assignees] + new_assignees) - (old_associations[:assignees] & new_assignees)
invalidate_cache_counts(issuable, users: affected_assignees.compact) invalidate_cache_counts(issuable, users: affected_assignees.compact)
after_update(issuable) after_update(issuable)
...@@ -212,9 +204,8 @@ class IssuableBaseService < BaseService ...@@ -212,9 +204,8 @@ class IssuableBaseService < BaseService
execute_hooks( execute_hooks(
issuable, issuable,
'update', 'update',
old_labels: old_labels, old_associations: old_associations
old_assignees: old_assignees, )
old_total_time_spent: old_total_time_spent)
issuable.update_project_counter_caches if update_project_counters issuable.update_project_counter_caches if update_project_counters
end end
...@@ -267,6 +258,18 @@ class IssuableBaseService < BaseService ...@@ -267,6 +258,18 @@ class IssuableBaseService < BaseService
end end
end end
def associations_before_update(issuable)
associations =
{
labels: issuable.labels.to_a,
mentioned_users: issuable.mentioned_users.to_a,
assignees: issuable.assignees.to_a
}
associations[:total_time_spent] = issuable.total_time_spent if issuable.respond_to?(:total_time_spent)
associations
end
def has_changes?(issuable, old_labels: [], old_assignees: []) def has_changes?(issuable, old_labels: [], old_assignees: [])
valid_attrs = [:title, :description, :assignee_id, :milestone_id, :target_branch] valid_attrs = [:title, :description, :assignee_id, :milestone_id, :target_branch]
......
module Issues module Issues
class BaseService < ::IssuableBaseService class BaseService < ::IssuableBaseService
def hook_data(issue, action, old_labels: [], old_assignees: [], old_total_time_spent: nil) def hook_data(issue, action, old_associations: {})
hook_data = issue.to_hook_data(current_user, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) hook_data = issue.to_hook_data(current_user, old_associations: old_associations)
hook_data[:object_attributes][:action] = action hook_data[:object_attributes][:action] = action
hook_data hook_data
...@@ -22,8 +22,8 @@ module Issues ...@@ -22,8 +22,8 @@ module Issues
issue, issue.project, current_user, old_assignees) issue, issue.project, current_user, old_assignees)
end end
def execute_hooks(issue, action = 'open', old_labels: [], old_assignees: [], old_total_time_spent: nil) def execute_hooks(issue, action = 'open', old_associations: {})
issue_data = hook_data(issue, action, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) issue_data = hook_data(issue, action, old_associations: old_associations)
hooks_scope = issue.confidential? ? :confidential_issue_hooks : :issue_hooks hooks_scope = issue.confidential? ? :confidential_issue_hooks : :issue_hooks
issue.project.execute_hooks(issue_data, hooks_scope) issue.project.execute_hooks(issue_data, hooks_scope)
issue.project.execute_services(issue_data, hooks_scope) issue.project.execute_services(issue_data, hooks_scope)
......
...@@ -14,9 +14,10 @@ module Issues ...@@ -14,9 +14,10 @@ module Issues
end end
def handle_changes(issue, options) def handle_changes(issue, options)
old_labels = options[:old_labels] || [] old_associations = options.fetch(:old_associations, {})
old_mentioned_users = options[:old_mentioned_users] || [] old_labels = old_associations.fetch(:labels, [])
old_assignees = options[:old_assignees] || [] old_mentioned_users = old_associations.fetch(:mentioned_users, [])
old_assignees = old_associations.fetch(:assignees, [])
if has_changes?(issue, old_labels: old_labels, old_assignees: old_assignees) if has_changes?(issue, old_labels: old_labels, old_assignees: old_assignees)
todo_service.mark_pending_todos_as_done(issue, current_user) todo_service.mark_pending_todos_as_done(issue, current_user)
......
...@@ -4,8 +4,8 @@ module MergeRequests ...@@ -4,8 +4,8 @@ module MergeRequests
SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil) SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil)
end end
def hook_data(merge_request, action, old_rev: nil, old_labels: [], old_assignees: [], old_total_time_spent: nil) def hook_data(merge_request, action, old_rev: nil, old_associations: {})
hook_data = merge_request.to_hook_data(current_user, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) hook_data = merge_request.to_hook_data(current_user, old_associations: old_associations)
hook_data[:object_attributes][:action] = action hook_data[:object_attributes][:action] = action
if old_rev && !Gitlab::Git.blank_ref?(old_rev) if old_rev && !Gitlab::Git.blank_ref?(old_rev)
hook_data[:object_attributes][:oldrev] = old_rev hook_data[:object_attributes][:oldrev] = old_rev
...@@ -14,9 +14,9 @@ module MergeRequests ...@@ -14,9 +14,9 @@ module MergeRequests
hook_data hook_data
end end
def execute_hooks(merge_request, action = 'open', old_rev: nil, old_labels: [], old_assignees: [], old_total_time_spent: nil) def execute_hooks(merge_request, action = 'open', old_rev: nil, old_associations: {})
if merge_request.project if merge_request.project
merge_data = hook_data(merge_request, action, old_rev: old_rev, old_labels: old_labels, old_assignees: old_assignees, old_total_time_spent: old_total_time_spent) merge_data = hook_data(merge_request, action, old_rev: old_rev, old_associations: old_associations)
merge_request.project.execute_hooks(merge_data, :merge_request_hooks) merge_request.project.execute_hooks(merge_data, :merge_request_hooks)
merge_request.project.execute_services(merge_data, :merge_request_hooks) merge_request.project.execute_services(merge_data, :merge_request_hooks)
end end
......
...@@ -22,8 +22,9 @@ module MergeRequests ...@@ -22,8 +22,9 @@ module MergeRequests
end end
def handle_changes(merge_request, options) def handle_changes(merge_request, options)
old_labels = options[:old_labels] || [] old_associations = options.fetch(:old_associations, {})
old_mentioned_users = options[:old_mentioned_users] || [] old_labels = old_associations.fetch(:labels, [])
old_mentioned_users = old_associations.fetch(:mentioned_users, [])
if has_changes?(merge_request, old_labels: old_labels) if has_changes?(merge_request, old_labels: old_labels)
todo_service.mark_pending_todos_as_done(merge_request, current_user) todo_service.mark_pending_todos_as_done(merge_request, current_user)
......
...@@ -283,7 +283,7 @@ describe Issuable do ...@@ -283,7 +283,7 @@ describe Issuable do
'labels' => [[labels[0].hook_attrs], [labels[1].hook_attrs]] 'labels' => [[labels[0].hook_attrs], [labels[1].hook_attrs]]
)) ))
issue.to_hook_data(user, old_labels: [labels[0]]) issue.to_hook_data(user, old_associations: { labels: [labels[0]] })
end end
end end
...@@ -302,7 +302,7 @@ describe Issuable do ...@@ -302,7 +302,7 @@ describe Issuable do
'total_time_spent' => [1, 2] 'total_time_spent' => [1, 2]
)) ))
issue.to_hook_data(user, old_total_time_spent: 1) issue.to_hook_data(user, old_associations: { total_time_spent: 1 })
end end
end end
...@@ -322,7 +322,7 @@ describe Issuable do ...@@ -322,7 +322,7 @@ describe Issuable do
'assignees' => [[user.hook_attrs], [user.hook_attrs, user2.hook_attrs]] 'assignees' => [[user.hook_attrs], [user.hook_attrs, user2.hook_attrs]]
)) ))
issue.to_hook_data(user, old_assignees: [user]) issue.to_hook_data(user, old_associations: { assignees: [user] })
end end
end end
...@@ -345,7 +345,7 @@ describe Issuable do ...@@ -345,7 +345,7 @@ describe Issuable do
'assignee' => [user.hook_attrs, user2.hook_attrs] 'assignee' => [user.hook_attrs, user2.hook_attrs]
)) ))
merge_request.to_hook_data(user, old_assignees: [user]) merge_request.to_hook_data(user, old_associations: { assignees: [user] })
end end
end end
end end
......
...@@ -65,7 +65,7 @@ describe MergeRequests::UpdateService, :mailer do ...@@ -65,7 +65,7 @@ describe MergeRequests::UpdateService, :mailer do
end end
end end
it 'mathces base expectations' do it 'matches base expectations' do
expect(@merge_request).to be_valid expect(@merge_request).to be_valid
expect(@merge_request.title).to eq('New title') expect(@merge_request.title).to eq('New title')
expect(@merge_request.assignee).to eq(user2) expect(@merge_request.assignee).to eq(user2)
...@@ -78,9 +78,17 @@ describe MergeRequests::UpdateService, :mailer do ...@@ -78,9 +78,17 @@ describe MergeRequests::UpdateService, :mailer do
end end
it 'executes hooks with update action' do it 'executes hooks with update action' do
expect(service) expect(service).to have_received(:execute_hooks)
.to have_received(:execute_hooks) .with(
.with(@merge_request, 'update', old_labels: [], old_assignees: [user3], old_total_time_spent: 0) @merge_request,
'update',
old_associations: {
labels: [],
mentioned_users: [user2],
assignees: [user3],
total_time_spent: 0
}
)
end end
it 'sends email to user2 about assign of new merge request and email to user3 about merge request unassignment' do it 'sends email to user2 about assign of new merge request and email to user3 about merge request unassignment' do
......
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