Commit 579a0be4 authored by Sean McGivern's avatar Sean McGivern

Merge branch '268356-add-escalation-policy-graphql' into 'master'

GraphQL types for escalation policy and rules

See merge request gitlab-org/gitlab!61439
parents 1e9c4c5d 07889067
...@@ -5199,6 +5199,29 @@ The edge type for [`EpicList`](#epiclist). ...@@ -5199,6 +5199,29 @@ The edge type for [`EpicList`](#epiclist).
| <a id="epiclistedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. | | <a id="epiclistedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="epiclistedgenode"></a>`node` | [`EpicList`](#epiclist) | The item at the end of the edge. | | <a id="epiclistedgenode"></a>`node` | [`EpicList`](#epiclist) | The item at the end of the edge. |
#### `EscalationPolicyTypeConnection`
The connection type for [`EscalationPolicyType`](#escalationpolicytype).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="escalationpolicytypeconnectionedges"></a>`edges` | [`[EscalationPolicyTypeEdge]`](#escalationpolicytypeedge) | A list of edges. |
| <a id="escalationpolicytypeconnectionnodes"></a>`nodes` | [`[EscalationPolicyType]`](#escalationpolicytype) | A list of nodes. |
| <a id="escalationpolicytypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `EscalationPolicyTypeEdge`
The edge type for [`EscalationPolicyType`](#escalationpolicytype).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="escalationpolicytypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="escalationpolicytypeedgenode"></a>`node` | [`EscalationPolicyType`](#escalationpolicytype) | The item at the end of the edge. |
#### `EventConnection` #### `EventConnection`
The connection type for [`Event`](#event). The connection type for [`Event`](#event).
...@@ -8609,6 +8632,32 @@ Check permissions for the current user on an epic. ...@@ -8609,6 +8632,32 @@ Check permissions for the current user on an epic.
| <a id="epicpermissionsreadepiciid"></a>`readEpicIid` | [`Boolean!`](#boolean) | Indicates the user can perform `read_epic_iid` on this resource. | | <a id="epicpermissionsreadepiciid"></a>`readEpicIid` | [`Boolean!`](#boolean) | Indicates the user can perform `read_epic_iid` on this resource. |
| <a id="epicpermissionsupdateepic"></a>`updateEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `update_epic` on this resource. | | <a id="epicpermissionsupdateepic"></a>`updateEpic` | [`Boolean!`](#boolean) | Indicates the user can perform `update_epic` on this resource. |
### `EscalationPolicyType`
Represents an escalation policy.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="escalationpolicytypedescription"></a>`description` | [`String`](#string) | The description of the escalation policy. |
| <a id="escalationpolicytypeid"></a>`id` | [`IncidentManagementEscalationPolicyID`](#incidentmanagementescalationpolicyid) | ID of the escalation policy. |
| <a id="escalationpolicytypename"></a>`name` | [`String`](#string) | The name of the escalation policy. |
| <a id="escalationpolicytyperules"></a>`rules` | [`[EscalationRuleType!]`](#escalationruletype) | Steps of the escalation policy. |
### `EscalationRuleType`
Represents an escalation rule for an escalation policy.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="escalationruletypeelapsedtimeseconds"></a>`elapsedTimeSeconds` | [`Int`](#int) | The time in seconds before the rule is activated. |
| <a id="escalationruletypeid"></a>`id` | [`IncidentManagementEscalationRuleID`](#incidentmanagementescalationruleid) | ID of the escalation policy. |
| <a id="escalationruletypeoncallschedule"></a>`oncallSchedule` | [`IncidentManagementOncallSchedule`](#incidentmanagementoncallschedule) | The on-call schedule to notify. |
| <a id="escalationruletypestatus"></a>`status` | [`EscalationRuleStatus`](#escalationrulestatus) | The status required to prevent the rule from activating. |
### `Event` ### `Event`
Representing an event. Representing an event.
...@@ -10909,6 +10958,7 @@ Represents vulnerability finding of a security report on the pipeline. ...@@ -10909,6 +10958,7 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projecthttpurltorepo"></a>`httpUrlToRepo` | [`String`](#string) | URL to connect to the project via HTTPS. | | <a id="projecthttpurltorepo"></a>`httpUrlToRepo` | [`String`](#string) | URL to connect to the project via HTTPS. |
| <a id="projectid"></a>`id` | [`ID!`](#id) | ID of the project. | | <a id="projectid"></a>`id` | [`ID!`](#id) | ID of the project. |
| <a id="projectimportstatus"></a>`importStatus` | [`String`](#string) | Status of import background job of the project. | | <a id="projectimportstatus"></a>`importStatus` | [`String`](#string) | Status of import background job of the project. |
| <a id="projectincidentmanagementescalationpolicies"></a>`incidentManagementEscalationPolicies` | [`EscalationPolicyTypeConnection`](#escalationpolicytypeconnection) | Incident Management escalation policies of the project. (see [Connections](#connections)) |
| <a id="projectissuesenabled"></a>`issuesEnabled` | [`Boolean`](#boolean) | Indicates if Issues are enabled for the current user. | | <a id="projectissuesenabled"></a>`issuesEnabled` | [`Boolean`](#boolean) | Indicates if Issues are enabled for the current user. |
| <a id="projectjiraimportstatus"></a>`jiraImportStatus` | [`String`](#string) | Status of Jira import background job of the project. | | <a id="projectjiraimportstatus"></a>`jiraImportStatus` | [`String`](#string) | Status of Jira import background job of the project. |
| <a id="projectjiraimports"></a>`jiraImports` | [`JiraImportConnection`](#jiraimportconnection) | Jira imports into the project. (see [Connections](#connections)) | | <a id="projectjiraimports"></a>`jiraImports` | [`JiraImportConnection`](#jiraimportconnection) | Jira imports into the project. (see [Connections](#connections)) |
...@@ -11182,6 +11232,18 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -11182,6 +11232,18 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectenvironmentssearch"></a>`search` | [`String`](#string) | Search query for environment name. | | <a id="projectenvironmentssearch"></a>`search` | [`String`](#string) | Search query for environment name. |
| <a id="projectenvironmentsstates"></a>`states` | [`[String!]`](#string) | States of environments that should be included in result. | | <a id="projectenvironmentsstates"></a>`states` | [`[String!]`](#string) | States of environments that should be included in result. |
##### `Project.incidentManagementEscalationPolicy`
Incident Management escalation policy of the project.
Returns [`EscalationPolicyType`](#escalationpolicytype).
###### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectincidentmanagementescalationpolicyid"></a>`id` | [`IncidentManagementEscalationPolicyID!`](#incidentmanagementescalationpolicyid) | ID of the escalation policy. |
##### `Project.incidentManagementOncallSchedules` ##### `Project.incidentManagementOncallSchedules`
Incident Management On-call schedules of the project. Incident Management On-call schedules of the project.
...@@ -13966,6 +14028,15 @@ Epic ID wildcard values. ...@@ -13966,6 +14028,15 @@ Epic ID wildcard values.
| <a id="epicwildcardidany"></a>`ANY` | Any epic is assigned. | | <a id="epicwildcardidany"></a>`ANY` | Any epic is assigned. |
| <a id="epicwildcardidnone"></a>`NONE` | No epic is assigned. | | <a id="epicwildcardidnone"></a>`NONE` | No epic is assigned. |
### `EscalationRuleStatus`
Escalation rule statuses.
| Value | Description |
| ----- | ----------- |
| <a id="escalationrulestatusacknowledged"></a>`ACKNOWLEDGED` | . |
| <a id="escalationrulestatusresolved"></a>`RESOLVED` | . |
### `EventAction` ### `EventAction`
Event action. Event action.
...@@ -15013,6 +15084,18 @@ Represents a unique identifier that is Base64 obfuscated. It is often used to re ...@@ -15013,6 +15084,18 @@ Represents a unique identifier that is Base64 obfuscated. It is often used to re
An ISO 8601-encoded date. An ISO 8601-encoded date.
### `IncidentManagementEscalationPolicyID`
A `IncidentManagementEscalationPolicyID` is a global ID. It is encoded as a string.
An example `IncidentManagementEscalationPolicyID` is: `"gid://gitlab/IncidentManagement::EscalationPolicy/1"`.
### `IncidentManagementEscalationRuleID`
A `IncidentManagementEscalationRuleID` is a global ID. It is encoded as a string.
An example `IncidentManagementEscalationRuleID` is: `"gid://gitlab/IncidentManagement::EscalationRule/1"`.
### `IncidentManagementOncallParticipantID` ### `IncidentManagementOncallParticipantID`
A `IncidentManagementOncallParticipantID` is a global ID. It is encoded as a string. A `IncidentManagementOncallParticipantID` is a global ID. It is encoded as a string.
......
# frozen_string_literal: true
module IncidentManagement
class EscalationPoliciesFinder
def initialize(current_user, project, params = {})
@current_user = current_user
@project = project
@params = params
end
def execute
return IncidentManagement::EscalationPolicy.none unless allowed?
collection = project.incident_management_escalation_policies
by_id(collection)
end
private
attr_reader :current_user, :project, :params
def allowed?
Ability.allowed?(current_user, :read_incident_management_escalation_policy, project)
end
def by_id(collection)
return collection unless params[:id]
collection.id_in(params[:id])
end
end
end
...@@ -132,6 +132,19 @@ module EE ...@@ -132,6 +132,19 @@ module EE
extras: [:lookahead], extras: [:lookahead],
resolver: ::Resolvers::IncidentManagement::OncallScheduleResolver resolver: ::Resolvers::IncidentManagement::OncallScheduleResolver
field :incident_management_escalation_policies,
::Types::IncidentManagement::EscalationPolicyType.connection_type,
null: true,
description: 'Incident Management escalation policies of the project.',
extras: [:lookahead],
resolver: ::Resolvers::IncidentManagement::EscalationPoliciesResolver
field :incident_management_escalation_policy,
::Types::IncidentManagement::EscalationPolicyType,
null: true,
description: 'Incident Management escalation policy of the project.',
resolver: ::Resolvers::IncidentManagement::EscalationPoliciesResolver.single
field :api_fuzzing_ci_configuration, field :api_fuzzing_ci_configuration,
::Types::AppSec::Fuzzing::Api::CiConfigurationType, ::Types::AppSec::Fuzzing::Api::CiConfigurationType,
null: true, null: true,
......
# frozen_string_literal: true
module Resolvers
module IncidentManagement
class EscalationPoliciesResolver < BaseResolver
include LooksAhead
alias_method :project, :object
type Types::IncidentManagement::EscalationPolicyType.connection_type, null: true
when_single do
argument :id,
::Types::GlobalIDType[::IncidentManagement::EscalationPolicy],
required: true,
description: 'ID of the escalation policy.',
prepare: ->(id, ctx) { id.model_id }
end
def resolve_with_lookahead(**args)
apply_lookahead(::IncidentManagement::EscalationPoliciesFinder.new(current_user, project, args).execute)
end
private
def preloads
{
rules: [{ rules: :oncall_schedule }]
}
end
end
end
end
# frozen_string_literal: true
module Types
module IncidentManagement
class EscalationPolicyType < BaseObject
graphql_name 'EscalationPolicyType'
description 'Represents an escalation policy'
authorize :read_incident_management_escalation_policy
field :id, Types::GlobalIDType[::IncidentManagement::EscalationPolicy],
null: true,
description: 'ID of the escalation policy.'
field :name, GraphQL::STRING_TYPE,
null: true,
description: 'The name of the escalation policy.'
field :description, GraphQL::STRING_TYPE,
null: true,
description: 'The description of the escalation policy.'
field :rules, [Types::IncidentManagement::EscalationRuleType],
null: true,
description: 'Steps of the escalation policy.'
end
end
end
# frozen_string_literal: true
module Types
module IncidentManagement
class EscalationRuleStatusEnum < BaseEnum
graphql_name 'EscalationRuleStatus'
description 'Escalation rule statuses'
::IncidentManagement::EscalationRule.statuses.each_key do |status|
value status.to_s.upcase, value: status, description: "#{::AlertManagement::Alert::STATUS_DESCRIPTIONS[status]}."
end
end
end
end
# frozen_string_literal: true
module Types
module IncidentManagement
# rubocop: disable Graphql/AuthorizeTypes
class EscalationRuleType < BaseObject
graphql_name 'EscalationRuleType'
description 'Represents an escalation rule for an escalation policy'
field :id, Types::GlobalIDType[::IncidentManagement::EscalationRule],
null: true,
description: 'ID of the escalation policy.'
field :oncall_schedule, Types::IncidentManagement::OncallScheduleType,
null: true,
description: 'The on-call schedule to notify.'
field :elapsed_time_seconds, GraphQL::INT_TYPE,
null: true,
description: 'The time in seconds before the rule is activated.'
field :status, Types::IncidentManagement::EscalationRuleStatusEnum,
null: true,
description: 'The status required to prevent the rule from activating.'
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
...@@ -105,6 +105,7 @@ module EE ...@@ -105,6 +105,7 @@ module EE
has_many :incident_management_oncall_schedules, class_name: 'IncidentManagement::OncallSchedule', inverse_of: :project has_many :incident_management_oncall_schedules, class_name: 'IncidentManagement::OncallSchedule', inverse_of: :project
has_many :incident_management_oncall_rotations, class_name: 'IncidentManagement::OncallRotation', through: :incident_management_oncall_schedules, source: :rotations has_many :incident_management_oncall_rotations, class_name: 'IncidentManagement::OncallRotation', through: :incident_management_oncall_schedules, source: :rotations
has_many :incident_management_escalation_policies, class_name: 'IncidentManagement::EscalationPolicy', inverse_of: :project
has_one :security_orchestration_policy_configuration, class_name: 'Security::OrchestrationPolicyConfiguration', foreign_key: :project_id, inverse_of: :project has_one :security_orchestration_policy_configuration, class_name: 'Security::OrchestrationPolicyConfiguration', foreign_key: :project_id, inverse_of: :project
......
# frozen_string_literal: true
module IncidentManagement
class EscalationPolicyPolicy < ::BasePolicy
delegate :project
end
end
---
title: Add GraphQL types for escalation policies and rules
merge_request: 61439
author:
type: added
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
FactoryBot.define do FactoryBot.define do
factory :incident_management_escalation_rule, class: 'IncidentManagement::EscalationRule' do factory :incident_management_escalation_rule, class: 'IncidentManagement::EscalationRule' do
association :policy, factory: :incident_management_escalation_policy association :policy, factory: :incident_management_escalation_policy
association :oncall_schedule, factory: :incident_management_oncall_schedule oncall_schedule { association :incident_management_oncall_schedule, project: policy.project }
status { IncidentManagement::EscalationRule.statuses[:acknowledged] } status { IncidentManagement::EscalationRule.statuses[:acknowledged] }
elapsed_time_seconds { 5.minutes } elapsed_time_seconds { 5.minutes }
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe IncidentManagement::EscalationPoliciesFinder do
let_it_be(:current_user) { create(:user) }
let_it_be_with_refind(:project) { create(:project) }
let_it_be(:escalation_policy) { create(:incident_management_escalation_policy, project: project) }
let_it_be(:escalation_policy_2) { create(:incident_management_escalation_policy, project: project) }
let_it_be(:escalation_policy_from_another_project) { create(:incident_management_escalation_policy) }
let(:params) { {} }
describe '#execute' do
subject(:execute) { described_class.new(current_user, project, params).execute }
context 'when feature is available' do
before do
stub_licensed_features(oncall_schedules: true, escalation_policies: true)
stub_feature_flags(escalation_policies_mvc: project)
end
context 'when user has permissions' do
before do
project.add_maintainer(current_user)
end
it 'returns project escalation policies' do
is_expected.to contain_exactly(escalation_policy, escalation_policy_2)
end
context 'when id given' do
let(:params) { { id: escalation_policy.id } }
it { is_expected.to contain_exactly(escalation_policy) }
context 'an array of ids given' do
let(:params) { { id: [escalation_policy.id, escalation_policy_2.id] } }
it { is_expected.to contain_exactly(escalation_policy, escalation_policy_2) }
end
end
end
context 'when user has no permissions' do
it { is_expected.to eq(IncidentManagement::EscalationPolicy.none) }
end
end
context 'when feature is not avaiable' do
before do
stub_licensed_features(oncall_schedules: true, escalation_policies: false)
stub_feature_flags(escalation_policies_mvc: project)
end
it { is_expected.to eq(IncidentManagement::EscalationPolicy.none) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::IncidentManagement::EscalationPoliciesResolver do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:policy) { create(:incident_management_escalation_policy, project: project) }
let(:args) { {} }
let(:resolver) { described_class }
subject(:resolved_policies) { sync(resolve_escalation_policies(args, current_user: current_user).to_a) }
before do
stub_licensed_features(oncall_schedules: true, escalation_policies: true)
stub_feature_flags(escalation_policies_mvc: project)
project.add_reporter(current_user)
end
specify do
expect(described_class).to have_nullable_graphql_type(Types::IncidentManagement::EscalationPolicyType.connection_type)
end
it 'returns escalation policies' do
expect(resolved_policies.length).to eq(1)
expect(resolved_policies.first).to be_a(::IncidentManagement::EscalationPolicy)
expect(resolved_policies.first).to have_attributes(id: policy.id)
end
context 'when resolving a single item' do
let(:resolver) { described_class.single }
subject(:resolved_policy) { sync(resolve_escalation_policies(args, current_user: current_user)) }
context 'when id given' do
let(:args) { { id: policy.to_global_id } }
it 'returns the policy' do
expect(resolved_policy).to eq(policy)
end
end
end
context 'when user does not have permissions' do
let(:another_user) { create(:user) }
subject(:resolved_policies) { sync(resolve_escalation_policies(args, current_user: another_user).to_a) }
it 'returns no policies' do
expect(resolved_policies.length).to eq(0)
end
end
private
def resolve_escalation_policies(args = {}, context = { current_user: current_user })
resolve(resolver, obj: project, args: args, ctx: context)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['EscalationPolicyType'] do
specify { expect(described_class.graphql_name).to eq('EscalationPolicyType') }
specify { expect(described_class).to require_graphql_authorizations(:read_incident_management_escalation_policy) }
it 'exposes the expected fields' do
expected_fields = %i[
id
name
description
rules
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['EscalationRuleType'] do
specify { expect(described_class.graphql_name).to eq('EscalationRuleType') }
it 'exposes the expected fields' do
expected_fields = %i[
id
oncall_schedule
elapsed_time_seconds
status
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end
...@@ -20,7 +20,7 @@ RSpec.describe GitlabSchema.types['Project'] do ...@@ -20,7 +20,7 @@ RSpec.describe GitlabSchema.types['Project'] do
vulnerabilities vulnerability_scanners requirement_states_count vulnerabilities vulnerability_scanners requirement_states_count
vulnerability_severities_count packages compliance_frameworks vulnerabilities_count_by_day vulnerability_severities_count packages compliance_frameworks vulnerabilities_count_by_day
security_dashboard_path iterations iteration_cadences cluster_agents repository_size_excess actual_repository_size_limit security_dashboard_path iterations iteration_cadences cluster_agents repository_size_excess actual_repository_size_limit
code_coverage_summary api_fuzzing_ci_configuration path_locks code_coverage_summary api_fuzzing_ci_configuration path_locks incident_management_escalation_policies incident_management_escalation_policy
] ]
expect(described_class).to include_graphql_fields(*expected_fields) expect(described_class).to include_graphql_fields(*expected_fields)
......
...@@ -60,6 +60,7 @@ RSpec.describe Project do ...@@ -60,6 +60,7 @@ RSpec.describe Project do
it { is_expected.to have_many(:incident_management_oncall_schedules).class_name('IncidentManagement::OncallSchedule') } it { is_expected.to have_many(:incident_management_oncall_schedules).class_name('IncidentManagement::OncallSchedule') }
it { is_expected.to have_many(:incident_management_oncall_rotations).through(:incident_management_oncall_schedules).source(:rotations) } it { is_expected.to have_many(:incident_management_oncall_rotations).through(:incident_management_oncall_schedules).source(:rotations) }
it { is_expected.to have_many(:incident_management_escalation_policies).class_name('IncidentManagement::EscalationPolicy') }
describe '#jira_vulnerabilities_integration_enabled?' do describe '#jira_vulnerabilities_integration_enabled?' do
context 'when project lacks a jira_service relation' do context 'when project lacks a jira_service relation' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'getting Incident Management escalation policies' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let(:params) { {} }
let(:fields) do
<<~QUERY
nodes {
#{all_graphql_fields_for('EscalationPolicyType')}
}
QUERY
end
let(:query) do
graphql_query_for(
'project',
{ 'fullPath' => project.full_path },
query_graphql_field('incidentManagementEscalationPolicies', {}, fields)
)
end
let(:escalation_policies) { graphql_data.dig('project', 'incidentManagementEscalationPolicies', 'nodes') }
before do
stub_licensed_features(oncall_schedules: true, escalation_policies: true)
stub_feature_flags(escalation_policies_mvc: project)
end
context 'without project permissions' do
let(:user) { create(:user) }
before do
post_graphql(query, current_user: current_user)
end
it_behaves_like 'a working graphql query'
it { expect(escalation_policies).to be_nil }
end
context 'with project permissions' do
before do
project.add_reporter(current_user)
end
context 'with unavailable feature' do
before do
stub_licensed_features(escalation_policies: false)
post_graphql(query, current_user: current_user)
end
it_behaves_like 'a working graphql query'
it { expect(escalation_policies).to be_empty }
end
context 'without escalation policies' do
before do
post_graphql(query, current_user: current_user)
end
it_behaves_like 'a working graphql query'
it { expect(escalation_policies).to be_empty }
end
context 'with escalation policies' do
let_it_be(:policy) { create(:incident_management_escalation_policy, project: project) }
let_it_be(:second_policy) { create(:incident_management_escalation_policy, project: project) }
let(:last_policy) { escalation_policies.last }
before do
post_graphql(query, current_user: current_user)
end
it_behaves_like 'a working graphql query'
it 'returns the correct properties of the escalation policy' do
expect(escalation_policies.size).to eq(2)
expect(last_policy).to include(
'id' => policy.to_global_id.to_s,
'name' => policy.name,
'description' => policy.description
)
end
context 'requesting single policy' do
let(:query) do
graphql_query_for(
'project',
{ 'fullPath' => project.full_path },
query_graphql_field('incidentManagementEscalationPolicy', { id: policy.to_global_id.to_s }, all_graphql_fields_for('EscalationPolicyType'))
)
end
it_behaves_like 'a working graphql query'
it 'returns the correct properties of the escalation policy' do
policy_data = graphql_data.dig('project', 'incidentManagementEscalationPolicy')
last_policy_rule = policy.rules.last
expect(policy_data).to include(
'id' => policy.to_global_id.to_s,
'name' => policy.name,
'description' => policy.description,
'rules' => [
{
'id' => last_policy_rule.to_global_id.to_s,
'elapsedTimeSeconds' => last_policy_rule.elapsed_time_seconds,
'status' => last_policy_rule.status.upcase,
'oncallSchedule' => {
'iid' => last_policy_rule.oncall_schedule.iid.to_s,
'name' => last_policy_rule.oncall_schedule.name,
'description' => last_policy_rule.oncall_schedule.description,
'timezone' => last_policy_rule.oncall_schedule.timezone
}
}
]
)
end
end
end
end
end
...@@ -571,6 +571,7 @@ project: ...@@ -571,6 +571,7 @@ project:
- exported_protected_branches - exported_protected_branches
- incident_management_oncall_schedules - incident_management_oncall_schedules
- incident_management_oncall_rotations - incident_management_oncall_rotations
- incident_management_escalation_policies
- debian_distributions - debian_distributions
- merge_request_metrics - merge_request_metrics
- security_orchestration_policy_configuration - security_orchestration_policy_configuration
......
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