Commit 55b747ee authored by Jan Provaznik's avatar Jan Provaznik Committed by Thong Kuah

Create an event on epic actions

Creates new event when an epic is created, closed, reopened or
commented.
parent 6898a225
...@@ -19,6 +19,7 @@ class Board < ApplicationRecord ...@@ -19,6 +19,7 @@ class Board < ApplicationRecord
def parent def parent
@parent ||= group || project @parent ||= group || project
end end
alias_method :resource_parent, :parent
def group_board? def group_board?
group_id.present? group_id.present?
......
...@@ -277,6 +277,10 @@ module Issuable ...@@ -277,6 +277,10 @@ module Issuable
end end
end end
def resource_parent
project
end
def milestone_available? def milestone_available?
project_id == milestone&.project_id || project.ancestors_upto.compact.include?(milestone&.group) project_id == milestone&.project_id || project.ancestors_upto.compact.include?(milestone&.group)
end end
......
...@@ -51,6 +51,7 @@ class Event < ApplicationRecord ...@@ -51,6 +51,7 @@ class Event < ApplicationRecord
belongs_to :author, class_name: "User" belongs_to :author, class_name: "User"
belongs_to :project belongs_to :project
belongs_to :group
belongs_to :target, -> { belongs_to :target, -> {
# If the association for "target" defines an "author" association we want to # If the association for "target" defines an "author" association we want to
......
...@@ -262,6 +262,7 @@ class Milestone < ApplicationRecord ...@@ -262,6 +262,7 @@ class Milestone < ApplicationRecord
def parent def parent
group || project group || project
end end
alias_method :resource_parent, :parent
def group_milestone? def group_milestone?
group_id.present? group_id.present?
......
...@@ -477,6 +477,7 @@ class Note < ApplicationRecord ...@@ -477,6 +477,7 @@ class Note < ApplicationRecord
def parent def parent
project project
end end
alias_method :resource_parent, :parent
private private
......
...@@ -146,6 +146,7 @@ class Todo < ApplicationRecord ...@@ -146,6 +146,7 @@ class Todo < ApplicationRecord
def parent def parent
project project
end end
alias_method :resource_parent, :parent
def unmergeable? def unmergeable?
action == UNMERGEABLE action == UNMERGEABLE
......
...@@ -95,16 +95,25 @@ class EventCreateService ...@@ -95,16 +95,25 @@ class EventCreateService
private private
def create_record_event(record, current_user, status) def create_record_event(record, current_user, status)
create_event(record.project, current_user, status, target_id: record.id, target_type: record.class.name) create_event(record.resource_parent, current_user, status, target_id: record.id, target_type: record.class.name)
end end
def create_event(project, current_user, status, attributes = {}) def create_event(resource_parent, current_user, status, attributes = {})
attributes.reverse_merge!( attributes.reverse_merge!(
project: project,
action: status, action: status,
author_id: current_user.id author_id: current_user.id
) )
resource_parent_attr = case resource_parent
when Project
:project
when Group
:group
end
attributes[resource_parent_attr] = resource_parent if resource_parent_attr
Event.create!(attributes) Event.create!(attributes)
end end
end end
EventCreateService.prepend_if_ee('EE::EventCreateService')
# frozen_string_literal: true
class AddGroupColumnToEvents < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
add_reference :events, :group, index: true, foreign_key: { to_table: :namespaces, on_delete: :cascade }
end
end
...@@ -1310,9 +1310,11 @@ ActiveRecord::Schema.define(version: 2019_09_02_160015) do ...@@ -1310,9 +1310,11 @@ ActiveRecord::Schema.define(version: 2019_09_02_160015) do
t.datetime_with_timezone "updated_at", null: false t.datetime_with_timezone "updated_at", null: false
t.integer "action", limit: 2, null: false t.integer "action", limit: 2, null: false
t.string "target_type" t.string "target_type"
t.bigint "group_id"
t.index ["action"], name: "index_events_on_action" t.index ["action"], name: "index_events_on_action"
t.index ["author_id", "project_id"], name: "index_events_on_author_id_and_project_id" t.index ["author_id", "project_id"], name: "index_events_on_author_id_and_project_id"
t.index ["created_at", "author_id"], name: "analytics_index_events_on_created_at_and_author_id" t.index ["created_at", "author_id"], name: "analytics_index_events_on_created_at_and_author_id"
t.index ["group_id"], name: "index_events_on_group_id"
t.index ["project_id", "created_at"], name: "index_events_on_project_id_and_created_at" t.index ["project_id", "created_at"], name: "index_events_on_project_id_and_created_at"
t.index ["project_id", "id"], name: "index_events_on_project_id_and_id" t.index ["project_id", "id"], name: "index_events_on_project_id_and_id"
t.index ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id" t.index ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id"
...@@ -3838,6 +3840,7 @@ ActiveRecord::Schema.define(version: 2019_09_02_160015) do ...@@ -3838,6 +3840,7 @@ ActiveRecord::Schema.define(version: 2019_09_02_160015) do
add_foreign_key "epics", "users", column: "assignee_id", name: "fk_dccd3f98fc", on_delete: :nullify add_foreign_key "epics", "users", column: "assignee_id", name: "fk_dccd3f98fc", on_delete: :nullify
add_foreign_key "epics", "users", column: "author_id", name: "fk_3654b61b03", on_delete: :cascade add_foreign_key "epics", "users", column: "author_id", name: "fk_3654b61b03", on_delete: :cascade
add_foreign_key "epics", "users", column: "closed_by_id", name: "fk_aa5798e761", on_delete: :nullify add_foreign_key "epics", "users", column: "closed_by_id", name: "fk_aa5798e761", on_delete: :nullify
add_foreign_key "events", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "events", "projects", on_delete: :cascade add_foreign_key "events", "projects", on_delete: :cascade
add_foreign_key "events", "users", column: "author_id", name: "fk_edfd187b6f", on_delete: :cascade add_foreign_key "events", "users", column: "author_id", name: "fk_edfd187b6f", on_delete: :cascade
add_foreign_key "fork_network_members", "fork_networks", on_delete: :cascade add_foreign_key "fork_network_members", "fork_networks", on_delete: :cascade
......
...@@ -37,6 +37,7 @@ module EE ...@@ -37,6 +37,7 @@ module EE
belongs_to :due_date_sourcing_milestone, class_name: 'Milestone' belongs_to :due_date_sourcing_milestone, class_name: 'Milestone'
belongs_to :parent, class_name: "Epic" belongs_to :parent, class_name: "Epic"
has_many :children, class_name: "Epic", foreign_key: :parent_id has_many :children, class_name: "Epic", foreign_key: :parent_id
has_many :events, as: :target, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.epics&.maximum(:iid) } has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.epics&.maximum(:iid) }
...@@ -208,6 +209,10 @@ module EE ...@@ -208,6 +209,10 @@ module EE
end end
end end
def resource_parent
group
end
def assignees def assignees
Array(assignee) Array(assignee)
end end
......
...@@ -58,6 +58,7 @@ module EE ...@@ -58,6 +58,7 @@ module EE
def parent def parent
for_epic? ? noteable.group : super for_epic? ? noteable.group : super
end end
alias_method :resource_parent, :parent
def notify_after_create def notify_after_create
noteable&.after_note_created(self) noteable&.after_note_created(self)
......
...@@ -8,6 +8,7 @@ module EE ...@@ -8,6 +8,7 @@ module EE
def parent def parent
project || group project || group
end end
alias_method :resource_parent, :parent
def for_design? def for_design?
target_type == DesignManagement::Design.name target_type == DesignManagement::Design.name
......
# frozen_string_literal: true
module EE
module EventCreateService
def open_epic(epic, current_user)
create_record_event(epic, current_user, ::Event::CREATED)
end
def close_epic(epic, current_user)
create_record_event(epic, current_user, ::Event::CLOSED)
end
def reopen_epic(epic, current_user)
create_record_event(epic, current_user, ::Event::REOPENED)
end
end
end
...@@ -13,6 +13,7 @@ module Epics ...@@ -13,6 +13,7 @@ module Epics
def close_epic(epic) def close_epic(epic)
if epic.close if epic.close
epic.update(closed_by: current_user) epic.update(closed_by: current_user)
event_service.close_epic(epic, current_user)
SystemNoteService.change_status(epic, nil, current_user, epic.state) SystemNoteService.change_status(epic, nil, current_user, epic.state)
notification_service.close_epic(epic, current_user) notification_service.close_epic(epic, current_user)
end end
......
...@@ -12,6 +12,7 @@ module Epics ...@@ -12,6 +12,7 @@ module Epics
def reopen_epic(epic) def reopen_epic(epic)
if epic.reopen if epic.reopen
event_service.reopen_epic(epic, current_user)
SystemNoteService.change_status(epic, nil, current_user, epic.state) SystemNoteService.change_status(epic, nil, current_user, epic.state)
notification_service.reopen_epic(epic, current_user) notification_service.reopen_epic(epic, current_user)
end end
......
...@@ -7,6 +7,7 @@ class NewEpicWorker ...@@ -7,6 +7,7 @@ class NewEpicWorker
def perform(epic_id, user_id) def perform(epic_id, user_id)
return unless objects_found?(epic_id, user_id) return unless objects_found?(epic_id, user_id)
EventCreateService.new.open_epic(issuable, user)
NotificationService.new.new_epic(issuable) NotificationService.new.new_epic(issuable)
issuable.create_cross_references!(user) issuable.create_cross_references!(user)
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe EventCreateService do
let(:service) { described_class.new }
describe 'Epics' do
let(:epic) { create(:epic) }
describe '#open_epic' do
it "creates new event" do
event = service.open_epic(epic, epic.author)
expect_event(event, Event::CREATED)
end
end
describe '#close_epic' do
it "creates new event" do
event = service.close_epic(epic, epic.author)
expect_event(event, Event::CLOSED)
end
end
describe '#reopen_epic' do
it "creates new event" do
event = service.reopen_epic(epic, epic.author)
expect_event(event, Event::REOPENED)
end
end
describe '#leave_note' do
it "creates new event" do
note = create(:note, noteable: epic)
event = service.leave_note(note, epic.author)
expect_event(event, Event::COMMENTED)
end
end
def expect_event(event, action)
expect(event).to be_persisted
expect(event.action).to eq action
expect(event.project_id).to be_nil
expect(event.group_id).to eq epic.group_id
end
end
end
...@@ -59,6 +59,10 @@ describe Epics::CloseService do ...@@ -59,6 +59,10 @@ describe Epics::CloseService do
subject.execute(epic) subject.execute(epic)
end end
it "creates new event" do
expect { subject.execute(epic) }.to change { Event.count }
end
end end
context 'when trying to close a closed epic' do context 'when trying to close a closed epic' do
...@@ -87,6 +91,10 @@ describe Epics::CloseService do ...@@ -87,6 +91,10 @@ describe Epics::CloseService do
subject.execute(epic) subject.execute(epic)
end end
it "does not create an event" do
expect { subject.execute(epic) }.not_to change { Event.count }
end
end end
end end
......
...@@ -59,6 +59,10 @@ describe Epics::ReopenService do ...@@ -59,6 +59,10 @@ describe Epics::ReopenService do
subject.execute(epic) subject.execute(epic)
end end
it "creates new event" do
expect { subject.execute(epic) }.to change { Event.count }
end
end end
context 'when trying to reopen an opened epic' do context 'when trying to reopen an opened epic' do
...@@ -87,6 +91,10 @@ describe Epics::ReopenService do ...@@ -87,6 +91,10 @@ describe Epics::ReopenService do
subject.execute(epic) subject.execute(epic)
end end
it "does not create an event" do
expect { subject.execute(epic) }.not_to change { Event.count }
end
end end
end end
......
...@@ -42,6 +42,10 @@ describe NewEpicWorker do ...@@ -42,6 +42,10 @@ describe NewEpicWorker do
stub_licensed_features(epics: true) stub_licensed_features(epics: true)
end end
it 'creates an event' do
expect { worker.perform(epic.id, user.id) }.to change { Event.count }.from(0).to(1)
end
context 'user watches group' do context 'user watches group' do
before do before do
create( create(
......
...@@ -26,6 +26,7 @@ issues: ...@@ -26,6 +26,7 @@ issues:
events: events:
- author - author
- project - project
- group
- target - target
- push_event_payload - push_event_payload
notes: notes:
......
...@@ -33,6 +33,7 @@ Event: ...@@ -33,6 +33,7 @@ Event:
- target_type - target_type
- target_id - target_id
- project_id - project_id
- group_id
- created_at - created_at
- updated_at - updated_at
- action - action
......
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