mirror of
https://github.com/discourse/discourse.git
synced 2024-12-02 17:43:43 +08:00
40fa96777d
This moves us away from the delayed drops pattern which was problematic on two counts. First, it uses a hardcoded "delay for" duration which may be too short for certain deployment strategies. Second, delayed drop doesn't ensure that it only runs after the latest application code has been deployed. If the migration runs and the application code fails to deploy, running the migration after "delay for" has been met will cause the application to blow up. The new strategy allows post deployment migrations to be skipped if the env `SKIP_POST_DEPLOYMENT_MIGRATIONS` is provided. ``` SKIP_POST_DEPLOYMENT_MIGRATIONS=1 rake db:migrate -> deploy app servers SKIP_POST_DEPLOYMENT_MIGRATIONS=0 rake db:migrate ``` To aid with the generation of a post deployment migration, a generator has been added. Simply run `rails generate post_migration`.
126 lines
3.2 KiB
Ruby
126 lines
3.2 KiB
Ruby
require 'rails_helper'
|
|
require_dependency 'migration/column_dropper'
|
|
|
|
RSpec.describe Migration::ColumnDropper do
|
|
def has_column?(table, column)
|
|
DB.exec(<<~SQL, table: table, column: column) == 1
|
|
SELECT 1
|
|
FROM INFORMATION_SCHEMA.COLUMNS
|
|
WHERE
|
|
table_schema = 'public' AND
|
|
table_name = :table AND
|
|
column_name = :column
|
|
SQL
|
|
end
|
|
|
|
describe ".execute_drop" do
|
|
let(:columns) { %w{junk junk2} }
|
|
|
|
before do
|
|
columns.each do |column|
|
|
DB.exec("ALTER TABLE topics ADD COLUMN #{column} int")
|
|
end
|
|
end
|
|
|
|
after do
|
|
columns.each do |column|
|
|
DB.exec("ALTER TABLE topics DROP COLUMN IF EXISTS #{column}")
|
|
end
|
|
end
|
|
|
|
it "drops the columns" do
|
|
Migration::ColumnDropper.execute_drop("topics", columns)
|
|
|
|
columns.each do |column|
|
|
expect(has_column?('topics', column)).to eq(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '.mark_readonly' do
|
|
let(:table_name) { "table_with_readonly_column" }
|
|
|
|
before do
|
|
DB.exec <<~SQL
|
|
CREATE TABLE #{table_name} (topic_id INTEGER, email TEXT);
|
|
|
|
INSERT INTO #{table_name} (topic_id, email)
|
|
VALUES (1, 'something@email.com');
|
|
SQL
|
|
|
|
Migration::ColumnDropper.mark_readonly(table_name, 'email')
|
|
end
|
|
|
|
after do
|
|
ActiveRecord::Base.connection.reset!
|
|
|
|
DB.exec <<~SQL
|
|
DROP TABLE IF EXISTS #{table_name};
|
|
DROP FUNCTION IF EXISTS #{Migration::BaseDropper.readonly_function_name(table_name, 'email')} CASCADE;
|
|
SQL
|
|
end
|
|
|
|
it 'should be droppable' do
|
|
Migration::ColumnDropper.execute_drop(table_name, ['email'])
|
|
|
|
expect(has_trigger?(Migration::BaseDropper.readonly_trigger_name(
|
|
table_name, 'email'
|
|
))).to eq(false)
|
|
|
|
expect(has_column?(table_name, 'email')).to eq(false)
|
|
end
|
|
|
|
it 'should prevent updates to the readonly column' do
|
|
begin
|
|
DB.exec <<~SQL
|
|
UPDATE #{table_name}
|
|
SET email = 'testing@email.com'
|
|
WHERE topic_id = 1;
|
|
SQL
|
|
rescue PG::RaiseException => e
|
|
[
|
|
"Discourse: email in #{table_name} is readonly",
|
|
'discourse_functions.raise_table_with_readonly_column_email_readonly()'
|
|
].each do |message|
|
|
expect(e.message).to include(message)
|
|
end
|
|
end
|
|
end
|
|
|
|
it 'should allow updates to the other columns' do
|
|
DB.exec <<~SQL
|
|
UPDATE #{table_name}
|
|
SET topic_id = 2
|
|
WHERE topic_id = 1
|
|
SQL
|
|
|
|
expect(
|
|
ActiveRecord::Base.exec_sql("SELECT * FROM #{table_name};").values
|
|
).to include([2, "something@email.com"])
|
|
end
|
|
|
|
it 'should prevent insertions to the readonly column' do
|
|
expect do
|
|
ActiveRecord::Base.connection.raw_connection.exec <<~SQL
|
|
INSERT INTO #{table_name} (topic_id, email)
|
|
VALUES (2, 'something@email.com');
|
|
SQL
|
|
end.to raise_error(
|
|
PG::RaiseException,
|
|
/Discourse: email in table_with_readonly_column is readonly/
|
|
)
|
|
end
|
|
|
|
it 'should allow insertions to the other columns' do
|
|
DB.exec <<~SQL
|
|
INSERT INTO #{table_name} (topic_id)
|
|
VALUES (2);
|
|
SQL
|
|
|
|
expect(
|
|
DB.query_single("SELECT topic_id FROM #{table_name} WHERE topic_id = 2")
|
|
).to eq([2])
|
|
end
|
|
end
|
|
end
|