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
1
Merge Requests
1
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
nexedi
gitlab-ce
Commits
3a0ad99d
Commit
3a0ad99d
authored
Nov 07, 2017
by
Michael Kozono
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add untracked files to uploads
parent
8315c66a
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
752 additions
and
34 deletions
+752
-34
lib/gitlab/background_migration/populate_untracked_uploads.rb
...gitlab/background_migration/populate_untracked_uploads.rb
+133
-11
spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
...b/background_migration/populate_untracked_uploads_spec.rb
+581
-0
spec/migrations/track_untracked_uploads_spec.rb
spec/migrations/track_untracked_uploads_spec.rb
+38
-23
No files found.
lib/gitlab/background_migration/populate_untracked_uploads.rb
View file @
3a0ad99d
...
@@ -4,27 +4,149 @@ module Gitlab
...
@@ -4,27 +4,149 @@ module Gitlab
class
UnhashedUploadFile
<
ActiveRecord
::
Base
class
UnhashedUploadFile
<
ActiveRecord
::
Base
self
.
table_name
=
'unhashed_upload_files'
self
.
table_name
=
'unhashed_upload_files'
# Ends with /:random_hex/:filename
FILE_UPLOADER_PATH_PATTERN
=
/\/\h+\/[^\/]+\z/
# These regex patterns are tested against a relative path, relative to
# the upload directory.
# For convenience, if there exists a capture group in the pattern, then
# it indicates the model_id.
PATH_PATTERNS
=
[
{
pattern:
/\A-\/system\/appearance\/logo\/(\d+)/
,
uploader:
'AttachmentUploader'
,
model_type:
'Appearance'
,
},
{
pattern:
/\A-\/system\/appearance\/header_logo\/(\d+)/
,
uploader:
'AttachmentUploader'
,
model_type:
'Appearance'
,
},
{
pattern:
/\A-\/system\/note\/attachment\/(\d+)/
,
uploader:
'AttachmentUploader'
,
model_type:
'Note'
,
},
{
pattern:
/\A-\/system\/user\/avatar\/(\d+)/
,
uploader:
'AvatarUploader'
,
model_type:
'User'
,
},
{
pattern:
/\A-\/system\/group\/avatar\/(\d+)/
,
uploader:
'AvatarUploader'
,
model_type:
'Group'
,
},
{
pattern:
/\A-\/system\/project\/avatar\/(\d+)/
,
uploader:
'AvatarUploader'
,
model_type:
'Project'
,
},
{
pattern:
FILE_UPLOADER_PATH_PATTERN
,
uploader:
'FileUploader'
,
model_type:
'Project'
},
]
scope
:untracked
,
->
{
where
(
tracked:
false
)
}
scope
:untracked
,
->
{
where
(
tracked:
false
)
}
def
ensure_tracked!
def
ensure_tracked!
# TODO
return
if
persisted?
&&
tracked?
# unless unhashed_upload_file.in_uploads?
# unhashed_upload_file.add_to_uploads
unless
in_uploads?
# end
add_to_uploads
#
end
# unhashed_upload_file.mark_as_tracked
mark_as_tracked
end
end
def
model_id
def
in_uploads?
# TODO
# Even though we are checking relative paths, path is enough to
# uniquely identify uploads. There is no ambiguity between
# FileUploader paths and other Uploader paths because we use the /-/
# separator kind of like an escape character. Project full_path will
# never conflict with an upload path starting with "uploads/-/".
Upload
.
exists?
(
path:
upload_path
)
end
end
def
model_type
def
add_to_uploads
# TODO
Upload
.
create!
(
path:
upload_path
,
uploader:
uploader
,
model_type:
model_type
,
model_id:
model_id
,
size:
file_size
)
end
def
mark_as_tracked
self
.
tracked
=
true
self
.
save!
end
def
upload_path
# UnhashedUploadFile#path is absolute, but Upload#path depends on uploader
if
uploader
==
'FileUploader'
# Path relative to project directory in uploads
matchd
=
path_relative_to_upload_dir
.
match
(
FILE_UPLOADER_PATH_PATTERN
)
matchd
[
0
].
sub
(
/\A\//
,
''
)
# remove leading slash
else
path_relative_to_carrierwave_root
end
end
end
def
uploader
def
uploader
# TODO
PATH_PATTERNS
.
each
do
|
path_pattern_map
|
if
path_relative_to_upload_dir
.
match
(
path_pattern_map
[
:pattern
])
return
path_pattern_map
[
:uploader
]
end
end
end
def
model_type
PATH_PATTERNS
.
each
do
|
path_pattern_map
|
if
path_relative_to_upload_dir
.
match
(
path_pattern_map
[
:pattern
])
return
path_pattern_map
[
:model_type
]
end
end
end
def
model_id
PATH_PATTERNS
.
each
do
|
path_pattern_map
|
matchd
=
path_relative_to_upload_dir
.
match
(
path_pattern_map
[
:pattern
])
# If something is captured (matchd[1] is not nil), it is a model_id
return
matchd
[
1
]
if
matchd
&&
matchd
[
1
]
end
# Only the FileUploader pattern will not match an ID
file_uploader_model_id
end
def
file_size
File
.
size
(
path
)
end
# Not including a leading slash
def
path_relative_to_upload_dir
@path_relative_to_upload_dir
||=
path
.
sub
(
/\A
#{
Gitlab
::
BackgroundMigration
::
PrepareUnhashedUploads
::
UPLOAD_DIR
}
\//
,
''
)
end
# Not including a leading slash
def
path_relative_to_carrierwave_root
"uploads/
#{
path_relative_to_upload_dir
}
"
end
private
def
file_uploader_model_id
pattern_to_capture_full_path
=
/\A(.+)
#{
FILE_UPLOADER_PATH_PATTERN
}
/
matchd
=
path_relative_to_upload_dir
.
match
(
pattern_to_capture_full_path
)
raise
"Could not capture project full_path from a FileUploader path:
\"
#{
path_relative_to_upload_dir
}
\"
"
unless
matchd
full_path
=
matchd
[
1
]
project
=
Project
.
find_by_full_path
(
full_path
)
project
.
id
.
to_s
end
end
end
end
...
...
spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
0 → 100644
View file @
3a0ad99d
This diff is collapsed.
Click to expand it.
spec/migrations/track_untracked_uploads_spec.rb
View file @
3a0ad99d
...
@@ -2,6 +2,10 @@ require 'spec_helper'
...
@@ -2,6 +2,10 @@ require 'spec_helper'
require
Rails
.
root
.
join
(
'db'
,
'post_migrate'
,
'20171103140253_track_untracked_uploads'
)
require
Rails
.
root
.
join
(
'db'
,
'post_migrate'
,
'20171103140253_track_untracked_uploads'
)
describe
TrackUntrackedUploads
,
:migration
,
:sidekiq
do
describe
TrackUntrackedUploads
,
:migration
,
:sidekiq
do
class
UnhashedUploadFile
<
ActiveRecord
::
Base
self
.
table_name
=
'unhashed_upload_files'
end
matcher
:be_scheduled_migration
do
matcher
:be_scheduled_migration
do
match
do
|
migration
|
match
do
|
migration
|
BackgroundMigrationWorker
.
jobs
.
any?
do
|
job
|
BackgroundMigrationWorker
.
jobs
.
any?
do
|
job
|
...
@@ -30,10 +34,6 @@ describe TrackUntrackedUploads, :migration, :sidekiq do
...
@@ -30,10 +34,6 @@ describe TrackUntrackedUploads, :migration, :sidekiq do
end
end
it
'has a path field long enough for really long paths'
do
it
'has a path field long enough for really long paths'
do
class
UnhashedUploadFile
<
ActiveRecord
::
Base
self
.
table_name
=
'unhashed_upload_files'
end
migrate!
migrate!
max_length_namespace_path
=
max_length_project_path
=
max_length_filename
=
'a'
*
255
max_length_namespace_path
=
max_length_project_path
=
max_length_filename
=
'a'
*
255
...
@@ -57,7 +57,8 @@ describe TrackUntrackedUploads, :migration, :sidekiq do
...
@@ -57,7 +57,8 @@ describe TrackUntrackedUploads, :migration, :sidekiq do
uploaded_file
=
fixture_file_upload
(
fixture
)
uploaded_file
=
fixture_file_upload
(
fixture
)
user1
.
update
(
avatar:
uploaded_file
)
user1
.
update
(
avatar:
uploaded_file
)
project1
.
update
(
avatar:
uploaded_file
)
project1
.
update
(
avatar:
uploaded_file
)
UploadService
.
new
(
project1
,
uploaded_file
,
FileUploader
).
execute
# Markdown upload
upload_result
=
UploadService
.
new
(
project1
,
uploaded_file
,
FileUploader
).
execute
# Markdown upload
@project1_markdown_upload_path
=
upload_result
[
:url
].
sub
(
/\A\/uploads\//
,
''
)
appearance
.
update
(
logo:
uploaded_file
)
appearance
.
update
(
logo:
uploaded_file
)
# Untracked, by doing normal file upload then deleting records from DB
# Untracked, by doing normal file upload then deleting records from DB
...
@@ -65,48 +66,62 @@ describe TrackUntrackedUploads, :migration, :sidekiq do
...
@@ -65,48 +66,62 @@ describe TrackUntrackedUploads, :migration, :sidekiq do
user2
.
update
(
avatar:
uploaded_file
)
user2
.
update
(
avatar:
uploaded_file
)
user2
.
uploads
.
delete_all
user2
.
uploads
.
delete_all
project2
.
update
(
avatar:
uploaded_file
)
project2
.
update
(
avatar:
uploaded_file
)
UploadService
.
new
(
project2
,
uploaded_file
,
FileUploader
).
execute
# Markdown upload
upload_result
=
UploadService
.
new
(
project2
,
uploaded_file
,
FileUploader
).
execute
# Markdown upload
@project2_markdown_upload_path
=
upload_result
[
:url
].
sub
(
/\A\/uploads\//
,
''
)
project2
.
uploads
.
delete_all
project2
.
uploads
.
delete_all
appearance
.
update
(
header_logo:
uploaded_file
)
appearance
.
update
(
header_logo:
uploaded_file
)
appearance
.
uploads
.
last
.
destroy
appearance
.
uploads
.
last
.
destroy
end
end
it
'
schedules backgroun
d migrations'
do
it
'
tracks untracke
d migrations'
do
Sidekiq
::
Testing
.
inline!
do
Sidekiq
::
Testing
.
inline!
do
migrate!
migrate!
# Tracked uploads still exist
# Tracked uploads still exist
expect
(
user1
.
uploads
.
first
.
attributes
).
to
include
({
expect
(
user1
.
reload
.
uploads
.
first
.
attributes
).
to
include
({
"path"
=>
"uploads/-/system/user/avatar/
1
/rails_sample.jpg"
,
"path"
=>
"uploads/-/system/user/avatar/
#{
user1
.
id
}
/rails_sample.jpg"
,
"uploader"
=>
"AvatarUploader"
"uploader"
=>
"AvatarUploader"
})
})
expect
(
project1
.
uploads
.
first
.
attributes
).
to
include
({
expect
(
project1
.
reload
.
uploads
.
first
.
attributes
).
to
include
({
"path"
=>
"uploads/-/system/project/avatar/
1
/rails_sample.jpg"
,
"path"
=>
"uploads/-/system/project/avatar/
#{
project1
.
id
}
/rails_sample.jpg"
,
"uploader"
=>
"AvatarUploader"
"uploader"
=>
"AvatarUploader"
})
})
expect
(
appearance
.
uploads
.
first
.
attributes
).
to
include
({
expect
(
appearance
.
reload
.
uploads
.
first
.
attributes
).
to
include
({
"path"
=>
"uploads/-/system/appearance/logo/
1
/rails_sample.jpg"
,
"path"
=>
"uploads/-/system/appearance/logo/
#{
appearance
.
id
}
/rails_sample.jpg"
,
"uploader"
=>
"AttachmentUploader"
"uploader"
=>
"AttachmentUploader"
})
})
expect
(
project1
.
uploads
.
last
.
path
).
to
match
(
/\w+\/rails_sample\.jpg/
)
expect
(
project1
.
uploads
.
last
.
attributes
).
to
include
({
expect
(
project1
.
uploads
.
last
.
uploader
).
to
eq
(
'FileUploader'
)
"path"
=>
@project1_markdown_upload_path
,
"uploader"
=>
"FileUploader"
})
# Untracked uploads are now tracked
# Untracked uploads are now tracked
expect
(
user2
.
uploads
.
first
.
attributes
).
to
include
({
expect
(
user2
.
reload
.
uploads
.
first
.
attributes
).
to
include
({
"path"
=>
"uploads/-/system/user/avatar/
2
/rails_sample.jpg"
,
"path"
=>
"uploads/-/system/user/avatar/
#{
user2
.
id
}
/rails_sample.jpg"
,
"uploader"
=>
"AvatarUploader"
"uploader"
=>
"AvatarUploader"
})
})
expect
(
project2
.
uploads
.
first
.
attributes
).
to
include
({
expect
(
project2
.
reload
.
uploads
.
first
.
attributes
).
to
include
({
"path"
=>
"uploads/-/system/project/avatar/
2
/rails_sample.jpg"
,
"path"
=>
"uploads/-/system/project/avatar/
#{
project2
.
id
}
/rails_sample.jpg"
,
"uploader"
=>
"AvatarUploader"
"uploader"
=>
"AvatarUploader"
})
})
expect
(
appearance
.
uploads
.
count
).
to
eq
(
2
)
expect
(
appearance
.
reload
.
uploads
.
count
).
to
eq
(
2
)
expect
(
appearance
.
uploads
.
last
.
attributes
).
to
include
({
expect
(
appearance
.
uploads
.
last
.
attributes
).
to
include
({
"path"
=>
"uploads/-/system/appearance/header_logo/
1
/rails_sample.jpg"
,
"path"
=>
"uploads/-/system/appearance/header_logo/
#{
appearance
.
id
}
/rails_sample.jpg"
,
"uploader"
=>
"AttachmentUploader"
"uploader"
=>
"AttachmentUploader"
})
})
expect
(
project2
.
uploads
.
last
.
path
).
to
match
(
/\w+\/rails_sample\.jpg/
)
expect
(
project2
.
uploads
.
last
.
attributes
).
to
include
({
expect
(
project2
.
uploads
.
last
.
uploader
).
to
eq
(
'FileUploader'
)
"path"
=>
@project2_markdown_upload_path
,
"uploader"
=>
"FileUploader"
})
end
end
it
'all UnhashedUploadFile records are marked as tracked'
do
Sidekiq
::
Testing
.
inline!
do
migrate!
expect
(
UnhashedUploadFile
.
count
).
to
eq
(
8
)
expect
(
UnhashedUploadFile
.
count
).
to
eq
(
UnhashedUploadFile
.
where
(
tracked:
true
).
count
)
end
end
end
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