Commit d8f6a9d6 authored by pbair's avatar pbair

Move file manipulation into CustomStructure class

Move logic for manipulating the gitlab_structure.sql file into the
CustomStructure class rather than directly in the rake task, to prevent
multiple versions of the file being written inadvertently.
parent dc349c67
...@@ -3,10 +3,18 @@ ...@@ -3,10 +3,18 @@
module Gitlab module Gitlab
module Database module Database
class CustomStructure class CustomStructure
def dump(io) CUSTOM_DUMP_FILE = 'db/gitlab_structure.sql'.freeze
io << "SET search_path=public;\n\n"
dump_partitioned_foreign_keys(io) if partitioned_foreign_keys_exist? def dump
File.open(self.class.custom_dump_filepath, 'wb') do |io|
io << "SET search_path=public;\n\n"
dump_partitioned_foreign_keys(io) if partitioned_foreign_keys_exist?
end
end
def self.custom_dump_filepath
Rails.root.join(CUSTOM_DUMP_FILE)
end end
private private
......
namespace :gitlab do namespace :gitlab do
namespace :db do namespace :db do
CUSTOM_DUMP_FILE = 'db/gitlab_structure.sql'.freeze
desc 'GitLab | DB | Manually insert schema migration version' desc 'GitLab | DB | Manually insert schema migration version'
task :mark_migration_complete, [:version] => :environment do |_, args| task :mark_migration_complete, [:version] => :environment do |_, args|
unless args[:version] unless args[:version]
...@@ -96,15 +94,13 @@ namespace :gitlab do ...@@ -96,15 +94,13 @@ namespace :gitlab do
desc 'This dumps GitLab specific database details - it runs after db:structure:dump' desc 'This dumps GitLab specific database details - it runs after db:structure:dump'
task :dump_custom_structure do |task_name| task :dump_custom_structure do |task_name|
File.open(CUSTOM_DUMP_FILE, 'wb+') do |io| Gitlab::Database::CustomStructure.new.dump
Gitlab::Database::CustomStructure.new.dump(io)
end
# Allow this task to be called multiple times, as happens when running db:migrate:redo # Allow this task to be called multiple times, as happens when running db:migrate:redo
Rake::Task[task_name].reenable Rake::Task[task_name].reenable
end end
desc 'This loads Gitlab specific database details - runs after db:structure:dump' desc 'This loads GitLab specific database details - runs after db:structure:dump'
task :load_custom_structure do task :load_custom_structure do
configuration = Rails.application.config_for(:database) configuration = Rails.application.config_for(:database)
...@@ -113,9 +109,10 @@ namespace :gitlab do ...@@ -113,9 +109,10 @@ namespace :gitlab do
ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password'] ENV['PGPASSWORD'] = configuration['password'].to_s if configuration['password']
ENV['PGUSER'] = configuration['username'].to_s if configuration['username'] ENV['PGUSER'] = configuration['username'].to_s if configuration['username']
args = ['-v', 'ON_ERROR_STOP=1', '-q', '-X', '-f', CUSTOM_DUMP_FILE] dump_filepath = Gitlab::Database::CustomStructure.custom_dump_filepath.to_path
args << configuration['database'] args = ['-v', 'ON_ERROR_STOP=1', '-q', '-X', '-f', dump_filepath, configuration['database']]
system('psql', *args)
Kernel.system('psql', *args)
end end
# Inform Rake that custom tasks should be run every time rake db:structure:dump is run # Inform Rake that custom tasks should be run every time rake db:structure:dump is run
......
...@@ -4,11 +4,16 @@ require 'spec_helper' ...@@ -4,11 +4,16 @@ require 'spec_helper'
describe Gitlab::Database::CustomStructure do describe Gitlab::Database::CustomStructure do
let_it_be(:structure) { described_class.new } let_it_be(:structure) { described_class.new }
let_it_be(:filepath) { Rails.root.join(described_class::CUSTOM_DUMP_FILE) }
let(:io) { StringIO.new } let(:io) { StringIO.new }
before do
allow(File).to receive(:open).with(filepath, anything).and_yield(io)
end
context 'when there are no partitioned_foreign_keys' do context 'when there are no partitioned_foreign_keys' do
it 'dumps a valid structure file' do it 'dumps a valid structure file' do
structure.dump(io) structure.dump
expect(io.string).to eq("SET search_path=public;\n\n") expect(io.string).to eq("SET search_path=public;\n\n")
end end
...@@ -24,8 +29,8 @@ describe Gitlab::Database::CustomStructure do ...@@ -24,8 +29,8 @@ describe Gitlab::Database::CustomStructure do
cascade_delete: false, from_table: 'issues', from_column: 'moved_to_id', to_table: 'issues', to_column: 'id') cascade_delete: false, from_table: 'issues', from_column: 'moved_to_id', to_table: 'issues', to_column: 'id')
end end
it 'dumps a file with the command to restore the keys' do it 'dumps a file with the command to restore the current keys' do
structure.dump(io) structure.dump
expect(io.string).to eq(<<~DATA) expect(io.string).to eq(<<~DATA)
SET search_path=public; SET search_path=public;
...@@ -35,6 +40,20 @@ describe Gitlab::Database::CustomStructure do ...@@ -35,6 +40,20 @@ describe Gitlab::Database::CustomStructure do
#{second_fk.id}\tfalse\tissues\tmoved_to_id\tissues\tid #{second_fk.id}\tfalse\tissues\tmoved_to_id\tissues\tid
\\. \\.
DATA DATA
first_fk.destroy
io.truncate(0)
io.rewind
structure.dump
expect(io.string).to eq(<<~DATA)
SET search_path=public;
COPY partitioned_foreign_keys (id, cascade_delete, from_table, from_column, to_table, to_column) FROM STDIN;
#{second_fk.id}\tfalse\tissues\tmoved_to_id\tissues\tid
\\.
DATA
end end
end end
end end
...@@ -115,19 +115,43 @@ describe 'gitlab:db namespace rake task' do ...@@ -115,19 +115,43 @@ describe 'gitlab:db namespace rake task' do
end end
it 'can be executed multiple times within another rake task' do it 'can be executed multiple times within another rake task' do
Rake::Task.define_task(test_task_name => :environment) do expect_multiple_executions_of_task(test_task_name, clean_rake_task) do
expect_next_instance_of(Gitlab::Database::SchemaCleaner) do |cleaner| expect_next_instance_of(Gitlab::Database::SchemaCleaner) do |cleaner|
expect(cleaner).to receive(:clean).with(output) expect(cleaner).to receive(:clean).with(output)
end end
Rake::Task[clean_rake_task].invoke end
end
end
expect_next_instance_of(Gitlab::Database::SchemaCleaner) do |cleaner| describe 'load_custom_structure' do
expect(cleaner).to receive(:clean).with(output) let_it_be(:db_config) { Rails.application.config_for(:database) }
let_it_be(:custom_load_task) { 'gitlab:db:load_custom_structure' }
let_it_be(:custom_filepath) { Pathname.new('db/directory') }
it 'use the psql command to load the custom structure file' do
expect(Gitlab::Database::CustomStructure).to receive(:custom_dump_filepath).and_return(custom_filepath)
expect(Kernel).to receive(:system)
.with('psql', any_args, custom_filepath.to_path, db_config['database'])
run_rake_task(custom_load_task)
end
end
describe 'dump_custom_structure' do
let_it_be(:test_task_name) { 'gitlab:db:_test_multiple_task_executions' }
let_it_be(:custom_dump_task) { 'gitlab:db:dump_custom_structure' }
after do
Rake::Task[test_task_name].clear if Rake::Task.task_defined?(test_task_name)
end
it 'can be executed multiple times within another rake task' do
expect_multiple_executions_of_task(test_task_name, custom_dump_task) do
expect_next_instance_of(Gitlab::Database::CustomStructure) do |custom_structure|
expect(custom_structure).to receive(:dump)
end end
Rake::Task[clean_rake_task].invoke
end end
run_rake_task(test_task_name)
end end
end end
...@@ -135,4 +159,16 @@ describe 'gitlab:db namespace rake task' do ...@@ -135,4 +159,16 @@ describe 'gitlab:db namespace rake task' do
Rake::Task[task_name].reenable Rake::Task[task_name].reenable
Rake.application.invoke_task task_name Rake.application.invoke_task task_name
end end
def expect_multiple_executions_of_task(test_task_name, task_to_invoke, count: 2)
Rake::Task.define_task(test_task_name => :environment) do
count.times do
yield
Rake::Task[task_to_invoke].invoke
end
end
run_rake_task(test_task_name)
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment