0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 13:08:40 +08:00
discourse/lib/upcoming_changes/auto_promotion_initializer.rb
Martin Brennan fb9bb31983
FEATURE: Notify admins of upcoming changes and log events (#37003)
This commit adds several pieces of functionality to help keep admins
in the loop about upcoming changes.

First of all, there is a new initializer on boot that will notify admins
about
newly available upcoming changes, as well as log removed changes and
status movement of existing changes.

* When there is a new upcoming change, we only notify admins about
   it when the status is the `promote_upcoming_changes_on_status` - 1,
   e.g. if `promote_upcoming_changes_on_status` is `beta` then we only
   tell admin about the change once it has reached `alpha`. This means
   we may log the `added` event in one deploy, but only actually notify
   admins in a subsequent deploy.
* We log removed upcoming changes so we can automatically delete old
   site setting data in a future job as needed.

We also now  notify  admins when  upcoming changes are automatically
promoted to enabled based on the site's
`promote_upcoming_changes_on_status`:

<img width="378" height="600" alt="image"
src="https://github.com/user-attachments/assets/4200fbee-9990-4bbc-a378-85946e631e77"
/>

In addition, we now show an indicator in the admin sidebar
if there are new upcoming changes that have been added since
they last visited the upcoming change config page. This data
is stored in a user custom field, because Redis is ephemeral,
and storing in the User table is overkill because 99% of users
are not staff:

<img width="248" height="112" alt="image"
src="https://github.com/user-attachments/assets/4c3d3cf7-ac39-45f8-a2c8-a049cb85b8e9"
/>

Finally, this commit moves both the Track and Promote initializer
logic behind a `DistributedMutex`, we don't want multiple processes
running the same logic here, it needs to be only once.

---------

Co-authored-by: Loïc Guitaut <loic@discourse.org>
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
2026-01-21 12:45:54 +10:00

91 lines
3.1 KiB
Ruby
Vendored

# frozen_string_literal: true
module UpcomingChanges
class AutoPromotionInitializer
def self.log_prefix(site)
"[Upcoming changes promoter (#{site})]: "
end
def self.verbose_log(site, level, message)
return unless SiteSetting.upcoming_change_verbose_logging
Rails.logger.public_send(level, "#{log_prefix(site)} #{message}")
end
def self.call
RailsMultisite::ConnectionManagement.safe_each_connection do |site|
next if !SiteSetting.enable_upcoming_changes
verbose_log(site, :info, "Starting promotion check for upcoming changes.")
if SiteSetting.upcoming_change_site_settings.empty?
verbose_log(site, :info, "No upcoming changes present.")
next
end
DistributedMutex.synchronize("promote_upcoming_changes_#{site}") do
SiteSetting.upcoming_change_site_settings.each do |setting_name|
UpcomingChanges::Promote.call(
params: {
setting_name:,
promotion_status_threshold: SiteSetting.promote_upcoming_changes_on_status,
},
guardian: Guardian.new(Discourse.system_user),
) do |result|
on_failed_policy(:meets_promotion_criteria) do
verbose_log(
site,
:warn,
"'#{setting_name}' did not meet promotion criteria. Current status is #{UpcomingChanges.change_status(setting_name)}, required status is #{SiteSetting.promote_upcoming_changes_on_status}.",
)
end
on_failed_policy(:setting_not_modified) do
verbose_log(
site,
:warn,
"'#{setting_name}' has already been modified by an admin, skipping promotion.",
)
end
on_failed_policy(:setting_not_already_enabled) do
verbose_log(
site,
:warn,
"'#{setting_name}' is already enabled, skipping promotion.",
)
end
on_failed_contract do |contract|
verbose_log(
site,
:error,
"Contract failure when promoting '#{setting_name}': #{contract.errors.full_messages.join(", ")}",
)
end
on_failed_step(:toggle_upcoming_change) do
verbose_log(
site,
:error,
"Failed to promote '#{setting_name}' via toggle_upcoming_change, an unexpected error occurred.",
)
end
on_failure do |error|
verbose_log(
site,
:error,
"Failed to promote '#{setting_name}', an unexpected error occurred. Error: #{error&.backtrace&.join("\n")}",
)
end
on_success do
verbose_log(site, :info, "Successfully promoted '#{setting_name}' to enabled.")
end
end
end
end
end
end
end
end