Commit f0adf28ed917d8ebedc89c954e31b1f1f9e4b6fc

Authored by Dmitriy Zaporozhets
2 parents 05c9ab94 535339a6

Merge branch 'event-create-service' into 'master'

EventCreateService class

The goal is to collect all event creation logic in one place called EventCreateService.
Because now its placed in observers, controllers, services etc
app/models/event.rb
... ... @@ -47,14 +47,6 @@ class Event < ActiveRecord::Base
47 47 scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
48 48  
49 49 class << self
50   - def determine_action(record)
51   - if [Issue, MergeRequest].include? record.class
52   - Event::CREATED
53   - elsif record.kind_of? Note
54   - Event::COMMENTED
55   - end
56   - end
57   -
58 50 def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads')
59 51 commit = project.repository.commit(ref.target)
60 52  
... ...
app/observers/activity_observer.rb
... ... @@ -1,35 +0,0 @@
1   -class ActivityObserver < BaseObserver
2   - observe :issue, :note, :milestone
3   -
4   - def after_create(record)
5   - if record.kind_of?(Note)
6   - # Skip system notes, like status changes and cross-references.
7   - return true if record.system?
8   -
9   - # Skip wall notes to prevent spamming of dashboard
10   - return true if record.noteable_type.blank?
11   - end
12   -
13   - create_event(record, Event.determine_action(record)) if current_user
14   - end
15   -
16   - def after_close(record, transition)
17   - create_event(record, Event::CLOSED)
18   - end
19   -
20   - def after_reopen(record, transition)
21   - create_event(record, Event::REOPENED)
22   - end
23   -
24   - protected
25   -
26   - def create_event(record, status)
27   - Event.create(
28   - project: record.project,
29   - target_id: record.id,
30   - target_type: record.class.name,
31   - action: status,
32   - author_id: current_user.id
33   - )
34   - end
35   -end
app/observers/base_observer.rb
... ... @@ -3,6 +3,10 @@ class BaseObserver &lt; ActiveRecord::Observer
3 3 NotificationService.new
4 4 end
5 5  
  6 + def event_service
  7 + EventCreateService.new
  8 + end
  9 +
6 10 def log_info message
7 11 Gitlab::AppLogger.info message
8 12 end
... ...
app/observers/issue_observer.rb
1 1 class IssueObserver < BaseObserver
2 2 def after_create(issue)
3 3 notification.new_issue(issue, current_user)
  4 + event_service.open_issue(issue, current_user)
4 5 issue.create_cross_references!(issue.project, current_user)
5 6 execute_hooks(issue)
6 7 end
7 8  
8 9 def after_close(issue, transition)
9 10 notification.close_issue(issue, current_user)
  11 + event_service.close_issue(issue, current_user)
10 12 create_note(issue)
11 13 execute_hooks(issue)
12 14 end
13 15  
14 16 def after_reopen(issue, transition)
  17 + event_service.reopen_issue(issue, current_user)
15 18 create_note(issue)
16 19 execute_hooks(issue)
17 20 end
... ...
app/observers/merge_request_observer.rb
1   -class MergeRequestObserver < ActivityObserver
2   - observe :merge_request
3   -
  1 +class MergeRequestObserver < BaseObserver
4 2 def after_create(merge_request)
5   - if merge_request.author_id
6   - create_event(merge_request, Event.determine_action(merge_request))
7   - end
8   -
  3 + event_service.open_mr(merge_request, current_user)
9 4 notification.new_merge_request(merge_request, current_user)
10 5 merge_request.create_cross_references!(merge_request.project, current_user)
11 6 execute_hooks(merge_request)
12 7 end
13 8  
14 9 def after_close(merge_request, transition)
15   - create_event(merge_request, Event::CLOSED)
  10 + event_service.close_mr(merge_request, current_user)
