From ae84e350d85a7d49c0de24b250f2356b44bc6df5 Mon Sep 17 00:00:00 2001
From: Bob Van Landuyt <bob@gitlab.com>
Date: Thu, 18 May 2017 17:15:10 +0200
Subject: [PATCH 1/3] Only rename exact matches for the route

The only path we need to rename is the exact match `old_path` and
child matches `old_path/%` instead of `old_path` wich would rename
routes that just look similar.
---
 .../rename_reserved_paths_migration/v1/rename_base.rb    | 4 +++-
 .../v1/rename_base_spec.rb                               | 9 +++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

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 5397877b5d5..f32340be4b0 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
@@ -41,7 +41,9 @@ module Gitlab
                                             new_full_path)
 
             update_column_in_batches(:routes, :path, replace_statement)  do |table, query|
-              query.where(MigrationClasses::Route.arel_table[:path].matches("#{old_full_path}%"))
+              path_or_children = table[:path].eq(old_full_path)
+                                   .or(table[:path].matches("#{old_full_path}/%"))
+              query.where(path_or_children)
             end
           end
 
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 64bc5fc0429..a3ab4e3dd9e 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
@@ -107,6 +107,15 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase do
         expect(new_path).to eq('the-path0')
       end
 
+      it "doesn't rename routes that start with a similar name" do
+        other_namespace = create(:namespace, path: 'the-path-but-not-really')
+        project = create(:empty_project, path: 'the-project', namespace: other_namespace)
+
+        subject.rename_path_for_routable(migration_namespace(namespace))
+
+        expect(project.route.reload.path).to eq('the-path-but-not-really/the-project')
+      end
+
       context "the-path namespace -> subgroup -> the-path0 project" do
         it "updates the route of the project correctly" do
           subgroup = create(:group, path: "subgroup", parent: namespace)
-- 
GitLab


From 8053d08f92419f344d07df206db4e8b1a91dc834 Mon Sep 17 00:00:00 2001
From: Bob Van Landuyt <bob@gitlab.com>
Date: Thu, 18 May 2017 20:14:44 +0200
Subject: [PATCH 2/3] Update username when renaming a user-namespace

---
 .../v1/migration_classes.rb                   |  8 ++++++
 .../v1/rename_namespaces.rb                   |  6 +++++
 .../v1/rename_namespaces_spec.rb              | 27 ++++++++++++++++++-
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/lib/gitlab/database/rename_reserved_paths_migration/v1/migration_classes.rb b/lib/gitlab/database/rename_reserved_paths_migration/v1/migration_classes.rb
index 4fdcb682c2f..5481024db8e 100644
--- a/lib/gitlab/database/rename_reserved_paths_migration/v1/migration_classes.rb
+++ b/lib/gitlab/database/rename_reserved_paths_migration/v1/migration_classes.rb
@@ -48,6 +48,14 @@ module Gitlab
             def self.name
               'Namespace'
             end
+
+            def kind
+              type == 'Group' ? 'group' : 'user'
+            end
+          end
+
+          class User < ActiveRecord::Base
+            self.table_name = 'users'
           end
 
           class Route < ActiveRecord::Base
diff --git a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces.rb b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces.rb
index b9f4f3cff3c..2958ad4b8e5 100644
--- a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces.rb
+++ b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces.rb
@@ -29,9 +29,15 @@ module Gitlab
             move_repositories(namespace, old_full_path, new_full_path)
             move_uploads(old_full_path, new_full_path)
             move_pages(old_full_path, new_full_path)
+            rename_user(old_full_path, new_full_path) if namespace.kind == 'user'
             remove_cached_html_for_projects(projects_for_namespace(namespace).map(&:id))
           end
 
+          def rename_user(old_username, new_username)
+            MigrationClasses::User.where(username: old_username)
+              .update_all(username: new_username)
+          end
+
           def move_repositories(namespace, old_full_path, new_full_path)
             repo_paths_for_namespace(namespace).each do |repository_storage_path|
               # Ensure old directory exists before moving it
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
index ec444942804..c56fded7516 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
@@ -137,7 +137,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
   end
 
   describe "#rename_namespace" do
-    let(:namespace) { create(:namespace, path: 'the-path') }
+    let(:namespace) { create(:group, name: 'the-path') }
 
     it 'renames paths & routes for the namespace' do
       expect(subject).to receive(:rename_path_for_routable).
@@ -177,6 +177,31 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
 
       subject.rename_namespace(namespace)
     end
+
+    it "doesn't rename users for other namespaces" do
+      expect(subject).not_to receive(:rename_user)
+
+      subject.rename_namespace(namespace)
+    end
+
+    it 'renames the username of a namespace for a user' do
+      user = create(:user, username: 'the-path')
+
+      expect(subject).to receive(:rename_user).with('the-path', 'the-path0')
+
+      subject.rename_namespace(user.namespace)
+    end
+  end
+
+  describe '#rename_user' do
+    it 'renames a username' do
+      subject = described_class.new([], migration)
+      user = create(:user, username: 'broken')
+
+      subject.rename_user('broken', 'broken0')
+
+      expect(user.reload.username).to eq('broken0')
+    end
   end
 
   describe '#rename_namespaces' do
-- 
GitLab


From 8f9acafebded01f9ed5ce7dd9cb8b58e1f9f930a Mon Sep 17 00:00:00 2001
From: Bob Van Landuyt <bob@gitlab.com>
Date: Thu, 18 May 2017 20:41:26 +0200
Subject: [PATCH 3/3] Make sure we do a case insensitive like

---
 .../database/rename_reserved_paths_migration/v1/rename_base.rb | 3 +--
 1 file changed, 1 insertion(+), 2 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 f32340be4b0..d60fd4bb551 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
@@ -41,8 +41,7 @@ module Gitlab
                                             new_full_path)
 
             update_column_in_batches(:routes, :path, replace_statement)  do |table, query|
-              path_or_children = table[:path].eq(old_full_path)
-                                   .or(table[:path].matches("#{old_full_path}/%"))
+              path_or_children = table[:path].matches_any([old_full_path, "#{old_full_path}/%"])
               query.where(path_or_children)
             end
           end
-- 
GitLab