Mercurial > hg > soundsoftware-site
comparison lib/tasks/migrate_from_mantis.rake @ 1115:433d4f72a19b redmine-2.2
Update to Redmine SVN revision 11137 on 2.2-stable branch
author | Chris Cannam |
---|---|
date | Mon, 07 Jan 2013 12:01:42 +0000 |
parents | 0579821a129a |
children | 622f24f53b42 261b3d9a4903 |
comparison
equal
deleted
inserted
replaced
929:5f33065ddc4b | 1115:433d4f72a19b |
---|---|
1 # redMine - project management software | 1 # Redmine - project management software |
2 # Copyright (C) 2006-2007 Jean-Philippe Lang | 2 # Copyright (C) 2006-2012 Jean-Philippe Lang |
3 # | 3 # |
4 # This program is free software; you can redistribute it and/or | 4 # This program is free software; you can redistribute it and/or |
5 # modify it under the terms of the GNU General Public License | 5 # modify it under the terms of the GNU General Public License |
6 # as published by the Free Software Foundation; either version 2 | 6 # as published by the Free Software Foundation; either version 2 |
7 # of the License, or (at your option) any later version. | 7 # of the License, or (at your option) any later version. |
8 # | 8 # |
9 # This program is distributed in the hope that it will be useful, | 9 # This program is distributed in the hope that it will be useful, |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 # GNU General Public License for more details. | 12 # GNU General Public License for more details. |
13 # | 13 # |
14 # You should have received a copy of the GNU General Public License | 14 # You should have received a copy of the GNU General Public License |
15 # along with this program; if not, write to the Free Software | 15 # along with this program; if not, write to the Free Software |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
18 desc 'Mantis migration script' | 18 desc 'Mantis migration script' |
21 require 'iconv' | 21 require 'iconv' |
22 require 'pp' | 22 require 'pp' |
23 | 23 |
24 namespace :redmine do | 24 namespace :redmine do |
25 task :migrate_from_mantis => :environment do | 25 task :migrate_from_mantis => :environment do |
26 | 26 |
27 module MantisMigrate | 27 module MantisMigrate |
28 | 28 |
29 DEFAULT_STATUS = IssueStatus.default | 29 DEFAULT_STATUS = IssueStatus.default |
30 assigned_status = IssueStatus.find_by_position(2) | 30 assigned_status = IssueStatus.find_by_position(2) |
31 resolved_status = IssueStatus.find_by_position(3) | 31 resolved_status = IssueStatus.find_by_position(3) |
32 feedback_status = IssueStatus.find_by_position(4) | 32 feedback_status = IssueStatus.find_by_position(4) |
33 closed_status = IssueStatus.find :first, :conditions => { :is_closed => true } | 33 closed_status = IssueStatus.find :first, :conditions => { :is_closed => true } |
37 40 => DEFAULT_STATUS, # confirmed | 37 40 => DEFAULT_STATUS, # confirmed |
38 50 => assigned_status, # assigned | 38 50 => assigned_status, # assigned |
39 80 => resolved_status, # resolved | 39 80 => resolved_status, # resolved |
40 90 => closed_status # closed | 40 90 => closed_status # closed |
41 } | 41 } |
42 | 42 |
43 priorities = IssuePriority.all | 43 priorities = IssuePriority.all |
44 DEFAULT_PRIORITY = priorities[2] | 44 DEFAULT_PRIORITY = priorities[2] |
45 PRIORITY_MAPPING = {10 => priorities[1], # none | 45 PRIORITY_MAPPING = {10 => priorities[1], # none |
46 20 => priorities[1], # low | 46 20 => priorities[1], # low |
47 30 => priorities[2], # normal | 47 30 => priorities[2], # normal |
48 40 => priorities[3], # high | 48 40 => priorities[3], # high |
49 50 => priorities[4], # urgent | 49 50 => priorities[4], # urgent |
50 60 => priorities[5] # immediate | 50 60 => priorities[5] # immediate |
51 } | 51 } |
52 | 52 |
53 TRACKER_BUG = Tracker.find_by_position(1) | 53 TRACKER_BUG = Tracker.find_by_position(1) |
54 TRACKER_FEATURE = Tracker.find_by_position(2) | 54 TRACKER_FEATURE = Tracker.find_by_position(2) |
55 | 55 |
56 roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC') | 56 roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC') |
57 manager_role = roles[0] | 57 manager_role = roles[0] |
58 developer_role = roles[1] | 58 developer_role = roles[1] |
59 DEFAULT_ROLE = roles.last | 59 DEFAULT_ROLE = roles.last |
60 ROLE_MAPPING = {10 => DEFAULT_ROLE, # viewer | 60 ROLE_MAPPING = {10 => DEFAULT_ROLE, # viewer |
62 40 => DEFAULT_ROLE, # updater | 62 40 => DEFAULT_ROLE, # updater |
63 55 => developer_role, # developer | 63 55 => developer_role, # developer |
64 70 => manager_role, # manager | 64 70 => manager_role, # manager |
65 90 => manager_role # administrator | 65 90 => manager_role # administrator |
66 } | 66 } |
67 | 67 |
68 CUSTOM_FIELD_TYPE_MAPPING = {0 => 'string', # String | 68 CUSTOM_FIELD_TYPE_MAPPING = {0 => 'string', # String |
69 1 => 'int', # Numeric | 69 1 => 'int', # Numeric |
70 2 => 'int', # Float | 70 2 => 'int', # Float |
71 3 => 'list', # Enumeration | 71 3 => 'list', # Enumeration |
72 4 => 'string', # Email | 72 4 => 'string', # Email |
73 5 => 'bool', # Checkbox | 73 5 => 'bool', # Checkbox |
74 6 => 'list', # List | 74 6 => 'list', # List |
75 7 => 'list', # Multiselection list | 75 7 => 'list', # Multiselection list |
76 8 => 'date', # Date | 76 8 => 'date', # Date |
77 } | 77 } |
78 | 78 |
79 RELATION_TYPE_MAPPING = {1 => IssueRelation::TYPE_RELATES, # related to | 79 RELATION_TYPE_MAPPING = {1 => IssueRelation::TYPE_RELATES, # related to |
80 2 => IssueRelation::TYPE_RELATES, # parent of | 80 2 => IssueRelation::TYPE_RELATES, # parent of |
81 3 => IssueRelation::TYPE_RELATES, # child of | 81 3 => IssueRelation::TYPE_RELATES, # child of |
82 0 => IssueRelation::TYPE_DUPLICATES, # duplicate of | 82 0 => IssueRelation::TYPE_DUPLICATES, # duplicate of |
83 4 => IssueRelation::TYPE_DUPLICATES # has duplicate | 83 4 => IssueRelation::TYPE_DUPLICATES # has duplicate |
84 } | 84 } |
85 | 85 |
86 class MantisUser < ActiveRecord::Base | 86 class MantisUser < ActiveRecord::Base |
87 set_table_name :mantis_user_table | 87 self.table_name = :mantis_user_table |
88 | 88 |
89 def firstname | 89 def firstname |
90 @firstname = realname.blank? ? username : realname.split.first[0..29] | 90 @firstname = realname.blank? ? username : realname.split.first[0..29] |
91 @firstname | 91 @firstname |
92 end | 92 end |
93 | 93 |
94 def lastname | 94 def lastname |
95 @lastname = realname.blank? ? '-' : realname.split[1..-1].join(' ')[0..29] | 95 @lastname = realname.blank? ? '-' : realname.split[1..-1].join(' ')[0..29] |
96 @lastname = '-' if @lastname.blank? | 96 @lastname = '-' if @lastname.blank? |
97 @lastname | 97 @lastname |
98 end | 98 end |
99 | 99 |
100 def email | 100 def email |
101 if read_attribute(:email).match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i) && | 101 if read_attribute(:email).match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i) && |
102 !User.find_by_mail(read_attribute(:email)) | 102 !User.find_by_mail(read_attribute(:email)) |
103 @email = read_attribute(:email) | 103 @email = read_attribute(:email) |
104 else | 104 else |
105 @email = "#{username}@foo.bar" | 105 @email = "#{username}@foo.bar" |
106 end | 106 end |
107 end | 107 end |
108 | 108 |
109 def username | 109 def username |
110 read_attribute(:username)[0..29].gsub(/[^a-zA-Z0-9_\-@\.]/, '-') | 110 read_attribute(:username)[0..29].gsub(/[^a-zA-Z0-9_\-@\.]/, '-') |
111 end | 111 end |
112 end | 112 end |
113 | 113 |
114 class MantisProject < ActiveRecord::Base | 114 class MantisProject < ActiveRecord::Base |
115 set_table_name :mantis_project_table | 115 self.table_name = :mantis_project_table |
116 has_many :versions, :class_name => "MantisVersion", :foreign_key => :project_id | 116 has_many :versions, :class_name => "MantisVersion", :foreign_key => :project_id |
117 has_many :categories, :class_name => "MantisCategory", :foreign_key => :project_id | 117 has_many :categories, :class_name => "MantisCategory", :foreign_key => :project_id |
118 has_many :news, :class_name => "MantisNews", :foreign_key => :project_id | 118 has_many :news, :class_name => "MantisNews", :foreign_key => :project_id |
119 has_many :members, :class_name => "MantisProjectUser", :foreign_key => :project_id | 119 has_many :members, :class_name => "MantisProjectUser", :foreign_key => :project_id |
120 | 120 |
121 def identifier | 121 def identifier |
122 read_attribute(:name).gsub(/[^a-z0-9\-]+/, '-').slice(0, Project::IDENTIFIER_MAX_LENGTH) | 122 read_attribute(:name).gsub(/[^a-z0-9\-]+/, '-').slice(0, Project::IDENTIFIER_MAX_LENGTH) |
123 end | 123 end |
124 end | 124 end |
125 | 125 |
126 class MantisVersion < ActiveRecord::Base | 126 class MantisVersion < ActiveRecord::Base |
127 set_table_name :mantis_project_version_table | 127 self.table_name = :mantis_project_version_table |
128 | 128 |
129 def version | 129 def version |
130 read_attribute(:version)[0..29] | 130 read_attribute(:version)[0..29] |
131 end | 131 end |
132 | 132 |
133 def description | 133 def description |
134 read_attribute(:description)[0..254] | 134 read_attribute(:description)[0..254] |
135 end | 135 end |
136 end | 136 end |
137 | 137 |
138 class MantisCategory < ActiveRecord::Base | 138 class MantisCategory < ActiveRecord::Base |
139 set_table_name :mantis_project_category_table | 139 self.table_name = :mantis_project_category_table |
140 end | 140 end |
141 | 141 |
142 class MantisProjectUser < ActiveRecord::Base | 142 class MantisProjectUser < ActiveRecord::Base |
143 set_table_name :mantis_project_user_list_table | 143 self.table_name = :mantis_project_user_list_table |
144 end | 144 end |
145 | 145 |
146 class MantisBug < ActiveRecord::Base | 146 class MantisBug < ActiveRecord::Base |
147 set_table_name :mantis_bug_table | 147 self.table_name = :mantis_bug_table |
148 belongs_to :bug_text, :class_name => "MantisBugText", :foreign_key => :bug_text_id | 148 belongs_to :bug_text, :class_name => "MantisBugText", :foreign_key => :bug_text_id |
149 has_many :bug_notes, :class_name => "MantisBugNote", :foreign_key => :bug_id | 149 has_many :bug_notes, :class_name => "MantisBugNote", :foreign_key => :bug_id |
150 has_many :bug_files, :class_name => "MantisBugFile", :foreign_key => :bug_id | 150 has_many :bug_files, :class_name => "MantisBugFile", :foreign_key => :bug_id |
151 has_many :bug_monitors, :class_name => "MantisBugMonitor", :foreign_key => :bug_id | 151 has_many :bug_monitors, :class_name => "MantisBugMonitor", :foreign_key => :bug_id |
152 end | 152 end |
153 | 153 |
154 class MantisBugText < ActiveRecord::Base | 154 class MantisBugText < ActiveRecord::Base |
155 set_table_name :mantis_bug_text_table | 155 self.table_name = :mantis_bug_text_table |
156 | 156 |
157 # Adds Mantis steps_to_reproduce and additional_information fields | 157 # Adds Mantis steps_to_reproduce and additional_information fields |
158 # to description if any | 158 # to description if any |
159 def full_description | 159 def full_description |
160 full_description = description | 160 full_description = description |
161 full_description += "\n\n*Steps to reproduce:*\n\n#{steps_to_reproduce}" unless steps_to_reproduce.blank? | 161 full_description += "\n\n*Steps to reproduce:*\n\n#{steps_to_reproduce}" unless steps_to_reproduce.blank? |
162 full_description += "\n\n*Additional information:*\n\n#{additional_information}" unless additional_information.blank? | 162 full_description += "\n\n*Additional information:*\n\n#{additional_information}" unless additional_information.blank? |
163 full_description | 163 full_description |
164 end | 164 end |
165 end | 165 end |
166 | 166 |
167 class MantisBugNote < ActiveRecord::Base | 167 class MantisBugNote < ActiveRecord::Base |
168 set_table_name :mantis_bugnote_table | 168 self.table_name = :mantis_bugnote_table |
169 belongs_to :bug, :class_name => "MantisBug", :foreign_key => :bug_id | 169 belongs_to :bug, :class_name => "MantisBug", :foreign_key => :bug_id |
170 belongs_to :bug_note_text, :class_name => "MantisBugNoteText", :foreign_key => :bugnote_text_id | 170 belongs_to :bug_note_text, :class_name => "MantisBugNoteText", :foreign_key => :bugnote_text_id |
171 end | 171 end |
172 | 172 |
173 class MantisBugNoteText < ActiveRecord::Base | 173 class MantisBugNoteText < ActiveRecord::Base |
174 set_table_name :mantis_bugnote_text_table | 174 self.table_name = :mantis_bugnote_text_table |
175 end | 175 end |
176 | 176 |
177 class MantisBugFile < ActiveRecord::Base | 177 class MantisBugFile < ActiveRecord::Base |
178 set_table_name :mantis_bug_file_table | 178 self.table_name = :mantis_bug_file_table |
179 | 179 |
180 def size | 180 def size |
181 filesize | 181 filesize |
182 end | 182 end |
183 | 183 |
184 def original_filename | 184 def original_filename |
185 MantisMigrate.encode(filename) | 185 MantisMigrate.encode(filename) |
186 end | 186 end |
187 | 187 |
188 def content_type | 188 def content_type |
189 file_type | 189 file_type |
190 end | 190 end |
191 | 191 |
192 def read(*args) | 192 def read(*args) |
193 if @read_finished | 193 if @read_finished |
194 nil | 194 nil |
195 else | 195 else |
196 @read_finished = true | 196 @read_finished = true |
197 content | 197 content |
198 end | 198 end |
199 end | 199 end |
200 end | 200 end |
201 | 201 |
202 class MantisBugRelationship < ActiveRecord::Base | 202 class MantisBugRelationship < ActiveRecord::Base |
203 set_table_name :mantis_bug_relationship_table | 203 self.table_name = :mantis_bug_relationship_table |
204 end | 204 end |
205 | 205 |
206 class MantisBugMonitor < ActiveRecord::Base | 206 class MantisBugMonitor < ActiveRecord::Base |
207 set_table_name :mantis_bug_monitor_table | 207 self.table_name = :mantis_bug_monitor_table |
208 end | 208 end |
209 | 209 |
210 class MantisNews < ActiveRecord::Base | 210 class MantisNews < ActiveRecord::Base |
211 set_table_name :mantis_news_table | 211 self.table_name = :mantis_news_table |
212 end | 212 end |
213 | 213 |
214 class MantisCustomField < ActiveRecord::Base | 214 class MantisCustomField < ActiveRecord::Base |
215 set_table_name :mantis_custom_field_table | 215 self.table_name = :mantis_custom_field_table |
216 set_inheritance_column :none | 216 set_inheritance_column :none |
217 has_many :values, :class_name => "MantisCustomFieldString", :foreign_key => :field_id | 217 has_many :values, :class_name => "MantisCustomFieldString", :foreign_key => :field_id |
218 has_many :projects, :class_name => "MantisCustomFieldProject", :foreign_key => :field_id | 218 has_many :projects, :class_name => "MantisCustomFieldProject", :foreign_key => :field_id |
219 | 219 |
220 def format | 220 def format |
221 read_attribute :type | 221 read_attribute :type |
222 end | 222 end |
223 | 223 |
224 def name | 224 def name |
225 read_attribute(:name)[0..29] | 225 read_attribute(:name)[0..29] |
226 end | 226 end |
227 end | 227 end |
228 | 228 |
229 class MantisCustomFieldProject < ActiveRecord::Base | 229 class MantisCustomFieldProject < ActiveRecord::Base |
230 set_table_name :mantis_custom_field_project_table | 230 self.table_name = :mantis_custom_field_project_table |
231 end | 231 end |
232 | 232 |
233 class MantisCustomFieldString < ActiveRecord::Base | 233 class MantisCustomFieldString < ActiveRecord::Base |
234 set_table_name :mantis_custom_field_string_table | 234 self.table_name = :mantis_custom_field_string_table |
235 end | 235 end |
236 | 236 |
237 | |
238 def self.migrate | 237 def self.migrate |
239 | 238 |
240 # Users | 239 # Users |
241 print "Migrating users" | 240 print "Migrating users" |
242 User.delete_all "login <> 'admin'" | 241 User.delete_all "login <> 'admin'" |
243 users_map = {} | 242 users_map = {} |
244 users_migrated = 0 | 243 users_migrated = 0 |
245 MantisUser.find(:all).each do |user| | 244 MantisUser.find(:all).each do |user| |
246 u = User.new :firstname => encode(user.firstname), | 245 u = User.new :firstname => encode(user.firstname), |
247 :lastname => encode(user.lastname), | 246 :lastname => encode(user.lastname), |
248 :mail => user.email, | 247 :mail => user.email, |
249 :last_login_on => user.last_visit | 248 :last_login_on => user.last_visit |
250 u.login = user.username | 249 u.login = user.username |
251 u.password = 'mantis' | 250 u.password = 'mantis' |
252 u.status = User::STATUS_LOCKED if user.enabled != 1 | 251 u.status = User::STATUS_LOCKED if user.enabled != 1 |
253 u.admin = true if user.access_level == 90 | 252 u.admin = true if user.access_level == 90 |
254 next unless u.save! | 253 next unless u.save! |
255 users_migrated += 1 | 254 users_migrated += 1 |
256 users_map[user.id] = u.id | 255 users_map[user.id] = u.id |
257 print '.' | 256 print '.' |
258 end | 257 end |
259 puts | 258 puts |
260 | 259 |
261 # Projects | 260 # Projects |
262 print "Migrating projects" | 261 print "Migrating projects" |
263 Project.destroy_all | 262 Project.destroy_all |
264 projects_map = {} | 263 projects_map = {} |
265 versions_map = {} | 264 versions_map = {} |
266 categories_map = {} | 265 categories_map = {} |
267 MantisProject.find(:all).each do |project| | 266 MantisProject.find(:all).each do |project| |
268 p = Project.new :name => encode(project.name), | 267 p = Project.new :name => encode(project.name), |
269 :description => encode(project.description) | 268 :description => encode(project.description) |
270 p.identifier = project.identifier | 269 p.identifier = project.identifier |
271 next unless p.save | 270 next unless p.save |
272 projects_map[project.id] = p.id | 271 projects_map[project.id] = p.id |
273 p.enabled_module_names = ['issue_tracking', 'news', 'wiki'] | 272 p.enabled_module_names = ['issue_tracking', 'news', 'wiki'] |
274 p.trackers << TRACKER_BUG | 273 p.trackers << TRACKER_BUG unless p.trackers.include?(TRACKER_BUG) |
275 p.trackers << TRACKER_FEATURE | 274 p.trackers << TRACKER_FEATURE unless p.trackers.include?(TRACKER_FEATURE) |
276 print '.' | 275 print '.' |
277 | 276 |
278 # Project members | 277 # Project members |
279 project.members.each do |member| | 278 project.members.each do |member| |
280 m = Member.new :user => User.find_by_id(users_map[member.user_id]), | 279 m = Member.new :user => User.find_by_id(users_map[member.user_id]), |
281 :roles => [ROLE_MAPPING[member.access_level] || DEFAULT_ROLE] | 280 :roles => [ROLE_MAPPING[member.access_level] || DEFAULT_ROLE] |
282 m.project = p | 281 m.project = p |
283 m.save | 282 m.save |
284 end | 283 end |
285 | 284 |
286 # Project versions | 285 # Project versions |
287 project.versions.each do |version| | 286 project.versions.each do |version| |
288 v = Version.new :name => encode(version.version), | 287 v = Version.new :name => encode(version.version), |
289 :description => encode(version.description), | 288 :description => encode(version.description), |
290 :effective_date => (version.date_order ? version.date_order.to_date : nil) | 289 :effective_date => (version.date_order ? version.date_order.to_date : nil) |
291 v.project = p | 290 v.project = p |
292 v.save | 291 v.save |
293 versions_map[version.id] = v.id | 292 versions_map[version.id] = v.id |
294 end | 293 end |
295 | 294 |
296 # Project categories | 295 # Project categories |
297 project.categories.each do |category| | 296 project.categories.each do |category| |
298 g = IssueCategory.new :name => category.category[0,30] | 297 g = IssueCategory.new :name => category.category[0,30] |
299 g.project = p | 298 g.project = p |
300 g.save | 299 g.save |
301 categories_map[category.category] = g.id | 300 categories_map[category.category] = g.id |
302 end | 301 end |
303 end | 302 end |
304 puts | 303 puts |
305 | 304 |
306 # Bugs | 305 # Bugs |
307 print "Migrating bugs" | 306 print "Migrating bugs" |
308 Issue.destroy_all | 307 Issue.destroy_all |
309 issues_map = {} | 308 issues_map = {} |
310 keep_bug_ids = (Issue.count == 0) | 309 keep_bug_ids = (Issue.count == 0) |
311 MantisBug.find_each(:batch_size => 200) do |bug| | 310 MantisBug.find_each(:batch_size => 200) do |bug| |
312 next unless projects_map[bug.project_id] && users_map[bug.reporter_id] | 311 next unless projects_map[bug.project_id] && users_map[bug.reporter_id] |
313 i = Issue.new :project_id => projects_map[bug.project_id], | 312 i = Issue.new :project_id => projects_map[bug.project_id], |
314 :subject => encode(bug.summary), | 313 :subject => encode(bug.summary), |
315 :description => encode(bug.bug_text.full_description), | 314 :description => encode(bug.bug_text.full_description), |
316 :priority => PRIORITY_MAPPING[bug.priority] || DEFAULT_PRIORITY, | 315 :priority => PRIORITY_MAPPING[bug.priority] || DEFAULT_PRIORITY, |
317 :created_on => bug.date_submitted, | 316 :created_on => bug.date_submitted, |
318 :updated_on => bug.last_updated | 317 :updated_on => bug.last_updated |
319 i.author = User.find_by_id(users_map[bug.reporter_id]) | 318 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? | 319 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? | 320 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 | 321 i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS |
323 i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG) | 322 i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG) |
324 i.id = bug.id if keep_bug_ids | 323 i.id = bug.id if keep_bug_ids |
325 next unless i.save | 324 next unless i.save |
326 issues_map[bug.id] = i.id | 325 issues_map[bug.id] = i.id |
327 print '.' | 326 print '.' |
328 STDOUT.flush | 327 STDOUT.flush |
329 | 328 |
330 # Assignee | 329 # Assignee |
331 # Redmine checks that the assignee is a project member | 330 # Redmine checks that the assignee is a project member |
332 if (bug.handler_id && users_map[bug.handler_id]) | 331 if (bug.handler_id && users_map[bug.handler_id]) |
333 i.assigned_to = User.find_by_id(users_map[bug.handler_id]) | 332 i.assigned_to = User.find_by_id(users_map[bug.handler_id]) |
334 i.save_with_validation(false) | 333 i.save(:validate => false) |
335 end | 334 end |
336 | 335 |
337 # Bug notes | 336 # Bug notes |
338 bug.bug_notes.each do |note| | 337 bug.bug_notes.each do |note| |
339 next unless users_map[note.reporter_id] | 338 next unless users_map[note.reporter_id] |
340 n = Journal.new :notes => encode(note.bug_note_text.note), | 339 n = Journal.new :notes => encode(note.bug_note_text.note), |
341 :created_on => note.date_submitted | 340 :created_on => note.date_submitted |
342 n.user = User.find_by_id(users_map[note.reporter_id]) | 341 n.user = User.find_by_id(users_map[note.reporter_id]) |
343 n.journalized = i | 342 n.journalized = i |
344 n.save | 343 n.save |
345 end | 344 end |
346 | 345 |
347 # Bug files | 346 # Bug files |
348 bug.bug_files.each do |file| | 347 bug.bug_files.each do |file| |
349 a = Attachment.new :created_on => file.date_added | 348 a = Attachment.new :created_on => file.date_added |
350 a.file = file | 349 a.file = file |
351 a.author = User.find :first | 350 a.author = User.find :first |
352 a.container = i | 351 a.container = i |
353 a.save | 352 a.save |
354 end | 353 end |
355 | 354 |
356 # Bug monitors | 355 # Bug monitors |
357 bug.bug_monitors.each do |monitor| | 356 bug.bug_monitors.each do |monitor| |
358 next unless users_map[monitor.user_id] | 357 next unless users_map[monitor.user_id] |
359 i.add_watcher(User.find_by_id(users_map[monitor.user_id])) | 358 i.add_watcher(User.find_by_id(users_map[monitor.user_id])) |
360 end | 359 end |
361 end | 360 end |
362 | 361 |
363 # update issue id sequence if needed (postgresql) | 362 # update issue id sequence if needed (postgresql) |
364 Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!') | 363 Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!') |
365 puts | 364 puts |
366 | 365 |
367 # Bug relationships | 366 # Bug relationships |
368 print "Migrating bug relations" | 367 print "Migrating bug relations" |
369 MantisBugRelationship.find(:all).each do |relation| | 368 MantisBugRelationship.find(:all).each do |relation| |
370 next unless issues_map[relation.source_bug_id] && issues_map[relation.destination_bug_id] | 369 next unless issues_map[relation.source_bug_id] && issues_map[relation.destination_bug_id] |
371 r = IssueRelation.new :relation_type => RELATION_TYPE_MAPPING[relation.relationship_type] | 370 r = IssueRelation.new :relation_type => RELATION_TYPE_MAPPING[relation.relationship_type] |
374 pp r unless r.save | 373 pp r unless r.save |
375 print '.' | 374 print '.' |
376 STDOUT.flush | 375 STDOUT.flush |
377 end | 376 end |
378 puts | 377 puts |
379 | 378 |
380 # News | 379 # News |
381 print "Migrating news" | 380 print "Migrating news" |
382 News.destroy_all | 381 News.destroy_all |
383 MantisNews.find(:all, :conditions => 'project_id > 0').each do |news| | 382 MantisNews.find(:all, :conditions => 'project_id > 0').each do |news| |
384 next unless projects_map[news.project_id] | 383 next unless projects_map[news.project_id] |
390 n.save | 389 n.save |
391 print '.' | 390 print '.' |
392 STDOUT.flush | 391 STDOUT.flush |
393 end | 392 end |
394 puts | 393 puts |
395 | 394 |
396 # Custom fields | 395 # Custom fields |
397 print "Migrating custom fields" | 396 print "Migrating custom fields" |
398 IssueCustomField.destroy_all | 397 IssueCustomField.destroy_all |
399 MantisCustomField.find(:all).each do |field| | 398 MantisCustomField.find(:all).each do |field| |
400 f = IssueCustomField.new :name => field.name[0..29], | 399 f = IssueCustomField.new :name => field.name[0..29], |
407 next unless f.save | 406 next unless f.save |
408 print '.' | 407 print '.' |
409 STDOUT.flush | 408 STDOUT.flush |
410 # Trackers association | 409 # Trackers association |
411 f.trackers = Tracker.find :all | 410 f.trackers = Tracker.find :all |
412 | 411 |
413 # Projects association | 412 # Projects association |
414 field.projects.each do |project| | 413 field.projects.each do |project| |
415 f.projects << Project.find_by_id(projects_map[project.project_id]) if projects_map[project.project_id] | 414 f.projects << Project.find_by_id(projects_map[project.project_id]) if projects_map[project.project_id] |
416 end | 415 end |
417 | 416 |
418 # Values | 417 # Values |
419 field.values.each do |value| | 418 field.values.each do |value| |
420 v = CustomValue.new :custom_field_id => f.id, | 419 v = CustomValue.new :custom_field_id => f.id, |
421 :value => value.value | 420 :value => value.value |
422 v.customized = Issue.find_by_id(issues_map[value.bug_id]) if issues_map[value.bug_id] | 421 v.customized = Issue.find_by_id(issues_map[value.bug_id]) if issues_map[value.bug_id] |
423 v.save | 422 v.save |
424 end unless f.new_record? | 423 end unless f.new_record? |
425 end | 424 end |
426 puts | 425 puts |
427 | 426 |
428 puts | 427 puts |
429 puts "Users: #{users_migrated}/#{MantisUser.count}" | 428 puts "Users: #{users_migrated}/#{MantisUser.count}" |
430 puts "Projects: #{Project.count}/#{MantisProject.count}" | 429 puts "Projects: #{Project.count}/#{MantisProject.count}" |
431 puts "Memberships: #{Member.count}/#{MantisProjectUser.count}" | 430 puts "Memberships: #{Member.count}/#{MantisProjectUser.count}" |
432 puts "Versions: #{Version.count}/#{MantisVersion.count}" | 431 puts "Versions: #{Version.count}/#{MantisVersion.count}" |
437 puts "Bug relations: #{IssueRelation.count}/#{MantisBugRelationship.count}" | 436 puts "Bug relations: #{IssueRelation.count}/#{MantisBugRelationship.count}" |
438 puts "Bug monitors: #{Watcher.count}/#{MantisBugMonitor.count}" | 437 puts "Bug monitors: #{Watcher.count}/#{MantisBugMonitor.count}" |
439 puts "News: #{News.count}/#{MantisNews.count}" | 438 puts "News: #{News.count}/#{MantisNews.count}" |
440 puts "Custom fields: #{IssueCustomField.count}/#{MantisCustomField.count}" | 439 puts "Custom fields: #{IssueCustomField.count}/#{MantisCustomField.count}" |
441 end | 440 end |
442 | 441 |
443 def self.encoding(charset) | 442 def self.encoding(charset) |
444 @ic = Iconv.new('UTF-8', charset) | 443 @ic = Iconv.new('UTF-8', charset) |
445 rescue Iconv::InvalidEncoding | 444 rescue Iconv::InvalidEncoding |
446 return false | 445 return false |
447 end | 446 end |
448 | 447 |
449 def self.establish_connection(params) | 448 def self.establish_connection(params) |
450 constants.each do |const| | 449 constants.each do |const| |
451 klass = const_get(const) | 450 klass = const_get(const) |
452 next unless klass.respond_to? 'establish_connection' | 451 next unless klass.respond_to? 'establish_connection' |
453 klass.establish_connection params | 452 klass.establish_connection params |
454 end | 453 end |
455 end | 454 end |
456 | 455 |
457 def self.encode(text) | 456 def self.encode(text) |
458 @ic.iconv text | 457 @ic.iconv text |
459 rescue | 458 rescue |
460 text | 459 text |
461 end | 460 end |
462 end | 461 end |
463 | 462 |
464 puts | 463 puts |
465 if Redmine::DefaultData::Loader.no_data? | 464 if Redmine::DefaultData::Loader.no_data? |
466 puts "Redmine configuration need to be loaded before importing data." | 465 puts "Redmine configuration need to be loaded before importing data." |
467 puts "Please, run this first:" | 466 puts "Please, run this first:" |
468 puts | 467 puts |
469 puts " rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\"" | 468 puts " rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\"" |
470 exit | 469 exit |
471 end | 470 end |
472 | 471 |
473 puts "WARNING: Your Redmine data will be deleted during this process." | 472 puts "WARNING: Your Redmine data will be deleted during this process." |
474 print "Are you sure you want to continue ? [y/N] " | 473 print "Are you sure you want to continue ? [y/N] " |
475 STDOUT.flush | 474 STDOUT.flush |
476 break unless STDIN.gets.match(/^y$/i) | 475 break unless STDIN.gets.match(/^y$/i) |
477 | 476 |
478 # Default Mantis database settings | 477 # Default Mantis database settings |
479 db_params = {:adapter => 'mysql', | 478 db_params = {:adapter => 'mysql2', |
480 :database => 'bugtracker', | 479 :database => 'bugtracker', |
481 :host => 'localhost', | 480 :host => 'localhost', |
482 :username => 'root', | 481 :username => 'root', |
483 :password => '' } | 482 :password => '' } |
484 | 483 |
485 puts | 484 puts |
486 puts "Please enter settings for your Mantis database" | 485 puts "Please enter settings for your Mantis database" |
487 [:adapter, :host, :database, :username, :password].each do |param| | 486 [:adapter, :host, :database, :username, :password].each do |param| |
488 print "#{param} [#{db_params[param]}]: " | 487 print "#{param} [#{db_params[param]}]: " |
489 value = STDIN.gets.chomp! | 488 value = STDIN.gets.chomp! |
490 db_params[param] = value unless value.blank? | 489 db_params[param] = value unless value.blank? |
491 end | 490 end |
492 | 491 |
493 while true | 492 while true |
494 print "encoding [UTF-8]: " | 493 print "encoding [UTF-8]: " |
495 STDOUT.flush | 494 STDOUT.flush |
496 encoding = STDIN.gets.chomp! | 495 encoding = STDIN.gets.chomp! |
497 encoding = 'UTF-8' if encoding.blank? | 496 encoding = 'UTF-8' if encoding.blank? |
498 break if MantisMigrate.encoding encoding | 497 break if MantisMigrate.encoding encoding |
499 puts "Invalid encoding!" | 498 puts "Invalid encoding!" |
500 end | 499 end |
501 puts | 500 puts |
502 | 501 |
503 # Make sure bugs can refer bugs in other projects | 502 # Make sure bugs can refer bugs in other projects |
504 Setting.cross_project_issue_relations = 1 if Setting.respond_to? 'cross_project_issue_relations' | 503 Setting.cross_project_issue_relations = 1 if Setting.respond_to? 'cross_project_issue_relations' |
505 | 504 |
506 # Turn off email notifications | 505 # Turn off email notifications |
507 Setting.notified_events = [] | 506 Setting.notified_events = [] |
508 | 507 |
509 MantisMigrate.establish_connection db_params | 508 MantisMigrate.establish_connection db_params |
510 MantisMigrate.migrate | 509 MantisMigrate.migrate |
511 end | 510 end |
512 end | 511 end |