From b9e34ef098026eaa451f42927ce72cb5ba48f413 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Sat, 25 Mar 2023 19:39:24 -0400 Subject: [PATCH] Migration warning helper, and only run in production env (#24253) --- db/migrate/20170918125918_ids_to_bigints.rb | 26 +++------ ...0180528141303_fix_accounts_unique_index.rb | 25 +++------ ...024224956_migrate_account_conversations.rb | 18 ++---- lib/mastodon/migration_warning.rb | 55 +++++++++++++++++++ 4 files changed, 77 insertions(+), 47 deletions(-) create mode 100644 lib/mastodon/migration_warning.rb diff --git a/db/migrate/20170918125918_ids_to_bigints.rb b/db/migrate/20170918125918_ids_to_bigints.rb index bf875e4e5..e3fc34a51 100644 --- a/db/migrate/20170918125918_ids_to_bigints.rb +++ b/db/migrate/20170918125918_ids_to_bigints.rb @@ -1,7 +1,9 @@ -require Rails.root.join('lib', 'mastodon', 'migration_helpers') +require_relative '../../lib/mastodon/migration_helpers' +require_relative '../../lib/mastodon/migration_warning' class IdsToBigints < ActiveRecord::Migration[5.1] include Mastodon::MigrationHelpers + include Mastodon::MigrationWarning disable_ddl_transaction! @@ -69,24 +71,12 @@ class IdsToBigints < ActiveRecord::Migration[5.1] ] included_columns << [:deprecated_preview_cards, :id] if table_exists?(:deprecated_preview_cards) - # Print out a warning that this will probably take a while. - if $stdout.isatty - say '' - say 'WARNING: This migration may take a *long* time for large instances' - say 'It will *not* lock tables for any significant time, but it may run' - say 'for a very long time. We will pause for 10 seconds to allow you to' - say 'interrupt this migration if you are not ready.' - say '' - say 'This migration has some sections that can be safely interrupted' - say 'and restarted later, and will tell you when those are occurring.' - say '' - say 'For more information, see https://github.com/mastodon/mastodon/pull/5088' + migration_duration_warning(<<~EXPLANATION) + This migration has some sections that can be safely interrupted + and restarted later, and will tell you when those are occurring. - 10.downto(1) do |i| - say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true - sleep 1 - end - end + For more information, see https://github.com/mastodon/mastodon/pull/5088 + EXPLANATION tables = included_columns.map(&:first).uniq table_sizes = {} diff --git a/db/migrate/20180528141303_fix_accounts_unique_index.rb b/db/migrate/20180528141303_fix_accounts_unique_index.rb index 0b39f7107..1e67b4bb4 100644 --- a/db/migrate/20180528141303_fix_accounts_unique_index.rb +++ b/db/migrate/20180528141303_fix_accounts_unique_index.rb @@ -1,4 +1,8 @@ +require_relative '../../lib/mastodon/migration_warning' + class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2] + include Mastodon::MigrationWarning + class Account < ApplicationRecord # Dummy class, to make migration possible across version changes has_one :user, inverse_of: :account @@ -35,22 +39,11 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2] disable_ddl_transaction! def up - if $stdout.isatty - say '' - say 'WARNING: This migration may take a *long* time for large instances' - say 'It will *not* lock tables for any significant time, but it may run' - say 'for a very long time. We will pause for 10 seconds to allow you to' - say 'interrupt this migration if you are not ready.' - say '' - say 'This migration will irreversibly delete user accounts with duplicate' - say 'usernames. You may use the `rake mastodon:maintenance:find_duplicate_usernames`' - say 'task to manually deal with such accounts before running this migration.' - - 10.downto(1) do |i| - say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true - sleep 1 - end - end + migration_duration_warning(<<~EXPLANATION) + This migration will irreversibly delete user accounts with duplicate + usernames. You may use the `rake mastodon:maintenance:find_duplicate_usernames` + task to manually deal with such accounts before running this migration. + EXPLANATION duplicates = Account.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM accounts GROUP BY lower(username), lower(domain) HAVING count(*) > 1').to_ary diff --git a/db/migrate/20181024224956_migrate_account_conversations.rb b/db/migrate/20181024224956_migrate_account_conversations.rb index aca6638e1..e4dcdb18b 100644 --- a/db/migrate/20181024224956_migrate_account_conversations.rb +++ b/db/migrate/20181024224956_migrate_account_conversations.rb @@ -1,4 +1,8 @@ +require_relative '../../lib/mastodon/migration_warning' + class MigrateAccountConversations < ActiveRecord::Migration[5.2] + include Mastodon::MigrationWarning + disable_ddl_transaction! class Mention < ApplicationRecord @@ -62,19 +66,7 @@ class MigrateAccountConversations < ActiveRecord::Migration[5.2] end def up - if $stdout.isatty - say '' - say 'WARNING: This migration may take a *long* time for large instances' - say 'It will *not* lock tables for any significant time, but it may run' - say 'for a very long time. We will pause for 10 seconds to allow you to' - say 'interrupt this migration if you are not ready.' - say '' - - 10.downto(1) do |i| - say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true - sleep 1 - end - end + migration_duration_warning migrated = 0 last_time = Time.zone.now diff --git a/lib/mastodon/migration_warning.rb b/lib/mastodon/migration_warning.rb new file mode 100644 index 000000000..227f6705d --- /dev/null +++ b/lib/mastodon/migration_warning.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Mastodon + module MigrationWarning + WARNING_SECONDS = 10 + + DEFAULT_WARNING = <<~WARNING_MESSAGE + WARNING: This migration may take a *long* time for large instances. + It will *not* lock tables for any significant time, but it may run + for a very long time. We will pause for #{WARNING_SECONDS} seconds to allow you to + interrupt this migration if you are not ready. + WARNING_MESSAGE + + def migration_duration_warning(explanation = nil) + return unless valid_environment? + + announce_warning(explanation) + + announce_countdown + end + + private + + def announce_countdown + WARNING_SECONDS.downto(1) do |i| + say "Continuing in #{i} second#{i == 1 ? '' : 's'}...", true + sleep 1 + end + end + + def valid_environment? + $stdout.isatty && Rails.env.production? + end + + def announce_warning(explanation) + announce_message prepare_message(explanation) + end + + def announce_message(text) + say '' + text.each_line do |line| + say(line) + end + say '' + end + + def prepare_message(explanation) + if explanation.blank? + DEFAULT_WARNING + else + DEFAULT_WARNING + "\n#{explanation}" + end + end + end +end