#!/usr/bin/perl -w ####################################### ##Shpatserman Maria #07.02.2010 # # XML Parser and Creator Bugzilla's xml # ####################################### use strict; use XML::Writer; use IO::File; use MIME::Base64 qw(encode_base64); use XML::DOM; use XML::DOM::XPath; use Data::Dumper; use File::MMagic::XS; use Getopt::Compact; #Function creates xml node to_node with data from from_node sub create_node{ my( $defect, $writer,$from_node,$to_node) =@_; my @testnodes = $defect->findnodes( $from_node); my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); $writer->dataElement($to_node,$str); } #Function creates xml node time (creation_ts , delta_ts ...) sub create_node_time{ my( $defect, $writer,$from_node,$to_node) =@_; my @testnodes = $defect->findnodes( $from_node); my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); my $Y = substr($str, 6, 4); my $m = substr($str, 3, 2); my $d = substr($str, 0, 2); my $formatdate= "$Y-$m-$d 10:29:28"; $writer->dataElement($to_node,$formatdate); } #Function creates xml node with data value sub create_node_value{ my($writer,$name_node,$value) = @_; $writer->dataElement($name_node, $value); } #Function creates xml node product with data from from_node sub create_node_product{ my($defect, $writer,$from_node,$to_node) = @_; #TesTrack component => Bugzilla product my %products = ("\x{41f}\x{440}\x{43e}\x{434}\x{443}\x{43a}\x{442} 1" => "СПб - Продукт 1", "\x{41f}\x{440}\x{43e}\x{434}\x{443}\x{43a}\x{442} 2" => "СПб - Продукт 2", "\x{41f}\x{440}\x{43e}\x{434}\x{443}\x{43a}\x{442} 3" => "СПб - Продукт 3"); my @testnodes = $defect->findnodes( $from_node); my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); $str =~ s/(\s*)(.*)(\s*)/$2/; #print Dumper($str); my $node_text = $products{$str}; $writer->dataElement($to_node,$node_text); } #Function creates xml node version with data from from_node sub create_node_version{ my($defect, $writer,$from_node,$to_node) = @_; #TestTrack product => Bugzilla version my %versions = ("\x{412}\x{435}\x{440}\x{441}\x{438}\x{44f} 1" => "V1", "\x{412}\x{435}\x{440}\x{441}\x{438}\x{44f} 2" => "V2", "\x{412}\x{435}\x{440}\x{441}\x{438}\x{44f} 3" => "V3"); my @testnodes = $defect->findnodes( $from_node); my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); $str =~ s/(\s*)(.*)(\s*)/$2/; #print Dumper($str); my $node_text = $versions{$str}; $writer->dataElement($to_node,$node_text); } #Function creates xml node bug_status from from_node sub create_node_status{ my($defect, $writer,$from_node,$to_node) = @_; #TestTrack defect-status => Bugzilla bug_status my %bug_status = ("Open" => "NEW", "Open (Verify Failed)" => "NEW", "Open (Re-Opened)" => "NEW", "Fixed" => "RESOLVED", "Closed" => "CLOSED", "Closed (Fixed)" => "CLOSED", "Closed (Verified)" => "CLOSED"); my @testnodes = $defect->findnodes( $from_node); my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); $str =~ s/(\s*)(.*)(\s*)/$2/; #print Dumper($str); my $node_text = $bug_status{$str}; $writer->dataElement($to_node,$node_text); if (($node_text eq "RESOLVED")||($node_text eq "CLOSED")) { $writer->dataElement("resolution","FIXED");} } #Function creates xml node priority from from_node sub create_node_priority{ my($defect, $writer,$from_node,$to_node) = @_; my @testnodes = $defect->findnodes( $from_node); my $node = $testnodes[0]; my $str =''.$node->getFirstChild()->getData(); $str =~ s/(\s*)(.*)(\s*)/$2/; my $node_text =""; if( ($str eq '1') || ($str eq '2')) { $node_text = "В дистрибутив";} elsif ($str eq '3') { $node_text = "Срочно";} else { $node_text = "Несрочно";} $writer->dataElement($to_node,$node_text); } #Function get full name and email by surname sub getname_email_users { my $user =$_[0]; my %users=("Sokunova" => ["Сокунова М.А.", 'sokunova@xxxxx.ru'], "Ivanov" =>["Иванов Ю.Л.", 'ivanov@xxxxx.ru'], "Petrov" => ["Петров И.И.", 'petrov@xxxxx.ru']); my $name = $users{$user}[0]; my $email = $users{$user}[1]; return($name, $email); } #Function creates xml node reporter from from_node sub create_node_reporter{ my($defect, $writer,$from_node,$to_node) = @_; my @testnodes = $defect->findnodes( $from_node); my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); $str =~ s/(\s*)(.*?)(\s*)/$2/; my @name_email = &getname_email_users($str); $writer->dataElement($to_node,$name_email[1], 'name' => $name_email[0]); } #Function creates xml node qa_contact from from_node sub create_node_qacontact{ my($defect, $writer,$from_str,$to_node) = @_; my @name_email = &getname_email_users($from_str); $writer->dataElement($to_node,$name_email[1], 'name' => $name_email[0]); } #Function creates xml node assigned_to from from_node sub create_node_assignedto{ my($defect, $writer,$from_node,$to_node) = @_; #Get nodes currently-assigned-to my @testnodes = $defect->findnodes( $from_node); #No assignes for a bug - assigne to any tester if ($#testnodes <0) { my $str ="Sokunova"; my @name_email = &getname_email_users($str); $writer->dataElement($to_node,$name_email[1], 'name' => $name_email[0]); } else { my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); $str =~ s/(\s*)(.*?)(\s*)/$2/; my @name_email = &getname_email_users($str); #Creates assigned_to with data from first element from array $writer->dataElement($to_node,$name_email[1], 'name' => $name_email[0]); #Delete first element shift(@testnodes); #All other elements creates cc nodes foreach my $node_cc (@testnodes) { $str = $node_cc->getFirstChild()->getData(); $str =~ s/(\s*)(.*?)(\s*)/$2/; #print $str ,"\n"; @name_email = &getname_email_users($str); #print $name_email[0], $name_email[1], "\n"; $writer->dataElement('cc',$name_email[1]); } } } #Function creates xml node long_desc from from_node sub create_node_longdesc_first{ my($defect, $writer,$from_node,$to_node) = @_; $writer->startTag($to_node, 'isprivate'=>'0'); #who my @testnodes =$defect->findnodes( $from_node.'/found-by/last-name'); my $node = $testnodes[0]; my $str =$node->getFirstChild()->getData(); $str =~ s/(\s*)(.*?)(\s*)/$2/; my @name_email = &getname_email_users($str); $writer->dataElement('who',$name_email[1], 'name' => $name_email[0]); @testnodes =$defect->findnodes( $from_node.'/date-found'); $node = $testnodes[0]; $str =$node->getFirstChild()->getData(); $writer->dataElement('bug_when',$str); @testnodes =$defect->findnodes( $from_node.'/description'); $node = $testnodes[0]; $str =$node->getFirstChild()->getData(); $writer->dataElement('thetext',$str); $writer->endTag(); } #Function creates xml long_desc from from_node (comments) sub create_node_longdesc_comments{ my($defect, $writer,$from_node,$to_node) = @_; my $defect_events = $defect->getElementsByTagName( $from_node); for(my $i=0; $i < $defect_events->getLength;$i++){ my $node = $defect_events->item($i); $writer->startTag($to_node, 'isprivate'=>'0'); my @sub_nodes = $node->findnodes('event-author/last-name'); my $sub_node = $sub_nodes[0]; my $str; unless((defined($sub_node->getFirstChild()))) { $str= "Sokunova"; } else { $str =$sub_node->getFirstChild()->getData(); } $str =~ s/(\s*)(.*?)(\s*)/$2/; my @name_email = &getname_email_users($str); $writer->dataElement('who',$name_email[1], 'name' => $name_email[0]); @sub_nodes = $node->findnodes('event-date'); $sub_node = $sub_nodes[0]; $str =$sub_node->getFirstChild()->getData(); my $Y = substr($str, 6); my $m = substr($str, 3, 2); my $d = substr($str, 0, 2); my $formatdate= "$Y-$m-$d 10:29:28"; $writer->dataElement('bug_when',$formatdate); @sub_nodes =$node->findnodes('notes'); if($#sub_nodes <0 ) { $writer->startTag('thetext'); $writer->endTag('thetext'); } else { $sub_node =$sub_nodes[0]; $str=$sub_node->getFirstChild()->getData(); $writer->dataElement('thetext',$str); } $writer->endTag(); } } #Function creates xml node attachment from from_node sub create_node_attachment { my($defect, $writer,$from_node,$to_node) = @_; my $defect_attachs = $defect->getElementsByTagName($from_node); my $n=$defect_attachs->getLength; #print "Lenght atach = $n \n"; for (my $i =0; $i < $defect_attachs->getLength; $i++) { my $node = $defect_attachs->item($i); $writer->startTag('attachment', 'isobsolete' => '0', 'ispatch' => '0', 'isprivate' =>'0'); $writer->dataElement('attachid','2'); my $href = $node->getAttributeNode ("create-date"); my $date =$href->getValue; my $Y = substr($date, 0, 4); my $m = substr($date, 4, 2); my $d = substr($date, 6); my $formatdate= "$Y-$m-$d 10:29"; $writer->dataElement('date',$formatdate); $href = $node->getAttributeNode ("name"); $writer->dataElement('desc',$href->getValue); $writer->dataElement('filename',$href->getValue); $href = $node->getAttributeNode("filespec"); my $filename = $href->getValue; my $magic = File::MMagic::XS->new(); my $mime = $magic->get_mime($filename); #Get type of the file (text/plain...) $writer->dataElement('type',$mime); $href = $node->getAttributeNode ("sizebytes"); $writer->dataElement('size',$href->getValue); $writer->dataElement('attacher','sokunova@xxxxx.ru'); $writer->startTag('data','encoding' => 'base64'); #Make from dat file base64 string and put it into xml node my $encode_str = &encode_file($filename); $writer->raw($encode_str); $writer->endTag('data'); $writer->endTag('attachment'); } } #Function Creates from file base64 string sub encode_file { my $filename = $_[0]; open(DAT, $filename) or die "$!"; #Open file in binary mode binmode(DAT); my $buff; my $str=''; while(read(DAT , $buff, 60*57)){ $str =$str. encode_base64($buff); } close(DAT); return $str; } #Function creates correct bugzilla xml from another bugtracker sub bugzilla_structure { my( $defect, $writer) =@_; #creating &create_node($defect,$writer,'defect-number','bug_id'); #creating &create_node_time($defect, $writer, 'date-created', 'creation_ts'); #creating &create_node($defect, $writer, 'summary', 'short_desc'); #creating &create_node_time($defect,$writer, 'date-last-modified','delta_ts'); #creating &create_node_value($writer, 'reporter_accessible', '1'); #creating &create_node_value($writer, 'cclist_accessible', '1'); #creating &create_node_value($writer, 'classification_id', '5'); #creating &create_node_value($writer, 'classification', 'СПб'); #creating &create_node_product($defect,$writer,'component','product'); #creating &create_node_value($writer, 'component','Интерфейс пользователя'); #creating &create_node_version($defect,$writer,'product', 'version'); #creating &create_node_value($writer, 'rep_platform', 'Intel 32'); #creating &create_node_value($writer, 'op_sys', 'Windows XP'); #creating &create_node_status($defect,$writer,'defect-status','bug_status'); #creating &create_node_priority($defect,$writer,'priority','priority'); #creating &create_node_value($writer, 'bug_severity','Ошибка'); #creating &create_node_value($writer, 'target_milestone','---'); #creating &create_node_value($writer, 'everconfirmed','1'); #creating &create_node_reporter($defect,$writer, 'entered-by/last-name','reporter'); #creating and &create_node_assignedto($defect, $writer, 'currently-assigned-to/last-name','assigned_to'); #creating &create_node_value($writer, 'estimated_time', '0.00'); #creating &create_node_value($writer, 'remaining_time', '0.00'); #creating &create_node_value($writer, 'actual_time', '0.00'); #creating &create_node_qacontact($defect, $writer, 'Sokunova', 'qa_contact'); #creating &create_node_value($writer, 'group', 'Доступ - Продукты СПб'); #creating &create_node_longdesc_first($defect,$writer,'reported-by-record','long_desc'); #creating - comments &create_node_longdesc_comments($defect,$writer,'defect-event','long_desc'); #creating &create_node_attachment($defect,$writer, 'attachment', 'attachment'); } #Function get all defect nodes and make it for a bug nodes sub parse_xml{ my $doc = $_[0]; my $writer = $_[1]; #Parse all defects in xml tree my $defects = $doc->getElementsByTagName("defect"); for(my $i=0; $i < $defects->getLength;$i++){ my $defect = $defects->item($i); #create Node for all $writer->startTag('bug'); #Creating bugzilla structure &bugzilla_structure($defect,$writer); $writer->endTag('bug'); } } #Function add the start title to xml and starting parsing sub print_xml{ my ($output, $testrakxml) =@_; my $dom_parser = new XML::DOM::Parser; my $doc = $dom_parser->parsefile ($testrakxml); my $root = $doc->getDocumentElement(); my $writer = new XML::Writer(OUTPUT => $output, UNSAFE =>1); $writer->xmlDecl('UTF-8','yes'); #Starting XML file $writer->doctype('bugzilla',undef,'bugzilla.dtd'); $writer->startTag('bugzilla', 'version' => '3.4.2', 'urlbase' => 'http://localhost/TestTrack/', 'maintainer' => 'bugzilla@xxxxx.ru', 'exporter' => 'sokunova@xxxxx.ru'); &parse_xml($doc, $writer); #Ending XML file $writer->endTag(); $writer->end; } my $keys = new Getopt::Compact (name => 'parser XML program', version => '1.1', struct=> [ [[qw(i input_xml)],qq(XML file for parsing - TestTrack format),'=s'], [[qw(o output_xml)],qq(XML file will be saved in bugzilla format),'=s'], ] ); my $opts = $keys->opts; if (!defined($$opts{input_xml}) || !defined($$opts{output_xml})) { print "Enter xml for parsing and xml for save \n"; exit 0; } print " INPUT = $$opts{input_xml} OUTPUT = $$opts{output_xml} \n"; my $output = new IO::File(">$$opts{output_xml}"); my $testrakxml= $$opts{input_xml}; &print_xml($output, $testrakxml);