Commit 3d64c5b7 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'sy-abbreviate-escalation-rule-limit' into 'master'

Shorten error messages for escalation rule count and fix edge case

See merge request gitlab-org/gitlab!65623
parents 8ed107a5 0e9561ff
...@@ -4,8 +4,6 @@ module IncidentManagement ...@@ -4,8 +4,6 @@ module IncidentManagement
class EscalationRule < ApplicationRecord class EscalationRule < ApplicationRecord
self.table_name = 'incident_management_escalation_rules' self.table_name = 'incident_management_escalation_rules'
MAX_RULE_PER_POLICY_COUNT = 10
belongs_to :policy, class_name: 'EscalationPolicy', inverse_of: 'rules', foreign_key: 'policy_id' belongs_to :policy, class_name: 'EscalationPolicy', inverse_of: 'rules', foreign_key: 'policy_id'
belongs_to :oncall_schedule, class_name: 'OncallSchedule', inverse_of: 'rotations', foreign_key: 'oncall_schedule_id' belongs_to :oncall_schedule, class_name: 'OncallSchedule', inverse_of: 'rotations', foreign_key: 'oncall_schedule_id'
...@@ -18,16 +16,5 @@ module IncidentManagement ...@@ -18,16 +16,5 @@ module IncidentManagement
numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 24.hours } numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 24.hours }
validates :policy_id, uniqueness: { scope: [:oncall_schedule_id, :status, :elapsed_time_seconds], message: _('must have a unique schedule, status, and elapsed time') } validates :policy_id, uniqueness: { scope: [:oncall_schedule_id, :status, :elapsed_time_seconds], message: _('must have a unique schedule, status, and elapsed time') }
validate :rules_count_not_exceeded, on: :create, if: :policy
private
def rules_count_not_exceeded
# We need to add to the count if we aren't creating the rules at the same time as the policy.
rules_count = policy.new_record? ? policy.rules.size : policy.rules.size + 1
errors.add(:base, "cannot have more than #{MAX_RULE_PER_POLICY_COUNT} rules") if rules_count > MAX_RULE_PER_POLICY_COUNT
end
end end
end end
...@@ -3,10 +3,16 @@ ...@@ -3,10 +3,16 @@
module IncidentManagement module IncidentManagement
module EscalationPolicies module EscalationPolicies
class BaseService class BaseService
MAX_RULE_COUNT = 10
def allowed? def allowed?
user&.can?(:admin_incident_management_escalation_policy, project) user&.can?(:admin_incident_management_escalation_policy, project)
end end
def too_many_rules?
params[:rules_attributes] && params[:rules_attributes].size > MAX_RULE_COUNT
end
def invalid_schedules? def invalid_schedules?
params[:rules_attributes]&.any? { |attrs| attrs[:oncall_schedule]&.project != project } params[:rules_attributes]&.any? { |attrs| attrs[:oncall_schedule]&.project != project }
end end
...@@ -27,6 +33,10 @@ module IncidentManagement ...@@ -27,6 +33,10 @@ module IncidentManagement
error(_('Escalation policies must have at least one rule')) error(_('Escalation policies must have at least one rule'))
end end
def error_too_many_rules
error(_('Escalation policies may not have more than %{rule_count} rules') % { rule_count: MAX_RULE_COUNT })
end
def error_bad_schedules def error_bad_schedules
error(_('All escalations rules must have a schedule in the same project as the policy')) error(_('All escalations rules must have a schedule in the same project as the policy'))
end end
......
...@@ -21,6 +21,7 @@ module IncidentManagement ...@@ -21,6 +21,7 @@ module IncidentManagement
def execute def execute
return error_no_permissions unless allowed? return error_no_permissions unless allowed?
return error_no_rules if params[:rules_attributes].blank? return error_no_rules if params[:rules_attributes].blank?
return error_too_many_rules if too_many_rules?
return error_bad_schedules if invalid_schedules? return error_bad_schedules if invalid_schedules?
escalation_policy = project.incident_management_escalation_policies.create(params) escalation_policy = project.incident_management_escalation_policies.create(params)
......
...@@ -26,6 +26,7 @@ module IncidentManagement ...@@ -26,6 +26,7 @@ module IncidentManagement
def execute def execute
return error_no_permissions unless allowed? return error_no_permissions unless allowed?
return error_no_rules if empty_rules? return error_no_rules if empty_rules?
return error_too_many_rules if too_many_rules?
return error_bad_schedules if invalid_schedules? return error_bad_schedules if invalid_schedules?
reconcile_rules! reconcile_rules!
......
...@@ -20,13 +20,5 @@ RSpec.describe IncidentManagement::EscalationRule do ...@@ -20,13 +20,5 @@ RSpec.describe IncidentManagement::EscalationRule do
it { is_expected.to validate_presence_of(:elapsed_time_seconds) } it { is_expected.to validate_presence_of(:elapsed_time_seconds) }
it { is_expected.to validate_numericality_of(:elapsed_time_seconds).is_greater_than_or_equal_to(0).is_less_than_or_equal_to(24.hours) } it { is_expected.to validate_numericality_of(:elapsed_time_seconds).is_greater_than_or_equal_to(0).is_less_than_or_equal_to(24.hours) }
it { is_expected.to validate_uniqueness_of(:policy_id).scoped_to([:oncall_schedule_id, :status, :elapsed_time_seconds] ).with_message('must have a unique schedule, status, and elapsed time') } it { is_expected.to validate_uniqueness_of(:policy_id).scoped_to([:oncall_schedule_id, :status, :elapsed_time_seconds] ).with_message('must have a unique schedule, status, and elapsed time') }
it 'validates the number of rules' do
policy = create(:incident_management_escalation_policy, rule_count: 10)
rule = build(:incident_management_escalation_rule, policy: policy)
expect(rule).not_to be_valid
expect(rule.errors).to contain_exactly("cannot have more than #{described_class::MAX_RULE_PER_POLICY_COUNT} rules")
end
end end
end end
...@@ -71,6 +71,20 @@ RSpec.describe IncidentManagement::EscalationPolicies::CreateService do ...@@ -71,6 +71,20 @@ RSpec.describe IncidentManagement::EscalationPolicies::CreateService do
it_behaves_like 'error response', 'Escalation policies must have at least one rule' it_behaves_like 'error response', 'Escalation policies must have at least one rule'
end end
context 'too many rules are given' do
let(:rule_params) do
(0..10).map do |idx|
{
oncall_schedule: oncall_schedule,
elapsed_time_seconds: idx,
status: :acknowledged
}
end
end
it_behaves_like 'error response', 'Escalation policies may not have more than 10 rules'
end
context 'oncall schedule is blank' do context 'oncall schedule is blank' do
before do before do
rule_params[0][:oncall_schedule] = nil rule_params[0][:oncall_schedule] = nil
......
...@@ -148,6 +148,21 @@ RSpec.describe IncidentManagement::EscalationPolicies::UpdateService do ...@@ -148,6 +148,21 @@ RSpec.describe IncidentManagement::EscalationPolicies::UpdateService do
it_behaves_like 'error response', 'Escalation policies must have at least one rule' it_behaves_like 'error response', 'Escalation policies must have at least one rule'
end end
context 'when too many rules are given' do
let(:rule_params) { [*existing_rules_params, *new_rule_params] }
let(:new_rule_params) do
(0..9).map do |idx|
{
oncall_schedule: oncall_schedule,
elapsed_time_seconds: idx,
status: :acknowledged
}
end
end
it_behaves_like 'error response', 'Escalation policies may not have more than 10 rules'
end
context 'when the on-call schedule is not present on the rule' do context 'when the on-call schedule is not present on the rule' do
let(:rule_params) { [new_rule_params.except(:oncall_schedule)] } let(:rule_params) { [new_rule_params.except(:oncall_schedule)] }
......
...@@ -12990,6 +12990,9 @@ msgstr "" ...@@ -12990,6 +12990,9 @@ msgstr ""
msgid "Escalation policies" msgid "Escalation policies"
msgstr "" msgstr ""
msgid "Escalation policies may not have more than %{rule_count} rules"
msgstr ""
msgid "Escalation policies must have at least one rule" msgid "Escalation policies must have at least one rule"
msgstr "" msgstr ""
......
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