diff options
author | Bob Van Landuyt <bob@gitlab.com> | 2017-06-06 17:24:32 +0200 |
---|---|---|
committer | Bob Van Landuyt <bob@vanlanduyt.co> | 2017-06-26 17:49:30 +0200 |
commit | 0faff42d7cc62dba50ca99ab1bc034c285311409 (patch) | |
tree | 8b92d208c13fa80410248ac4c7ce1b1135bbf1c7 | |
parent | 3e84b6336f3d61ff56e3e8ef5cc5d8ca08ef0432 (diff) | |
download | gitlab-ce-0faff42d7cc62dba50ca99ab1bc034c285311409.tar.gz |
Add methods to revert project renames
4 files changed, 146 insertions, 22 deletions
diff --git a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base.rb b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base.rb index a8febf4ec62..29f21b08e6c 100644 --- a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base.rb +++ b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base.rb @@ -7,6 +7,7 @@ module Gitlab delegate :update_column_in_batches, :replace_sql, + :say, to: :migration def initialize(paths, migration) @@ -26,13 +27,18 @@ module Gitlab new_path = rename_path(namespace_path, old_path) new_full_path = join_routable_path(namespace_path, new_path) + perform_rename(routable, old_full_path, new_full_path) + + [old_full_path, new_full_path] + end + + def perform_rename(routable, old_full_path, new_full_path) # skips callbacks & validations - routable.class.where(id: routable) - .update_all(path: new_path) + new_path = new_full_path.split('/').last + routable.class.where(id: routable). + update_all(path: new_path) rename_routes(old_full_path, new_full_path) - - [old_full_path, new_full_path] end def rename_routes(old_full_path, new_full_path) @@ -86,7 +92,10 @@ module Gitlab def move_folders(directory, old_relative_path, new_relative_path) old_path = File.join(directory, old_relative_path) - return unless File.directory?(old_path) + unless File.directory?(old_path) + say "#{old_path} doesn't exist, skipping" + return + end new_path = File.join(directory, new_relative_path) FileUtils.mv(old_path, new_path) @@ -115,10 +124,25 @@ module Gitlab end def track_rename(type, old_path, new_path) - key = "rename:#{migration.version}:#{type}" + key = redis_key_for_type(type) Gitlab::Redis.with { |redis| redis.lpush(key, [old_path, new_path].to_json) } end + def reverts_for_type(type) + key = redis_key_for_type(type) + Gitlab::Redis.with do |redis| + while rename_info = redis.lpop(key) + path_before_rename, path_after_rename = JSON.parse(rename_info) + say "renaming #{type} from #{path_after_rename} back to #{path_before_rename}" + yield(path_before_rename, path_after_rename) + end + end + end + + def redis_key_for_type(type) + "rename:#{migration.version}:#{type}" + end + def file_storage? CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File end diff --git a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb index 59e47120159..1d2a41d91bb 100644 --- a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb +++ b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb @@ -18,12 +18,31 @@ module Gitlab track_rename('project', old_full_path, new_full_path) + move_project_folders(project, old_full_path, new_full_path) + end + + def move_project_folders(project, old_full_path, new_full_path) move_repository(project, old_full_path, new_full_path) move_repository(project, "#{old_full_path}.wiki", "#{new_full_path}.wiki") move_uploads(old_full_path, new_full_path) move_pages(old_full_path, new_full_path) end + def revert_renames + reverts_for_type('project') do |path_before_rename, current_path| + matches_path = MigrationClasses::Route.arel_table[:path].matches(current_path) + project = MigrationClasses::Project.joins(:route) + .where(matches_path).first + if project + perform_rename(project, current_path, path_before_rename) + + move_project_folders(project, current_path, path_before_rename) + else + say "Couldn't rename project##{project.id} from #{current_path} back to #{path_before_rename}, project no longer exists" + end + end + end + def move_repository(project, old_path, new_path) unless gitlab_shell.mv_repository(project.repository_storage_path, old_path, diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb index fa3c86bbb4f..4f6f06f0d07 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb @@ -153,6 +153,30 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca end end + describe '#perform_rename' do + describe 'for namespaces' do + let(:namespace) { create(:namespace, path: 'the-path') } + it 'renames the path' do + subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed') + + expect(namespace.reload.path).to eq('renamed') + end + + it 'renames all the routes for the namespace' do + child = create(:group, path: 'child', parent: namespace) + project = create(:project, namespace: child, path: 'the-project') + other_one = create(:namespace, path: 'the-path-is-similar') + + subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed') + + expect(namespace.reload.route.path).to eq('renamed') + expect(child.reload.route.path).to eq('renamed/child') + expect(project.reload.route.path).to eq('renamed/child/the-project') + expect(other_one.reload.route.path).to eq('the-path-is-similar') + end + end + end + describe '#move_pages' do it 'moves the pages directory' do expect(subject).to receive(:move_folders) @@ -220,4 +244,17 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca expect(new_path).to eq('path/to/renamed') end end + + describe '#reverts_for_type', redis: true do + it 'yields for each tracked rename' do + subject.track_rename('project', 'old_path', 'new_path') + subject.track_rename('project', 'old_path2', 'new_path2') + subject.track_rename('namespace', 'namespace_path', 'new_namespace_path') + + expect { |b| subject.reverts_for_type('project', &b) } + .to yield_successive_args(%w(old_path2 new_path2), %w(old_path new_path)) + expect { |b| subject.reverts_for_type('namespace', &b) } + .to yield_with_args('namespace_path', 'new_namespace_path') + end + end end diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb index ed2f2241ab6..f87f4371353 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb @@ -3,6 +3,12 @@ require 'spec_helper' describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :truncate do let(:migration) { FakeRenameReservedPathMigrationV1.new } let(:subject) { described_class.new(['the-path'], migration) } + let(:project) do + create(:empty_project, + path: 'the-path', + namespace: create(:namespace, path: 'known-parent' )) + end + before do allow(migration).to receive(:say) @@ -47,12 +53,6 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr end describe '#rename_project' do - let(:project) do - create(:empty_project, - path: 'the-path', - namespace: create(:namespace, path: 'known-parent' )) - end - it 'renames path & route for the project' do expect(subject).to receive(:rename_path_for_routable) .with(project) @@ -63,34 +63,42 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr expect(project.reload.path).to eq('the-path0') end + it 'tracks the rename' do + expect(subject).to receive(:track_rename) + .with('project', 'known-parent/the-path', 'known-parent/the-path0') + + subject.rename_project(project) + end + + it 'renames the folders for the project' do + expect(subject).to receive(:move_project_folders).with(project, 'known-parent/the-path', 'known-parent/the-path0') + + subject.rename_project(project) + end + end + + describe '#move_project_folders' do it 'moves the wiki & the repo' do expect(subject).to receive(:move_repository) .with(project, 'known-parent/the-path.wiki', 'known-parent/the-path0.wiki') expect(subject).to receive(:move_repository) .with(project, 'known-parent/the-path', 'known-parent/the-path0') - subject.rename_project(project) + subject.move_project_folders(project, 'known-parent/the-path', 'known-parent/the-path0') end it 'moves uploads' do expect(subject).to receive(:move_uploads) .with('known-parent/the-path', 'known-parent/the-path0') - subject.rename_project(project) + subject.move_project_folders(project, 'known-parent/the-path', 'known-parent/the-path0') end it 'moves pages' do expect(subject).to receive(:move_pages) .with('known-parent/the-path', 'known-parent/the-path0') - subject.rename_project(project) - end - - it 'tracks the rename' do - expect(subject).to receive(:track_rename) - .with('project', 'known-parent/the-path', 'known-parent/the-path0') - - subject.rename_project(project) + subject.move_project_folders(project, 'known-parent/the-path', 'known-parent/the-path0') end end @@ -106,4 +114,40 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr expect(File.directory?(expected_path)).to be(true) end end + + describe '#revert_renames', redis: true do + it 'renames the routes back to the previous values' do + subject.rename_project(project) + + expect(subject).to receive(:perform_rename) + .with( + kind_of(Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Project), + 'known-parent/the-path0', + 'known-parent/the-path' + ).and_call_original + + subject.revert_renames + + expect(project.reload.path).to eq('the-path') + expect(project.route.path).to eq('known-parent/the-path') + end + + it 'moves the repositories back to their original place' do + project.create_repository + subject.rename_project(project) + + expected_path = File.join(TestEnv.repos_path, 'known-parent', 'the-path.git') + + expect(subject).to receive(:move_project_folders) + .with( + kind_of(Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Project), + 'known-parent/the-path0', + 'known-parent/the-path' + ).and_call_original + + subject.revert_renames + + expect(File.directory?(expected_path)).to be_truthy + end + end end |