DEV: Promote old post-deploy migrations to pre-deploy migrations (#13477)

Having a large number of post-deploy migrations running out-of-numerical-sequence with pre-deploy migrations can be problematic. For example, if we have the sequence

- db/migrate/2017... - add column
- db/post_migrate/2018... - drop the column
- db/migrate/2021... - add the same column again

It will work fine in numerical order. But if you run the pre-deploy migrations **followed by** the post-deploy migrations, you will not get the same result.

Our post-deploy system is designed to allow for seamless upgrades of Discourse. However, it is reasonable for us to only support this totally seamless experience for a limited period of time. This commit moves all post_deploy migrations which are more than 1 year old (i.e. more than 2 major Discourse versions ago) into the regular pre-deploy migrations directory. This limits the impact of any edge cases caused by out-of-numerical-sequence migrations.
This commit is contained in:
David Taylor
2021-06-22 16:02:24 +01:00
committed by GitHub
parent 820068ddaf
commit e76c583b91
30 changed files with 9 additions and 2 deletions

View File

@@ -1,87 +0,0 @@
# frozen_string_literal: true
require 'migration/column_dropper'
require 'badge_posts_view_manager'
class RemoveSuperfluousColumns < ActiveRecord::Migration[5.2]
DROPPED_COLUMNS ||= {
user_profiles: %i{
card_image_badge_id
},
categories: %i{
logo_url
background_url
suppress_from_homepage
},
groups: %i{
visible
public
alias_level
},
theme_fields: %i{target},
user_stats: %i{first_topic_unread_at},
topics: %i{
auto_close_at
auto_close_user_id
auto_close_started_at
auto_close_based_on_last_post
auto_close_hours
inappropriate_count
bookmark_count
off_topic_count
illegal_count
notify_user_count
last_unread_at
vote_count
},
users: %i{
email
email_always
mailing_list_mode
email_digests
email_direct
email_private_messages
external_links_in_new_tab
enable_quoting
dynamic_favicon
disable_jump_reply
edit_history_public
automatically_unpin_topics
digest_after_days
auto_track_topics_after_msecs
new_topic_duration_minutes
last_redirected_to_top_at
auth_token
auth_token_updated_at
blocked
silenced
trust_level_locked
},
user_auth_tokens: %i{legacy},
user_options: %i{theme_key},
themes: %i{key},
email_logs: %i{
topic_id
reply_key
skipped
skipped_reason
},
posts: %i{vote_count}
}
def up
BadgePostsViewManager.drop!
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
DB.exec "DROP FUNCTION IF EXISTS first_unread_topic_for(int)"
BadgePostsViewManager.create!
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,21 +0,0 @@
# frozen_string_literal: true
require 'migration/table_dropper'
class RemoveSuperfluousTables < ActiveRecord::Migration[5.2]
DROPPED_TABLES ||= %i{
category_featured_users
versions
topic_status_updates
}
def up
DROPPED_TABLES.each do |table|
Migration::TableDropper.execute_drop(table)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
require 'migration/column_dropper'
class DropGroupLockedTrustLevelFromUser < ActiveRecord::Migration[5.2]
DROPPED_COLUMNS ||= {
posts: %i{group_locked_trust_level}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
class MigrateUrlSiteSettings < ActiveRecord::Migration[5.2]
def change
# Do nothing, the migration was moved into a onceoff job
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
require 'migration/column_dropper'
class RemoveUploadedMetaIdFromCategory < ActiveRecord::Migration[5.2]
DROPPED_COLUMNS ||= {
categories: %i{uploaded_meta_id}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
class DropQueuedPostIdFromUserActions < ActiveRecord::Migration[5.2]
def up
remove_column :user_actions, :queued_post_id
end
def down
add_column :user_actions, :queued_post_id, :integer
end
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
class DropQueuedPosts < ActiveRecord::Migration[5.2]
def up
drop_table :queued_posts
end
end

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
require 'migration/table_dropper'
class DropUnusedAuthTables < ActiveRecord::Migration[5.2]
def change
# this migration was defect
end
end

View File

@@ -1,20 +0,0 @@
# frozen_string_literal: true
require 'migration/table_dropper'
class DropUnusedAuthTablesAgain < ActiveRecord::Migration[5.2]
DROPPED_TABLES ||= %i{
facebook_user_infos
twitter_user_infos
}
def up
DROPPED_TABLES.each do |table|
Migration::TableDropper.execute_drop(table)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,23 +0,0 @@
# frozen_string_literal: true
require 'migration/column_dropper'
class DropEmailUserOptionsColumns < ActiveRecord::Migration[5.2]
DROPPED_COLUMNS ||= {
user_options: %i{
email_direct
email_private_messages
email_always
},
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
class DropClaimedById < ActiveRecord::Migration[5.2]
def up
remove_column :reviewables, :claimed_by_id
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
require 'migration/column_dropper'
class RemoveViaEmailFromInvite < ActiveRecord::Migration[5.2]
DROPPED_COLUMNS ||= {
invites: %i{via_email}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
class ChangeNotificationLevel < ActiveRecord::Migration[6.0]
def up
change_column :category_users, :notification_level, :integer, null: true
end
def down
change_column :category_users, :notification_level, :integer, null: false
end
end

View File

@@ -1,48 +0,0 @@
# frozen_string_literal: true
class RemoveSuppressFromLatestFromCategory < ActiveRecord::Migration[6.0]
DROPPED_COLUMNS ||= {
categories: %i{suppress_from_latest}
}
def up
ids = DB.query_single("SELECT id::text FROM categories WHERE suppress_from_latest = TRUE")
if ids.present?
muted_ids = DB.query_single("SELECT value from site_settings WHERE name = 'default_categories_muted'").first
ids += muted_ids.split("|") if muted_ids.present?
ids.uniq!
# We shouldn't encourage to have more than 10 categories in `default_categories_muted` site setting.
if ids.count <= 10
# CategoryUser.notification_levels[:muted] is 0, avoid reaching to object model
DB.exec(<<~SQL, muted: 0)
INSERT INTO category_users (category_id, user_id, notification_level)
SELECT c.id category_id, u.id user_id, :muted
FROM users u
CROSS JOIN categories c
LEFT JOIN category_users cu
ON u.id = cu.user_id
AND c.id = cu.category_id
WHERE c.suppress_from_latest = TRUE
AND cu.notification_level IS NULL
ON CONFLICT DO NOTHING
SQL
DB.exec(<<~SQL, value: ids.join("|"))
UPDATE site_settings
SET value = :value
WHERE name = 'default_categories_muted'
SQL
end
end
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,20 +0,0 @@
# frozen_string_literal: true
require 'migration/table_dropper'
class DropUnusedGoogleInstagramAuthTables < ActiveRecord::Migration[6.0]
DROPPED_TABLES ||= %i{
google_user_infos
instagram_user_infos
}
def up
DROPPED_TABLES.each do |table|
Migration::TableDropper.execute_drop(table)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,16 +0,0 @@
# frozen_string_literal: true
class RemoveKeyFromApiKeys < ActiveRecord::Migration[6.0]
DROPPED_COLUMNS ||= {
api_keys: %i{key}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
class MakePostReplyIdColumnReadOnly < ActiveRecord::Migration[6.0]
def up
Migration::ColumnDropper.mark_readonly(:post_replies, :reply_id)
DB.exec("DROP FUNCTION IF EXISTS post_replies_sync_reply_id() CASCADE")
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,23 +0,0 @@
# frozen_string_literal: true
class DropUnusedColumns < ActiveRecord::Migration[6.0]
DROPPED_COLUMNS ||= {
post_replies: %i{
reply_id
},
user_profiles: %i{
card_background
profile_background
}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
class DropOldUnreadPmNotificationIndices < ActiveRecord::Migration[6.0]
def up
DB.exec("DROP INDEX IF EXISTS index_notifications_on_user_id_and_id")
DB.exec("DROP INDEX IF EXISTS index_notifications_on_read_or_n_type")
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,17 +0,0 @@
# frozen_string_literal: true
class RemoveKeyFromUserApiKey < ActiveRecord::Migration[6.0]
DROPPED_COLUMNS ||= {
user_api_keys: %i{key}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
class DropAutomaticMembershipRetroactiveFromGroup < ActiveRecord::Migration[6.0]
DROPPED_COLUMNS ||= {
groups: %i{
automatic_membership_retroactive
}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,13 +0,0 @@
# frozen_string_literal: true
class RemoveCanonicalEmailFromUserEmails < ActiveRecord::Migration[6.0]
def up
execute <<~SQL
ALTER TABLE user_emails
DROP COLUMN IF EXISTS canonical_email
SQL
end
def down
# nothing to do, we already nuke the migrations
end
end

View File

@@ -1,41 +0,0 @@
# frozen_string_literal: true
class RemoveAvgTimeFromTopicsPosts < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
# this makes it re-runnable and also works if it was not created initially
execute <<~SQL
ALTER TABLE topics DROP COLUMN IF EXISTS avg_time
SQL
ActiveRecord::Base.transaction do
execute "DROP VIEW badge_posts"
execute <<~SQL
ALTER TABLE posts DROP COLUMN IF EXISTS avg_time
SQL
# we must recreate this view every time we amend posts
# p.* is auto expanded and persisted into the view definition
# at create time
execute <<~SQL
CREATE VIEW badge_posts AS
SELECT p.*
FROM posts p
JOIN topics t ON t.id = p.topic_id
JOIN categories c ON c.id = t.category_id
WHERE c.allow_badges AND
p.deleted_at IS NULL AND
t.deleted_at IS NULL AND
NOT c.read_restricted AND
t.visible AND
p.post_type IN (1,2,3)
SQL
end
end
def down
# do nothing re-runnable
end
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
class AllowNullOldEmailOnEmailChangeRequests < ActiveRecord::Migration[6.0]
def up
change_column :email_change_requests, :old_email, :string, null: true
end
def down
change_column :email_change_requests, :old_email, :string, null: false
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
class DropTopicReplyCount < ActiveRecord::Migration[6.0]
DROPPED_COLUMNS ||= {
user_stats: %i{
topic_reply_count
}
}
def up
DROPPED_COLUMNS.each do |table, columns|
Migration::ColumnDropper.execute_drop(table, columns)
end
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
class RemoveFksFromBookmarks < ActiveRecord::Migration[6.0]
def change
remove_foreign_key :bookmarks, :topics
remove_foreign_key :bookmarks, :posts
remove_foreign_key :bookmarks, :users
end
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
class RemoveAccessControlPostFk < ActiveRecord::Migration[6.0]
def change
remove_foreign_key :uploads, column: :access_control_post_id
end
end

View File

@@ -1,40 +0,0 @@
# frozen_string_literal: true
class RemoveImageUrlFromPostAndTopic < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
execute <<~SQL
ALTER TABLE topics DROP COLUMN IF EXISTS image_url
SQL
ActiveRecord::Base.transaction do
execute "DROP VIEW badge_posts"
execute <<~SQL
ALTER TABLE posts DROP COLUMN IF EXISTS image_url
SQL
# we must recreate this view every time we amend posts
# p.* is auto expanded and persisted into the view definition
# at create time
execute <<~SQL
CREATE VIEW badge_posts AS
SELECT p.*
FROM posts p
JOIN topics t ON t.id = p.topic_id
JOIN categories c ON c.id = t.category_id
WHERE c.allow_badges AND
p.deleted_at IS NULL AND
t.deleted_at IS NULL AND
NOT c.read_restricted AND
t.visible AND
p.post_type IN (1,2,3)
SQL
end
end
def down
# do nothing re-runnable
end
end

View File

@@ -1,48 +0,0 @@
# frozen_string_literal: true
class CorrectPostsSchema < ActiveRecord::Migration[6.0]
# In the past, rails changed the default behavior for varchar columns
# This only affects older discourse installations
# This migration removes the character limits from posts columns, so that they match modern behavior
#
# To modify the posts table schema we need to recreate the badge_posts view
# This should be done in a transaction
def up
result = DB.query <<~SQL
SELECT character_maximum_length
FROM information_schema.columns
WHERE table_schema='public'
AND table_name = 'posts'
AND column_name IN ('action_code', 'edit_reason')
SQL
# No need to continue if the schema is already correct
return if result.all? { |r| r.character_maximum_length.nil? }
execute "DROP VIEW badge_posts"
execute "ALTER TABLE posts ALTER COLUMN action_code TYPE varchar"
execute "ALTER TABLE posts ALTER COLUMN edit_reason TYPE varchar"
# we must recreate this view every time we amend posts
# p.* is auto expanded and persisted into the view definition
# at create time
execute <<~SQL
CREATE VIEW badge_posts AS
SELECT p.*
FROM posts p
JOIN topics t ON t.id = p.topic_id
JOIN categories c ON c.id = t.category_id
WHERE c.allow_badges AND
p.deleted_at IS NULL AND
t.deleted_at IS NULL AND
NOT c.read_restricted AND
t.visible AND
p.post_type IN (1,2,3)
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end