Commit d72b4042 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Rename projects with reserved path names

We cant have project with name 'project' or 'tree' anymore.
This merge request containts a migration that will find and rename all
projects using reserved names by adding N digit to the end of the name.
Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parent 79ce691d
......@@ -921,7 +921,7 @@ class Project < ActiveRecord::Base
Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present"
# we currently doesn't support renaming repository if it contains tags in container registry
raise Exception.new('Project cannot be renamed, because tags are present in its container registry')
raise StandardError.new('Project cannot be renamed, because tags are present in its container registry')
end
if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace)
......@@ -948,7 +948,7 @@ class Project < ActiveRecord::Base
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise Exception.new('repository cannot be renamed')
raise StandardError.new('repository cannot be renamed')
end
Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
......
---
title: Rename projects wth reserved names
merge_request: 8234
author:
class RenameReservedProjectNames < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
include Gitlab::ShellAdapter
DOWNTIME = false
class Project < ActiveRecord::Base; end
def up
threads = reserved_projects.each_slice(100).map do |slice|
Thread.new do
rename_projects(slice)
end
end
threads.each(&:join)
end
def down
# nothing to do here
end
private
def reserved_projects
select_all("SELECT p.id, p.path, p.repository_storage, n.path AS namespace_path, n.id AS namespace_id FROM projects p
INNER JOIN namespaces n ON n.id = p.namespace_id
WHERE p.path IN (
'.well-known', 'all', 'assets', 'files', 'groups', 'hooks', 'issues',
'merge_requests', 'new', 'profile', 'projects', 'public', 'repository',
'robots.txt', 's', 'snippets', 'teams', 'u', 'unsubscribes', 'users',
'tree', 'commits', 'wikis', 'new', 'edit', 'create', 'update', 'logs_tree',
'preview', 'blob', 'blame', 'raw', 'files', 'create_dir', 'find_file')")
end
def route_exists?(full_path)
select_all("SELECT id, path FROM routes WHERE path = '#{quote_string(full_path)}'").present?
end
# Adds number to the end of the path that is not taken by other route
def rename_path(namespace_path, path_was)
counter = 0
path = "#{path_was}#{counter}"
while route_exists?("#{namespace_path}/#{path}")
counter += 1
path = "#{path_was}#{counter}"
end
path
end
def rename_projects(projects)
projects.each do |row|
id = row['id']
path_was = row['path']
namespace_path = row['namespace_path']
path = rename_path(namespace_path, path_was)
project = Project.find_by(id: id)
begin
# Because project path update is quite complex operation we can't safely
# copy-paste all code from GitLab. As exception we use Rails code here
if project &&
project.respond_to?(:update_attributes) &&
project.update_attributes(path: path) &&
project.respond_to?(:rename_repo)
project.rename_repo
end
rescue => e
Rails.logger.error "Exception when rename project #{id}: #{e.message}"
end
end
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20161221140236) do
ActiveRecord::Schema.define(version: 20161221153951) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......
# encoding: utf-8
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20161221153951_rename_reserved_project_names.rb')
describe RenameReservedProjectNames do
let(:migration) { described_class.new }
let!(:project) { create(:project) }
before do
project.path = 'projects'
project.save!(validate: false)
allow(Thread).to receive(:new).and_yield
end
describe '#up' do
context 'when project repository exists' do
before { project.create_repository }
context 'when no exception is raised' do
it 'renames project with reserved names' do
migration.up
expect(project.reload.path).to eq('projects0')
end
end
context 'when exception is raised during rename' do
before do
allow(project).to receive(:rename_repo).and_raise(StandardError)
end
it 'captures exception from project rename' do
expect { migration.up }.not_to raise_error
end
end
end
context 'when project repository does not exist' do
it 'does not raise error' do
expect { migration.up }.not_to raise_error
end
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