diff options
3 files changed, 123 insertions, 0 deletions
diff --git a/changelogs/unreleased/tc-clean-pending-delete-projects.yml b/changelogs/unreleased/tc-clean-pending-delete-projects.yml new file mode 100644 index 00000000000..31b43999c31 --- /dev/null +++ b/changelogs/unreleased/tc-clean-pending-delete-projects.yml @@ -0,0 +1,4 @@ +--- +title: Add post-deploy migration to clean up projects in `pending_delete` state +merge_request: 11044 +author: diff --git a/db/post_migrate/20170502101023_clean_up_pending_delete_projects.rb b/db/post_migrate/20170502101023_clean_up_pending_delete_projects.rb new file mode 100644 index 00000000000..52c7c160ea2 --- /dev/null +++ b/db/post_migrate/20170502101023_clean_up_pending_delete_projects.rb @@ -0,0 +1,47 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class CleanUpPendingDeleteProjects < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + admin = User.find_by(admin: true) + return unless admin + + Project.unscoped.where(pending_delete: true).each { |project| delete_project(project, admin) } + end + + def down + # noop + end + + private + + def delete_project(project, user) + project.team.truncate + + unlink_fork(project) if project.forked? + + [:events, :issues, :merge_requests, :labels, :milestones, :notes, :snippets].each do |thing| + project.send(thing).delete_all + end + + # Override Project#remove_pages for this instance so it doesn't do anything + def project.remove_pages + end + + project.destroy! + end + + def unlink_fork(project) + merge_requests = project.forked_from_project.merge_requests.opened.from_project(project) + + merge_requests.update_all(state: 'closed') + + project.forked_project_link.destroy + end +end diff --git a/spec/migrations/clean_up_pending_delete_projects_spec.rb b/spec/migrations/clean_up_pending_delete_projects_spec.rb new file mode 100644 index 00000000000..a7c13f91245 --- /dev/null +++ b/spec/migrations/clean_up_pending_delete_projects_spec.rb @@ -0,0 +1,72 @@ +# encoding: utf-8 + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170502101023_clean_up_pending_delete_projects.rb') + +describe CleanUpPendingDeleteProjects do + let(:migration) { described_class.new } + let!(:admin) { create(:admin) } + let!(:project) { create(:empty_project, pending_delete: true) } + + describe '#up' do + it 'only cleans up pending delete projects' do + create(:empty_project) + + expect do + migration.up + end.to change { Project.unscoped.count }.by(-1) + end + + it "truncates the project's team" do + project.add_master(admin) + + expect_any_instance_of(ProjectTeam).to receive(:truncate) + + migration.up + end + + it 'calls Project#destroy!' do + expect_any_instance_of(Project).to receive(:destroy!) + + migration.up + end + + it 'does not do anything in Project#remove_pages method' do + expect(Gitlab::PagesTransfer).not_to receive(:new) + + migration.up + end + + context 'project not a fork of another project' do + it "doesn't call unlink_fork" do + expect(migration).not_to receive(:unlink_fork) + + migration.up + end + end + + context 'project forked from another' do + let!(:parent_project) { create(:empty_project) } + + before do + create(:forked_project_link, forked_to_project: project, forked_from_project: parent_project) + end + + it 'closes open merge requests' do + project.update_attribute(:pending_delete, false) # needed to create the MR + merge_request = create(:merge_request, source_project: project, target_project: parent_project) + project.update_attribute(:pending_delete, true) + + migration.up + + expect(merge_request.reload).to be_closed + end + + it 'destroys the link' do + migration.up + + expect(parent_project.forked_project_links).to be_empty + end + end + end +end |