20 |
20 |
require 'active_record'
|
21 |
21 |
require 'iconv'
|
22 |
22 |
require 'pp'
|
23 |
|
|
|
23 |
ActiveRecord::Base.record_timestamps = false
|
24 |
24 |
namespace :redmine do
|
25 |
25 |
task :migrate_from_mantis => :environment do
|
26 |
26 |
|
... | ... | |
41 |
41 |
}
|
42 |
42 |
|
43 |
43 |
priorities = IssuePriority.all
|
44 |
|
DEFAULT_PRIORITY = priorities[2]
|
45 |
|
PRIORITY_MAPPING = {10 => priorities[1], # none
|
46 |
|
20 => priorities[1], # low
|
47 |
|
30 => priorities[2], # normal
|
48 |
|
40 => priorities[3], # high
|
49 |
|
50 => priorities[4], # urgent
|
50 |
|
60 => priorities[5] # immediate
|
|
44 |
DEFAULT_PRIORITY = priorities[1]
|
|
45 |
PRIORITY_MAPPING = {10 => priorities[0], # none
|
|
46 |
20 => priorities[0], # low
|
|
47 |
30 => priorities[1], # normal
|
|
48 |
40 => priorities[2], # high
|
|
49 |
50 => priorities[3], # urgent
|
|
50 |
60 => priorities[4] # immediate
|
51 |
51 |
}
|
52 |
52 |
|
53 |
53 |
TRACKER_BUG = Tracker.find_by_position(1)
|
... | ... | |
82 |
82 |
0 => IssueRelation::TYPE_DUPLICATES, # duplicate of
|
83 |
83 |
4 => IssueRelation::TYPE_DUPLICATES # has duplicate
|
84 |
84 |
}
|
85 |
|
|
|
85 |
|
86 |
86 |
class MantisUser < ActiveRecord::Base
|
87 |
87 |
set_table_name :mantis_user_table
|
88 |
88 |
|
... | ... | |
119 |
119 |
has_many :members, :class_name => "MantisProjectUser", :foreign_key => :project_id
|
120 |
120 |
|
121 |
121 |
def identifier
|
122 |
|
read_attribute(:name).gsub(/[^a-z0-9\-]+/, '-').slice(0, Project::IDENTIFIER_MAX_LENGTH)
|
|
122 |
read_attribute(:name).slice(0, Project::IDENTIFIER_MAX_LENGTH).downcase.gsub(/[^a-z0-9\-]+/, '-')
|
123 |
123 |
end
|
124 |
124 |
end
|
125 |
125 |
|
|
126 |
class MantisProjectHierarchy < ActiveRecord::Base
|
|
127 |
set_table_name :mantis_project_hierarchy_table
|
|
128 |
end
|
|
129 |
|
126 |
130 |
class MantisVersion < ActiveRecord::Base
|
127 |
131 |
set_table_name :mantis_project_version_table
|
128 |
132 |
|
... | ... | |
136 |
140 |
end
|
137 |
141 |
|
138 |
142 |
class MantisCategory < ActiveRecord::Base
|
139 |
|
set_table_name :mantis_project_category_table
|
|
143 |
set_table_name :mantis_category_table
|
|
144 |
def category
|
|
145 |
read_attribute(:name).slice(0,30)
|
|
146 |
end
|
140 |
147 |
end
|
141 |
148 |
|
142 |
149 |
class MantisProjectUser < ActiveRecord::Base
|
... | ... | |
149 |
156 |
has_many :bug_notes, :class_name => "MantisBugNote", :foreign_key => :bug_id
|
150 |
157 |
has_many :bug_files, :class_name => "MantisBugFile", :foreign_key => :bug_id
|
151 |
158 |
has_many :bug_monitors, :class_name => "MantisBugMonitor", :foreign_key => :bug_id
|
|
159 |
belongs_to :category, :class_name => "MantisCategory", :foreign_key => :category_id
|
152 |
160 |
end
|
153 |
161 |
|
154 |
162 |
class MantisBugText < ActiveRecord::Base
|
... | ... | |
243 |
251 |
users_map = {}
|
244 |
252 |
users_migrated = 0
|
245 |
253 |
MantisUser.find(:all).each do |user|
|
246 |
|
u = User.new :firstname => encode(user.firstname),
|
247 |
|
:lastname => encode(user.lastname),
|
248 |
|
:mail => user.email,
|
249 |
|
:last_login_on => user.last_visit
|
250 |
|
u.login = user.username
|
251 |
|
u.password = 'mantis'
|
252 |
|
u.status = User::STATUS_LOCKED if user.enabled != 1
|
253 |
|
u.admin = true if user.access_level == 90
|
254 |
|
next unless u.save!
|
255 |
|
users_migrated += 1
|
256 |
|
users_map[user.id] = u.id
|
257 |
|
print '.'
|
|
254 |
u = User.new :firstname => encode(user.firstname),
|
|
255 |
:lastname => encode(user.lastname),
|
|
256 |
:mail => user.email,
|
|
257 |
:last_login_on => user.last_visit
|
|
258 |
u.login = user.username
|
|
259 |
u.password = 'mantis'
|
|
260 |
u.status = User::STATUS_LOCKED if user.enabled != 1
|
|
261 |
u.admin = true if user.access_level == 90
|
|
262 |
next unless u.save!
|
|
263 |
users_migrated += 1
|
|
264 |
users_map[user.id] = u.id
|
|
265 |
print '.'
|
258 |
266 |
end
|
259 |
267 |
puts
|
260 |
268 |
|
... | ... | |
265 |
273 |
versions_map = {}
|
266 |
274 |
categories_map = {}
|
267 |
275 |
MantisProject.find(:all).each do |project|
|
268 |
|
p = Project.new :name => encode(project.name),
|
269 |
|
:description => encode(project.description)
|
270 |
|
p.identifier = project.identifier
|
271 |
|
next unless p.save
|
272 |
|
projects_map[project.id] = p.id
|
273 |
|
p.enabled_module_names = ['issue_tracking', 'news', 'wiki']
|
274 |
|
p.trackers << TRACKER_BUG
|
275 |
|
p.trackers << TRACKER_FEATURE
|
276 |
|
print '.'
|
277 |
|
|
278 |
|
# Project members
|
279 |
|
project.members.each do |member|
|
|
276 |
p = Project.new :name => encode(project.name),
|
|
277 |
:description => encode(project.description),
|
|
278 |
:trackers => [TRACKER_BUG,TRACKER_FEATURE]
|
|
279 |
p.identifier = project.identifier
|
|
280 |
p.is_public = (project.view_state == 10)
|
|
281 |
next unless p.save
|
|
282 |
projects_map[project.id] = p.id
|
|
283 |
p.enabled_module_names = ['issue_tracking', 'news', 'wiki']
|
|
284 |
print '.'
|
|
285 |
|
|
286 |
# Project members
|
|
287 |
project.members.each do |member|
|
280 |
288 |
m = Member.new :user => User.find_by_id(users_map[member.user_id]),
|
281 |
|
:roles => [ROLE_MAPPING[member.access_level] || DEFAULT_ROLE]
|
282 |
|
m.project = p
|
283 |
|
m.save
|
284 |
|
end
|
285 |
|
|
286 |
|
# Project versions
|
287 |
|
project.versions.each do |version|
|
|
289 |
:roles => [ROLE_MAPPING[member.access_level] || DEFAULT_ROLE]
|
|
290 |
m.project = p
|
|
291 |
m.save
|
|
292 |
end
|
|
293 |
|
|
294 |
# Project versions
|
|
295 |
project.versions.each do |version|
|
288 |
296 |
v = Version.new :name => encode(version.version),
|
289 |
297 |
:description => encode(version.description),
|
290 |
|
:effective_date => (version.date_order ? version.date_order.to_date : nil)
|
|
298 |
:effective_date => (version.date_order ? Time.at(version.date_order).to_date : nil)
|
291 |
299 |
v.project = p
|
292 |
300 |
v.save
|
293 |
301 |
versions_map[version.id] = v.id
|
294 |
|
end
|
295 |
|
|
296 |
|
# Project categories
|
297 |
|
project.categories.each do |category|
|
298 |
|
g = IssueCategory.new :name => category.category[0,30]
|
|
302 |
end
|
|
303 |
|
|
304 |
# Project categories
|
|
305 |
project.categories.each do |category|
|
|
306 |
g = IssueCategory.new :name => category.category
|
299 |
307 |
g.project = p
|
300 |
308 |
g.save
|
301 |
309 |
categories_map[category.category] = g.id
|
302 |
|
end
|
|
310 |
end
|
303 |
311 |
end
|
|
312 |
puts
|
|
313 |
|
|
314 |
# Project Hierarchy
|
|
315 |
print "Making Project Hierarchy"
|
|
316 |
MantisProjectHierarchy.find(:all).each do |link|
|
|
317 |
next unless p = Project.find_by_id(projects_map[link.child_id])
|
|
318 |
p.set_parent!(projects_map[link.parent_id])
|
|
319 |
print '.'
|
|
320 |
end
|
304 |
321 |
puts
|
305 |
322 |
|
306 |
323 |
# Bugs
|
... | ... | |
310 |
327 |
keep_bug_ids = (Issue.count == 0)
|
311 |
328 |
MantisBug.find_each(:batch_size => 200) do |bug|
|
312 |
329 |
next unless projects_map[bug.project_id] && users_map[bug.reporter_id]
|
313 |
|
i = Issue.new :project_id => projects_map[bug.project_id],
|
|
330 |
i = Issue.new :project_id => projects_map[bug.project_id],
|
314 |
331 |
:subject => encode(bug.summary),
|
315 |
332 |
:description => encode(bug.bug_text.full_description),
|
316 |
333 |
:priority => PRIORITY_MAPPING[bug.priority] || DEFAULT_PRIORITY,
|
317 |
|
:created_on => bug.date_submitted,
|
318 |
|
:updated_on => bug.last_updated
|
319 |
|
i.author = User.find_by_id(users_map[bug.reporter_id])
|
320 |
|
i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category[0,30]) unless bug.category.blank?
|
321 |
|
i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank?
|
322 |
|
i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS
|
323 |
|
i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG)
|
324 |
|
i.id = bug.id if keep_bug_ids
|
325 |
|
next unless i.save
|
326 |
|
issues_map[bug.id] = i.id
|
327 |
|
print '.'
|
328 |
|
STDOUT.flush
|
|
334 |
:created_on => Time.at(bug.date_submitted)
|
|
335 |
i.author = User.find_by_id(users_map[bug.reporter_id])
|
|
336 |
i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category) unless bug.category.blank?
|
|
337 |
i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank?
|
|
338 |
i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS
|
|
339 |
i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG)
|
|
340 |
i.start_date = Time.at(bug.date_submitted).to_date
|
|
341 |
i.due_date = (bug.due_date <= bug.date_submitted)? nil:Time.at(bug.due_date).to_date
|
|
342 |
i.updated_on = Time.at(bug.last_updated)
|
|
343 |
i.id = bug.id if keep_bug_ids
|
|
344 |
next unless i.save
|
|
345 |
issues_map[bug.id] = i.id
|
|
346 |
print '.'
|
|
347 |
STDOUT.flush
|
329 |
348 |
|
330 |
349 |
# Assignee
|
331 |
350 |
# Redmine checks that the assignee is a project member
|
... | ... | |
333 |
352 |
i.assigned_to = User.find_by_id(users_map[bug.handler_id])
|
334 |
353 |
i.save_with_validation(false)
|
335 |
354 |
end
|
336 |
|
|
337 |
|
# Bug notes
|
338 |
|
bug.bug_notes.each do |note|
|
339 |
|
next unless users_map[note.reporter_id]
|
|
355 |
|
|
356 |
# Bug notes
|
|
357 |
bug.bug_notes.each do |note|
|
|
358 |
next unless users_map[note.reporter_id]
|
340 |
359 |
n = Journal.new :notes => encode(note.bug_note_text.note),
|
341 |
|
:created_on => note.date_submitted
|
|
360 |
:created_on => Time.at(note.date_submitted)
|
342 |
361 |
n.user = User.find_by_id(users_map[note.reporter_id])
|
343 |
362 |
n.journalized = i
|
344 |
363 |
n.save
|
345 |
|
end
|
346 |
|
|
|
364 |
end
|
|
365 |
|
347 |
366 |
# Bug files
|
348 |
367 |
bug.bug_files.each do |file|
|
349 |
368 |
a = Attachment.new :created_on => file.date_added
|
... | ... | |
376 |
395 |
STDOUT.flush
|
377 |
396 |
end
|
378 |
397 |
puts
|
379 |
|
|
380 |
398 |
# News
|
381 |
399 |
print "Migrating news"
|
382 |
400 |
News.destroy_all
|
... | ... | |
385 |
403 |
n = News.new :project_id => projects_map[news.project_id],
|
386 |
404 |
:title => encode(news.headline[0..59]),
|
387 |
405 |
:description => encode(news.body),
|
388 |
|
:created_on => news.date_posted
|
|
406 |
:created_on => Time.at(news.date_posted)
|
389 |
407 |
n.author = User.find_by_id(users_map[news.poster_id])
|
390 |
408 |
n.save
|
391 |
409 |
print '.'
|
... | ... | |
508 |
526 |
|
509 |
527 |
MantisMigrate.establish_connection db_params
|
510 |
528 |
MantisMigrate.migrate
|
|
529 |
|
511 |
530 |
end
|
512 |
531 |
end
|