summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToon Claes <toon@gitlab.com>2017-05-02 13:59:18 +0200
committerToon Claes <toon@gitlab.com>2017-05-10 15:01:27 +0200
commit1af540122563c372c03668f36e6a2123bff94222 (patch)
tree9e4774b63a625d475c0797d05cd11a3adf127200
parent09c2aab4aa4661b147545e2c41b6a0100fc57b11 (diff)
downloadgitlab-ce-1af540122563c372c03668f36e6a2123bff94222.tar.gz
Add post-deploy migrate to cleanup projects in pending delete state
There are many projects in `pending_delete` state, this post-deploy migration cleans them up. The script is based on https://gitlab.com/gitlab-org/gitlab-ce/snippets/1648654 and https://gitlab.com/gitlab-org/gitlab-ce/snippets/1611429. The use of these scripts were described in https://gitlab.com/gitlab-com/infrastructure/issues/888.
-rw-r--r--changelogs/unreleased/tc-clean-pending-delete-projects.yml4
-rw-r--r--db/post_migrate/20170502101023_clean_up_pending_delete_projects.rb47
-rw-r--r--spec/migrations/clean_up_pending_delete_projects_spec.rb72
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