mirror of
https://github.com/discourse/discourse.git
synced 2026-03-04 01:15:08 +08:00
We notify admins both when an upcoming change is available for preview (at promotion status - 1) and when an upcoming change is automatically promoted. There are cases where multiple changes might be deployed at the same time, and we want to avoid sending multiple notifications to admins in a short period of time. This PR consolidates the notifications for both events into a single notification that includes all relevant changes. So for new upcoming changes, admins will receive a single notification that lists all the changes that are now available for preview. For automatic promotions, admins will receive a single notification that lists all the changes that were automatically promoted. In addition, this PR follows up on https://github.com/discourse/discourse/pull/38051 and directly links the notifications to a filtered list of upcoming changes by setting name. <img width="338" alt="image" src="https://github.com/user-attachments/assets/6febc7d7-0122-4f3b-8cbe-04d03721a709" /> <img width="332" alt="image" src="https://github.com/user-attachments/assets/46f2f886-8a6f-46f5-8038-bce3305d788f" /> ### Testing * Start with a fresh DB * Make sure `upcoming_change_verbose_logging` and `enable_upcoming_changes` are true * Choose a couple of upcoming changes and update their statuses in `site_settings.yml` to `beta` * Log in to the site and go to http://localhost:4200/sidekiq/scheduler and find the CheckUpcomingChanges job and run it * You should receive a notification for the changes becoming available, do not read the notification * Change another upcoming change to beta and run the job again * You should not get another notification, the third change should be merged into the first notification * Now update some of the same changes to `stable` status * Run the job again * You should get a new notification saying the changes were automatically enabled * Now update another of the same changes to `stable` status * You should not get another notification, the third change should be merged into the notification for enabled changes --------- Co-authored-by: awesomerobot <kris.aubuchon@discourse.org>
281 lines
9.8 KiB
Ruby
281 lines
9.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe UpcomingChanges::NotifyPromotions do
|
|
describe ".call" do
|
|
subject(:result) { described_class.call }
|
|
|
|
fab!(:admin)
|
|
fab!(:admin_2, :admin)
|
|
|
|
let(:enable_upload_debug_mode_status) { :stable }
|
|
let(:show_user_menu_avatars_status) { :beta }
|
|
|
|
before do
|
|
SiteSetting.promote_upcoming_changes_on_status = :stable
|
|
SiteSetting.stubs(:upcoming_change_site_settings).returns(
|
|
%i[enable_upload_debug_mode show_user_menu_avatars],
|
|
)
|
|
|
|
mock_upcoming_change_metadata(
|
|
{
|
|
enable_upload_debug_mode: {
|
|
impact: "other,developers",
|
|
status: enable_upload_debug_mode_status,
|
|
impact_type: "other",
|
|
impact_role: "developers",
|
|
},
|
|
show_user_menu_avatars: {
|
|
impact: "feature,all_members",
|
|
status: show_user_menu_avatars_status,
|
|
impact_type: "feature",
|
|
impact_role: "all_members",
|
|
},
|
|
},
|
|
)
|
|
end
|
|
|
|
context "when there is an error when trying to process a change" do
|
|
before do
|
|
StaffActionLogger
|
|
.any_instance
|
|
.stubs(:log_upcoming_change_toggle)
|
|
.raises(StandardError, "test error")
|
|
end
|
|
|
|
it "returns the errors" do
|
|
expect(result[:change_notification_statuses]).to match(
|
|
enable_upload_debug_mode: {
|
|
success: false,
|
|
error: "test error",
|
|
error_key: :unexpected_error,
|
|
backtrace: a_kind_of(Array),
|
|
},
|
|
show_user_menu_avatars: {
|
|
success: false,
|
|
error: "Setting show_user_menu_avatars does not meet or exceed the promotion status",
|
|
error_key: :does_not_meet_or_exceed_promotion_status,
|
|
},
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when everything is ok" do
|
|
it { is_expected.to run_successfully }
|
|
|
|
it "returns a state of all settings as success or failure, along with the related error message" do
|
|
expect(result[:change_notification_statuses]).to match(
|
|
enable_upload_debug_mode: {
|
|
success: true,
|
|
},
|
|
show_user_menu_avatars: {
|
|
success: false,
|
|
error: "Setting show_user_menu_avatars does not meet or exceed the promotion status",
|
|
error_key: :does_not_meet_or_exceed_promotion_status,
|
|
},
|
|
)
|
|
end
|
|
|
|
it "logs the change context in the staff action log" do
|
|
expect { result }.to change {
|
|
UserHistory.where(
|
|
action: UserHistory.actions[:upcoming_change_toggled],
|
|
subject: "enable_upload_debug_mode",
|
|
).count
|
|
}.by(1)
|
|
|
|
expect(UserHistory.last.context).to eq(
|
|
I18n.t(
|
|
"staff_action_logs.upcoming_changes.log_promoted",
|
|
change_status: UpcomingChanges.change_status(:enable_upload_debug_mode).to_s.titleize,
|
|
base_path: Discourse.base_path,
|
|
),
|
|
)
|
|
end
|
|
|
|
it "notifies admins about the upcoming change" do
|
|
expect { result }.to change {
|
|
Notification
|
|
.where(
|
|
notification_type: Notification.types[:upcoming_change_automatically_promoted],
|
|
user_id: [admin.id, admin_2.id],
|
|
)
|
|
.where("data::text LIKE ?", "%enable_upload_debug_mode%")
|
|
.count
|
|
}.by(2)
|
|
|
|
notification = Notification.where("data::text LIKE ?", "%enable_upload_debug_mode%").last
|
|
data = JSON.parse(notification.data)
|
|
expect(data["upcoming_change_names"]).to eq(["enable_upload_debug_mode"])
|
|
expect(data["upcoming_change_humanized_names"]).to eq(["Enable upload debug mode"])
|
|
expect(data["count"]).to eq(1)
|
|
end
|
|
|
|
it "creates an admins_notified_automatic_promotion event" do
|
|
expect { result }.to change {
|
|
UpcomingChangeEvent.where(
|
|
event_type: :admins_notified_automatic_promotion,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
).count
|
|
}.by(1)
|
|
end
|
|
|
|
it "triggers DiscourseEvent for the promoted setting" do
|
|
events = DiscourseEvent.track_events { result }
|
|
event =
|
|
events.find do |e|
|
|
e[:event_name] == :upcoming_change_enabled &&
|
|
e[:params].first == :enable_upload_debug_mode
|
|
end
|
|
|
|
expect(event).to be_present
|
|
expect(event[:params]).to eq([:enable_upload_debug_mode])
|
|
end
|
|
|
|
context "when multiple settings meet promotion criteria" do
|
|
let(:show_user_menu_avatars_status) { :stable }
|
|
|
|
it "processes all eligible settings into consolidated notifications" do
|
|
result
|
|
|
|
notifications =
|
|
Notification.where(
|
|
notification_type: Notification.types[:upcoming_change_automatically_promoted],
|
|
user_id: [admin.id, admin_2.id],
|
|
)
|
|
expect(notifications.count).to eq(2)
|
|
|
|
data = JSON.parse(notifications.first.data)
|
|
expect(data["upcoming_change_names"]).to contain_exactly(
|
|
"enable_upload_debug_mode",
|
|
"show_user_menu_avatars",
|
|
)
|
|
expect(data["count"]).to eq(2)
|
|
end
|
|
|
|
it "creates events for all promoted settings" do
|
|
expect { result }.to change {
|
|
UpcomingChangeEvent.where(
|
|
event_type: :admins_notified_automatic_promotion,
|
|
upcoming_change_name: %i[enable_upload_debug_mode show_user_menu_avatars],
|
|
).count
|
|
}.by(2)
|
|
end
|
|
|
|
it "triggers DiscourseEvent for all promoted settings" do
|
|
events = DiscourseEvent.track_events { result }
|
|
promoted_events = events.select { |e| e[:event_name] == :upcoming_change_enabled }
|
|
|
|
expect(promoted_events.length).to eq(2)
|
|
expect(promoted_events.map { |e| e[:params].first }).to contain_exactly(
|
|
:enable_upload_debug_mode,
|
|
:show_user_menu_avatars,
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when there are no upcoming changes" do
|
|
before { SiteSetting.stubs(:upcoming_change_site_settings).returns([]) }
|
|
|
|
it "does not create any notifications" do
|
|
expect { result }.not_to change { Notification.count }
|
|
end
|
|
|
|
it "does not trigger any events" do
|
|
events = DiscourseEvent.track_events { result }
|
|
expect(events.select { |e| e[:event_name] == :upcoming_change_enabled }).to be_empty
|
|
end
|
|
end
|
|
|
|
context "when settings do not meet promotion status" do
|
|
let(:enable_upload_debug_mode_status) { :beta }
|
|
let(:show_user_menu_avatars_status) { :alpha }
|
|
|
|
it "does not create any notifications" do
|
|
expect { result }.not_to change { Notification.count }
|
|
end
|
|
|
|
it "does not trigger any events" do
|
|
events = DiscourseEvent.track_events { result }
|
|
expect(events.select { |e| e[:event_name] == :upcoming_change_enabled }).to be_empty
|
|
end
|
|
|
|
it "returns the correct error and error key" do
|
|
expect(result[:change_notification_statuses][:enable_upload_debug_mode]).to match(
|
|
success: false,
|
|
error: "Setting enable_upload_debug_mode does not meet or exceed the promotion status",
|
|
error_key: :does_not_meet_or_exceed_promotion_status,
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when settings are already notified about promotion" do
|
|
before do
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :admins_notified_automatic_promotion,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
acting_user: Discourse.system_user,
|
|
)
|
|
end
|
|
|
|
it "does not notify admins again for the already-notified setting" do
|
|
expect { result }.not_to change {
|
|
Notification
|
|
.where(notification_type: Notification.types[:upcoming_change_automatically_promoted])
|
|
.where("data::text LIKE ?", "%enable_upload_debug_mode%")
|
|
.count
|
|
}
|
|
end
|
|
|
|
it "does not trigger event for the already-notified setting" do
|
|
events = DiscourseEvent.track_events { result }
|
|
expect(
|
|
events.select do |e|
|
|
e[:event_name] == :upcoming_change_enabled &&
|
|
e[:params].first == :enable_upload_debug_mode
|
|
end,
|
|
).to be_empty
|
|
end
|
|
|
|
it "returns the correct error and error key" do
|
|
expect(result[:change_notification_statuses][:enable_upload_debug_mode]).to match(
|
|
success: false,
|
|
error: "Setting enable_upload_debug_mode has already notified admins about promotion",
|
|
error_key: :already_notified_about_promotion,
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when settings are opted out" do
|
|
before { SiteSetting.enable_upload_debug_mode = false }
|
|
|
|
it "does not notify admins for opted-out settings" do
|
|
expect { result }.not_to change {
|
|
Notification
|
|
.where(notification_type: Notification.types[:upcoming_change_automatically_promoted])
|
|
.where("data::text LIKE ?", "%enable_upload_debug_mode%")
|
|
.count
|
|
}
|
|
end
|
|
|
|
it "does not trigger event for opted-out settings" do
|
|
events = DiscourseEvent.track_events { result }
|
|
expect(
|
|
events.select do |e|
|
|
e[:event_name] == :upcoming_change_enabled &&
|
|
e[:params].first == :enable_upload_debug_mode
|
|
end,
|
|
).to be_empty
|
|
end
|
|
|
|
it "returns the correct error and error key" do
|
|
expect(result[:change_notification_statuses][:enable_upload_debug_mode]).to match(
|
|
success: false,
|
|
error:
|
|
"Setting enable_upload_debug_mode has been manually opted in or out by an admin, we did not notify admins about promotion",
|
|
error_key: :already_manually_toggled,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|