diff --git a/app/graphql/graphql_triggers.rb b/app/graphql/graphql_triggers.rb index b39875b83a99e1fce62959312583e85e6584d281..8086d8c02a4afc9bc3fe1d029939be8d32a2a0e4 100644 --- a/app/graphql/graphql_triggers.rb +++ b/app/graphql/graphql_triggers.rb @@ -21,3 +21,5 @@ def self.issuable_dates_updated(issuable) GitlabSchema.subscriptions.trigger('issuableDatesUpdated', { issuable_id: issuable.to_gid }, issuable) end end + +GraphqlTriggers.prepend_mod diff --git a/app/graphql/types/subscription_type.rb b/app/graphql/types/subscription_type.rb index b1db0c2754a1edc1f0c90a77d4587cf11445532b..ef701bbfc1073c6606359ec9d26fb936fc739ee7 100644 --- a/app/graphql/types/subscription_type.rb +++ b/app/graphql/types/subscription_type.rb @@ -25,3 +25,5 @@ class SubscriptionType < ::Types::BaseObject description: 'Triggered when the reviewers of a merge request are updated.' end end + +Types::SubscriptionType.prepend_mod diff --git a/ee/app/graphql/ee/graphql_triggers.rb b/ee/app/graphql/ee/graphql_triggers.rb new file mode 100644 index 0000000000000000000000000000000000000000..16ebeb6ce59511546f42c94616f213d5090dba40 --- /dev/null +++ b/ee/app/graphql/ee/graphql_triggers.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module EE + module GraphqlTriggers + extend ActiveSupport::Concern + prepended do + def self.issuable_weight_updated(issuable) + ::GitlabSchema.subscriptions.trigger('issuableWeightUpdated', { issuable_id: issuable.to_gid }, issuable) + end + end + end +end diff --git a/ee/app/graphql/ee/types/subscription_type.rb b/ee/app/graphql/ee/types/subscription_type.rb new file mode 100644 index 0000000000000000000000000000000000000000..d2ceebc6d5dc02dd4dcbea885fd94081619d0f54 --- /dev/null +++ b/ee/app/graphql/ee/types/subscription_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module EE + module Types + module SubscriptionType + extend ActiveSupport::Concern + + prepended do + field :issuable_weight_updated, subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the weight of an issuable is updated.' + end + end + end +end diff --git a/ee/app/services/ee/issues/update_service.rb b/ee/app/services/ee/issues/update_service.rb index cf93a0e6c6b7fffc8284a6e05c82487cb07a93ef..214b027c8c47f1b98a28def1dcc2b56d1a63534d 100644 --- a/ee/app/services/ee/issues/update_service.rb +++ b/ee/app/services/ee/issues/update_service.rb @@ -36,6 +36,7 @@ def handle_changes(issue, _options) super handle_iteration_change(issue) + handle_weight_change(issue) end override :before_update @@ -60,6 +61,12 @@ def handle_iteration_change(issue) send_iteration_change_notification(issue) end + def handle_weight_change(issue) + return unless issue.previous_changes.key?(:weight) + + ::GraphqlTriggers.issuable_weight_updated(issue) + end + def send_iteration_change_notification(issue) if issue.iteration.nil? notification_service.async.removed_iteration_issue(issue, current_user) diff --git a/ee/spec/graphql/graphql_triggers_spec.rb b/ee/spec/graphql/graphql_triggers_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..94c90907a453341dc9759fa368ef2f1ff8b6bf3e --- /dev/null +++ b/ee/spec/graphql/graphql_triggers_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GraphqlTriggers do + describe '.issuable_weight_updated' do + let(:work_item) { create(:work_item) } + + it 'triggers the issuableWeightUpdated subscription' do + expect(GitlabSchema.subscriptions).to receive(:trigger).with( + 'issuableWeightUpdated', + { issuable_id: work_item.to_gid }, + work_item + ).and_call_original + + ::GraphqlTriggers.issuable_weight_updated(work_item) + end + end +end diff --git a/ee/spec/graphql/types/subscription_type_spec.rb b/ee/spec/graphql/types/subscription_type_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..147ab37a140b1e1958999353ba026c82973f55b3 --- /dev/null +++ b/ee/spec/graphql/types/subscription_type_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['Subscription'] do + it 'has the expected fields' do + expected_fields = %i[ + issuable_weight_updated + ] + + expect(described_class).to include_graphql_fields(*expected_fields) + end +end diff --git a/ee/spec/services/ee/issues/update_service_spec.rb b/ee/spec/services/ee/issues/update_service_spec.rb index 7ea85a8d642108714980a744724e17816fcfadc2..648ceae693956cec007d1ddf11620739bc134845 100644 --- a/ee/spec/services/ee/issues/update_service_spec.rb +++ b/ee/spec/services/ee/issues/update_service_spec.rb @@ -20,6 +20,40 @@ def update_issue(opts) described_class.new(project: project, current_user: user, params: opts).execute(issue) end + context 'updating weight' do + before do + stub_licensed_features(issue_weights: true) + + project.add_developer(user) + + issue.update!(weight: 1) + end + + context 'when weight is changed' do + it "triggers 'issuableWeightUpdated' for issuable weight update subscription" do + expect(GraphqlTriggers).to receive(:issuable_weight_updated).with(issue).and_call_original + + update_issue(weight: nil) + end + end + + context 'when weight remains unchanged' do + it "does not trigger 'issuableWeightUpdated' for issuable weight update subscription" do + expect(GraphqlTriggers).not_to receive(:issuable_weight_updated) + + update_issue(weight: 1) + end + end + + context 'when weight param is not provided' do + it "does not trigger 'issuableWeightUpdated' for issuable weight update subscription" do + expect(GraphqlTriggers).not_to receive(:issuable_weight_updated) + + update_issue(title: "foobar") + end + end + end + context 'refresh epic dates' do before do issue.update!(epic: epic) diff --git a/ee/spec/services/work_items/update_service_spec.rb b/ee/spec/services/work_items/update_service_spec.rb index 2ce0361768d06af81dde0680fff4a10f9efa9808..7d220c0bda860ab170eb1187e2f1024e216ccd28 100644 --- a/ee/spec/services/work_items/update_service_spec.rb +++ b/ee/spec/services/work_items/update_service_spec.rb @@ -11,6 +11,18 @@ let(:current_user) { developer } describe '#execute' do + let(:service) do + described_class.new( + project: project, + current_user: current_user, + params: {}, + spam_params: spam_params, + widget_params: widget_params + ) + end + + subject { service.execute(work_item) } + before do stub_spam_services end @@ -22,17 +34,7 @@ } end - let(:service) do - described_class.new( - project: project, - current_user: current_user, - params: {}, - spam_params: spam_params, - widget_params: widget_params - ) - end - - let(:service_execute) { service.execute(work_item) } + let(:service_execute) { subject } let(:supported_widgets) do [ @@ -43,5 +45,47 @@ ] end end + + context 'when updating widgets' do + context 'for the weight widget' do + let(:widget_params) { { weight_widget: { weight: new_weight } } } + + before do + stub_licensed_features(issue_weights: true) + + work_item.update!(weight: 1) + end + + context 'when weight is changed' do + let(:new_weight) { nil } + + it "triggers 'issuableWeightUpdated' for issuable weight update subscription" do + expect(GraphqlTriggers).to receive(:issuable_weight_updated).with(work_item).and_call_original + + subject + end + end + + context 'when weight remains unchanged' do + let(:new_weight) { 1 } + + it "does not trigger 'issuableWeightUpdated' for issuable weight update subscription" do + expect(GraphqlTriggers).not_to receive(:issuable_weight_updated) + + subject + end + end + + context 'when weight widget param is not provided' do + let(:widget_params) {} + + it "does not trigger 'issuableWeightUpdated' for issuable weight update subscription" do + expect(GraphqlTriggers).not_to receive(:issuable_weight_updated) + + subject + end + end + end + end end end diff --git a/spec/graphql/types/subscription_type_spec.rb b/spec/graphql/types/subscription_type_spec.rb index 91e42e1f6c2c99e33dffe45bb48f04a001133a2c..860cbbf0c151d8091eb578a46efdf68a61d972c1 100644 --- a/spec/graphql/types/subscription_type_spec.rb +++ b/spec/graphql/types/subscription_type_spec.rb @@ -13,6 +13,6 @@ merge_request_reviewers_updated ] - expect(described_class).to have_graphql_fields(*expected_fields).only + expect(described_class).to include_graphql_fields(*expected_fields) end end