Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
gitlab-ce
Commits
969ccec7
Commit
969ccec7
authored
Aug 02, 2017
by
Bob Van Landuyt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Don't rename the system namespace
parent
69eb4be7
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
4 additions
and
485 deletions
+4
-485
changelogs/unreleased/bvl-rollback-renamed-system-namespace.yml
...logs/unreleased/bvl-rollback-renamed-system-namespace.yml
+4
-0
db/migrate/20170316163800_rename_system_namespaces.rb
db/migrate/20170316163800_rename_system_namespaces.rb
+0
-231
spec/migrations/rename_system_namespaces_spec.rb
spec/migrations/rename_system_namespaces_spec.rb
+0
-254
No files found.
changelogs/unreleased/bvl-rollback-renamed-system-namespace.yml
0 → 100644
View file @
969ccec7
---
title
:
Don't rename namespace called system when upgrading from 9.1.x to
9.5
merge_request
:
13228
author
:
db/migrate/20170316163800_rename_system_namespaces.rb
deleted
100644 → 0
View file @
69eb4be7
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class
RenameSystemNamespaces
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
include
Gitlab
::
ShellAdapter
disable_ddl_transaction!
class
User
<
ActiveRecord
::
Base
self
.
table_name
=
'users'
end
class
Namespace
<
ActiveRecord
::
Base
self
.
table_name
=
'namespaces'
belongs_to
:parent
,
class_name:
'RenameSystemNamespaces::Namespace'
has_one
:route
,
as: :source
has_many
:children
,
class_name:
'RenameSystemNamespaces::Namespace'
,
foreign_key: :parent_id
belongs_to
:owner
,
class_name:
'RenameSystemNamespaces::User'
# Overridden to have the correct `source_type` for the `route` relation
def
self
.
name
'Namespace'
end
def
full_path
if
route
&&
route
.
path
.
present?
@full_path
||=
route
.
path
else
update_route
if
persisted?
build_full_path
end
end
def
build_full_path
if
parent
&&
path
parent
.
full_path
+
'/'
+
path
else
path
end
end
def
update_route
prepare_route
route
.
save
end
def
prepare_route
route
||
build_route
(
source:
self
)
route
.
path
=
build_full_path
route
.
name
=
build_full_name
@full_path
=
nil
@full_name
=
nil
end
def
build_full_name
if
parent
&&
name
parent
.
human_name
+
' / '
+
name
else
name
end
end
def
human_name
owner
&
.
name
end
end
class
Route
<
ActiveRecord
::
Base
self
.
table_name
=
'routes'
belongs_to
:source
,
polymorphic:
true
end
class
Project
<
ActiveRecord
::
Base
self
.
table_name
=
'projects'
def
repository_storage_path
Gitlab
.
config
.
repositories
.
storages
[
repository_storage
][
'path'
]
end
end
DOWNTIME
=
false
def
up
return
unless
system_namespace
old_path
=
system_namespace
.
path
old_full_path
=
system_namespace
.
full_path
# Only remove the last occurrence of the path name to get the parent namespace path
namespace_path
=
remove_last_occurrence
(
old_full_path
,
old_path
)
new_path
=
rename_path
(
namespace_path
,
old_path
)
new_full_path
=
join_namespace_path
(
namespace_path
,
new_path
)
Namespace
.
where
(
id:
system_namespace
).
update_all
(
path:
new_path
)
# skips callbacks & validations
replace_statement
=
replace_sql
(
Route
.
arel_table
[
:path
],
old_full_path
,
new_full_path
)
route_matches
=
[
old_full_path
,
"
#{
old_full_path
}
/%"
]
update_column_in_batches
(
:routes
,
:path
,
replace_statement
)
do
|
table
,
query
|
query
.
where
(
Route
.
arel_table
[
:path
].
matches_any
(
route_matches
))
end
clear_cache_for_namespace
(
system_namespace
)
# tasks here are based on `Namespace#move_dir`
move_repositories
(
system_namespace
,
old_full_path
,
new_full_path
)
move_namespace_folders
(
uploads_dir
,
old_full_path
,
new_full_path
)
if
file_storage?
move_namespace_folders
(
pages_dir
,
old_full_path
,
new_full_path
)
end
def
down
# nothing to do
end
def
remove_last_occurrence
(
string
,
pattern
)
string
.
reverse
.
sub
(
pattern
.
reverse
,
""
).
reverse
end
def
move_namespace_folders
(
directory
,
old_relative_path
,
new_relative_path
)
old_path
=
File
.
join
(
directory
,
old_relative_path
)
return
unless
File
.
directory?
(
old_path
)
new_path
=
File
.
join
(
directory
,
new_relative_path
)
FileUtils
.
mv
(
old_path
,
new_path
)
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
gitlab_shell
.
add_namespace
(
repository_storage_path
,
old_full_path
)
unless
gitlab_shell
.
mv_namespace
(
repository_storage_path
,
old_full_path
,
new_full_path
)
say
"Exception moving path
#{
repository_storage_path
}
from
#{
old_full_path
}
to
#{
new_full_path
}
"
end
end
end
def
rename_path
(
namespace_path
,
path_was
)
counter
=
0
path
=
"
#{
path_was
}#{
counter
}
"
while
route_exists?
(
join_namespace_path
(
namespace_path
,
path
))
counter
+=
1
path
=
"
#{
path_was
}#{
counter
}
"
end
path
end
def
route_exists?
(
full_path
)
Route
.
where
(
Route
.
arel_table
[
:path
].
matches
(
full_path
)).
any?
end
def
join_namespace_path
(
namespace_path
,
path
)
if
namespace_path
.
present?
File
.
join
(
namespace_path
,
path
)
else
path
end
end
def
system_namespace
@system_namespace
||=
Namespace
.
where
(
parent_id:
nil
)
.
where
(
arel_table
[
:path
].
matches
(
system_namespace_path
))
.
first
end
def
system_namespace_path
"system"
end
def
clear_cache_for_namespace
(
namespace
)
project_ids
=
projects_for_namespace
(
namespace
).
pluck
(
:id
)
update_column_in_batches
(
:projects
,
:description_html
,
nil
)
do
|
table
,
query
|
query
.
where
(
table
[
:id
].
in
(
project_ids
))
end
update_column_in_batches
(
:issues
,
:description_html
,
nil
)
do
|
table
,
query
|
query
.
where
(
table
[
:project_id
].
in
(
project_ids
))
end
update_column_in_batches
(
:merge_requests
,
:description_html
,
nil
)
do
|
table
,
query
|
query
.
where
(
table
[
:target_project_id
].
in
(
project_ids
))
end
update_column_in_batches
(
:notes
,
:note_html
,
nil
)
do
|
table
,
query
|
query
.
where
(
table
[
:project_id
].
in
(
project_ids
))
end
update_column_in_batches
(
:milestones
,
:description_html
,
nil
)
do
|
table
,
query
|
query
.
where
(
table
[
:project_id
].
in
(
project_ids
))
end
end
def
projects_for_namespace
(
namespace
)
namespace_ids
=
child_ids_for_parent
(
namespace
,
ids:
[
namespace
.
id
])
namespace_or_children
=
Project
.
arel_table
[
:namespace_id
].
in
(
namespace_ids
)
Project
.
unscoped
.
where
(
namespace_or_children
)
end
# This won't scale to huge trees, but it should do for a handful of namespaces
# called `system`.
def
child_ids_for_parent
(
namespace
,
ids:
[])
namespace
.
children
.
each
do
|
child
|
ids
<<
child
.
id
child_ids_for_parent
(
child
,
ids:
ids
)
if
child
.
children
.
any?
end
ids
end
def
repo_paths_for_namespace
(
namespace
)
projects_for_namespace
(
namespace
).
distinct
.
select
(
:repository_storage
).
map
(
&
:repository_storage_path
)
end
def
uploads_dir
File
.
join
(
Rails
.
root
,
"public"
,
"uploads"
)
end
def
pages_dir
Settings
.
pages
.
path
end
def
file_storage?
CarrierWave
::
Uploader
::
Base
.
storage
==
CarrierWave
::
Storage
::
File
end
def
arel_table
Namespace
.
arel_table
end
end
spec/migrations/rename_system_namespaces_spec.rb
deleted
100644 → 0
View file @
69eb4be7
require
"spec_helper"
require
Rails
.
root
.
join
(
"db"
,
"migrate"
,
"20170316163800_rename_system_namespaces.rb"
)
describe
RenameSystemNamespaces
,
truncate:
true
do
let
(
:migration
)
{
described_class
.
new
}
let
(
:test_dir
)
{
File
.
join
(
Rails
.
root
,
"tmp"
,
"tests"
,
"rename_namespaces_test"
)
}
let
(
:uploads_dir
)
{
File
.
join
(
test_dir
,
"public"
,
"uploads"
)
}
let
(
:system_namespace
)
do
namespace
=
build
(
:namespace
,
path:
"system"
)
namespace
.
save
(
validate:
false
)
namespace
end
def
save_invalid_routable
(
routable
)
routable
.
__send__
(
:prepare_route
)
routable
.
save
(
validate:
false
)
end
before
do
FileUtils
.
remove_dir
(
test_dir
)
if
File
.
directory?
(
test_dir
)
FileUtils
.
mkdir_p
(
uploads_dir
)
FileUtils
.
remove_dir
(
TestEnv
.
repos_path
)
if
File
.
directory?
(
TestEnv
.
repos_path
)
allow
(
migration
).
to
receive
(
:say
)
allow
(
migration
).
to
receive
(
:uploads_dir
).
and_return
(
uploads_dir
)
end
describe
"#system_namespace"
do
it
"only root namespaces called with path `system`"
do
system_namespace
system_namespace_with_parent
=
build
(
:namespace
,
path:
'system'
,
parent:
create
(
:namespace
))
system_namespace_with_parent
.
save
(
validate:
false
)
expect
(
migration
.
system_namespace
.
id
).
to
eq
(
system_namespace
.
id
)
end
end
describe
"#up"
do
before
do
system_namespace
end
it
"doesn't break if there are no namespaces called system"
do
Namespace
.
delete_all
migration
.
up
end
it
"renames namespaces called system"
do
migration
.
up
expect
(
system_namespace
.
reload
.
path
).
to
eq
(
"system0"
)
end
it
"renames the route to the namespace"
do
migration
.
up
expect
(
system_namespace
.
reload
.
full_path
).
to
eq
(
"system0"
)
end
it
"renames the route for projects of the namespace"
do
project
=
build
(
:project
,
:repository
,
path:
"project-path"
,
namespace:
system_namespace
)
save_invalid_routable
(
project
)
migration
.
up
expect
(
project
.
route
.
reload
.
path
).
to
eq
(
"system0/project-path"
)
end
it
"doesn't touch routes of namespaces that look like system"
do
namespace
=
create
(
:group
,
path:
'systemlookalike'
)
project
=
create
(
:project
,
:repository
,
namespace:
namespace
,
path:
'the-project'
)
migration
.
up
expect
(
project
.
route
.
reload
.
path
).
to
eq
(
'systemlookalike/the-project'
)
expect
(
namespace
.
route
.
reload
.
path
).
to
eq
(
'systemlookalike'
)
end
it
"moves the the repository for a project in the namespace"
do
project
=
build
(
:project
,
:repository
,
namespace:
system_namespace
,
path:
"system-project"
)
save_invalid_routable
(
project
)
TestEnv
.
copy_repo
(
project
,
bare_repo:
TestEnv
.
factory_repo_path_bare
,
refs:
TestEnv
::
BRANCH_SHA
)
expected_repo
=
File
.
join
(
TestEnv
.
repos_path
,
"system0"
,
"system-project.git"
)
migration
.
up
expect
(
File
.
directory?
(
expected_repo
)).
to
be
(
true
)
end
it
"moves the uploads for the namespace"
do
allow
(
migration
).
to
receive
(
:move_namespace_folders
).
with
(
Settings
.
pages
.
path
,
"system"
,
"system0"
)
expect
(
migration
).
to
receive
(
:move_namespace_folders
).
with
(
uploads_dir
,
"system"
,
"system0"
)
migration
.
up
end
it
"moves the pages for the namespace"
do
allow
(
migration
).
to
receive
(
:move_namespace_folders
).
with
(
uploads_dir
,
"system"
,
"system0"
)
expect
(
migration
).
to
receive
(
:move_namespace_folders
).
with
(
Settings
.
pages
.
path
,
"system"
,
"system0"
)
migration
.
up
end
describe
"clears the markdown cache for projects in the system namespace"
do
let!
(
:project
)
do
project
=
build
(
:project
,
:repository
,
namespace:
system_namespace
)
save_invalid_routable
(
project
)
project
end
it
'removes description_html from projects'
do
migration
.
up
expect
(
project
.
reload
.
description_html
).
to
be_nil
end
it
'removes issue descriptions'
do
issue
=
create
(
:issue
,
project:
project
,
description_html:
'Issue description'
)
migration
.
up
expect
(
issue
.
reload
.
description_html
).
to
be_nil
end
it
'removes merge request descriptions'
do
merge_request
=
create
(
:merge_request
,
source_project:
project
,
target_project:
project
,
description_html:
'MergeRequest description'
)
migration
.
up
expect
(
merge_request
.
reload
.
description_html
).
to
be_nil
end
it
'removes note html'
do
note
=
create
(
:note
,
project:
project
,
noteable:
create
(
:issue
,
project:
project
),
note_html:
'note description'
)
migration
.
up
expect
(
note
.
reload
.
note_html
).
to
be_nil
end
it
'removes milestone description'
do
milestone
=
create
(
:milestone
,
project:
project
,
description_html:
'milestone description'
)
migration
.
up
expect
(
milestone
.
reload
.
description_html
).
to
be_nil
end
end
context
"system namespace -> subgroup -> system0 project"
do
it
"updates the route of the project correctly"
do
subgroup
=
build
(
:group
,
path:
"subgroup"
,
parent:
system_namespace
)
save_invalid_routable
(
subgroup
)
project
=
build
(
:project
,
:repository
,
path:
"system0"
,
namespace:
subgroup
)
save_invalid_routable
(
project
)
migration
.
up
expect
(
project
.
route
.
reload
.
path
).
to
eq
(
"system0/subgroup/system0"
)
end
end
end
describe
"#move_repositories"
do
let
(
:namespace
)
{
create
(
:group
,
name:
"hello-group"
)
}
it
"moves a project for a namespace"
do
create
(
:project
,
:repository
,
namespace:
namespace
,
path:
"hello-project"
)
expected_path
=
File
.
join
(
TestEnv
.
repos_path
,
"bye-group"
,
"hello-project.git"
)
migration
.
move_repositories
(
namespace
,
"hello-group"
,
"bye-group"
)
expect
(
File
.
directory?
(
expected_path
)).
to
be
(
true
)
end
it
"moves a namespace in a subdirectory correctly"
do
child_namespace
=
create
(
:group
,
name:
"sub-group"
,
parent:
namespace
)
create
(
:project
,
:repository
,
namespace:
child_namespace
,
path:
"hello-project"
)
expected_path
=
File
.
join
(
TestEnv
.
repos_path
,
"hello-group"
,
"renamed-sub-group"
,
"hello-project.git"
)
migration
.
move_repositories
(
child_namespace
,
"hello-group/sub-group"
,
"hello-group/renamed-sub-group"
)
expect
(
File
.
directory?
(
expected_path
)).
to
be
(
true
)
end
it
"moves a parent namespace with subdirectories"
do
child_namespace
=
create
(
:group
,
name:
"sub-group"
,
parent:
namespace
)
create
(
:project
,
:repository
,
namespace:
child_namespace
,
path:
"hello-project"
)
expected_path
=
File
.
join
(
TestEnv
.
repos_path
,
"renamed-group"
,
"sub-group"
,
"hello-project.git"
)
migration
.
move_repositories
(
child_namespace
,
"hello-group"
,
"renamed-group"
)
expect
(
File
.
directory?
(
expected_path
)).
to
be
(
true
)
end
end
describe
"#move_namespace_folders"
do
it
"moves a namespace with files"
do
source
=
File
.
join
(
uploads_dir
,
"parent-group"
,
"sub-group"
)
FileUtils
.
mkdir_p
(
source
)
destination
=
File
.
join
(
uploads_dir
,
"parent-group"
,
"moved-group"
)
FileUtils
.
touch
(
File
.
join
(
source
,
"test.txt"
))
expected_file
=
File
.
join
(
destination
,
"test.txt"
)
migration
.
move_namespace_folders
(
uploads_dir
,
File
.
join
(
"parent-group"
,
"sub-group"
),
File
.
join
(
"parent-group"
,
"moved-group"
))
expect
(
File
.
exist?
(
expected_file
)).
to
be
(
true
)
end
it
"moves a parent namespace uploads"
do
source
=
File
.
join
(
uploads_dir
,
"parent-group"
,
"sub-group"
)
FileUtils
.
mkdir_p
(
source
)
destination
=
File
.
join
(
uploads_dir
,
"moved-parent"
,
"sub-group"
)
FileUtils
.
touch
(
File
.
join
(
source
,
"test.txt"
))
expected_file
=
File
.
join
(
destination
,
"test.txt"
)
migration
.
move_namespace_folders
(
uploads_dir
,
"parent-group"
,
"moved-parent"
)
expect
(
File
.
exist?
(
expected_file
)).
to
be
(
true
)
end
end
describe
"#child_ids_for_parent"
do
it
"collects child ids for all levels"
do
parent
=
create
(
:group
)
first_child
=
create
(
:group
,
parent:
parent
)
second_child
=
create
(
:group
,
parent:
parent
)
third_child
=
create
(
:group
,
parent:
second_child
)
all_ids
=
[
parent
.
id
,
first_child
.
id
,
second_child
.
id
,
third_child
.
id
]
collected_ids
=
migration
.
child_ids_for_parent
(
parent
,
ids:
[
parent
.
id
])
expect
(
collected_ids
).
to
contain_exactly
(
*
all_ids
)
end
end
describe
"#remove_last_ocurrence"
do
it
"removes only the last occurance of a string"
do
input
=
"this/is/system/namespace/with/system"
expect
(
migration
.
remove_last_occurrence
(
input
,
"system"
)).
to
eq
(
"this/is/system/namespace/with/"
)
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment