@@ -35,6 +35,8 @@ use File::Share qw( dist_dir );
3535use Path::Tiny qw( path ) ;
3636use List::Util qw( uniq ) ;
3737use base ' DBIx::Class::Schema' ;
38+ use Mojo::UserAgent;
39+ use DateTime::Format::ISO8601;
3840
3941__PACKAGE__ -> load_namespaces;
4042__PACKAGE__ -> load_components(qw/ Schema::Versioned/ );
@@ -97,4 +99,145 @@ sub ordered_schema_versions( $self ) {
9799 return ' 0.000' , @versions ;
98100}
99101
102+ =method populate_from_api
103+
104+ $schema->populate_from_api( \%search, @tables );
105+
106+ Populate the given tables from the CPAN Testers API (L<http://api.cpantesters.org> ).
107+ C<%search > has the following keys:
108+
109+ =over
110+
111+ =item dist
112+
113+ A distribution to populate
114+
115+ =item version
116+
117+ A distribution version to populate
118+
119+ =item author
120+
121+ Populate an author's data
122+
123+ =back
124+
125+ The available C<@tables > are:
126+
127+ =over
128+
129+ =item * upload
130+
131+ =item * release
132+
133+ =item * summary
134+
135+ =item * report
136+
137+ =back
138+
139+ =cut
140+
141+ sub populate_from_api ( $self , $search , @tables ) {
142+ my $ua = $self -> {_ua } ||= Mojo::UserAgent-> new;
143+ my $base_url = $self -> {_url } ||= ' http://api.cpantesters.org/v3' ;
144+ my $dtf = DateTime::Format::ISO8601-> new();
145+
146+ # Establish dependencies
147+ my %tables = map {; $_ => 1 } @tables ;
148+ my @order = qw( upload summary release report ) ;
149+ # release depends on data in uploads and summary
150+ if ( $tables { release } ) {
151+ @tables {qw( upload summary ) } = ( 1, 1 );
152+ }
153+ # summary depends on data in uploads
154+ if ( $tables { summary } ) {
155+ @tables {qw( upload ) } = ( 1 );
156+ }
157+
158+ # ; use Data::Dumper;
159+ # ; say "Fetching tables: " . Dumper \%tables;
160+
161+ for my $table ( @order ) {
162+ next unless $tables { $table };
163+ my $url = $base_url ;
164+ if ( $table eq ' upload' ) {
165+ $url .= ' /upload' ;
166+ if ( $search -> {dist } ) {
167+ $url .= ' /dist/' . $search -> {dist };
168+ }
169+ elsif ( $search -> {author } ) {
170+ $url .= ' /author/' . $search -> {author };
171+ }
172+ my $tx = $ua -> get( $url );
173+ my @rows = map {
174+ $_ -> {released } = $dtf -> parse_datetime( $_ -> {released } )-> epoch;
175+ $_ -> {type } = ' cpan' ;
176+ $_ ;
177+ } $tx -> res-> json-> @*;
178+ $self -> resultset( ' Upload' )-> populate( \@rows );
179+ }
180+
181+ if ( $table eq ' summary' ) {
182+ $url .= ' /summary' ;
183+ if ( $search -> {dist } ) {
184+ $url .= ' /' . $search -> {dist };
185+ if ( $search -> {version } ) {
186+ $url .= ' /' . $search -> {version };
187+ }
188+ }
189+ my $tx = $ua -> get( $url );
190+ my @rows = map {
191+ my $dt = $dtf -> parse_datetime( delete $_ -> {date } );
192+ $_ -> {postdate } = $dt -> strftime( ' %Y%m' );
193+ $_ -> {fulldate } = $dt -> strftime( ' %Y%m%d%H%M' );
194+ $_ -> {state } = delete $_ -> {grade };
195+ $_ -> {type } = 2;
196+ $_ -> {tester } = delete $_ -> {reporter };
197+ $_ -> {uploadid } = $self -> resultset( ' Upload' )
198+ -> search({ $_ -> %{qw( dist version ) } })
199+ -> first-> id;
200+ $_ ;
201+ } $tx -> res-> json-> @*;
202+ # ; use Data::Dumper;
203+ # ; say "Populate summary: " . Dumper \@rows;
204+ $self -> resultset( ' Stats' )-> populate( \@rows );
205+ }
206+
207+ if ( $table eq ' release' ) {
208+ $url .= ' /release' ;
209+ if ( $search -> {dist } ) {
210+ $url .= ' /dist/' . $search -> {dist };
211+ if ( $search -> {version } ) {
212+ $url .= ' /' . $search -> {version };
213+ }
214+ }
215+ elsif ( $search -> {author } ) {
216+ $url .= ' /author/' . $search -> {author };
217+ }
218+ my $tx = $ua -> get( $url );
219+ my @rows = map {
220+ delete $_ -> {author }; # Author is from Upload
221+ my $stats_rs = $self -> resultset( ' Stats' )
222+ -> search({ $_ -> %{qw( dist version ) } });
223+ $_ -> {id } = $stats_rs -> get_column( ' id' )-> max;
224+ $_ -> {guid } = $stats_rs -> find( $_ -> {id } )-> guid;
225+ my $upload = $self -> resultset( ' Upload' )
226+ -> search({ $_ -> %{qw( dist version ) } })
227+ -> first;
228+ $_ -> {oncpan } = $upload -> type eq ' cpan' ;
229+ $_ -> {uploadid } = $upload -> id;
230+ # XXX These are just wrong
231+ $_ -> {distmat } = 1;
232+ $_ -> {perlmat } = 1;
233+ $_ -> {patched } = 1;
234+ $_ ;
235+ } $tx -> res-> json-> @*;
236+ # ; use Data::Dumper;
237+ # ; say "Populate release: " . Dumper \@rows;
238+ $self -> resultset( ' Release' )-> populate( \@rows );
239+ }
240+ }
241+ }
242+
1002431;
0 commit comments