|
1 |
|
|
2 |
require 'active_record'
|
|
3 |
require 'iconv'
|
|
4 |
require 'pp'
|
|
5 |
|
|
6 |
$DBG = false
|
|
7 |
$stdout.sync = true
|
|
8 |
ActiveRecord::Base.record_timestamps = false
|
|
9 |
|
|
10 |
namespace :redmine do
|
|
11 |
desc 'Scarab migration script'
|
|
12 |
task :migrate_from_scarab => :environment do
|
|
13 |
|
|
14 |
module ScarabMigrate
|
|
15 |
TICKET_MAP = []
|
|
16 |
|
|
17 |
DEFAULT_STATUS = IssueStatus.default
|
|
18 |
assigned_status = IssueStatus.find_by_position(2)
|
|
19 |
resolved_status = IssueStatus.find_by_position(3)
|
|
20 |
feedback_status = IssueStatus.find_by_position(4)
|
|
21 |
closed_status = IssueStatus.find :first, :conditions => { :is_closed => true }
|
|
22 |
STATUS_MAPPING = {'New' => DEFAULT_STATUS,
|
|
23 |
'Reopened' => feedback_status,
|
|
24 |
'Assigned' => assigned_status,
|
|
25 |
'Resolved' => resolved_status,
|
|
26 |
'Unconfirmed' => feedback_status,
|
|
27 |
'Verified' => closed_status,
|
|
28 |
'Closed' => closed_status,
|
|
29 |
'Fixed' => closed_status,
|
|
30 |
'Invalid' => closed_status,
|
|
31 |
'Wontfix' => closed_status,
|
|
32 |
'Later' => feedback_status,
|
|
33 |
'Remind' => feedback_status,
|
|
34 |
'Duplicate' => closed_status,
|
|
35 |
'Worksforme' => closed_status,
|
|
36 |
'Moved' => closed_status,
|
|
37 |
'Init' => DEFAULT_STATUS,
|
|
38 |
'Assigned' => assigned_status,
|
|
39 |
'Assigend' => assigned_status,
|
|
40 |
'Missing Data' => feedback_status
|
|
41 |
}
|
|
42 |
|
|
43 |
priorities = Enumeration.get_values('IPRI')
|
|
44 |
DEFAULT_PRIORITY = priorities[0]
|
|
45 |
PRIORITY_MAPPING = {'lowest' => priorities[0],
|
|
46 |
'low' => priorities[0],
|
|
47 |
'normal' => priorities[1],
|
|
48 |
'high' => priorities[2],
|
|
49 |
'highest' => priorities[3],
|
|
50 |
# ---
|
|
51 |
'trivial' => priorities[0],
|
|
52 |
'minor' => priorities[1],
|
|
53 |
'major' => priorities[2],
|
|
54 |
'critical' => priorities[3],
|
|
55 |
'blocker' => priorities[4],
|
|
56 |
# --- 7
|
|
57 |
'Low' => priorities[0],
|
|
58 |
'Undecided' => priorities[0],
|
|
59 |
'Medium' => priorities[1],
|
|
60 |
'High' => priorities[2],
|
|
61 |
# --- 9
|
|
62 |
'Blocker' => priorities[4],
|
|
63 |
'Critical' => priorities[3],
|
|
64 |
'Major' => priorities[2],
|
|
65 |
'Normal' => priorities[1],
|
|
66 |
'Minor' => priorities[0],
|
|
67 |
'Trivial' => priorities[0],
|
|
68 |
'Enhancement' => priorities[0],
|
|
69 |
'Cosmetic' => priorities[0],
|
|
70 |
'Serious' => priorities[3],
|
|
71 |
'Undecided' => priorities[0]
|
|
72 |
}
|
|
73 |
|
|
74 |
|
|
75 |
TRACKER_BUG = Tracker.find_by_position(1)
|
|
76 |
TRACKER_FEATURE = Tracker.find_by_position(2)
|
|
77 |
DEFAULT_TRACKER = TRACKER_BUG
|
|
78 |
TRACKER_MAPPING = {'defect' => TRACKER_BUG,
|
|
79 |
'Enhancement' => TRACKER_FEATURE,
|
|
80 |
'task' => TRACKER_FEATURE,
|
|
81 |
'patch' =>TRACKER_FEATURE
|
|
82 |
}
|
|
83 |
|
|
84 |
roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC')
|
|
85 |
manager_role = roles[0]
|
|
86 |
developer_role = roles[1]
|
|
87 |
reporter_role = roles[2]
|
|
88 |
DEFAULT_ROLE = roles.last
|
|
89 |
ROLE_MAPPING = {'admin' => manager_role,
|
|
90 |
'developer' => developer_role,
|
|
91 |
'reporter' => reporter_role
|
|
92 |
}
|
|
93 |
ATTRIBUTE_NAMES = {
|
|
94 |
:NullAttribute => 0,
|
|
95 |
:Description => 1,
|
|
96 |
:AssignedTo => 2,
|
|
97 |
:Status => 3,
|
|
98 |
:Resolution => 4,
|
|
99 |
:Platform => 5,
|
|
100 |
:OperatingSystem => 6,
|
|
101 |
:Priority => 7,
|
|
102 |
:Vote => 8,
|
|
103 |
:Severity => 9,
|
|
104 |
:AssignedCC => 13,
|
|
105 |
:Summary => 11,
|
|
106 |
:FunctionalArea => 12,
|
|
107 |
:DueTime => 10022,
|
|
108 |
:Version => 10000,
|
|
109 |
:Projekt_type => 10020 # Internes / Externes Projekt
|
|
110 |
}
|
|
111 |
ATTACHMENT_TYPES = {
|
|
112 |
:ATTACHMENT => 1,
|
|
113 |
:COMMENT => 2,
|
|
114 |
:URL => 3,
|
|
115 |
:MODIFICATION => 4
|
|
116 |
}
|
|
117 |
|
|
118 |
class ScarabProject < ActiveRecord::Base
|
|
119 |
set_table_name :SCARAB_MODULE
|
|
120 |
set_primary_key :MODULE_ID
|
|
121 |
belongs_to :owner,
|
|
122 |
:class_name => "ScarabUser",
|
|
123 |
:foreign_key => :OWNER_ID
|
|
124 |
belongs_to :parent,
|
|
125 |
:class_name => "ScarabProject",
|
|
126 |
:foreign_key => :PARENT_ID
|
|
127 |
|
|
128 |
def id
|
|
129 |
read_attribute(:MODULE_ID)
|
|
130 |
end
|
|
131 |
|
|
132 |
def name
|
|
133 |
read_attribute(:MODULE_NAME)[0..29]
|
|
134 |
end
|
|
135 |
|
|
136 |
def identifier
|
|
137 |
prefix = ""
|
|
138 |
if parent.name.split("-").size > 1
|
|
139 |
prefix = parent.name.split("-")[0].downcase + "-"
|
|
140 |
end
|
|
141 |
|
|
142 |
idt = prefix + read_attribute(:MODULE_CODE)
|
|
143 |
if idt.size > 2
|
|
144 |
idt.underscore[0..19].gsub(/[^a-z0-9\-]/, '-')
|
|
145 |
else
|
|
146 |
idt.underscore[0..19].gsub(/[^a-z0-9\-]/, '-') + "-module"
|
|
147 |
end
|
|
148 |
end
|
|
149 |
|
|
150 |
def description
|
|
151 |
read_attribute(:MODULE_DESCRIPTION)
|
|
152 |
end
|
|
153 |
|
|
154 |
def parent_id
|
|
155 |
read_attribute(:PARENT_ID)
|
|
156 |
end
|
|
157 |
|
|
158 |
def owner_id
|
|
159 |
read_attribute(:OWNER_ID)
|
|
160 |
end
|
|
161 |
|
|
162 |
def deleted?
|
|
163 |
read_attribute(:DELETED).to_i == 1 ? true : false
|
|
164 |
end
|
|
165 |
end
|
|
166 |
|
|
167 |
class ScarabIssue < ActiveRecord::Base
|
|
168 |
set_table_name :SCARAB_ISSUE
|
|
169 |
set_primary_key :ISSUE_ID
|
|
170 |
|
|
171 |
belongs_to :project,
|
|
172 |
:class_name => "ScarabProject",
|
|
173 |
:foreign_key => :MODULE_ID
|
|
174 |
has_many :attribute_values,
|
|
175 |
:class_name => "ScarabIssueAttributeValue",
|
|
176 |
:foreign_key => :ISSUE_ID
|
|
177 |
has_many :activities,
|
|
178 |
:class_name => "ScarabActivity",
|
|
179 |
:foreign_key => :ISSUE_ID
|
|
180 |
has_many :attachments,
|
|
181 |
:class_name => "ScarabAttachment",
|
|
182 |
:foreign_key => :ISSUE_ID
|
|
183 |
|
|
184 |
def id
|
|
185 |
read_attribute(:ISSUE_ID)
|
|
186 |
end
|
|
187 |
|
|
188 |
def project_id
|
|
189 |
read_attribute(:MODULE_ID)
|
|
190 |
end
|
|
191 |
|
|
192 |
def scarab_number
|
|
193 |
"(_ScarabId_ *#" + read_attribute(:ID_PREFIX).to_s + read_attribute(:ID_COUNT).to_s + "*) "
|
|
194 |
end
|
|
195 |
|
|
196 |
def id_prefix
|
|
197 |
read_attribute(:ID_PREFIX)
|
|
198 |
end
|
|
199 |
|
|
200 |
def id_count
|
|
201 |
read_attribute(:ID_COUNT)
|
|
202 |
end
|
|
203 |
|
|
204 |
def created_transaction_id
|
|
205 |
read_attribute(:CREATED_TRANS_ID)
|
|
206 |
end
|
|
207 |
|
|
208 |
def updated_transaction_id
|
|
209 |
read_attribute(:LAST_TRANS_ID)
|
|
210 |
end
|
|
211 |
|
|
212 |
def deleted?
|
|
213 |
read_attribute(:DELETED).to_i == 1 ? true : false
|
|
214 |
end
|
|
215 |
|
|
216 |
def moved?
|
|
217 |
read_attribute(:MOVED).to_i == 1 ? true : false
|
|
218 |
end
|
|
219 |
end
|
|
220 |
|
|
221 |
class ScarabIssueAttributeValue < ActiveRecord::Base
|
|
222 |
set_table_name :SCARAB_ISSUE_ATTRIBUTE_VALUE
|
|
223 |
belongs_to :issue,
|
|
224 |
:class_name => "ScarabIssue",
|
|
225 |
:foreign_key => :ISSUE_ID
|
|
226 |
|
|
227 |
def value
|
|
228 |
read_attribute(:VALUE)
|
|
229 |
end
|
|
230 |
|
|
231 |
def user_id
|
|
232 |
read_attribute(:USER_ID)
|
|
233 |
end
|
|
234 |
end
|
|
235 |
|
|
236 |
class ScarabAttribute < ActiveRecord::Base
|
|
237 |
set_table_name :SCARAB_ATTRIBUTE
|
|
238 |
set_primary_key :ATTRIBUTE_ID
|
|
239 |
|
|
240 |
def name
|
|
241 |
read_attribute(:ATTRIBUTE_NAME)
|
|
242 |
end
|
|
243 |
end
|
|
244 |
|
|
245 |
class ScarabActivity < ActiveRecord::Base
|
|
246 |
set_table_name :SCARAB_ACTIVITY
|
|
247 |
set_primary_key :ACTIVITY_ID
|
|
248 |
belongs_to :issue,
|
|
249 |
:class_name => "ScarabIssue",
|
|
250 |
:foreign_key => :ISSUE_ID
|
|
251 |
belongs_to :transaction,
|
|
252 |
:class_name => "ScarabTransaction",
|
|
253 |
:foreign_key => :TRANSACTION_ID
|
|
254 |
belongs_to :attribute,
|
|
255 |
:class_name => "ScarabAttribute",
|
|
256 |
:foreign_key => :ATTRIBUTE_ID
|
|
257 |
|
|
258 |
def old_value
|
|
259 |
read_attribute(:OLD_VALUE)
|
|
260 |
end
|
|
261 |
|
|
262 |
def new_value
|
|
263 |
read_attribute(:NEW_VALUE)
|
|
264 |
end
|
|
265 |
|
|
266 |
def type
|
|
267 |
read_attribute(:ACTIVITY_TYPE)
|
|
268 |
end
|
|
269 |
|
|
270 |
def attribute_id
|
|
271 |
read_attribute(:ATTRIBUTE_ID)
|
|
272 |
end
|
|
273 |
end
|
|
274 |
|
|
275 |
class ScarabAttachment < ActiveRecord::Base
|
|
276 |
set_table_name :SCARAB_ATTACHMENT
|
|
277 |
set_primary_key :ATTACHMENT_ID
|
|
278 |
belongs_to :issue, :class_name => "ScarabIssue", :foreign_key => :ISSUE_ID
|
|
279 |
belongs_to :creator, :class_name => "ScarabUser", :foreign_key => :CREATED_BY
|
|
280 |
belongs_to :updator, :class_name => "ScarabUser", :foreign_key => :MODIFIED_BY
|
|
281 |
|
|
282 |
def name
|
|
283 |
read_attribute(:ATTACHMENT_NAME)
|
|
284 |
end
|
|
285 |
|
|
286 |
def data
|
|
287 |
read_attribute(:ATTACHMENT_DATA)
|
|
288 |
end
|
|
289 |
|
|
290 |
def attachment_type_id
|
|
291 |
read_attribute(:ATTACHMENT_TYPE_ID)
|
|
292 |
end
|
|
293 |
|
|
294 |
def original_filename
|
|
295 |
orig_file_name = ScarabMigrate.encode(read_attribute(:ATTACHMENT_FILE_PATH))
|
|
296 |
scarab_number = issue.id_prefix + issue.id_count.to_s
|
|
297 |
scarab_number + "_" + id.to_s + "_" + orig_file_name
|
|
298 |
end
|
|
299 |
|
|
300 |
def content_type
|
|
301 |
read_attribute(:ATTACHMENT_MIME_TYPE)
|
|
302 |
end
|
|
303 |
|
|
304 |
def exist?
|
|
305 |
File.file? scarab_fullpath
|
|
306 |
end
|
|
307 |
|
|
308 |
def read
|
|
309 |
File.open("#{scarab_fullpath}").read
|
|
310 |
end
|
|
311 |
|
|
312 |
def size
|
|
313 |
File.new("#{scarab_fullpath}").stat.blksize
|
|
314 |
end
|
|
315 |
|
|
316 |
def description
|
|
317 |
read_attribute(:ATTACHMENT_NAME)
|
|
318 |
end
|
|
319 |
|
|
320 |
def updated_date
|
|
321 |
read_attribute(:MODIFIED_DATE)
|
|
322 |
end
|
|
323 |
|
|
324 |
def created_date
|
|
325 |
read_attribute(:CREATED_DATE)
|
|
326 |
end
|
|
327 |
|
|
328 |
def deleted?
|
|
329 |
read_attribute(:DELETED) == 1 ? true : false
|
|
330 |
end
|
|
331 |
private
|
|
332 |
def scarab_fullpath
|
|
333 |
full_path = []
|
|
334 |
full_path << "#{ScarabMigrate.scarab_attachments_directory}"
|
|
335 |
full_path << "mod" + issue.project_id.to_s
|
|
336 |
full_path << "0" # TODO investigate what's "0" in scarab dir path
|
|
337 |
full_path << "#{original_filename}"
|
|
338 |
full_path.join(File::SEPARATOR)
|
|
339 |
end
|
|
340 |
end
|
|
341 |
|
|
342 |
class ScarabUser < ActiveRecord::Base
|
|
343 |
set_table_name :TURBINE_USER
|
|
344 |
has_many :projects,
|
|
345 |
:class_name => "ScarabProject",
|
|
346 |
:foreign_key => :OWNER_ID
|
|
347 |
has_many :transactions,
|
|
348 |
:class_name => "ScarabTransaction",
|
|
349 |
:foreign_key => :CREATED_BY
|
|
350 |
|
|
351 |
set_primary_key :USER_ID
|
|
352 |
|
|
353 |
def id
|
|
354 |
read_attribute(:USER_ID)
|
|
355 |
end
|
|
356 |
|
|
357 |
def username
|
|
358 |
read_attribute(:LOGIN_NAME)
|
|
359 |
end
|
|
360 |
|
|
361 |
def firstname
|
|
362 |
read_attribute(:FIRST_NAME)
|
|
363 |
end
|
|
364 |
|
|
365 |
def lastname
|
|
366 |
read_attribute(:LAST_NAME)
|
|
367 |
end
|
|
368 |
|
|
369 |
def email
|
|
370 |
read_attribute(:EMAIL)
|
|
371 |
end
|
|
372 |
|
|
373 |
def last_visit
|
|
374 |
read_attribute(:LAST_LOGIN)
|
|
375 |
end
|
|
376 |
|
|
377 |
def deleted?
|
|
378 |
read_attribute(:CONFIRM_VALUE) == 'DELETED'
|
|
379 |
end
|
|
380 |
end
|
|
381 |
|
|
382 |
class ScarabTransaction < ActiveRecord::Base
|
|
383 |
set_table_name :SCARAB_TRANSACTION
|
|
384 |
belongs_to :creator,
|
|
385 |
:class_name => "ScarabUser",
|
|
386 |
:foreign_key => :CREATED_BY
|
|
387 |
|
|
388 |
set_primary_key :TRANSACTION_ID
|
|
389 |
|
|
390 |
def id
|
|
391 |
read_attribute(:TRANSACTION_ID)
|
|
392 |
end
|
|
393 |
|
|
394 |
def date
|
|
395 |
read_attribute(:CREATED_DATE)
|
|
396 |
end
|
|
397 |
end
|
|
398 |
|
|
399 |
def self.connection_params
|
|
400 |
if %w(sqlite sqlite3).include?(scarab_adapter)
|
|
401 |
{:adapter => scarab_adapter,
|
|
402 |
:database => scarab_db_path}
|
|
403 |
else
|
|
404 |
{:adapter => scarab_adapter,
|
|
405 |
:database => scarab_db_name,
|
|
406 |
:host => scarab_db_host,
|
|
407 |
:port => scarab_db_port,
|
|
408 |
:username => scarab_db_username,
|
|
409 |
:password => scarab_db_password
|
|
410 |
}
|
|
411 |
end
|
|
412 |
end
|
|
413 |
|
|
414 |
def self.set_scarab_directory(path)
|
|
415 |
@@scarab_directory = path
|
|
416 |
raise "This directory doesn't exist!" unless File.directory?(path)
|
|
417 |
raise "#{scarab_attachments_directory} doesn't exist!" unless File.directory?(scarab_attachments_directory)
|
|
418 |
@@scarab_directory
|
|
419 |
rescue Exception => e
|
|
420 |
puts e
|
|
421 |
return false
|
|
422 |
end
|
|
423 |
|
|
424 |
def self.scarab_directory
|
|
425 |
@@scarab_directory
|
|
426 |
end
|
|
427 |
|
|
428 |
def self.set_scarab_adapter(adapter)
|
|
429 |
return false if adapter.blank?
|
|
430 |
raise "Unknown adapter: #{adapter}!" unless %w(sqlite sqlite3 mysql postgresql).include?(adapter)
|
|
431 |
# If adapter is sqlite or sqlite3, make sure that scarab.db exists
|
|
432 |
raise "#{scarab_db_path} doesn't exist!" if %w(sqlite sqlite3).include?(adapter) && !File.exist?(scarab_db_path)
|
|
433 |
@@scarab_adapter = adapter
|
|
434 |
rescue Exception => e
|
|
435 |
puts e
|
|
436 |
return false
|
|
437 |
end
|
|
438 |
|
|
439 |
def self.set_scarab_db_host(host)
|
|
440 |
return nil if host.blank?
|
|
441 |
@@scarab_db_host = host
|
|
442 |
end
|
|
443 |
|
|
444 |
def self.set_scarab_db_port(port)
|
|
445 |
return nil if port.to_i == 0
|
|
446 |
@@scarab_db_port = port.to_i
|
|
447 |
end
|
|
448 |
|
|
449 |
def self.set_scarab_db_name(name)
|
|
450 |
return nil if name.blank?
|
|
451 |
@@scarab_db_name = name
|
|
452 |
end
|
|
453 |
|
|
454 |
def self.set_scarab_db_username(username)
|
|
455 |
@@scarab_db_username = username
|
|
456 |
end
|
|
457 |
|
|
458 |
def self.set_scarab_db_password(password)
|
|
459 |
@@scarab_db_password = password
|
|
460 |
end
|
|
461 |
|
|
462 |
def self.encoding(charset)
|
|
463 |
@ic = Iconv.new('UTF-8', charset)
|
|
464 |
rescue Iconv::InvalidEncoding
|
|
465 |
puts "Invalid encoding!"
|
|
466 |
return false
|
|
467 |
end
|
|
468 |
|
|
469 |
mattr_reader :scarab_directory, :scarab_adapter, :scarab_db_host, :scarab_db_port, :scarab_db_name, :scarab_db_username, :scarab_db_password
|
|
470 |
|
|
471 |
def self.scarab_db_path; "#{scarab_directory}/db/scarab.db" end
|
|
472 |
def self.scarab_attachments_directory
|
|
473 |
"#{scarab_directory}/" # TODO set correctly
|
|
474 |
end
|
|
475 |
|
|
476 |
def self.establish_connection
|
|
477 |
constants.each do |const|
|
|
478 |
klass = const_get(const)
|
|
479 |
next unless klass.respond_to? 'establish_connection'
|
|
480 |
klass.establish_connection connection_params
|
|
481 |
end
|
|
482 |
end
|
|
483 |
|
|
484 |
def self.migrate
|
|
485 |
establish_connection
|
|
486 |
|
|
487 |
# Users
|
|
488 |
print "Migrating users"
|
|
489 |
#User.delete_all "login <> 'admin'"
|
|
490 |
users_map = {}
|
|
491 |
users_migrated = 0
|
|
492 |
ScarabUser.find(:all).each do |user|
|
|
493 |
next if user.deleted?
|
|
494 |
u = User.new :firstname => encode(user.firstname),
|
|
495 |
:lastname => encode(user.lastname),
|
|
496 |
:mail => user.email,
|
|
497 |
:last_login_on => user.last_visit
|
|
498 |
u.login = user.username
|
|
499 |
u.password = 'scarab'
|
|
500 |
#u.admin = true if user.access_level == 90
|
|
501 |
next unless u.save
|
|
502 |
users_migrated += 1
|
|
503 |
users_map[user.id] = u.id
|
|
504 |
print '.'
|
|
505 |
end
|
|
506 |
puts
|
|
507 |
|
|
508 |
|
|
509 |
# Projects
|
|
510 |
print "Migrating projects"
|
|
511 |
#Project.destroy_all
|
|
512 |
projects_map = {}
|
|
513 |
versions_map = {}
|
|
514 |
categories_map = {}
|
|
515 |
ScarabProject.find(:all, :order => :MODULE_ID).each do |project|
|
|
516 |
next if project.deleted?
|
|
517 |
next if project.id == 0 # Global Scarab parent project, do not migrate
|
|
518 |
p = Project.new :name => encode(project.name),
|
|
519 |
:description => encode(project.description),
|
|
520 |
:created_on => Time.now,
|
|
521 |
:updated_on => Time.now
|
|
522 |
|
|
523 |
# Project parent relationship
|
|
524 |
parent = ScarabProject.find(:first, :conditions => {:MODULE_ID => project.parent_id})
|
|
525 |
unless project.parent_id == 0
|
|
526 |
p.parent_id = Project.find(:first, :conditions => {:identifier => parent.identifier}).id
|
|
527 |
end
|
|
528 |
|
|
529 |
p.identifier = project.identifier
|
|
530 |
|
|
531 |
print "\nCreate project: " + project.name + " [yN] "
|
|
532 |
answer = STDIN.gets.chomp!
|
|
533 |
next unless answer == "y"
|
|
534 |
|
|
535 |
unless p.save
|
|
536 |
p p.errors if $DBG
|
|
537 |
next
|
|
538 |
end
|
|
539 |
projects_map[project.id] = p.id
|
|
540 |
p.enabled_module_names = ['issue_tracking', 'news', 'wiki']
|
|
541 |
p.trackers << TRACKER_BUG
|
|
542 |
p.trackers << TRACKER_FEATURE
|
|
543 |
puts "created with identifier: " + p.identifier
|
|
544 |
|
|
545 |
# Project Owner as manager member
|
|
546 |
scarab_owner = ScarabUser.find(:first, :conditions => {:USER_ID => project.owner_id})
|
|
547 |
owner = Member.new
|
|
548 |
owner.role = ROLE_MAPPING['admin']
|
|
549 |
owner.user = User.find(:first, :conditions => {:login => scarab_owner.username})
|
|
550 |
owner.project = p
|
|
551 |
owner.save
|
|
552 |
end
|
|
553 |
puts
|
|
554 |
|
|
555 |
|
|
556 |
# Issues
|
|
557 |
print "Migrating issues"
|
|
558 |
issues_map = {}
|
|
559 |
moved = 0
|
|
560 |
deleted = 0
|
|
561 |
no_scarab_project = 0
|
|
562 |
no_project = 0
|
|
563 |
not_validated = 0
|
|
564 |
issue_counter = 0
|
|
565 |
ScarabIssue.find(:all, :order => 'ISSUE_ID ASC').each do |issue|
|
|
566 |
issue_counter += 1
|
|
567 |
if issue.deleted?
|
|
568 |
deleted += 1
|
|
569 |
next
|
|
570 |
end
|
|
571 |
if issue.moved?
|
|
572 |
moved += 1
|
|
573 |
next
|
|
574 |
end
|
|
575 |
scarab_project = ScarabProject.find(:first, :conditions => {:MODULE_ID => issue.project_id})
|
|
576 |
unless scarab_project
|
|
577 |
no_scarab_project += 1
|
|
578 |
next
|
|
579 |
end
|
|
580 |
project = Project.find(:first, :conditions => {:identifier => scarab_project.identifier})
|
|
581 |
unless project
|
|
582 |
no_project += 1
|
|
583 |
next
|
|
584 |
end
|
|
585 |
i = Issue.new :project_id => project.id
|
|
586 |
|
|
587 |
description = ScarabIssueAttributeValue.find(:first, :conditions => {
|
|
588 |
:ISSUE_ID => issue.id,
|
|
589 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Description]
|
|
590 |
})
|
|
591 |
summary = ScarabIssueAttributeValue.find(:first, :conditions => {
|
|
592 |
:ISSUE_ID => issue.id,
|
|
593 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Summary]
|
|
594 |
})
|
|
595 |
if summary && summary.value && summary.value.size > 1
|
|
596 |
i.subject = encode(summary.value)
|
|
597 |
else
|
|
598 |
i.subject = encode(description.value[0..40])
|
|
599 |
end
|
|
600 |
if description
|
|
601 |
i.description = issue.scarab_number.to_s + encode(description.value)
|
|
602 |
else
|
|
603 |
i.description = issue.scarab_number.to_s + encode(summary.value)
|
|
604 |
end
|
|
605 |
|
|
606 |
status = ScarabIssueAttributeValue.find(:first, :conditions => {
|
|
607 |
:ISSUE_ID => issue.id,
|
|
608 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Status]
|
|
609 |
})
|
|
610 |
i.status = status ? STATUS_MAPPING[status.value] : DEFAULT_STATUS
|
|
611 |
resolution = ScarabIssueAttributeValue.find(:first, :conditions => {
|
|
612 |
:ISSUE_ID => issue.id,
|
|
613 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Resolution]
|
|
614 |
})
|
|
615 |
i.status = STATUS_MAPPING[resolution.value] if resolution && resolution.value
|
|
616 |
|
|
617 |
severity = ScarabIssueAttributeValue.find(:first, :conditions => {
|
|
618 |
:ISSUE_ID => issue.id,
|
|
619 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Severity]
|
|
620 |
})
|
|
621 |
if severity
|
|
622 |
i.priority = PRIORITY_MAPPING[severity.value]
|
|
623 |
i.tracker = TRACKER_MAPPING[severity.value] || TRACKER_BUG
|
|
624 |
else
|
|
625 |
priority = ScarabIssueAttributeValue.find(:first, :conditions => {
|
|
626 |
:ISSUE_ID => issue.id,
|
|
627 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:Priority]
|
|
628 |
})
|
|
629 |
i.priority = PRIORITY_MAPPING[priority.value] if priority
|
|
630 |
i.tracker = TRACKER_BUG
|
|
631 |
end
|
|
632 |
|
|
633 |
created_transaction = ScarabTransaction.find(:first, :conditions => {
|
|
634 |
:TRANSACTION_ID => issue.created_transaction_id
|
|
635 |
})
|
|
636 |
scarab_author = ScarabUser.find(:first, :conditions => {:USER_ID => created_transaction.creator.id})
|
|
637 |
i.author = User.find(:first, :conditions => {:login => scarab_author.username})
|
|
638 |
i.author ||= User.find(:first, :conditions => {:login => 'Admin'})
|
|
639 |
i.author ||= User.find(:first)
|
|
640 |
updated_transaction = ScarabTransaction.find(:first, :conditions => {
|
|
641 |
:TRANSACTION_ID => issue.updated_transaction_id
|
|
642 |
})
|
|
643 |
i.created_on = created_transaction ? created_transaction.date : Time.now
|
|
644 |
i.updated_on = updated_transaction ? updated_transaction.date : Time.now
|
|
645 |
|
|
646 |
assigned_tos = ScarabIssueAttributeValue.find(:all, :conditions => {
|
|
647 |
:ISSUE_ID => issue.id,
|
|
648 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:AssignedTo]
|
|
649 |
})
|
|
650 |
assigned_ccs = ScarabIssueAttributeValue.find(:all, :conditions => {
|
|
651 |
:ISSUE_ID => issue.id,
|
|
652 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:AssignedCC]
|
|
653 |
})
|
|
654 |
scarab_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_tos[0].user_id}) if assigned_tos[0]
|
|
655 |
i.assigned_to = User.find(:first, :conditions => {:login => scarab_assignee.username}) if scarab_assignee
|
|
656 |
|
|
657 |
# Assigned to as 'developer' Member of current Project
|
|
658 |
assigned_tos.each do |assigned_to|
|
|
659 |
s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_to.user_id})
|
|
660 |
developer = Member.new
|
|
661 |
developer.role = ROLE_MAPPING['developer']
|
|
662 |
r_user = User.find(:first, :conditions => {:login => s_assignee.username})
|
|
663 |
developer.user = r_user
|
|
664 |
developer.project = project
|
|
665 |
#i.add_watcher(r_user)
|
|
666 |
next unless developer.save
|
|
667 |
end
|
|
668 |
|
|
669 |
# Assigned to as 'reporter' Member of current Project
|
|
670 |
assigned_ccs.each do |assigned_cc|
|
|
671 |
s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_cc.user_id})
|
|
672 |
reporter = Member.new
|
|
673 |
reporter.role = ROLE_MAPPING['reporter']
|
|
674 |
r_user = User.find(:first, :conditions => {:login => s_assignee.username})
|
|
675 |
reporter.user = r_user
|
|
676 |
reporter.project = project
|
|
677 |
#i.add_watcher(r_user)
|
|
678 |
next unless reporter.save
|
|
679 |
end
|
|
680 |
|
|
681 |
due_date = ScarabIssueAttributeValue.find(:first, :conditions => {
|
|
682 |
:ISSUE_ID => issue.id,
|
|
683 |
:ATTRIBUTE_ID => ATTRIBUTE_NAMES[:DueTime]
|
|
684 |
})
|
|
685 |
i.due_date = due_date if due_date
|
|
686 |
|
|
687 |
unless i.save
|
|
688 |
p i.errors if $DBG
|
|
689 |
not_validated += 1
|
|
690 |
next
|
|
691 |
end
|
|
692 |
|
|
693 |
# Issue Watchers (to)
|
|
694 |
assigned_tos.each do |assigned_to|
|
|
695 |
s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_to.user_id})
|
|
696 |
r_user = User.find(:first, :conditions => {:login => s_assignee.username})
|
|
697 |
i.add_watcher(r_user)
|
|
698 |
end
|
|
699 |
# Issue Watchers (cc)
|
|
700 |
assigned_ccs.each do |assigned_cc|
|
|
701 |
s_assignee = ScarabUser.find(:first, :conditions => {:USER_ID => assigned_cc.user_id})
|
|
702 |
r_user = User.find(:first, :conditions => {:login => s_assignee.username})
|
|
703 |
i.add_watcher(r_user)
|
|
704 |
end
|
|
705 |
|
|
706 |
# Issue Attachments (Comments and Attachments)
|
|
707 |
issue.attachments.each do |a|
|
|
708 |
next if a.deleted?
|
|
709 |
if a.attachment_type_id == ATTACHMENT_TYPES[:COMMENT] ||
|
|
710 |
a.attachment_type_id == ATTACHMENT_TYPES[:MODIFICATION]
|
|
711 |
j = Journal.new
|
|
712 |
next unless encode(a.data).size > 0
|
|
713 |
j.notes = encode(a.data)
|
|
714 |
if r_user = User.find(:first, :conditions => {:login => a.creator.username})
|
|
715 |
j.user = r_user
|
|
716 |
elsif r_adminuser = User.find(:first, :conditions => {:login => 'Admin'})
|
|
717 |
j.user = r_adminuser
|
|
718 |
else
|
|
719 |
j.user = User.find(:first)
|
|
720 |
end
|
|
721 |
j.created_on = a.created_date
|
|
722 |
j.journalized = i
|
|
723 |
unless j.save
|
|
724 |
p j.errors if $DBG
|
|
725 |
next
|
|
726 |
end
|
|
727 |
elsif a.attachment_type_id == ATTACHMENT_TYPES[:ATTACHMENT]
|
|
728 |
r_attachement = Attachment.new :created_on => a.created_date
|
|
729 |
if r_user = User.find(:first, :conditions => {:login => a.creator.username})
|
|
730 |
r_attachement.author = r_user
|
|
731 |
elsif r_adminuser = User.find(:first, :conditions => {:login => 'Admin'})
|
|
732 |
r_attachement.author = r_adminuser
|
|
733 |
else
|
|
734 |
r_attachement.author = User.find(:first)
|
|
735 |
end
|
|
736 |
r_attachement.container = i
|
|
737 |
r_attachement.description = a.name
|
|
738 |
r_attachement.file = a
|
|
739 |
r_attachement.save
|
|
740 |
end
|
|
741 |
end
|
|
742 |
|
|
743 |
# Issue Activities
|
|
744 |
notes_transaction_map = {}
|
|
745 |
issue.activities.each do |a|
|
|
746 |
if a.type == "user_attribute_changed" || a.type == "attribute_changed"
|
|
747 |
if !a.new_value || a.new_value.size == 0
|
|
748 |
next
|
|
749 |
end
|
|
750 |
notes_transaction_map[a.transaction] = [] unless notes_transaction_map[a.transaction]
|
|
751 |
attribute_name = "* *" + a.attribute.name + "*: "
|
|
752 |
from = "_changed from_ " + encode(a.old_value) if a.old_value
|
|
753 |
to = " _to_ " + encode(a.new_value) if a.new_value
|
|
754 |
notes_transaction_map[a.transaction] << attribute_name.to_s + from.to_s + to.to_s
|
|
755 |
end
|
|
756 |
end
|
|
757 |
notes_transaction_map.each do |t, notes|
|
|
758 |
j = Journal.new
|
|
759 |
j.notes = notes.join("\n")
|
|
760 |
if r_user = User.find(:first, :conditions => {:login => t.creator.username})
|
|
761 |
j.user = r_user
|
|
762 |
elsif r_adminuser = User.find(:first, :conditions => {:login => 'Admin'})
|
|
763 |
j.user = r_adminuser
|
|
764 |
else
|
|
765 |
j.user = User.find(:first)
|
|
766 |
end
|
|
767 |
j.created_on = t.date
|
|
768 |
j.journalized = i
|
|
769 |
unless j.save
|
|
770 |
p j.errors if $DBG
|
|
771 |
next
|
|
772 |
end
|
|
773 |
end
|
|
774 |
|
|
775 |
print "."
|
|
776 |
end
|
|
777 |
puts
|
|
778 |
|
|
779 |
# Summary
|
|
780 |
puts
|
|
781 |
puts "i moved: #{moved}" if $DBG
|
|
782 |
puts "i deleted: #{deleted}" if $DBG
|
|
783 |
puts "i no_project: #{no_project}" if $DBG
|
|
784 |
puts "i no_scarab_project: #{no_scarab_project}" if $DBG
|
|
785 |
puts "i not_validated: #{not_validated}" if $DBG
|
|
786 |
puts "i issue_counter: #{issue_counter}" if $DBG
|
|
787 |
puts "Users: #{users_migrated}/#{ScarabUser.count}"
|
|
788 |
puts "Projects: #{Project.count}/#{ScarabProject.count}"
|
|
789 |
puts "Issues: #{Issue.count}/#{ScarabIssue.count}"
|
|
790 |
puts "Comments and Attachments: #{Journal.count + Attachment.count}/#{ScarabAttachment.count + ScarabActivity.count}"
|
|
791 |
end
|
|
792 |
|
|
793 |
def self.encoding(charset)
|
|
794 |
@ic = Iconv.new('UTF-8', charset)
|
|
795 |
#rescue Iconv::InvalidEncoding
|
|
796 |
# return false
|
|
797 |
end
|
|
798 |
|
|
799 |
private
|
|
800 |
def self.encode(text)
|
|
801 |
@ic.iconv text
|
|
802 |
rescue
|
|
803 |
text
|
|
804 |
end
|
|
805 |
end
|
|
806 |
|
|
807 |
puts
|
|
808 |
if Redmine::DefaultData::Loader.no_data?
|
|
809 |
puts "Redmine configuration need to be loaded before importing data."
|
|
810 |
puts "Please, run this first:"
|
|
811 |
puts
|
|
812 |
puts " rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\""
|
|
813 |
exit
|
|
814 |
end
|
|
815 |
|
|
816 |
puts "WARNING: new projects will be added to Redmine during this process."
|
|
817 |
print "Are you sure you want to continue ? [y/N] "
|
|
818 |
break unless STDIN.gets.match(/^y$/i)
|
|
819 |
puts
|
|
820 |
|
|
821 |
def prompt(text, options = {}, &block)
|
|
822 |
default = options[:default] || ''
|
|
823 |
while true
|
|
824 |
print "#{text} [#{default}]: "
|
|
825 |
value = STDIN.gets.chomp!
|
|
826 |
value = default if value.blank?
|
|
827 |
break if yield value
|
|
828 |
end
|
|
829 |
end
|
|
830 |
|
|
831 |
DEFAULT_PORTS = {'mysql' => 3306, 'postgresql' => 5432}
|
|
832 |
|
|
833 |
prompt('Scarab attachments directory') {|directory| ScarabMigrate.set_scarab_directory directory.strip}
|
|
834 |
prompt('Scarab database adapter (sqlite, sqlite3, mysql, postgresql)', :default => 'mysql') {|adapter| ScarabMigrate.set_scarab_adapter adapter}
|
|
835 |
unless %w(sqlite sqlite3).include?(ScarabMigrate.scarab_adapter)
|
|
836 |
prompt('Scarab database host', :default => 'localhost') {|host| ScarabMigrate.set_scarab_db_host host}
|
|
837 |
prompt('Scarab database port', :default => DEFAULT_PORTS[ScarabMigrate.scarab_adapter]) {|port| ScarabMigrate.set_scarab_db_port port}
|
|
838 |
prompt('Scarab database name', :default => 'scarab') {|name| ScarabMigrate.set_scarab_db_name name}
|
|
839 |
prompt('Scarab database username', :default => 'root') {|username| ScarabMigrate.set_scarab_db_username username}
|
|
840 |
prompt('Scarab database password') {|password| ScarabMigrate.set_scarab_db_password password}
|
|
841 |
end
|
|
842 |
prompt('Scarab database encoding', :default => 'Latin1') {|encoding| ScarabMigrate.encoding encoding}
|
|
843 |
puts
|
|
844 |
|
|
845 |
ScarabMigrate.migrate
|
|
846 |
end
|
|
847 |
end
|