16 11 notification.close_mr(merge_request, current_user)
17 12 create_note(merge_request)
18 13 execute_hooks(merge_request)
19 14 end
20 15  
21 16 def after_reopen(merge_request, transition)
22   - create_event(merge_request, Event::REOPENED)
  17 + event_service.reopen_mr(merge_request, current_user)
23 18 create_note(merge_request)
24 19 execute_hooks(merge_request)
25 20 merge_request.reload_code
... ... @@ -33,16 +28,6 @@ class MergeRequestObserver &lt; ActivityObserver
33 28 execute_hooks(merge_request)
34 29 end
35 30  
36   - def create_event(record, status)
37   - Event.create(
38   - project: record.target_project,
39   - target_id: record.id,
40   - target_type: record.class.name,
41   - action: status,
42   - author_id: current_user.id
43   - )
44   - end
45   -
46 31 private
47 32  
48 33 # Create merge request note with service comment like 'Status changed to closed'
... ...
app/observers/milestone_observer.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class MilestoneObserver < BaseObserver
  2 + def after_create(milestone)
  3 + event_service.open_milestone(milestone, current_user)
  4 + end
  5 +
  6 + def after_close(milestone, transition)
  7 + event_service.close_milestone(milestone, current_user)
  8 + end
  9 +
  10 + def after_reopen(milestone, transition)
  11 + event_service.reopen_milestone(milestone, current_user)
  12 + end
  13 +end
... ...
app/observers/note_observer.rb
... ... @@ -2,6 +2,12 @@ class NoteObserver &lt; BaseObserver
2 2 def after_create(note)
3 3 notification.new_note(note)
4 4  
  5 + # Skip system notes, like status changes and cross-references.
  6 + # Skip wall notes to prevent spamming of dashboard
  7 + if note.noteable_type.present? && !note.system
  8 + event_service.leave_note(note, current_user)
  9 + end
  10 +
5 11 unless note.system?
6 12 # Create a cross-reference note if this Note contains GFM that names an
7 13 # issue, merge request, or commit.
... ...
app/services/event_create_service.rb 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +# EventCreateService class
  2 +#
  3 +# Used for creating events feed on dashboard after certain user action
  4 +#
  5 +# Ex.
  6 +# EventCreateService.new.new_issue(issue, current_user)
  7 +#
  8 +class EventCreateService
  9 + def open_issue(issue, current_user)
  10 + create_event(issue, current_user, Event::CREATED)
  11 + end
  12 +
  13 + def close_issue(issue, current_user)
  14 + create_event(issue, current_user, Event::CLOSED)
  15 + end
  16 +
  17 + def reopen_issue(issue, current_user)
  18 + create_event(issue, current_user, Event::REOPENED)
  19 + end
  20 +
  21 + def open_mr(merge_request, current_user)
  22 + create_event(merge_request, current_user, Event::CREATED)
  23 + end
  24 +
  25 + def close_mr(merge_request, current_user)
  26 + create_event(merge_request, current_user, Event::CLOSED)
  27 + end
  28 +
  29 + def reopen_mr(merge_request, current_user)
  30 + create_event(merge_request, current_user, Event::REOPENED)
  31 + end
  32 +
  33 + def merge_mr(merge_request, current_user)
  34 + create_event(merge_request, current_user, Event::MERGED)
  35 + end
  36 +
  37 + def open_milestone(milestone, current_user)
  38 + create_event(milestone, current_user, Event::CREATED)
  39 + end
  40 +
  41 + def close_milestone(milestone, current_user)
  42 + create_event(milestone, current_user, Event::CLOSED)
  43 + end
  44 +
  45 + def reopen_milestone(milestone, current_user)
  46 + create_event(milestone, current_user, Event::REOPENED)
  47 + end
  48 +
  49 + def leave_note(note, current_user)
  50 + create_event(note, current_user, Event::COMMENTED)
  51 + end
  52 +
  53 + private
  54 +
  55 + def create_event(record, current_user, status)
  56 + Event.create(
  57 + project: record.project,
  58 + target_id: record.id,
  59 + target_type: record.class.name,
  60 + action: status,
  61 + author_id: current_user.id
  62 + )
  63 + end
  64 +end
