Commit bc69be37 authored by Markus Koller's avatar Markus Koller

Merge branch 'enable-state-event-tracking-for-epics' into 'master'

Track state change events for Epics

See merge request gitlab-org/gitlab!42088
parents 7f06b7e4 cfe7ead9
......@@ -19,3 +19,5 @@ class ResourceStateEvent < ResourceEvent
issue || merge_request
end
end
ResourceStateEvent.prepend_if_ee('EE::ResourceStateEvent')
......@@ -13,14 +13,14 @@ module ResourceEvents
ResourceStateEvent.create(
user: user,
issue: issue,
merge_request: merge_request,
resource.class.underscore => resource,
source_commit: commit_id_of(mentionable_source),
source_merge_request_id: merge_request_id_of(mentionable_source),
state: ResourceStateEvent.states[state],
close_after_error_tracking_resolve: close_after_error_tracking_resolve,
close_auto_resolve_prometheus_alert: close_auto_resolve_prometheus_alert,
created_at: Time.zone.now)
created_at: Time.zone.now
)
resource.expire_note_etag_cache
end
......@@ -56,17 +56,5 @@ module ResourceEvents
mentionable_source.id
end
def issue
return unless resource.is_a?(Issue)
resource
end
def merge_request
return unless resource.is_a?(MergeRequest)
resource
end
end
end
......@@ -12,6 +12,7 @@ module EE
include Referable
include Awardable
include LabelEventable
include StateEventable
include UsageStatistics
include FromUnion
include EpicTreeSorting
......
# frozen_string_literal: true
module EE
module ResourceStateEvent
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
prepended do
belongs_to :epic
end
class_methods do
def issuable_attrs
%i(epic).freeze + super
end
end
override :issuable
def issuable
epic || super
end
end
end
---
title: Track state changes using resource state events for Epics
merge_request: 42088
author:
type: fixed
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ResourceStateEvent do
subject { build(:resource_state_event) }
it { is_expected.to belong_to(:epic) }
describe 'validations' do
describe 'Issuable validation' do
it 'is valid if only epic is set' do
subject.attributes = { epic: build_stubbed(:epic), issue: nil, merge_request: nil }
expect(subject).to be_valid
end
it 'is invalid if an epic and an issue is set' do
subject.attributes = { epic: build_stubbed(:epic), issue: build_stubbed(:issue), merge_request: nil }
expect(subject).not_to be_valid
end
end
end
end
......@@ -2,9 +2,9 @@
require 'spec_helper'
RSpec.describe Epics::CloseService do
let(:group) { create(:group, :internal) }
let(:user) { create(:user) }
let(:epic) { create(:epic, group: group) }
let_it_be(:group) { create(:group, :internal) }
let_it_be(:user) { create(:user) }
let_it_be(:epic, reload: true) { create(:epic, group: group) }
describe '#execute' do
subject { described_class.new(group, user) }
......@@ -25,7 +25,7 @@ RSpec.describe Epics::CloseService do
end
context 'when a user has permissions to update the epic' do
before do
before_all do
group.add_maintainer(user)
end
......@@ -42,6 +42,25 @@ RSpec.describe Epics::CloseService do
expect { subject.execute(epic) }.to change { epic.closed_at }
end
context 'when state event tracking is enabled' do
before do
stub_feature_flags(track_resource_state_change_events: true)
end
it 'creates a resource state event' do
expect { subject.execute(epic) }.to change { epic.resource_state_events.count }.by(1)
event = epic.resource_state_events.last
expect(event.state).to eq('closed')
end
end
context 'when state event tracking is disabled' do
before do
stub_feature_flags(track_resource_state_change_events: false)
end
it 'creates a system note about epic close' do
expect { subject.execute(epic) }.to change { epic.notes.count }.by(1)
......@@ -50,6 +69,7 @@ RSpec.describe Epics::CloseService do
expect(note.note).to eq('closed')
expect(note.system_note_metadata.action).to eq('closed')
end
end
it 'notifies the subscribers' do
notification_service = double
......@@ -82,8 +102,8 @@ RSpec.describe Epics::CloseService do
expect { subject.execute(epic) }.not_to change { epic.closed_by }
end
it 'does not create a system note' do
expect { subject.execute(epic) }.not_to change { epic.notes.count }
it 'does not create a resource state event' do
expect { subject.execute(epic) }.not_to change { epic.resource_state_events.count }
end
it 'does not send any emails' do
......
......@@ -2,9 +2,9 @@
require 'spec_helper'
RSpec.describe Epics::ReopenService do
let(:group) { create(:group, :internal) }
let(:user) { create(:user) }
let(:epic) { create(:epic, group: group, state: :closed, closed_at: Date.today, closed_by: user) }
let_it_be(:group) { create(:group, :internal) }
let_it_be(:user) { create(:user) }
let_it_be(:epic, reload: true) { create(:epic, group: group, state: :closed, closed_at: Date.today, closed_by: user) }
describe '#execute' do
subject { described_class.new(group, user) }
......@@ -25,7 +25,7 @@ RSpec.describe Epics::ReopenService do
end
context 'when a user has permissions to update the epic' do
before do
before_all do
group.add_maintainer(user)
end
......@@ -42,6 +42,25 @@ RSpec.describe Epics::ReopenService do
expect { subject.execute(epic) }.to change { epic.closed_at }.to(nil)
end
context 'when state event tracking is enabled' do
before do
stub_feature_flags(track_resource_state_change_events: true)
end
it 'creates a resource state event' do
expect { subject.execute(epic) }.to change { epic.resource_state_events.count }.by(1)
event = epic.resource_state_events.last
expect(event.state).to eq('opened')
end
end
context 'when state event tracking is disabled' do
before do
stub_feature_flags(track_resource_state_change_events: false)
end
it 'creates a system note about epic reopen' do
expect { subject.execute(epic) }.to change { epic.notes.count }.by(1)
......@@ -50,6 +69,7 @@ RSpec.describe Epics::ReopenService do
expect(note.note).to eq('opened')
expect(note.system_note_metadata.action).to eq('opened')
end
end
it 'notifies the subscribers' do
notification_service = double
......@@ -82,8 +102,8 @@ RSpec.describe Epics::ReopenService do
expect { subject.execute(epic) }.not_to change { epic.closed_by }
end
it 'does not create a system note' do
expect { subject.execute(epic) }.not_to change { epic.notes.count }
it 'does not create a resource state event' do
expect { subject.execute(epic) }.not_to change { epic.resource_state_events.count }
end
it 'does not send any emails' do
......
......@@ -691,6 +691,7 @@ epic:
- due_date_sourcing_epic
- events
- resource_label_events
- resource_state_events
- user_mentions
- note_authors
- boards_epic_user_preferences
......
......@@ -11,4 +11,32 @@ RSpec.describe ResourceStateEvent, type: :model do
it_behaves_like 'a resource event'
it_behaves_like 'a resource event for issues'
it_behaves_like 'a resource event for merge requests'
describe 'validations' do
describe 'Issuable validation' do
it 'is valid if an issue is set' do
subject.attributes = { issue: build_stubbed(:issue), merge_request: nil }
expect(subject).to be_valid
end
it 'is valid if a merge request is set' do
subject.attributes = { issue: nil, merge_request: build_stubbed(:merge_request) }
expect(subject).to be_valid
end
it 'is invalid if both issue and merge request are set' do
subject.attributes = { issue: build_stubbed(:issue), merge_request: build_stubbed(:merge_request) }
expect(subject).not_to be_valid
end
it 'is invalid if there is no issuable set' do
subject.attributes = { issue: nil, merge_request: nil }
expect(subject).not_to be_valid
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