Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 217 lines (172 sloc) 6.756 kb
fcc5114 @petdance first draft of rebuilt scraps
authored
1 #!/usr/local/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Carp::Always;
7
8 use 5.10.0;
9
10 use constant TICKET_MAX => 2500;
11 use constant BATCH_SIZE => 500;
12
13 use JSON;
14
15 use File::Slurp qw( write_file );
16 use LWP::Simple;
17
18 use lib '.';
19
20 use GH;
21
22 use Net::Trac;
23
24 exit main();
25
26 sub main {
27 my $trac = Net::Trac::Connection->new(
28 url => 'http://trac.parrot.org/parrot',
29 user => $ENV{TRAC_USER},
30 password => $ENV{TRAC_PASSWORD},
31 );
32
33 my @ids = 1..TICKET_MAX;
34
35 my $search = Net::Trac::TicketSearch->new( connection => $trac );
36
37 my $json = JSON->new->pretty->utf8;
38
39 mkdir( 'issues' );
40
41 unlink( glob( 'issues/*' ) );
42
43 my %unmatched_trac;
44 my %statuses;
45
46 while ( @ids ) {
47 my @id_batch = splice( @ids, 0, BATCH_SIZE );
48
49 $search->query(
50 id => [ @id_batch ],
51 status => { not => [ 'closed' ] },
52 );
53
54 say "Starting with ", $id_batch[0];
55 say "Here's one batch of ", scalar @{$search->results};
56 for my $ticket ( @{$search->results} ) {
57 my @labels;
58
59 if ( my $sev = $ticket->severity ) {
60 push( @labels, "Sev-$sev" );
61 }
62 if ( my $pri = $ticket->priority ) {
63 push( @labels, "Pri-$pri" );
64 }
65 if ( my $type = $ticket->type ) {
66 push( @labels, $type );
67 }
68 if ( my $component = $ticket->component ) {
69 $component = 'embed_extend' if $component =~ m{embed/extend}i;
70 push( @labels, $component ) unless $component eq 'none';
71 }
72
73 my $title = $ticket->summary;
74
75 my $body = $ticket->description;
76
77 # Replace Trac's literal format with Github's
78 $body =~ s/\{\{\{(.+?)\}\}\}/\r\n```$1```\r\n/smg;
79
80 my $trac_name = $ticket->reporter;
81 $trac_name =~ s/\@\x{2026}//;
82 my $gh_name = username_translate( $trac_name );
83
84 # Embed some trails
85 $body .= "\r\n\r\nOriginally http://trac.parrot.org/parrot/ticket/" . $ticket->id;
86 my $creator;
87 if ( $gh_name ) {
88 $creator = $gh_name;
89 }
90 else {
91 $body .= " by $trac_name";
92 $creator = { email => $trac_name };
93 ++$unmatched_trac{ $trac_name };
94 }
95
96 # Create basic ticket
97 my $created_at = $ticket->created; # DateTime object
98 $created_at = "$created_at"; # Force a stringify
99 my $issue = {
100 title => $title,
101 body => $body,
102 labels => [ @labels ],
103 creator => $creator,
104 created_at => $created_at,
105 };
106
107 my $tracid = $ticket->id;
108 my $ghid = next_ghid();
109
110 my $filename = "issues/$ghid.json";
111 write_file( $filename, $json->encode( $issue ) );
112
113 say $tracid, ' -> ', $filename, ' ', $title;
114
115 # http://developer.github.com/v3/issues/comments/
116 # http://search.cpan.org/dist/Net-Trac/lib/Net/Trac/TicketHistoryEntry.pm
117 # https://gist.github.com/7f75ced1fa7576412901
118
119 # Now do comments
120
121 my $history = Net::Trac::TicketHistory->new( connection => $trac );
122 $history->load( $ticket );
123
124 # Print the authors of all the changes to ticket #13
125 my @comments;
126 for my $entry ( @{ $history->entries } ) {
127 my $body = $entry->content;
128
129 $body =~ s/\bclass="ext-link"/ /g;
130 next if $body eq '';
131 next if $body eq 'Ticket created';
132
133 my $date = $entry->date; # DateTime object
134 $date = "$date"; # Force a stringify
135 my $author = $entry->author;
136 $author =~ s/\@\x{2026}//;
137
138 my $commenter;
139 my $gh_name = username_translate( $author );
140 if ( $gh_name ) {
141 $commenter = $gh_name;
142 }
143 else {
144 $body = "Trac commenter: $trac_name\r\n\r\n$body";
145 $commenter = { email => $author };
146 ++$unmatched_trac{ $author };
147 }
148
149 my $comment = {
150 created_at => $date,
151 user => $commenter,
152 body => $body,
153 };
154 push( @comments, $comment );
155 }
156
157 # Turn attachments into comments
158 my @attachments = $ticket->attachments;
159 for my $attachment ( @attachments ) {
160 my $size = $attachment->size;
161 my $author = $attachment->author;
162 $author =~ s/\@\x{2026}//;
163 my $gh_name = username_translate( $author );
164 my $date = $attachment->date;
165 $date = "$date"; # Force a stringify
166 my $body;
167 my $attacher;
168 if ( $gh_name ) {
169 $attacher = $gh_name;
170 $body = "$size byte attachment from $gh_name";
171 }
172 else {
173 $body = "$size byte attachment from $trac_name";
174 $attacher = { email => $author };
175 ++$unmatched_trac{ $author };
176 }
177 my $url = 'http://trac.parrot.org/parrot' . $attachment->url;
178 $body .= "\r\nat $url";
179 if ( $size < 80_000 ) {
180 my $content = get( $url );
181 die unless $content;
182 $body .= "\r\n\r\n```$content```";
183 say ' Encoded attachment of ', $size, ' bytes';
184 }
185 else {
186 $body .= "\r\nis too big for GitHub.";
187 say ' SKIPPED attachment of ', $size, ' bytes';
188 }
189 my $comment = {
190 created_at => $date,
191 user => $attacher,
192 body => $body,
193 };
194 push( @comments, $comment );
195 }
196
197 if ( my $ncomments = @comments ) {
198 @comments = sort { $a->{created_at} cmp $b->{created_at} } @comments;
199 my $filename = "issues/$ghid.comments.json";
200 say ' ', $ncomments, ' comments in ', $filename;
201 write_file( $filename, $json->encode( \@comments ) );
202 }
203 say '';
204 }
205 }
206
207 # {use Data::Show; show( \%unmatched_trac )}
208
209 return 0;
210 }
211
212 sub next_ghid {
213 state $id = 0;
214
215 return ++$id;
216 }
Something went wrong with that request. Please try again.