Commit 5890106c authored by Vitali Tatarintev's avatar Vitali Tatarintev

Add Update on-call schedule GraphQL mutation

Add a mutation to update on-call schedules
parent 2e0ab3a2
...@@ -14144,6 +14144,7 @@ type Mutation { ...@@ -14144,6 +14144,7 @@ type Mutation {
namespaceIncreaseStorageTemporarily(input: NamespaceIncreaseStorageTemporarilyInput!): NamespaceIncreaseStorageTemporarilyPayload namespaceIncreaseStorageTemporarily(input: NamespaceIncreaseStorageTemporarilyInput!): NamespaceIncreaseStorageTemporarilyPayload
oncallScheduleCreate(input: OncallScheduleCreateInput!): OncallScheduleCreatePayload oncallScheduleCreate(input: OncallScheduleCreateInput!): OncallScheduleCreatePayload
oncallScheduleDestroy(input: OncallScheduleDestroyInput!): OncallScheduleDestroyPayload oncallScheduleDestroy(input: OncallScheduleDestroyInput!): OncallScheduleDestroyPayload
oncallScheduleUpdate(input: OncallScheduleUpdateInput!): OncallScheduleUpdatePayload
pipelineCancel(input: PipelineCancelInput!): PipelineCancelPayload pipelineCancel(input: PipelineCancelInput!): PipelineCancelPayload
pipelineDestroy(input: PipelineDestroyInput!): PipelineDestroyPayload pipelineDestroy(input: PipelineDestroyInput!): PipelineDestroyPayload
pipelineRetry(input: PipelineRetryInput!): PipelineRetryPayload pipelineRetry(input: PipelineRetryInput!): PipelineRetryPayload
...@@ -14838,6 +14839,61 @@ type OncallScheduleDestroyPayload { ...@@ -14838,6 +14839,61 @@ type OncallScheduleDestroyPayload {
oncallSchedule: IncidentManagementOncallSchedule oncallSchedule: IncidentManagementOncallSchedule
} }
"""
Autogenerated input type of OncallScheduleUpdate
"""
input OncallScheduleUpdateInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
The description of the on-call schedule
"""
description: String
"""
The on-call schedule internal ID to update
"""
iid: String!
"""
The name of the on-call schedule
"""
name: String
"""
The project to update the on-call schedule in
"""
projectPath: ID!
"""
The timezone of the on-call schedule
"""
timezone: String
}
"""
Autogenerated return type of OncallScheduleUpdate
"""
type OncallScheduleUpdatePayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Errors encountered during execution of the mutation.
"""
errors: [String!]!
"""
The on-call schedule
"""
oncallSchedule: IncidentManagementOncallSchedule
}
""" """
Represents a package Represents a package
""" """
......
...@@ -41158,6 +41158,33 @@ ...@@ -41158,6 +41158,33 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "oncallScheduleUpdate",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "OncallScheduleUpdateInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "OncallScheduleUpdatePayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "pipelineCancel", "name": "pipelineCancel",
"description": null, "description": null,
...@@ -44104,6 +44131,152 @@ ...@@ -44104,6 +44131,152 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "INPUT_OBJECT",
"name": "OncallScheduleUpdateInput",
"description": "Autogenerated input type of OncallScheduleUpdate",
"fields": null,
"inputFields": [
{
"name": "projectPath",
"description": "The project to update the on-call schedule in",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "iid",
"description": "The on-call schedule internal ID to update",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "name",
"description": "The name of the on-call schedule",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "description",
"description": "The description of the on-call schedule",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "timezone",
"description": "The timezone of the on-call schedule",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "OncallScheduleUpdatePayload",
"description": "Autogenerated return type of OncallScheduleUpdate",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Errors encountered during execution of the mutation.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "oncallSchedule",
"description": "The on-call schedule",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "IncidentManagementOncallSchedule",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{ {
"kind": "OBJECT", "kind": "OBJECT",
"name": "Package", "name": "Package",
...@@ -2272,6 +2272,16 @@ Autogenerated return type of OncallScheduleDestroy. ...@@ -2272,6 +2272,16 @@ Autogenerated return type of OncallScheduleDestroy.
| `errors` | String! => Array | Errors encountered during execution of the mutation. | | `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `oncallSchedule` | IncidentManagementOncallSchedule | The on-call schedule | | `oncallSchedule` | IncidentManagementOncallSchedule | The on-call schedule |
### OncallScheduleUpdatePayload
Autogenerated return type of OncallScheduleUpdate.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `oncallSchedule` | IncidentManagementOncallSchedule | The on-call schedule |
### Package ### Package
Represents a package. Represents a package.
......
...@@ -49,6 +49,7 @@ module EE ...@@ -49,6 +49,7 @@ module EE
mount_mutation ::Mutations::Admin::Analytics::DevopsAdoption::Segments::Update mount_mutation ::Mutations::Admin::Analytics::DevopsAdoption::Segments::Update
mount_mutation ::Mutations::Admin::Analytics::DevopsAdoption::Segments::Delete mount_mutation ::Mutations::Admin::Analytics::DevopsAdoption::Segments::Delete
mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Create mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Create
mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Update
mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Destroy mount_mutation ::Mutations::IncidentManagement::OncallSchedule::Destroy
prepend(Types::DeprecatedMutations) prepend(Types::DeprecatedMutations)
......
# frozen_string_literal: true
module Mutations
module IncidentManagement
module OncallSchedule
class Update < OncallScheduleBase
graphql_name 'OncallScheduleUpdate'
argument :project_path, GraphQL::ID_TYPE,
required: true,
description: 'The project to update the on-call schedule in'
argument :iid, GraphQL::STRING_TYPE,
required: true,
description: 'The on-call schedule internal ID to update'
argument :name, GraphQL::STRING_TYPE,
required: false,
description: 'The name of the on-call schedule'
argument :description, GraphQL::STRING_TYPE,
required: false,
description: 'The description of the on-call schedule'
argument :timezone, GraphQL::STRING_TYPE,
required: false,
description: 'The timezone of the on-call schedule'
def resolve(args)
oncall_schedule = authorized_find!(project_path: args[:project_path], iid: args[:iid])
response ::IncidentManagement::OncallSchedules::UpdateService.new(
oncall_schedule,
current_user,
args.slice(:name, :description, :timezone)
).execute
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::IncidentManagement::OncallSchedule::Update do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:oncall_schedule) { create(:incident_management_oncall_schedule, project: project) }
let(:args) do
{
project_path: project.full_path,
iid: oncall_schedule.iid.to_s,
name: 'Updated name',
description: 'Updated description',
timezone: 'America/New_York'
}
end
specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_oncall_schedule) }
before do
stub_licensed_features(oncall_schedules: true)
end
describe '#resolve' do
subject(:resolve) { mutation_for(project, current_user).resolve(args) }
context 'user has access to project' do
before do
project.add_maintainer(current_user)
end
context 'when OncallSchedules::UpdateService responds with success' do
it 'returns the on-call schedule with no errors' do
expect(resolve).to eq(
oncall_schedule: oncall_schedule,
errors: []
)
end
end
context 'when OncallSchedules::UpdateService responds with an error' do
before do
allow_any_instance_of(::IncidentManagement::OncallSchedules::UpdateService)
.to receive(:execute)
.and_return(ServiceResponse.error(payload: { oncall_schedule: nil }, message: 'Name has already been taken'))
end
it 'returns errors' do
expect(resolve).to eq(
oncall_schedule: nil,
errors: ['Name has already been taken']
)
end
end
end
context 'when resource is not accessible to the user' do
it 'raises an error' do
expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
private
def mutation_for(project, user)
described_class.new(object: project, context: { current_user: user }, field: nil)
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Updating an on-call schedule' do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:oncall_schedule) { create(:incident_management_oncall_schedule, project: project) }
let(:variables) do
{
project_path: project.full_path,
iid: oncall_schedule.iid.to_s,
name: 'Updated name',
description: 'Updated description',
timezone: 'America/New_York'
}
end
let(:mutation) do
graphql_mutation(:oncall_schedule_update, variables) do
<<~QL
clientMutationId
errors
oncallSchedule {
iid
name
description
timezone
}
QL
end
end
let(:mutation_response) { graphql_mutation_response(:oncall_schedule_update) }
before do
stub_licensed_features(oncall_schedules: true)
project.add_maintainer(user)
end
it 'updates the on-call schedule' do
post_graphql_mutation(mutation, current_user: user)
oncall_schedule_response = mutation_response['oncallSchedule']
expect(response).to have_gitlab_http_status(:success)
expect(oncall_schedule_response.slice(*%w[iid name description timezone])).to eq(
'iid' => oncall_schedule.iid.to_s,
'name' => variables[:name],
'description' => variables[:description],
'timezone' => variables[:timezone]
)
end
end
...@@ -6,7 +6,7 @@ RSpec.describe IncidentManagement::OncallSchedules::UpdateService do ...@@ -6,7 +6,7 @@ RSpec.describe IncidentManagement::OncallSchedules::UpdateService do
let_it_be(:user_with_permissions) { create(:user) } let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) } let_it_be(:user_without_permissions) { create(:user) }
let_it_be_with_refind(:project) { create(:project) } let_it_be_with_refind(:project) { create(:project) }
let!(:oncall_schedule) { create(:incident_management_oncall_schedule, project: project) } let_it_be_with_reload(:oncall_schedule) { create(:incident_management_oncall_schedule, project: project) }
let(:current_user) { user_with_permissions } let(:current_user) { user_with_permissions }
let(:params) { { name: 'Updated name', description: 'Updated description', timezone: 'America/New_York' } } let(:params) { { name: 'Updated name', description: 'Updated description', timezone: 'America/New_York' } }
......
...@@ -31402,6 +31402,9 @@ msgstr "" ...@@ -31402,6 +31402,9 @@ msgstr ""
msgid "You have insufficient permissions to remove this HTTP integration" msgid "You have insufficient permissions to remove this HTTP integration"
msgstr "" msgstr ""
msgid "You have insufficient permissions to update an on-call schedule for this project"
msgstr ""
msgid "You have insufficient permissions to update this HTTP integration" msgid "You have insufficient permissions to update this HTTP integration"
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