blob: af1ad930aedd2867b77e4901ff217eb71ea0723a (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# This migration takes all legacy uploads (that were uploaded using AttachmentUploader)
# and migrate them to the new (FileUploader) location (=under projects).
#
# We have dependencies (uploaders) in this migration because extracting code would add a lot of complexity
# and possible errors could appear as the logic in the uploaders is not trivial.
#
# This migration will be removed in 12.4 in order to get rid of a migration that depends on
# the application code.
class MigrateLegacyUploads
include Database::MigrationHelpers
include ::Gitlab::Utils::StrongMemoize
# This class takes a legacy upload and migrates it to the correct location
class UploadMover
include Gitlab::Utils::StrongMemoize
attr_reader :upload, :project, :note
def initialize(upload)
@upload = upload
@note = Note.find_by(id: upload.model_id)
@project = note&.project
end
def execute
return unless upload
if !project
# if we don't have models associated with the upload we can not move it
say "MigrateLegacyUploads: Deleting upload due to model not found: #{upload.inspect}"
destroy_legacy_upload
elsif note.is_a?(LegacyDiffNote)
handle_legacy_note_upload
elsif !legacy_file_exists?
# if we can not find the file we just remove the upload record
say "MigrateLegacyUploads: Deleting upload due to file not found: #{upload.inspect}"
destroy_legacy_upload
else
migrate_upload
end
end
private
def migrate_upload
return unless copy_upload_to_project
add_upload_link_to_note_text
destroy_legacy_file
destroy_legacy_upload
end
# we should proceed and log whenever one upload copy fails, no matter the reasons
# rubocop: disable Lint/RescueException
def copy_upload_to_project
@uploader = FileUploader.copy_to(legacy_file_uploader, project)
say "MigrateLegacyUploads: Copied file #{legacy_file_uploader.file.path} -> #{@uploader.file.path}"
true
rescue Exception => e
say "MigrateLegacyUploads: File #{legacy_file_uploader.file.path} couldn't be copied to project uploads. Error: #{e.message}"
false
end
# rubocop: enable Lint/RescueException
def destroy_legacy_upload
note.remove_attachment = true
note.save
if upload.destroy
say "MigrateLegacyUploads: Upload #{upload.inspect} was destroyed."
else
say "MigrateLegacyUploads: Upload #{upload.inspect} destroy failed."
end
end
def destroy_legacy_file
legacy_file_uploader.file.delete
end
def add_upload_link_to_note_text
new_text = "#{note.note} \n #{@uploader.markdown_link}"
note.update!(
note: new_text
)
end
def legacy_file_uploader
strong_memoize(:legacy_file_uploader) do
uploader = upload.build_uploader
uploader.retrieve_from_store!(File.basename(upload.path))
uploader
end
end
def legacy_file_exists?
legacy_file_uploader.file.exists?
end
def handle_legacy_note_upload
note.note += "\n \n Attachment ##{upload.id} with URL \"#{note.attachment.url}\" failed to migrate \
for model class #{note.class}. See #{help_doc_link}."
note.save
say "MigrateLegacyUploads: LegacyDiffNote ##{note.id} found, can't move the file: #{upload.inspect} for upload ##{upload.id}. See #{help_doc_link}."
end
def say(message)
Rails.logger.info(message)
end
def help_doc_link
'https://docs.gitlab.com/ee/administration/troubleshooting/migrations.html#legacy-upload-migration'
end
end
def perform(start_id, end_id)
Upload.where(id: start_id..end_id, uploader: 'AttachmentUploader').find_each do |upload|
UploadMover.new(upload).execute
end
end
end
end
end
|