##// END OF EJS Templates
Support WikiCaps for Trac migrations...
Support WikiCaps for Trac migrations Trac wikis support WikiCaps for links to pages. They also use !WikiCaps syntax to prevent links. Support both. Uses patch from and closes #758. git-svn-id: http://redmine.rubyforge.org/svn/trunk@1242 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r1207:494a6ecfb0a9
r1228:87fb78be0b48
Show More
migrate_from_mantis.rake
505 lines | 18.6 KiB | text/x-ruby | RubyLexer
/ lib / tasks / migrate_from_mantis.rake
Jean-Philippe Lang
Mantis migration task initial import....
r620 # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
desc 'Mantis migration script'
require 'active_record'
require 'iconv'
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622 require 'pp'
Jean-Philippe Lang
Mantis migration task initial import....
r620
Jean-Philippe Lang
Added namespace for Redmine specific rake tasks....
r680 namespace :redmine do
Jean-Philippe Lang
Mantis migration task initial import....
r620 task :migrate_from_mantis => :environment do
module MantisMigrate
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 DEFAULT_STATUS = IssueStatus.default
Jean-Philippe Lang
More accurate status and role mapping in Mantis importer....
r621 assigned_status = IssueStatus.find_by_position(2)
resolved_status = IssueStatus.find_by_position(3)
feedback_status = IssueStatus.find_by_position(4)
closed_status = IssueStatus.find :first, :conditions => { :is_closed => true }
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 STATUS_MAPPING = {10 => DEFAULT_STATUS, # new
Jean-Philippe Lang
More accurate status and role mapping in Mantis importer....
r621 20 => feedback_status, # feedback
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 30 => DEFAULT_STATUS, # acknowledged
40 => DEFAULT_STATUS, # confirmed
Jean-Philippe Lang
More accurate status and role mapping in Mantis importer....
r621 50 => assigned_status, # assigned
80 => resolved_status, # resolved
90 => closed_status # closed
Jean-Philippe Lang
Mantis migration task initial import....
r620 }
Jean-Philippe Lang
Mantis importer: added priorities mapping....
r625
priorities = Enumeration.get_values('IPRI')
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 DEFAULT_PRIORITY = priorities[2]
Jean-Philippe Lang
Mantis importer: added priorities mapping....
r625 PRIORITY_MAPPING = {10 => priorities[1], # none
20 => priorities[1], # low
30 => priorities[2], # normal
40 => priorities[3], # high
50 => priorities[4], # urgent
60 => priorities[5] # immediate
}
Jean-Philippe Lang
Mantis migration task initial import....
r620
Jean-Philippe Lang
Mantis importer:...
r654 TRACKER_BUG = Tracker.find_by_position(1)
TRACKER_FEATURE = Tracker.find_by_position(2)
Jean-Philippe Lang
Mantis importer: added priorities mapping....
r625
Jean-Philippe Lang
Fixed Mantis importer: projects trackers and modules assignment...
r923 roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC')
manager_role = roles[0]
developer_role = roles[1]
DEFAULT_ROLE = roles.last
Jean-Philippe Lang
Mantis importer: fixed default role mapping...
r634 ROLE_MAPPING = {10 => DEFAULT_ROLE, # viewer
25 => DEFAULT_ROLE, # reporter
40 => DEFAULT_ROLE, # updater
Jean-Philippe Lang
More accurate status and role mapping in Mantis importer....
r621 55 => developer_role, # developer
70 => manager_role, # manager
90 => manager_role # administrator
Jean-Philippe Lang
Mantis migration task initial import....
r620 }
CUSTOM_FIELD_TYPE_MAPPING = {0 => 'string', # String
1 => 'int', # Numeric
2 => 'int', # Float
3 => 'list', # Enumeration
4 => 'string', # Email
5 => 'bool', # Checkbox
6 => 'list', # List
7 => 'list', # Multiselection list
8 => 'date', # Date
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622 }
RELATION_TYPE_MAPPING = {1 => IssueRelation::TYPE_RELATES, # related to
2 => IssueRelation::TYPE_RELATES, # parent of
3 => IssueRelation::TYPE_RELATES, # child of
0 => IssueRelation::TYPE_DUPLICATES, # duplicate of
4 => IssueRelation::TYPE_DUPLICATES # has duplicate
}
Jean-Philippe Lang
Mantis migration task initial import....
r620
class MantisUser < ActiveRecord::Base
set_table_name :mantis_user_table
def firstname
Jean-Philippe Lang
Mantis importer: few fixes in user mapping....
r1113 @firstname = realname.blank? ? username : realname.split.first[0..29]
@firstname.gsub!(/[^\w\s\'\-]/i, '')
@firstname
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
def lastname
Jean-Philippe Lang
Mantis importer: do not duplicate Mantis username in firstname and lastname if realname is blank....
r1144 @lastname = realname.blank? ? '-' : realname.split[1..-1].join(' ')[0..29]
Jean-Philippe Lang
Mantis importer: few fixes in user mapping....
r1113 @lastname.gsub!(/[^\w\s\'\-]/i, '')
@lastname = '-' if @lastname.blank?
@lastname
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
def email
Jean-Philippe Lang
Mantis importer: few fixes in user mapping....
r1113 if read_attribute(:email).match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i) &&
!User.find_by_mail(read_attribute(:email))
@email = read_attribute(:email)
Jean-Philippe Lang
Mantis migration task initial import....
r620 else
Jean-Philippe Lang
Mantis importer: few fixes in user mapping....
r1113 @email = "#{username}@foo.bar"
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
end
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631
def username
read_attribute(:username)[0..29].gsub(/[^a-zA-Z0-9_\-@\.]/, '-')
end
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
class MantisProject < ActiveRecord::Base
set_table_name :mantis_project_table
has_many :versions, :class_name => "MantisVersion", :foreign_key => :project_id
has_many :categories, :class_name => "MantisCategory", :foreign_key => :project_id
has_many :news, :class_name => "MantisNews", :foreign_key => :project_id
has_many :members, :class_name => "MantisProjectUser", :foreign_key => :project_id
def name
Jean-Philippe Lang
Project name format limitation removed (name can now contain any character)....
r936 read_attribute(:name)[0..29]
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
def identifier
Jean-Philippe Lang
Project name format limitation removed (name can now contain any character)....
r936 read_attribute(:name).underscore[0..19].gsub(/[^a-z0-9\-]/, '-')
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
end
class MantisVersion < ActiveRecord::Base
set_table_name :mantis_project_version_table
def version
read_attribute(:version)[0..29]
end
def description
read_attribute(:description)[0..254]
end
end
class MantisCategory < ActiveRecord::Base
set_table_name :mantis_project_category_table
end
class MantisProjectUser < ActiveRecord::Base
set_table_name :mantis_project_user_list_table
end
class MantisBug < ActiveRecord::Base
set_table_name :mantis_bug_table
belongs_to :bug_text, :class_name => "MantisBugText", :foreign_key => :bug_text_id
has_many :bug_notes, :class_name => "MantisBugNote", :foreign_key => :bug_id
has_many :bug_files, :class_name => "MantisBugFile", :foreign_key => :bug_id
Jean-Philippe Lang
Added migration of Mantis bug monitors....
r623 has_many :bug_monitors, :class_name => "MantisBugMonitor", :foreign_key => :bug_id
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
class MantisBugText < ActiveRecord::Base
Jean-Philippe Lang
Mantis importer: steps_to_reproduce and additional_information fields added to issue description....
r624 set_table_name :mantis_bug_text_table
# Adds Mantis steps_to_reproduce and additional_information fields
# to description if any
def full_description
full_description = description
full_description += "\n\n*Steps to reproduce:*\n\n#{steps_to_reproduce}" unless steps_to_reproduce.blank?
full_description += "\n\n*Additional information:*\n\n#{additional_information}" unless additional_information.blank?
full_description
end
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
class MantisBugNote < ActiveRecord::Base
set_table_name :mantis_bugnote_table
belongs_to :bug, :class_name => "MantisBug", :foreign_key => :bug_id
belongs_to :bug_note_text, :class_name => "MantisBugNoteText", :foreign_key => :bugnote_text_id
end
class MantisBugNoteText < ActiveRecord::Base
set_table_name :mantis_bugnote_text_table
end
class MantisBugFile < ActiveRecord::Base
set_table_name :mantis_bug_file_table
def size
filesize
end
def original_filename
Jean-Philippe Lang
Mantis importer:...
r1086 MantisMigrate.encode(filename)
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
def content_type
file_type
end
def read
content
end
end
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622 class MantisBugRelationship < ActiveRecord::Base
set_table_name :mantis_bug_relationship_table
end
Jean-Philippe Lang
Added migration of Mantis bug monitors....
r623 class MantisBugMonitor < ActiveRecord::Base
set_table_name :mantis_bug_monitor_table
end
Jean-Philippe Lang
Mantis migration task initial import....
r620 class MantisNews < ActiveRecord::Base
set_table_name :mantis_news_table
end
class MantisCustomField < ActiveRecord::Base
set_table_name :mantis_custom_field_table
set_inheritance_column :none
has_many :values, :class_name => "MantisCustomFieldString", :foreign_key => :field_id
has_many :projects, :class_name => "MantisCustomFieldProject", :foreign_key => :field_id
def format
read_attribute :type
end
def name
read_attribute(:name)[0..29].gsub(/[^\w\s\'\-]/, '-')
end
end
class MantisCustomFieldProject < ActiveRecord::Base
set_table_name :mantis_custom_field_project_table
end
class MantisCustomFieldString < ActiveRecord::Base
set_table_name :mantis_custom_field_string_table
end
def self.migrate
# Users
print "Migrating users"
User.delete_all "login <> 'admin'"
users_map = {}
users_migrated = 0
MantisUser.find(:all).each do |user|
u = User.new :firstname => encode(user.firstname),
:lastname => encode(user.lastname),
:mail => user.email,
:last_login_on => user.last_visit
u.login = user.username
u.password = 'mantis'
u.status = User::STATUS_LOCKED if user.enabled != 1
u.admin = true if user.access_level == 90
Jean-Philippe Lang
Mantis importer: few fixes in user mapping....
r1113 next unless u.save!
Jean-Philippe Lang
Mantis migration task initial import....
r620 users_migrated += 1
users_map[user.id] = u.id
print '.'
end
puts
# Projects
print "Migrating projects"
Project.destroy_all
projects_map = {}
versions_map = {}
categories_map = {}
MantisProject.find(:all).each do |project|
p = Project.new :name => encode(project.name),
:description => encode(project.description)
p.identifier = project.identifier
next unless p.save
projects_map[project.id] = p.id
Jean-Philippe Lang
Fixed Mantis importer: projects trackers and modules assignment...
r923 p.enabled_module_names = ['issue_tracking', 'news', 'wiki']
p.trackers << TRACKER_BUG
p.trackers << TRACKER_FEATURE
Jean-Philippe Lang
Mantis migration task initial import....
r620 print '.'
# Project members
project.members.each do |member|
Jean-Philippe Lang
Mantis importer: replaced find by find_by_id...
r630 m = Member.new :user => User.find_by_id(users_map[member.user_id]),
Jean-Philippe Lang
Mantis importer: fixed default role mapping...
r634 :role => ROLE_MAPPING[member.access_level] || DEFAULT_ROLE
Jean-Philippe Lang
Mantis migration task initial import....
r620 m.project = p
m.save
end
# Project versions
project.versions.each do |version|
v = Version.new :name => encode(version.version),
:description => encode(version.description),
:effective_date => version.date_order.to_date
v.project = p
v.save
versions_map[version.id] = v.id
end
# Project categories
project.categories.each do |category|
Jean-Philippe Lang
Mantis importer: issue categories truncated to 30 chars....
r653 g = IssueCategory.new :name => category.category[0,30]
Jean-Philippe Lang
Mantis migration task initial import....
r620 g.project = p
g.save
categories_map[category.category] = g.id
end
end
puts
# Bugs
print "Migrating bugs"
Issue.destroy_all
issues_map = {}
Jean-Philippe Lang
Make Mantis importer preserve bug ids....
r1132 keep_bug_ids = (Issue.count == 0)
MantisBug.find(:all, :order => 'id ASC').each do |bug|
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 next unless projects_map[bug.project_id] && users_map[bug.reporter_id]
Jean-Philippe Lang
Mantis migration task initial import....
r620 i = Issue.new :project_id => projects_map[bug.project_id],
:subject => encode(bug.summary),
Jean-Philippe Lang
Mantis importer: steps_to_reproduce and additional_information fields added to issue description....
r624 :description => encode(bug.bug_text.full_description),
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 :priority => PRIORITY_MAPPING[bug.priority] || DEFAULT_PRIORITY,
Jean-Philippe Lang
Mantis migration task initial import....
r620 :created_on => bug.date_submitted,
:updated_on => bug.last_updated
Jean-Philippe Lang
Mantis importer: replaced find by find_by_id...
r630 i.author = User.find_by_id(users_map[bug.reporter_id])
Jean-Philippe Lang
Mantis importer: small fix in categories mapping....
r655 i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category[0,30]) unless bug.category.blank?
Jean-Philippe Lang
Mantis migration task initial import....
r620 i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank?
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS
Jean-Philippe Lang
Mantis importer:...
r654 i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG)
Jean-Philippe Lang
Make Mantis importer preserve bug ids....
r1132 i.id = bug.id if keep_bug_ids
Jean-Philippe Lang
Mantis migration task initial import....
r620 next unless i.save
issues_map[bug.id] = i.id
print '.'
Jean-Philippe Lang
Mantis importer:...
r654
# Assignee
# Redmine checks that the assignee is a project member
if (bug.handler_id && users_map[bug.handler_id])
i.assigned_to = User.find_by_id(users_map[bug.handler_id])
i.save_with_validation(false)
end
Jean-Philippe Lang
Mantis migration task initial import....
r620
# Bug notes
bug.bug_notes.each do |note|
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 next unless users_map[note.reporter_id]
Jean-Philippe Lang
Mantis migration task initial import....
r620 n = Journal.new :notes => encode(note.bug_note_text.note),
:created_on => note.date_submitted
Jean-Philippe Lang
Mantis importer: replaced find by find_by_id...
r630 n.user = User.find_by_id(users_map[note.reporter_id])
Jean-Philippe Lang
Mantis migration task initial import....
r620 n.journalized = i
n.save
end
# Bug files
bug.bug_files.each do |file|
a = Attachment.new :created_on => file.date_added
a.file = file
a.author = User.find :first
a.container = i
a.save
end
Jean-Philippe Lang
Added migration of Mantis bug monitors....
r623
# Bug monitors
bug.bug_monitors.each do |monitor|
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 next unless users_map[monitor.user_id]
Jean-Philippe Lang
Added migration of Mantis bug monitors....
r623 i.add_watcher(User.find_by_id(users_map[monitor.user_id]))
end
Jean-Philippe Lang
Mantis migration task initial import....
r620 end
Jean-Philippe Lang
Make Mantis importer preserve bug ids....
r1132
# update issue id sequence if needed (postgresql)
Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!')
Jean-Philippe Lang
Mantis migration task initial import....
r620 puts
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622 # Bug relationships
print "Migrating bug relations"
MantisBugRelationship.find(:all).each do |relation|
next unless issues_map[relation.source_bug_id] && issues_map[relation.destination_bug_id]
r = IssueRelation.new :relation_type => RELATION_TYPE_MAPPING[relation.relationship_type]
r.issue_from = Issue.find_by_id(issues_map[relation.source_bug_id])
r.issue_to = Issue.find_by_id(issues_map[relation.destination_bug_id])
pp r unless r.save
print '.'
end
Jean-Philippe Lang
Added migration of Mantis bug monitors....
r623 puts
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622
Jean-Philippe Lang
Mantis migration task initial import....
r620 # News
print "Migrating news"
News.destroy_all
MantisNews.find(:all, :conditions => 'project_id > 0').each do |news|
next unless projects_map[news.project_id]
n = News.new :project_id => projects_map[news.project_id],
:title => encode(news.headline[0..59]),
:description => encode(news.body),
:created_on => news.date_posted
Jean-Philippe Lang
Mantis importer: replaced find by find_by_id...
r630 n.author = User.find_by_id(users_map[news.poster_id])
Jean-Philippe Lang
Mantis migration task initial import....
r620 n.save
print '.'
end
puts
# Custom fields
print "Migrating custom fields"
IssueCustomField.destroy_all
MantisCustomField.find(:all).each do |field|
f = IssueCustomField.new :name => field.name[0..29],
:field_format => CUSTOM_FIELD_TYPE_MAPPING[field.format],
:min_length => field.length_min,
:max_length => field.length_max,
:regexp => field.valid_regexp,
:possible_values => field.possible_values.split('|'),
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 :is_required => field.require_report?
Jean-Philippe Lang
Mantis migration task initial import....
r620 next unless f.save
print '.'
# Trackers association
f.trackers = Tracker.find :all
# Projects association
field.projects.each do |project|
f.projects << Project.find_by_id(projects_map[project.project_id]) if projects_map[project.project_id]
end
# Values
field.values.each do |value|
v = CustomValue.new :custom_field_id => f.id,
:value => value.value
v.customized = Issue.find_by_id(issues_map[value.bug_id]) if issues_map[value.bug_id]
v.save
end unless f.new_record?
end
puts
puts
puts "Users: #{users_migrated}/#{MantisUser.count}"
puts "Projects: #{Project.count}/#{MantisProject.count}"
puts "Memberships: #{Member.count}/#{MantisProjectUser.count}"
puts "Versions: #{Version.count}/#{MantisVersion.count}"
puts "Categories: #{IssueCategory.count}/#{MantisCategory.count}"
puts "Bugs: #{Issue.count}/#{MantisBug.count}"
puts "Bug notes: #{Journal.count}/#{MantisBugNote.count}"
puts "Bug files: #{Attachment.count}/#{MantisBugFile.count}"
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622 puts "Bug relations: #{IssueRelation.count}/#{MantisBugRelationship.count}"
Jean-Philippe Lang
Added migration of Mantis bug monitors....
r623 puts "Bug monitors: #{Watcher.count}/#{MantisBugMonitor.count}"
Jean-Philippe Lang
Mantis migration task initial import....
r620 puts "News: #{News.count}/#{MantisNews.count}"
puts "Custom fields: #{IssueCustomField.count}/#{MantisCustomField.count}"
end
def self.encoding(charset)
@ic = Iconv.new('UTF-8', charset)
rescue Iconv::InvalidEncoding
return false
end
def self.establish_connection(params)
constants.each do |const|
klass = const_get(const)
next unless klass.respond_to? 'establish_connection'
klass.establish_connection params
end
end
def self.encode(text)
@ic.iconv text
rescue
text
end
end
puts
Jean-Philippe Lang
Trac and Mantis importers: check that default configuration is loaded before processing....
r1207 if Redmine::DefaultData::Loader.no_data?
puts "Redmine configuration need to be loaded before importing data."
puts "Please, run this first:"
puts
puts " rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\""
exit
end
Jean-Philippe Lang
Mantis migration task initial import....
r620 puts "WARNING: Your Redmine data will be deleted during this process."
print "Are you sure you want to continue ? [y/N] "
break unless STDIN.gets.match(/^y$/i)
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622 # Default Mantis database settings
Jean-Philippe Lang
Mantis migration task initial import....
r620 db_params = {:adapter => 'mysql',
:database => 'bugtracker',
:host => 'localhost',
:username => 'root',
:password => '' }
puts
puts "Please enter settings for your Mantis database"
[:adapter, :host, :database, :username, :password].each do |param|
print "#{param} [#{db_params[param]}]: "
value = STDIN.gets.chomp!
db_params[param] = value unless value.blank?
end
while true
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 print "encoding [UTF-8]: "
Jean-Philippe Lang
Mantis migration task initial import....
r620 encoding = STDIN.gets.chomp!
Jean-Philippe Lang
Mantis importer: fixed a few bugs...
r631 encoding = 'UTF-8' if encoding.blank?
Jean-Philippe Lang
Mantis migration task initial import....
r620 break if MantisMigrate.encoding encoding
puts "Invalid encoding!"
end
puts
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622 # Make sure bugs can refer bugs in other projects
Jean-Philippe Lang
Small change to mantis importer to be 0.5.1 compatible....
r632 Setting.cross_project_issue_relations = 1 if Setting.respond_to? 'cross_project_issue_relations'
Jean-Philippe Lang
Added migration of Mantis bug relationships....
r622
Jean-Philippe Lang
Mantis migration task initial import....
r620 MantisMigrate.establish_connection db_params
MantisMigrate.migrate
end
Jean-Philippe Lang
Added namespace for Redmine specific rake tasks....
r680 end