#!/usr/bin/perl ############################################################################# # bugzilla2mantis.pl # # Script to convert data in bugzilla (2.16-18) to Mantis (0.19.0) # # Probably works with other versions of bugzilla as its datamodel is fairly # # stable. Likely to work with many versions of Mantis as well, as recent # # functionality is either not supported by Bugzilla or not imported. # # Relationships require at least Mantis 0.19.0. Everything else should work # # on Mantis 0.18.3 (and all of 0.18.x theoretically). If you have luck using# # specific releases of either Mantis or Bugzilla, please send them to # # cris@crisdaniluk.com. # # # ############################################################################# # -------- begin ------- # The original web site for this script doesn't exist anymore, but # I rediscovered this script here: # http://web.archive.org/web/*/http://crisdaniluk.com/bugzilla2mantis/bugzilla2mantis.pl # # I made some small changes, and added the possibility to # import attachments. Also I had to add a conversion from # utf8 to latin1, see end of script. # I prefixed all my changes with # Marc: # # I used this script successfully to convert a Bugzilla 2.16.7 database # to Mantis 1.0.7. # # Marc, yoda at schli dot ch # -------- end -------- # LICENSE # 1 You may use this code freely and without any obligation to me. # 2 You may use it in commercial applications. # 3 You may embed it. You may change it. # 4 You may print out thousands of copies to wallpaper your bedroom. # 5 You may even hide the fact that this was written by someone else # 6 BUT - You may NOT say you wrote it # 7 AND - You may spontaneously lose all of your information in Bugzilla and # have unforseen problems in Mantis. I do not represent that this code # works. You can make that determination on your own, after reviewing the # code. # 8 You should let me know what versions it does and does not work with # 9 You should (but aren't obligated to)send me any enhancements you make. # If you choose to, you understand your enhancements will be subject to # these terms. You will be given credit. # # Things not imported # Attachments - Because this does not directly load into Mantis, but # instead creates a SQL dump file for you, it can't really # handle the attachment blobs. I'm working on a separate # script to handle the attachment migration. # (Marc: this works now) # Milestones - mantis only uses versions. Versions can easily include # milestones, which is I think what most people do in Bugzilla as well. # If you need milestones that exist separate from versions, I recommend # either adding a custom field for milestone in mantis (a GREAT mantis # feature), or appending them to versions (i.e. "1.0 M1", "1.0 M2", ...) # Field Defs - This is a funky feature that doesn't have a direct match in # Mantis. If someone thinks this might be useful to massage # and import, please let me know, but its really useless... # Flags # Named Queries - These are user level saved queries. Bugzilla uses a weird # format to store these... not worth it. # Quips - I love quips, but I REALLY love not having people ask me if I # spent company time writing all of them # Series # Tokens # Votes - what a stupid feature # Things sort of imported # Users - permissions just don't match from Bugzilla to Mantis. Bugzilla # has a lot more "horizontal" permissions but Mantis has a lot of # vertical control (project specific access). Unfortunately you'll # have to update permissions by hand, but this shouldn't be a big # deal unless this is a huge migration. If so, look at emailflags # ALSO, passwords are not imported so the DEFAULT mantis password # is used. This is 'root'. # If you have a user with ID 1 in bugzilla, it will become the # admin user, overwriting the existing admin account. There is no # easy way around this since this preserves all IDs # IMPORT SETTINGS # Import relationships? $importRelationships = 1; # 1/0 # Merge - You can choose to merge Bugzilla into your existing # Mantis project. Note that at present time, consolidation is not # done. Users, projects, etc will be duplicated. If you need to have # this not happen, it is fairly easy to do by manually adding the # users and/or projects and circumventing that part of the import. # THIS IS NOT COMPLETELY IMPLEMENTED YET. #$preserveIds = 1; # 1/0 $sqlDumpFile = 'bugzilla2mantis.sql'; # DATABASE CONNECTION SETTINGS # This was designed for MySQL. MySQL automatically # updates the sequences if they're bypassed. Postgres # and Oracle won't. Be careful if you're not using MySQL. #b_dsn must look like dbi:mysql::: $b_dsn = 'dbi:mysql:::'; $b_user = ''; $b_password = ''; # VERSION SETTINGS # Bugzillas previous to 2.18 did not have their own project id or # private notes. If you're using 2.18, set these to 1. $bugzillaHasProjectID = 1; $bugzillaHasPrivateNotes = 1; # BUGZILLA => MANTIS ATTRIBUTE MAPPINGS # Feel free to customize these. Sometimes Mantis or Bugzilla would have # a unique attribute (e.g. Bugzilla has 9 priorities, but Mantis has 6) # so I choose some conservative defaults. You probably don't care. $bgzPriority{'P1'} = 10; $bgzPriority{'P2'} = 20; $bgzPriority{'P3'} = 20; $bgzPriority{'P4'} = 30; $bgzPriority{'P5'} = 30; $bgzPriority{'P6'} = 40; $bgzPriority{'P7'} = 40; $bgzPriority{'P8'} = 50; $bgzPriority{'P9'} = 60; # Mantis has no normal so I demoted minor to trivial to squeeze in normal # Marc: added all the existing mantis status $bgzSeverity{'enhancement'} = 10; #feature $bgzSeverity{'trivial'} = 20; #trivial # 30; #text $bgzSeverity{'minor'} = 40; #tweak $bgzSeverity{'normal'} = 50; #minor $bgzSeverity{'major'} = 60; #major $bgzSeverity{'critical'} = 70; #crash $bgzSeverity{'blocker'} = 80; #block # german version $bgzSeverity{'Erweiterung'} = 10; #feature $bgzSeverity{'Trivial'} = 20; #trivial # 30; #text $bgzSeverity{'Unkritisch'} = 40; #tweak $bgzSeverity{'normal'} = 50; #minor $bgzSeverity{'Wichtig'} = 60; #major $bgzSeverity{'Kritisch'} = 70; #crash $bgzSeverity{'Blockierend'} = 80; #block $bgzSeverity{'Vorschlag'} = 10; $bgzStatus{'UNCONFIRMED'} = 10; # new $bgzStatus{'NEW'} = 10; # new $bgzStatus{'ASSIGNED'} = 50; # assigned $bgzStatus{'REOPENED'} = 20; # SPECIAL CASE - Changes resolution! $bgzStatus{'RESOLVED'} = 80; # resolved $bgzStatus{'VERIFIED'} = 40; # confirmed $bgzStatus{'CLOSED'} = 90; # closed $bgzResolution{'FIXED'} = 20; # fixed $bgzResolution{'INVALID'} = 70; # not a bug $bgzResolution{'WONTFIX'} = 90; # wont fix $bgzResolution{'LATER'} = 80; # suspended $bgzResolution{'REMIND'} = 80; # suspended $bgzResolution{'DUPLICATE'} = 60; # duplicate $bgzResolution{'WORKSFORME'} = 40; # unable to duplicate $bgzResolution{'MOVED'} = 10; # open $bgzResolution{'REOPENED'} = 30; # reopened # END OF CONFIGURABLE STUFF use DBI; use POSIX; use 5.004; open(SQL, ">$sqlDumpFile")or die('Could not open SQL dump file'); my $b_dbh = DBI->connect($b_dsn, $b_user, $b_password); # BUGZILLA PROFILES => MANTIS USERS # id <= userid # username <= login_name # realname <= realname # email <= login_name # password <= cryptpassword # date_created = blank # last_visit = blank # enabled = 1 # protected = 0 # access_level = 10 # login_count = 0 # cookie_string = blank my @users; { my $cookieCounter = 1; # This is dumb. Even for Mantis.. my $strQuery = "SELECT userid, login_name, realname, cryptpassword FROM profiles"; my $qry = $b_dbh->prepare($strQuery); $qry->execute; while (my ($id, $name, $realname, $passwd) = $qry->fetchrow) { my %user; $user{'id'} = $id; $user{'username'} = $name; $user{'email'} = $name; $user{'realname'} = $realname; $user{'password'} = '63a9f0ea7bb98050796b649e85481845'; $user{'date_created'} = 'current_date'; $user{'last_visit'} = 'current_date'; $user{'enabled'} = 1; $user{'protected'} = 0; $user{'access_level'} = 10; $user{'login_count'} = 0; $user{'cookie_string'} = 'cookiestring'.++$cookieCounter; # Admin override.. if ($id == 1) { $user{'access_level'} = 90; } else { push(@users, \%user); } } foreach $user (@users) { print SQL "INSERT INTO mantis_user_table (id, username, realname, email, password, date_created, last_visit, enabled, protected, access_level, login_count, cookie_string) VALUES("; print SQL $b_dbh->quote(${$user}{'id'}).", "; print SQL $b_dbh->quote(${$user}{'username'}).", "; print SQL $b_dbh->quote(${$user}{'realname'}).", "; print SQL $b_dbh->quote(${$user}{'email'}).", "; print SQL $b_dbh->quote(${$user}{'password'}).", "; print SQL $b_dbh->quote(${$user}{'date_created'}).", "; print SQL $b_dbh->quote(${$user}{'last_visit'}).", "; print SQL $b_dbh->quote(${$user}{'enabled'}).", "; print SQL $b_dbh->quote(${$user}{'protected'}).", "; print SQL $b_dbh->quote(${$user}{'access_level'}).", "; print SQL $b_dbh->quote(${$user}{'login_count'}).", "; print SQL $b_dbh->quote(${$user}{'cookie_string'}).");\n"; } } # Milestoning and voting are not portable concepts in Mantis # Milestones will be ported, but not the default project settings. # enabled <= disallownew # access_min = 10 (public) # view_state = 10 (public) # file_path = nil # status = 10 my @projects; my %projectNameIdMap; { my $projectId = 0; my $strQuery; if ($bugzillaHasProjectID == 1) { $strQuery = "SELECT id, name, description, disallownew FROM products"; } else { $strQuery = "SELECT 1, product AS name, description, disallownew FROM products"; } my $qry = $b_dbh->prepare($strQuery); $qry->execute; while (my ($id, $name, $desc, $disallow) = $qry->fetchrow) { my %project; if ($bugzillaHasProjectID == 1) { $project{'id'} = $id; } else { $project{'id'} = ++$projectId; } $projectNameIdMap{$name} = $project{'id'}; $project{'name'} = $name; $project{'description'} = $desc; # Marc: fixed, was: = disallow; $project{'enabled'} = !$disallow; $project{'access_min'} = 10; $project{'view_state'} = 10; $project{'file_path'} = ''; $project{'status'} = 10; push(@projects, \%project); } foreach $project (@projects) { print SQL "INSERT INTO mantis_project_table (id, name, status, enabled, view_state, access_min, file_path, description) VALUES("; print SQL $b_dbh->quote(${$project}{'id'}).", "; print SQL $b_dbh->quote(${$project}{'name'}).", "; print SQL $b_dbh->quote(${$project}{'status'}).", "; print SQL $b_dbh->quote(${$project}{'enabled'}).", "; print SQL $b_dbh->quote(${$project}{'view_state'}).", "; print SQL $b_dbh->quote(${$project}{'access_min'}).", "; print SQL $b_dbh->quote(${$project}{'file_path'}).", "; print SQL $b_dbh->quote(${$project}{'description'}).");\n"; } } # BUGZILLA COMPONENTS => MANTIS CATEGORIES # project_id <= product_id* # category <= name # user_id <= initialowner* # Mantis does not use IDs for category names, so category names within # a project MUST be unique, which is not the case in Bugzilla. To make # sure this is not a problem, we will append the Bugzilla id to the name. # Note that this ID will not have any intrinsic meaning in Mantis itself, # but will allow an administrator to rename components if necessary. my @components; my %categoryNameIdMap; { my $strQuery; my $categoryId = 0; if ($bugzillaHasProjectID == 1) { $strQuery = "SELECT id, name, product_id, initialowner FROM components ORDER BY product_id"; } else { $strQuery = "SELECT 1, value, program, initialowner FROM components ORDER BY program"; } my $qry = $b_dbh->prepare($strQuery); $qry->execute; my $lastProduct = -1; my %categoryNames; while (my ($id, $name, $product, $owner) = $qry->fetchrow) { # If new product(ject), reset the dupe check if (($bugzillaHasProjectID == 1) && ($lastProduct != $product)) { %categoryNames = {}; } elsif (($bugzillaHasProjectID) == 0 && ($lastProduct ne $product)) { %categoryNames = {}; } # Check to see that this name doesn't already exist if (exists $categoryNames{$name}) { $name .= ' '.$id; } my %category; if ($bugzillaHasProjectID == 1) { $category{'project_id'} = $product; } else { $category{'project_id'} = $projectNameIdMap{$product}; } $category{'category'} = $name; $category{'user_id'} = $owner; $categoryNameIdMap{$category{'name'}} = $category{'id'}; # Store grouping info for dupe check $categoryNames{$name} = $name; $lastProduct = $product; push(@categories, \%category); } my %projuser; foreach $category (@categories) { print SQL "INSERT INTO mantis_project_category_table (project_id, category, user_id) VALUES("; print SQL $b_dbh->quote(${$category}{'project_id'}).", "; print SQL $b_dbh->quote(${$category}{'category'}).", "; print SQL $b_dbh->quote(${$category}{'user_id'}).");\n"; if ($projuser{${$category}{'project_id'}."-".${$category}{'user_id'}} != '1') { print SQL "INSERT INTO mantis_project_user_list_table (project_id, user_id, access_level) VALUES("; print SQL $b_dbh->quote(${$category}{'project_id'}).", "; print SQL $b_dbh->quote(${$category}{'user_id'}).", "; # developer print SQL $b_dbh->quote('55').");\n"; $projuser{${$category}{'project_id'}."-".${$category}{'user_id'}} = '1'; } } } # BUGZILLA VERSIONS => MANTIS VERSIONS # id = generated # project_id <= product_id* # version <= value # date_order = now # description = blank # released = 0 my @versions; { my $strQuery; if ($bugzillaHasProjectID == 1) { $strQuery = "SELECT value, product_id FROM versions"; } else { $strQuery = "SELECT value, program FROM versions"; } my $qry = $b_dbh->prepare($strQuery); $qry->execute; my $verID = 1; while (my ($value, $product) = $qry->fetchrow) { my %version; $version{'id'} = $verID++; if ($bugzillaHasProjectID == 1) { $version{'project_id'} = $product; } else { $version{'project_id'} = $projectNameIdMap{$product}; } $version{'version'} = $value; $version{'description'} = ''; $version{'date_order'} = 'current_date'; $version{'released'} = '0'; push(@versions, \%version); } foreach $version (@versions) { print SQL "INSERT INTO mantis_project_version_table (id, project_id, version, date_order, description, released) VALUES("; print SQL $b_dbh->quote(${$version}{'id'}).", "; print SQL $b_dbh->quote(${$version}{'project_id'}).", "; print SQL $b_dbh->quote(${$version}{'version'}).", "; print SQL $b_dbh->quote(${$version}{'date_order'}).", "; print SQL $b_dbh->quote(${$version}{'description'}).", "; print SQL $b_dbh->quote(${$version}{'released'}).");\n"; } } # BUGZILLA BUGS => MANTIS BUGS # id <= bug_id # project_id <= product_id* # reporter_id <= reporter # handler_id <= assigned_to # duplicate_id <= blank # priority <= priority # severity <= bug_severity # reproducibility <= 10 # status <= bug_status # resolution <= resolution # projection <= 10 # category <= component_id # date_submitted <= creation_ts # last_updated <= delta_ts # eta <= 10 # bug_text_id <= -1 (set later) # os <= op_sys # os_build <= blank # platform <= rep_platform # version <= version # fixed_in_version <= target_milestone # build <= blank # profile_id <= null # view_state <= 10 # summary <= short_desc # sponsorship_total <= null my %bugs; { my $strQuery; if ($bugzillaHasProjectID == 1) { $strQuery = "SELECT bug_id, assigned_to, bug_file_loc, bug_severity, bug_status, creation_ts, delta_ts, short_desc, op_sys, priority, product_id, rep_platform, reporter, version, (select name from components where id = component_id), resolution, target_milestone, short_desc FROM bugs"; } else { $strQuery = "SELECT bug_id, assigned_to, bug_file_loc, bug_severity, bug_status, creation_ts, delta_ts, short_desc, op_sys, priority, product, rep_platform, reporter, version, component_id, resolution, target_milestone, short_desc FROM bugs"; } my $qry = $b_dbh->prepare($strQuery); $qry->execute; while (my ($bug_id, $assigned_to, $bug_file_loc, $bug_severity, $bug_status, $creation_ts, $delta_ts, $short_desc, $op_sys, $priority, $product_id, $rep_platform, $reporter, $version, $component_id, $resolution, $target_milestone, $short_desc) = $qry->fetchrow) { my %bug; $bug{'id'} = $bug_id; if ($bugzillaHasProjectID == 1) { $bug{'project_id'} = $product_id; $bug{'category'} = $component_id; } else { $bug{'project_id'} = $projectNameIdMap{$product_id}; $bug{'category'} = $categoryNameIdMap{$component_id}; } $bug{'reporter_id'} = $reporter; $bug{'handler_id'} = $assigned_to; $bug{'duplicate_id'} = ''; # null $bug{'priority'} = $bgzPriority{$priority}; if (!(exists $bgzPriority{$priority})) { $bug{'priority'} = 50; } $bug{'severity'} = $bgzSeverity{$bug_severity}; $bug{'reproducibility'} = 10; $bug{'status'} = $bgzStatus{$bug_status}; $bug{'resolution'} = $bgzResolution{$resolution}; $bug{'projection'} = 10; $bug{'date_submitted'} = $creation_ts; $bug{'last_updated'} = $delta_ts; $bug{'eta'} = 10; $bug{'bug_text_id'} = -1; $bug{'os'} = $op_sys; $bug{'os_build'} = ''; $bug{'platform'} = $rep_platform; $bug{'version'} = $version; $bug{'fixed_in_version'} = $target_milestone; $bug{'build'} = ''; $bug{'profile_id'} = ''; # null $bug{'view_state'} = 10; # Marc: convert to iso $bug{'summary'} = toISO($short_desc); $bug{'sponsorship_total'} = ''; # null # If status is reopened, status should be assigned # and resolution should be REOPENED # Marc: changed, didn't make sense. if ($bug_status eq 'REOPENED') { $bug{'resolution'} = $bgzResolution{'REOPENED'}; } if ($bug{'resolution'} == '') { $bug{'resolution'} = 10; } $bugs{$bug_id} = \%bug; } # We don't iterate bugs out to the db yet to prevent a RI problem } # BUGZILLA LONGDESCS => MANTIS BUGTEXTS/BUGNOTES # Mantis has a separate table for the first bug note, which it considers # to be the bug description. Bugzilla doesn't have the idea of a # description. In order to make Mantis work as it should, the first # longdesc for each bug will be the bug description. Subsequent ones # will be bugnotes. # # DESCS # id <= generated # description <= thetext # steps_to_reproduce <= blank # additional_information <= blank # # NOTES # id <= generated # bug_id <= bug_id # reporter_id <= who # bugnote_text_id <= generated # view_state <= isprivate (10/50) # date_submitted <= bug_when # last_modified <= nil # # NOTES (text ref) # id <= generated # note <= thetext my @bugdescs; my @bugnotes; { my $strQuery; if ($bugzillaHasPrivateNotes == 1) { $strQuery = "SELECT bug_id, who, bug_when, thetext, isprivate FROM longdescs ORDER BY bug_id"; } else { $strQuery = "SELECT bug_id, who, bug_when, thetext, 10 FROM longdescs ORDER BY bug_id"; } my $qry = $b_dbh->prepare($strQuery); $qry->execute; my $lastBug = -1; my $bugNoteId = 0; my $bugDescId = 0; while (my ($bug_id, $who, $bug_when, $thetext, $isprivate) = $qry->fetchrow) { if ($lastBug == $bug_id) { # Bugnote my %note; $note{'id'} = ++$bugNoteId; $note{'bug_id'} = $bug_id; $note{'reporter_id'} = $who; $note{'bugnote_text_id'} = $bugNoteId; $note{'view_state'} = $isprivate==0?50:10; $note{'date_submitted'} = $bug_when; $note{'last_modified'} = 'current_date'; $note{'note'} = toISO($thetext); push(@bugnotes, \%note); } else { my %desc; $desc{'id'} = ++$bugDescId; $desc{'description'} = toISO($thetext); push(@bugdescs, \%desc); # We also have to update the bug... $bug = $bugs{$bug_id}; if ($bug != null) { # Marc: didn't work #${$bug}{'bug_text_id'} = $bugDescId; #$bugs{$bug_id} = \%bug; $$bug{'bug_text_id'} = $bugDescId; } } $lastBug = $bug_id; } foreach $desc (@bugdescs) { print SQL "INSERT INTO mantis_bug_text_table (id, description, steps_to_reproduce, additional_information) VALUES("; print SQL $b_dbh->quote(${$desc}{'id'}).", "; print SQL $b_dbh->quote(${$desc}{'description'}).", "; # print SQL $b_dbh->quote(${$desc}{'steps_to_reproduce'}).", "; # print SQL $b_dbh->quote(${$desc}{'additional_information'}).");\n"; print SQL $b_dbh->quote("").", "; print SQL $b_dbh->quote("").");\n"; } foreach $note (@bugnotes) { print SQL "INSERT INTO mantis_bugnote_text_table (id, note) VALUES("; print SQL $b_dbh->quote(${$note}{'id'}).", "; print SQL $b_dbh->quote(${$note}{'note'}).");\n"; print SQL "INSERT INTO mantis_bugnote_table (id, bug_id, reporter_id, bugnote_text_id, view_state, date_submitted, last_modified) VALUES("; print SQL $b_dbh->quote(${$note}{'id'}).", "; print SQL $b_dbh->quote(${$note}{'bug_id'}).", "; print SQL $b_dbh->quote(${$note}{'reporter_id'}).", "; print SQL $b_dbh->quote(${$note}{'bugnote_text_id'}).", "; print SQL $b_dbh->quote(${$note}{'view_state'}).", "; print SQL $b_dbh->quote(${$note}{'date_submitted'}).", "; print SQL $b_dbh->quote(${$note}{'last_modified'}).");\n"; } } # now iterate out the bugs themselves.. foreach $bug (values %bugs) { # $bug = $bugs{$bugid}; print SQL "INSERT INTO mantis_bug_table (id, project_id, reporter_id, handler_id, duplicate_id, priority, severity, reproducibility, status, resolution, projection, category, date_submitted, last_updated, eta, bug_text_id, os, os_build, platform, version, fixed_in_version, build, profile_id, view_state, summary, sponsorship_total) VALUES("; print SQL $b_dbh->quote(${$bug}{'id'}).", "; print SQL $b_dbh->quote(${$bug}{'project_id'}).", "; print SQL $b_dbh->quote(${$bug}{'reporter_id'}).", "; print SQL $b_dbh->quote(${$bug}{'handler_id'}).", "; print SQL $b_dbh->quote(${$bug}{'duplicate_id'}).", "; print SQL $b_dbh->quote(${$bug}{'priority'}).", "; print SQL $b_dbh->quote(${$bug}{'severity'}).", "; print SQL $b_dbh->quote(${$bug}{'reproducibility'}).", "; print SQL $b_dbh->quote(${$bug}{'status'}).", "; print SQL $b_dbh->quote(${$bug}{'resolution'}).", "; print SQL $b_dbh->quote(${$bug}{'projection'}).", "; print SQL $b_dbh->quote(${$bug}{'category'}).", "; print SQL $b_dbh->quote(${$bug}{'date_submitted'}).", "; print SQL $b_dbh->quote(${$bug}{'last_updated'}).", "; print SQL $b_dbh->quote(${$bug}{'eta'}).", "; print SQL $b_dbh->quote(${$bug}{'bug_text_id'}).", "; print SQL $b_dbh->quote(${$bug}{'os'}).", "; print SQL $b_dbh->quote(${$bug}{'os_build'}).", "; print SQL $b_dbh->quote(${$bug}{'platform'}).", "; print SQL $b_dbh->quote(${$bug}{'version'}).", "; print SQL $b_dbh->quote(${$bug}{'fixed_in_version'}).", "; print SQL $b_dbh->quote(${$bug}{'build'}).", "; print SQL $b_dbh->quote(${$bug}{'profile_id'}).", "; print SQL $b_dbh->quote(${$bug}{'view_state'}).", "; print SQL $b_dbh->quote(${$bug}{'summary'}).", "; print SQL $b_dbh->quote(${$bug}{'sponsorship_total'}).");\n"; } # BUGZILLA DEPENDENCIES => MANTIS RELATIONSHIPS # id = generated # source_bug_id <= blocked # destination_bug_id <= dependson # relationship_type = 1 - This is a related to, not child of. # Mantis doesn't have a specific blocker relationship type now. my @relationships; if ($importRelationships == 1) { my $strQuery = "SELECT blocked, dependson FROM dependencies"; my $qry = $b_dbh->prepare($strQuery); $qry->execute; my $relID = 1; while (my ($blocked, $dependson) = $qry->fetchrow) { my %relationship; $relationship{'id'} = $relID++; $relationship{'source_bug_id'} = $blocked; $relationship{'destination_bug_id'} = $dependson; $relationship{'relationship_type'} = '1'; push(@relationships, \%relationship); } foreach $relationship (@relationships) { print SQL "INSERT INTO mantis_bug_relationship_table (id, source_bug_id, destination_bug_id, relationship_type) VALUES("; print SQL $b_dbh->quote(${$relationship}{'id'}).", "; print SQL $b_dbh->quote(${$relationship}{'source_bug_id'}).", "; print SQL $b_dbh->quote(${$relationship}{'destination_bug_id'}).", "; print SQL $b_dbh->quote(${$relationship}{'relationship_type'}).");\n"; } } # Need to cache Bugzilla fields for activity my %fieldNameIdMap; { my $strQuery = "SELECT id, description FROM fielddefs"; my $qry = $b_dbh->prepare($strQuery); $qry->execute; while (my ($id, $desc) = $qry->fetchrow) { $fieldNameIdMap{$id} = $desc; } } # BUGZILLA ACTIVITY => MANTIS HISTORY # id <= generated # user_id <= wo # bug_id <= bug_id # date_modified <= bug_when # field_name <= fieldid # new_value <= added # old_value <= removed # type <= my @history; { my $activityId = 0; my $strQuery = "SELECT bug_id, who, bug_when, fieldid, added, removed FROM bugs_activity"; my $qry = $b_dbh->prepare($strQuery); $qry->execute; while (my ($bug_id, $who, $bug_when, $fieldid, $added, $removed) = $qry->fetchrow) { my %elem; $elem{'id'} = ++$activityId; $elem{'bug_id'} = $bug_id; $elem{'date_modified'} = $bug_when; $elem{'user_id'} = $who; $elem{'field_name'} = $fieldNameIdMap{$fieldid}; $elem{'new_value'} = $added; $elem{'old_value'} = $removed; $elem{'type'} = 0; push(@history, \%elem); } foreach $elem (@history) { print SQL "INSERT INTO mantis_bug_history_table (id, user_id, bug_id, date_modified, field_name, old_value, new_value, type) VALUES("; print SQL $b_dbh->quote(${$elem}{'id'}).", "; print SQL $b_dbh->quote(${$elem}{'user_id'}).", "; print SQL $b_dbh->quote(${$elem}{'bug_id'}).", "; print SQL $b_dbh->quote(${$elem}{'date_modified'}).", "; print SQL $b_dbh->quote(${$elem}{'field_name'}).", "; print SQL $b_dbh->quote(${$elem}{'old_value'}).", "; print SQL $b_dbh->quote(${$elem}{'new_value'}).", "; print SQL $b_dbh->quote(${$elem}{'type'}).");\n"; } } # Marc: convert attachments # BUGZILLA ATTACHMENTS => MANTIS BUG_FILE # id = generated # bug_id <= bug_id* # title <= blank # description = description # diskfile = ???? # filename = filename # folder = blank # filesize = generated # file_type = mimetype # date_added = creation_ts # content = thedata my @files; { my $strQuery; $strQuery = "SELECT attachments.bug_id, attachments.description, attachments.filename, attachments.mimetype, attachments.creation_ts, attach_data.thedata FROM attachments,attach_data where attach_data.id=attachments.attach_id "; my $qry = $b_dbh->prepare($strQuery); $qry->execute; my $fileID = 1; while (my ($bug_id, $description, $filename, $mimetype, $creation_ts, $thedata) = $qry->fetchrow) { my %file; $file{'id'} = $fileID++; $file{'bug_id'} = $bug_id; $file{'title'} = $description; $file{'description'} = ''; $file{'diskfile'} = ''; $file{'filename'} = $filename; $file{'folder'} = ''; $file{'filesize'} = length($thedata); $file{'file_type'} = $mimetype; $file{'date_added'} = $creation_ts; $file{'content'} = $thedata; push(@files, \%file); } foreach $file (@files) { print SQL "INSERT INTO mantis_bug_file_table (id, bug_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content) VALUES("; print SQL $b_dbh->quote(${$file}{'id'}).", "; print SQL $b_dbh->quote(${$file}{'bug_id'}).", "; print SQL $b_dbh->quote(${$file}{'title'}).", "; print SQL $b_dbh->quote(${$file}{'description'}).", "; print SQL $b_dbh->quote(${$file}{'diskfile'}).", "; print SQL $b_dbh->quote(${$file}{'filename'}).", "; print SQL $b_dbh->quote(${$file}{'folder'}).", "; print SQL $b_dbh->quote(${$file}{'filesize'}).", "; print SQL $b_dbh->quote(${$file}{'file_type'}).", "; print SQL $b_dbh->quote(${$file}{'date_added'}).", "; print SQL $b_dbh->quote(${$file}{'content'}).");\n"; } } #Mapping of custom fields my @cf; { my $strQuery; $strQuery = "SELECT fielddefs.name, fielddefs.description, fielddefs.type, fielddefs.enter_bug FROM fielddefs WHERE fielddefs.custom = 1 and fielddefs.obsolete = 0"; my $qry = $b_dbh->prepare($strQuery); $qry->execute; my $fileID = 1; while (my ($field_name, $description, $type, $on_enter_bug) = $qry->fetchrow) { my $possValues = "|"; if ($type != 1) { my $subQuery = "SELECT cf.value FROM " . $field_name . " cf"; my $query = $b_dbh->prepare($subQuery); $query->execute; while (my ($value) = $query->fetchrow) { $possValues = $possValues . $value . "|"; } } chop($possValues); my %file; $file{'id'} = $fileID++; $file{'bugzilla_name'} = $field_name; $file{'name'} = $description; if ($type == 1) { $file{'type'} = $type; } else { $file{'type'} = '6'; } $file{'possible_values'} = $possValues; $file{'default_value'} = ''; $file{'valid_regexp'} = ''; $file{'access_level_r'} = '10'; $file{'access_level_rw'} = '55'; $file{'lenght_min'} = '0'; if ($type != 1) { $file{'lenght_max'} = '0'; } else { $file{'lenght_max'} = '250'; } $file{'advanced'} = '0'; $file{'require_report'} = '0'; $file{'require_update'} = '0'; $file{'display_report'} = '0'; $file{'diplay_update'} = '0'; $file{'require_resolved'} = '0'; $file{'diplay_resolved'} = '0'; $file{'diplay_closed'} = '0'; $file{'require_closed'} = '0'; push(@cf, \%file); } foreach $file (@cf) { print SQL "INSERT INTO mantis_custom_field_table (id, name, type, possible_values, default_value, valid_regexp, access_level_r, access_level_rw, lenght_min, lenght_max, advanced, required_report, require_update, display_report, diplay_update, require_resolved, diplay_resolved, diplay_closed, require_closed ) VALUES("; print SQL $b_dbh->quote(${$file}{'id'}).", "; print SQL $b_dbh->quote(${$file}{'name'}).", "; print SQL $b_dbh->quote(${$file}{'type'}).", "; print SQL $b_dbh->quote(${$file}{'possible_values'}).", "; print SQL $b_dbh->quote(${$file}{'default_value'}).", "; print SQL $b_dbh->quote(${$file}{'valid_regexp'}).", "; print SQL $b_dbh->quote(${$file}{'access_level_r'}).", "; print SQL $b_dbh->quote(${$file}{'access_level_rw'}).", "; print SQL $b_dbh->quote(${$file}{'lenght_min'}).", "; print SQL $b_dbh->quote(${$file}{'lenght_max'}).", "; print SQL $b_dbh->quote(${$file}{'advanced'}).", "; print SQL $b_dbh->quote(${$file}{'require_report'}).", "; print SQL $b_dbh->quote(${$file}{'require_update'}).", "; print SQL $b_dbh->quote(${$file}{'display_report'}).", "; print SQL $b_dbh->quote(${$file}{'diplay_update'}).", "; print SQL $b_dbh->quote(${$file}{'require_resolved'}).", "; print SQL $b_dbh->quote(${$file}{'diplay_resolved'}).", "; print SQL $b_dbh->quote(${$file}{'diplay_closed'}).", "; print SQL $b_dbh->quote(${$file}{'require_closed'}).");\n"; my $strQuery; $strQuery = "SELECT bugs.bug_id, bugs.${$file}{'bugzilla_name'} FROM bugs"; my $qry = $b_dbh->prepare($strQuery); $qry->execute; while (my ($bug_id, $value) = $qry->fetchrow) { print SQL "INSERT INTO mantis_custom_field_string_table (field_id, bug_id, value) VALUES ("; print SQL $b_dbh->quote(${$file}{'id'}).", "; print SQL $b_dbh->quote($bug_id).","; print SQL $b_dbh->quote($value).");\n"; } } } # Marc: convert some text to iso use Unicode::String qw(latin1 utf8); sub toISO($) { my $text = $_[0]; # if this host was UTF-8 encoded: my $text_iso = (utf8($text))->latin1; my $text_utf8 = (latin1($text_iso))->utf8; # reverse check if ($text ne $text_utf8) { # print STDERR "Unequal reverse check! It seems your input data \"$text\" is ", # "ISO encoded already, so you don't need the latin1 encoding stuff here!\n"; # I'm going to fix this $text_iso = $text; } $text_iso; }