diff --git a/changelogs/unreleased/dz-rename-invalid-groups.yml b/changelogs/unreleased/dz-rename-invalid-groups.yml new file mode 100644 index 0000000000000000000000000000000000000000..90af42da01c91502db6dcd5c75c757f2dbcf2d69 --- /dev/null +++ b/changelogs/unreleased/dz-rename-invalid-groups.yml @@ -0,0 +1,4 @@ +--- +title: Rename groups with .git in the end of the path +merge_request: 8199 +author: diff --git a/db/migrate/20161220141214_remove_dot_git_from_group_names.rb b/db/migrate/20161220141214_remove_dot_git_from_group_names.rb new file mode 100644 index 0000000000000000000000000000000000000000..bd0e4b2cc07b8eb9fe2c45dd012afe2866becd4c --- /dev/null +++ b/db/migrate/20161220141214_remove_dot_git_from_group_names.rb @@ -0,0 +1,82 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class RemoveDotGitFromGroupNames < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + include Gitlab::ShellAdapter + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + def up + invalid_groups.each do |group| + path_was = group['path'] + path_was_wildcard = quote_string("#{path_was}/%") + path = quote_string(rename_path(path_was)) + + move_namespace(group['id'], path_was, path) + + execute "UPDATE routes SET path = '#{path}' WHERE source_type = 'Namespace' AND source_id = #{group['id']}" + execute "UPDATE namespaces SET path = '#{path}' WHERE id = #{group['id']}" + + select_all("SELECT id, path FROM routes WHERE path LIKE '#{path_was_wildcard}'").each do |route| + new_path = "#{path}/#{route['path'].split('/').last}" + execute "UPDATE routes SET path = '#{new_path}' WHERE id = #{route['id']}" + end + end + end + + def down + # nothing to do here + end + + private + + def invalid_groups + select_all("SELECT id, path FROM namespaces WHERE type = 'Group' AND path LIKE '%.git'") + end + + def route_exists?(path) + select_all("SELECT id, path FROM routes WHERE path = '#{quote_string(path)}'").present? + end + + # Accepts invalid path like test.git and returns test_git or + # test_git1 if test_git already taken + def rename_path(path) + # To stay closer with original name and reduce risk of duplicates + # we rename suffix instead of removing it + path = path.sub(/\.git\z/, '_git') + + counter = 0 + base = path + + while route_exists?(path) + counter += 1 + path = "#{base}#{counter}" + end + + path + end + + def move_namespace(group_id, path_was, path) + repository_storage_paths = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{group_id}").map do |row| + Gitlab.config.repositories.storages[row['repository_storage']] + end + + # Move the namespace directory in all storages paths used by member projects + repository_storage_paths.each do |repository_storage_path| + # Ensure old directory exists before moving it + gitlab_shell.add_namespace(repository_storage_path, path_was) + + unless gitlab_shell.mv_namespace(repository_storage_path, path_was, path) + Rails.logger.error "Exception moving path #{repository_storage_path} from #{path_was} to #{path}" + + # 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('namespace directory cannot be moved') + end + end + + Gitlab::UploadsTransfer.new.rename_namespace(path_was, path) + end +end diff --git a/db/schema.rb b/db/schema.rb index 14801b581e6e846ce3a2b2934e532d33731da7aa..13a847827cc06c13b68d543215584c13d7125e0f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20161213172958) do +ActiveRecord::Schema.define(version: 20161220141214) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -854,7 +854,7 @@ ActiveRecord::Schema.define(version: 20161213172958) do t.datetime "expires_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.string "scopes", default: "--- []\n", null: false + t.string "scopes", default: "--- []\n", null: false end add_index "personal_access_tokens", ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree