0
|
1 #!/usr/bin/perl -w
|
|
2
|
5
|
3 use JSON;
|
|
4 use YAML::XS qw(LoadFile Dump);
|
|
5 use URI;
|
|
6 use XML::Writer;
|
6
|
7 use IPC::Run qw(start finish);
|
5
|
8
|
1
|
9 our @ClassPath = qw(
|
|
10 /usr/share/java/xalan-j2-serializer.jar
|
|
11 /usr/share/java/xalan-j2.jar
|
|
12 /usr/share/java/xerces-j2.jar
|
|
13 /usr/share/java/xml-commons-resolver.jar
|
|
14 .
|
|
15 );
|
|
16
|
5
|
17 my $config = LoadFile("config.yaml");
|
|
18
|
|
19 if ( !( $config->{bugzilla}{url} =~ /\/$/ ) ) {
|
|
20 $config->{bugzilla}{url} .= "/";
|
|
21 }
|
|
22
|
|
23 my $bz = BzRest->new(
|
|
24 url => $config->{bugzilla}{url},
|
|
25 apikey => $config->{bugzilla}{apikey}
|
|
26 );
|
|
27
|
6
|
28 my @fields = qw(
|
|
29 id
|
|
30 summary
|
|
31 creation_time
|
|
32 last_change_time
|
|
33 creator
|
|
34 assigned_to
|
|
35
|
|
36 status
|
|
37 resolution
|
5
|
38
|
6
|
39 priority
|
|
40 severity
|
|
41 url
|
|
42
|
|
43 blocks
|
|
44 depends_on
|
|
45 cc
|
|
46
|
|
47 component
|
|
48 product
|
|
49 classification
|
|
50 version
|
|
51
|
|
52 actual_time
|
|
53 estimated_time
|
|
54 remainig_time
|
|
55 deadline
|
5
|
56 );
|
|
57
|
|
58 my %fieldsMap = (
|
6
|
59 summary => 'short_desc',
|
|
60 id => 'bug_id',
|
|
61 creator => 'reporter',
|
|
62 status => 'bug_status',
|
|
63 severity => 'bug_severity',
|
|
64 blocks => 'blocked',
|
|
65 depends_on => 'dependson',
|
|
66 creation_time => 'creation_ts',
|
5
|
67 last_change_time => 'delta_ts'
|
1
|
68 );
|
0
|
69
|
6
|
70 local (*HIN);
|
|
71
|
|
72 my $proc = start( [ 'saxon8', '-novw', '-', 'bug-list.xsl' ],
|
|
73 '<pipe', \*HIN, '>', \*STDOUT )
|
|
74 or die "failed to create pipe: $!";
|
|
75
|
|
76 my $writer = XML::Writer->new( OUTPUT => \*HIN, ENCODING => 'utf-8' );
|
5
|
77
|
|
78 $writer->xmlDecl("UTF-8");
|
|
79 $writer->startTag("bugzilla");
|
|
80
|
6
|
81 my %visited;
|
|
82 my @queue = (283);
|
|
83
|
|
84 while (@queue) {
|
|
85 @queue = grep not( $visited{$_}++ ), @queue;
|
|
86
|
|
87 last unless @queue;
|
|
88
|
|
89 print "#Fetching: ", join( ', ', @queue ), "\n";
|
|
90
|
|
91 my $bugs = $bz->GetBugs( { ids => \@queue } );
|
|
92
|
|
93 @queue = ();
|
|
94
|
|
95 foreach my $bug (@$bugs) {
|
|
96
|
|
97 push @queue, @{ $bug->{depends_on} }
|
|
98 if ( $bug->{depends_on} );
|
|
99
|
|
100 $writer->startTag("bug");
|
|
101 foreach my $field (@fields) {
|
|
102 next unless $bug->{$field};
|
|
103
|
|
104 my $tagName = $fieldsMap{$field} || $field;
|
|
105 my @values =
|
|
106 ref( $bug->{$field} )
|
|
107 && ref( $bug->{$field} ) eq 'ARRAY'
|
|
108 ? @{ $bug->{$field} }
|
|
109 : $bug->{$field};
|
|
110
|
|
111 foreach my $v (@values) {
|
|
112 $writer->dataElement( $tagName, $v );
|
|
113 }
|
5
|
114 }
|
6
|
115 $writer->endTag();
|
|
116
|
5
|
117 }
|
|
118 }
|
|
119
|
|
120 $writer->endTag();
|
|
121
|
6
|
122 close HIN;
|
|
123 finish($proc);
|
5
|
124
|
|
125 #xalan(
|
6
|
126 # in => \*OUT,
|
|
127 # out => \*STDOUT,
|
|
128 # params => [
|
|
129 #
|
|
130 # ]
|
5
|
131 #);
|
|
132
|
0
|
133 sub xalan {
|
5
|
134 my @params = @_;
|
1
|
135 return system 'java',
|
|
136 -cp => join( ':', @ClassPath ),
|
5
|
137 "org.apache.xalan.xslt.Process", @params;
|
|
138 }
|
|
139
|
|
140 package BzRest;
|
|
141 use fields qw(url apikey);
|
|
142 use LWP::UserAgent;
|
|
143 use XMLRPC::Lite;
|
|
144 use YAML::XS qw(Dump);
|
|
145
|
|
146 use constant { SELF => __PACKAGE__ };
|
|
147
|
|
148 sub new {
|
|
149 my $class = shift;
|
|
150 $class = ref $class || $class;
|
|
151
|
|
152 my $inst = fields::new($class);
|
|
153 $inst->CTOR(@_);
|
|
154
|
|
155 return $inst;
|
|
156 }
|
|
157
|
|
158 sub CTOR {
|
|
159 my SELF $this = shift;
|
|
160 my %params = @_;
|
|
161
|
|
162 $this->{url} = $params{url} or die "An url is required";
|
|
163 $this->{apikey} = $params{apikey} if $params{apikey};
|
|
164 }
|
|
165
|
|
166 sub GetBug {
|
|
167 my SELF $this = shift;
|
|
168 my $id = shift;
|
|
169 my %params = @_;
|
|
170
|
|
171 $params{api_key} = $this->{apikey};
|
|
172
|
|
173 my $bugurl = URI->new_abs( 'rest/bug/' . $id, $this->{url} );
|
|
174 $bugurl->query_form( \%params );
|
|
175
|
|
176 my $agent = LWP::UserAgent->new();
|
|
177 my $res = $agent->get($bugurl);
|
|
178
|
|
179 return $this->_AssertResponse( $res, $bugurl );
|
|
180 }
|
|
181
|
|
182 sub GetBugs {
|
|
183 my SELF $this = shift;
|
|
184
|
|
185 return $this->CallXMLRPC( 'Bug.get', shift )->{bugs};
|
|
186 }
|
|
187
|
|
188 sub CallXMLRPC {
|
|
189 my SELF $this = shift;
|
|
190 my ( $method, $params ) = @_;
|
|
191
|
|
192 die "Method must be specified" unless $method;
|
|
193 $params ||= {};
|
|
194
|
|
195 $params->{api_key} = $this->{apikey};
|
|
196 my $url = URI->new_abs( 'xmlrpc.cgi', $this->{url} );
|
|
197
|
|
198 my $result = XMLRPC::Lite->proxy($url)->call( $method, $params );
|
|
199
|
|
200 die $result->fault if $result->fault;
|
|
201 return $result->result;
|
|
202 }
|
|
203
|
|
204 sub _AssertResponse {
|
|
205 my SELF $this = shift;
|
|
206 my ( $res, $url ) = @_;
|
|
207
|
|
208 die "Failed to get any response: " . $url unless $res;
|
|
209
|
|
210 die "Failed to fetch: " . $url . ": " . $res->code unless $res->is_success;
|
|
211
|
|
212 my $bug = JSON->new()->utf8()->decode( $res->content );
|
|
213
|
|
214 die "Bugzilla failed: " . $bug->{message} if $bug->{error};
|
|
215
|
|
216 return $bug->{bugs};
|
0
|
217 }
|
|
218
|
|
219 __END__
|
|
220
|
|
221 =pod
|
|
222
|
|
223 =head1 NAME
|
|
224
|
|
225 C<translate.pl> - translates bugzilla xml buglist to TaskJuggler format
|
|
226
|
|
227 =head1 METHODS
|
|
228
|
|
229 =head2 xalan(%args)
|
|
230
|
|
231 =over
|
|
232
|
|
233 =item * -IN
|
|
234
|
|
235 Input file
|
|
236
|
|
237 =item * -OUT
|
|
238
|
|
239 Output file
|
|
240
|
|
241 =item * -XSL
|
|
242
|
|
243 XSLT file
|
|
244
|
|
245 =back
|
|
246
|
1
|
247 =cut
|