... ...
app/services/merge_requests/base_merge_service.rb
... ... @@ -8,13 +8,7 @@ module MergeRequests
8 8 end
9 9  
10 10 def create_merge_event(merge_request, current_user)
11   - Event.create(
12   - project: merge_request.target_project,
13   - target_id: merge_request.id,
14   - target_type: merge_request.class.name,
15   - action: Event::MERGED,
16   - author_id: current_user.id
17   - )
  11 + EventCreateService.new.merge_mr(merge_request, current_user)
18 12 end
19 13  
20 14 def execute_project_hooks(merge_request)
... ...
config/application.rb
... ... @@ -19,7 +19,7 @@ module Gitlab
19 19 # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
20 20  
21 21 # Activate observers that should always be running.
22   - config.active_record.observers = :activity_observer,
  22 + config.active_record.observers = :milestone_observer,
23 23 :project_activity_cache_observer,
24 24 :issue_observer,
25 25 :key_observer,
... ...
spec/observers/activity_observer_spec.rb
... ... @@ -1,61 +0,0 @@
1   -require 'spec_helper'
2   -
3   -describe ActivityObserver do
4   - let(:project) { create(:project) }
5   -
6   - before { Thread.current[:current_user] = create(:user) }
7   -
8   - def self.it_should_be_valid_event
9   - it { @event.should_not be_nil }
10   - it { @event.project.should == project }
11   - end
12   -
13   - describe "Issue created" do
14   - before do
15   - Issue.observers.enable :activity_observer do
16   - @issue = create(:issue, project: project)
17   - @event = Event.last
18   - end
19   - end
20   -
21   - it_should_be_valid_event
22   - it { @event.action.should == Event::CREATED }
23   - it { @event.target.should == @issue }
24   - end
25   -
26   - describe "Issue commented" do
27   - before do
28   - Note.observers.enable :activity_observer do
29   - @issue = create(:issue, project: project)
30   - @note = create(:note, noteable: @issue, project: project, author: @issue.author)
31   - @event = Event.last
32   - end
33   - end
34   -
35   - it_should_be_valid_event
36   - it { @event.action.should == Event::COMMENTED }
37   - it { @event.target.should == @note }
38   - end
39   -
40   - describe "Ignore system notes" do
41   - let(:author) { create(:user) }
42   - let!(:issue) { create(:issue, project: project) }
43   - let!(:other) { create(:issue) }
44   -
45   - it "should not create events for status change notes" do
46   - expect do
47   - Note.observers.enable :activity_observer do
48   - Note.create_status_change_note(issue, project, author, 'reopened', nil)
49   - end
50   - end.to_not change { Event.count }
51   - end
52   -
53   - it "should not create events for cross-reference notes" do
54   - expect do
55   - Note.observers.enable :activity_observer do
56   - Note.create_cross_reference_note(issue, other, author, issue.project)
57   - end
58   - end.to_not change { Event.count }
59   - end
60   - end
61   -end
spec/requests/api/issues_spec.rb
... ... @@ -100,16 +100,4 @@ describe API::API do
100 100 response.status.should == 405
101 101 end
102 102 end
103   -
104   - describe "PUT /projects/:id/issues/:issue_id to test observer on close" do
105   - before { enable_observers }
106   - after { disable_observers }
107   -
108   - it "should create an activity event when an issue is closed" do
109   - Event.should_receive(:create)
110   -
111   - put api("/projects/#{project.id}/issues/#{issue.id}", user),
112   - state_event: "close"
113   - end
114   - end
115 103 end
... ...
spec/services/event_create_service_spec.rb 0 → 100644
... ... @@ -0,0 +1,103 @@
  1 +require 'spec_helper'
  2 +
  3 +describe EventCreateService do
  4 + let(:service) { EventCreateService.new }
  5 +
  6 + describe 'Issues' do
  7 + describe :open_issue do
  8 + let(:issue) { create(:issue) }
  9 +
  10 + it { service.open_issue(issue, issue.author).should be_true }
  11 +
  12 + it "should create new event" do
  13 + expect { service.open_issue(issue, issue.author) }.to change { Event.count }
  14 + end
  15 + end
  16 +
  17 + describe :close_issue do
  18 + let(:issue) { create(:issue) }
  19 +
  20 + it { service.close_issue(issue, issue.author).should be_true }
  21 +
  22 + it "should create new event" do
  23 + expect { service.close_issue(issue, issue.author) }.to change { Event.count }
  24 + end
  25 + end
  26 +
  27 + describe :reopen_issue do
  28 + let(:issue) { create(:issue) }
  29 +
  30 + it { service.reopen_issue(issue, issue.author).should be_true }
  31 +
  32 + it "should create new event" do
  33 + expect { service.reopen_issue(issue, issue.author) }.to change { Event.count }
  34 + end
  35 + end
  36 + end
  37 +
  38 + describe 'Merge Requests' do
  39 + describe :open_mr do
  40 + let(:merge_request) { create(:merge_request) }
  41 +
  42 + it { service.open_mr(merge_request, merge_request.author).should be_true }
  43 +
  44 + it "should create new event" do
  45 + expect { service.open_mr(merge_request, merge_request.author) }.to change { Event.count }
  46 + end
  47 + end
  48 +
  49 + describe :close_mr do
  50 + let(:merge_request) { create(:merge_request) }
  51 +
  52 + it { service.close_mr(merge_request, merge_request.author).should be_true }
  53 +
  54 + it "should create new event" do
  55 + expect { service.close_mr(merge_request, merge_request.author) }.to change { Event.count }
  56 + end
  57 + end
  58 +
  59 + describe :merge_mr do
  60 + let(:merge_request) { create(:merge_request) }
  61 +
  62 + it { service.merge_mr(merge_request, merge_request.author).should be_true }
  63 +
  64 + it "should create new event" do
  65 + expect { service.merge_mr(merge_request, merge_request.author) }.to change { Event.count }
  66 + end
  67 + end
  68 +
  69 + describe :reopen_mr do
  70 + let(:merge_request) { create(:merge_request) }
  71 +
  72 + it { service.reopen_mr(merge_request, merge_request.author).should be_true }
  73 +
  74 + it "should create new event" do
  75 + expect { service.reopen_mr(merge_request, merge_request.author) }.to change { Event.count }
  76 + end
  77 + end
  78 + end
  79 +
  80 + describe 'Milestone' do
  81 + let(:user) { create :user }
  82 +
  83 + describe :open_milestone do
  84 + let(:milestone) { create(:milestone) }
  85 +
  86 + it { service.open_milestone(milestone, user).should be_true }
  87 +
  88 + it "should create new event" do
  89 + expect { service.open_milestone(milestone, user) }.to change { Event.count }
  90 + end
  91 + end
  92 +
  93 + describe :close_mr do
  94 + let(:milestone) { create(:milestone) }
  95 +
  96 + it { service.close_milestone(milestone, user).should be_true }
  97 +
  98 + it "should create new event" do
  99 + expect { service.close_milestone(milestone, user) }.to change { Event.count }
  100 + end
  101 + end
  102 + end
  103 +end
... ...
spec/support/test_env.rb
... ... @@ -90,7 +90,7 @@ module TestEnv
90 90 size: 12.45
91 91 )
92 92  
93   - ActivityObserver.any_instance.stub(
  93 + BaseObserver.any_instance.stub(
94 94 current_user: double("current_user", id: 1)
95 95 )
96 96 end
... ...