Commit 496da625 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch 'sy-update-incident-status-on-alert-changes' into 'master'

Sync alert status to incident status on alert status updates

See merge request gitlab-org/gitlab!77058
parents 093b46ee 7bc5c599
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module AlertManagement module AlertManagement
module Alerts module Alerts
class UpdateService class UpdateService < ::BaseProjectService
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
# @param alert [AlertManagement::Alert] # @param alert [AlertManagement::Alert]
...@@ -10,10 +10,10 @@ module AlertManagement ...@@ -10,10 +10,10 @@ module AlertManagement
# @param params [Hash] Attributes of the alert # @param params [Hash] Attributes of the alert
def initialize(alert, current_user, params) def initialize(alert, current_user, params)
@alert = alert @alert = alert
@current_user = current_user
@params = params
@param_errors = [] @param_errors = []
@status = params.delete(:status) @status = params.delete(:status)
super(project: alert.project, current_user: current_user, params: params)
end end
def execute def execute
...@@ -36,7 +36,7 @@ module AlertManagement ...@@ -36,7 +36,7 @@ module AlertManagement
private private
attr_reader :alert, :current_user, :params, :param_errors, :status attr_reader :alert, :param_errors, :status
def allowed? def allowed?
current_user&.can?(:update_alert_management_alert, alert) current_user&.can?(:update_alert_management_alert, alert)
...@@ -109,7 +109,7 @@ module AlertManagement ...@@ -109,7 +109,7 @@ module AlertManagement
end end
def add_assignee_system_note(old_assignees) def add_assignee_system_note(old_assignees)
SystemNoteService.change_issuable_assignees(alert, alert.project, current_user, old_assignees) SystemNoteService.change_issuable_assignees(alert, project, current_user, old_assignees)
end end
# ------ Status-related behavior ------- # ------ Status-related behavior -------
...@@ -129,6 +129,7 @@ module AlertManagement ...@@ -129,6 +129,7 @@ module AlertManagement
def handle_status_change def handle_status_change
add_status_change_system_note add_status_change_system_note
resolve_todos if alert.resolved? resolve_todos if alert.resolved?
sync_to_incident if should_sync_to_incident?
end end
def add_status_change_system_note def add_status_change_system_note
...@@ -139,6 +140,22 @@ module AlertManagement ...@@ -139,6 +140,22 @@ module AlertManagement
todo_service.resolve_todos_for_target(alert, current_user) todo_service.resolve_todos_for_target(alert, current_user)
end end
def sync_to_incident
::Issues::UpdateService.new(
project: project,
current_user: current_user,
params: { escalation_status: { status: status } }
).execute(alert.issue)
end
def should_sync_to_incident?
Feature.enabled?(:incident_escalations, project) &&
alert.issue &&
alert.issue.supports_escalation? &&
alert.issue.escalation_status &&
alert.issue.escalation_status.status != alert.status
end
def filter_duplicate def filter_duplicate
# Only need to check if changing to an open status # Only need to check if changing to an open status
return unless params[:status_event] && AlertManagement::Alert.open_status?(status) return unless params[:status_event] && AlertManagement::Alert.open_status?(status)
...@@ -154,7 +171,7 @@ module AlertManagement ...@@ -154,7 +171,7 @@ module AlertManagement
def open_alerts def open_alerts
strong_memoize(:open_alerts) do strong_memoize(:open_alerts) do
AlertManagement::Alert.for_fingerprint(alert.project, alert.fingerprint).open AlertManagement::Alert.for_fingerprint(project, alert.fingerprint).open
end end
end end
...@@ -166,7 +183,7 @@ module AlertManagement ...@@ -166,7 +183,7 @@ module AlertManagement
def open_alert_url_params def open_alert_url_params
open_alert = open_alerts.first open_alert = open_alerts.first
alert_path = Gitlab::Routing.url_helpers.details_project_alert_management_path(alert.project, open_alert) alert_path = Gitlab::Routing.url_helpers.details_project_alert_management_path(project, open_alert)
{ {
link_start: '<a href="%{url}">'.html_safe % { url: alert_path }, link_start: '<a href="%{url}">'.html_safe % { url: alert_path },
......
...@@ -27,7 +27,7 @@ module IncidentManagement ...@@ -27,7 +27,7 @@ module IncidentManagement
def sync_to_alert def sync_to_alert
return unless alert return unless alert
return unless escalation_status.status_previously_changed? return if alert.status == escalation_status.status
::AlertManagement::Alerts::UpdateService.new( ::AlertManagement::Alerts::UpdateService.new(
alert, alert,
......
...@@ -235,6 +235,59 @@ RSpec.describe AlertManagement::Alerts::UpdateService do ...@@ -235,6 +235,59 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
it_behaves_like 'adds a system note' it_behaves_like 'adds a system note'
end end
context 'with an associated issue' do
let_it_be(:issue, reload: true) { create(:issue, project: project) }
before do
alert.update!(issue: issue)
end
shared_examples 'does not sync with the incident status' do
specify do
expect(::Issues::UpdateService).not_to receive(:new)
expect { response }.to change { alert.acknowledged? }.to(true)
end
end
it_behaves_like 'does not sync with the incident status'
context 'when the issue is an incident' do
before do
issue.update!(issue_type: Issue.issue_types[:incident])
end
it_behaves_like 'does not sync with the incident status'
context 'when the incident has an escalation status' do
let_it_be(:escalation_status, reload: true) { create(:incident_management_issuable_escalation_status, issue: issue) }
it 'updates the incident escalation status with the new alert status' do
expect(::Issues::UpdateService).to receive(:new).once.and_call_original
expect(described_class).to receive(:new).once.and_call_original
expect { response }.to change { escalation_status.reload.acknowledged? }.to(true)
.and change { alert.reload.acknowledged? }.to(true)
end
context 'when the statuses match' do
before do
escalation_status.update!(status_event: :acknowledge)
end
it_behaves_like 'does not sync with the incident status'
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(incident_escalations: false)
end
it_behaves_like 'does not sync with the incident status'
end
end
end
end
end end
end end
end end
...@@ -31,14 +31,12 @@ RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateServic ...@@ -31,14 +31,12 @@ RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateServic
end end
context 'with status attributes' do context 'with status attributes' do
it 'updates an the associated alert with status changes' do it 'updates the alert with the new alert status' do
expect(::AlertManagement::Alerts::UpdateService) expect(::AlertManagement::Alerts::UpdateService).to receive(:new).once.and_call_original
.to receive(:new) expect(described_class).to receive(:new).once.and_call_original
.with(alert, current_user, { status: :acknowledged })
.and_call_original
expect(result).to be_success expect { result }.to change { escalation_status.reload.acknowledged? }.to(true)
expect(alert.reload.status).to eq(escalation_status.reload.status) .and change { alert.reload.acknowledged? }.to(true)
end end
context 'when incident is not associated with an alert' do context 'when incident is not associated with an alert' do
...@@ -49,7 +47,7 @@ RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateServic ...@@ -49,7 +47,7 @@ RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateServic
it_behaves_like 'does not attempt to update the alert' it_behaves_like 'does not attempt to update the alert'
end end
context 'when status was not changed' do context 'when new status matches the current status' do
let(:status_event) { :trigger } let(:status_event) { :trigger }
it_behaves_like 'does not attempt to update the alert' it_behaves_like 'does not attempt to update the alert'
......
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