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 @@
module AlertManagement
module Alerts
class UpdateService
class UpdateService < ::BaseProjectService
include Gitlab::Utils::StrongMemoize
# @param alert [AlertManagement::Alert]
......@@ -10,10 +10,10 @@ module AlertManagement
# @param params [Hash] Attributes of the alert
def initialize(alert, current_user, params)
@alert = alert
@current_user = current_user
@params = params
@param_errors = []
@status = params.delete(:status)
super(project: alert.project, current_user: current_user, params: params)
end
def execute
......@@ -36,7 +36,7 @@ module AlertManagement
private
attr_reader :alert, :current_user, :params, :param_errors, :status
attr_reader :alert, :param_errors, :status
def allowed?
current_user&.can?(:update_alert_management_alert, alert)
......@@ -109,7 +109,7 @@ module AlertManagement
end
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
# ------ Status-related behavior -------
......@@ -129,6 +129,7 @@ module AlertManagement
def handle_status_change
add_status_change_system_note
resolve_todos if alert.resolved?
sync_to_incident if should_sync_to_incident?
end
def add_status_change_system_note
......@@ -139,6 +140,22 @@ module AlertManagement
todo_service.resolve_todos_for_target(alert, current_user)
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
# Only need to check if changing to an open status
return unless params[:status_event] && AlertManagement::Alert.open_status?(status)
......@@ -154,7 +171,7 @@ module AlertManagement
def open_alerts
strong_memoize(:open_alerts) do
AlertManagement::Alert.for_fingerprint(alert.project, alert.fingerprint).open
AlertManagement::Alert.for_fingerprint(project, alert.fingerprint).open
end
end
......@@ -166,7 +183,7 @@ module AlertManagement
def open_alert_url_params
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 },
......
......@@ -27,7 +27,7 @@ module IncidentManagement
def sync_to_alert
return unless alert
return unless escalation_status.status_previously_changed?
return if alert.status == escalation_status.status
::AlertManagement::Alerts::UpdateService.new(
alert,
......
......@@ -235,6 +235,59 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
it_behaves_like 'adds a system note'
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
......@@ -31,14 +31,12 @@ RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateServic
end
context 'with status attributes' do
it 'updates an the associated alert with status changes' do
expect(::AlertManagement::Alerts::UpdateService)
.to receive(:new)
.with(alert, current_user, { status: :acknowledged })
.and_call_original
it 'updates the alert with the new alert status' do
expect(::AlertManagement::Alerts::UpdateService).to receive(:new).once.and_call_original
expect(described_class).to receive(:new).once.and_call_original
expect(result).to be_success
expect(alert.reload.status).to eq(escalation_status.reload.status)
expect { result }.to change { escalation_status.reload.acknowledged? }.to(true)
.and change { alert.reload.acknowledged? }.to(true)
end
context 'when incident is not associated with an alert' do
......@@ -49,7 +47,7 @@ RSpec.describe IncidentManagement::IssuableEscalationStatuses::AfterUpdateServic
it_behaves_like 'does not attempt to update the alert'
end
context 'when status was not changed' do
context 'when new status matches the current status' do
let(:status_event) { :trigger }
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