Skip to content

Commit 09d2847

Browse files
committed
add fetch command to populate database from API
This is useful for development instances to give them some real data for testing purposes. This does not yet download full reports. That should be completed before the ticket is considered done. Refs #20
1 parent 1c4035e commit 09d2847

File tree

4 files changed

+449
-1
lines changed

4 files changed

+449
-1
lines changed

bin/cpantesters-schema

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ our $VERSION = '0.024';
2020
# check what version our database is running
2121
cpantesters-schema check
2222
23+
# fetch data from the CPAN Testers API to populate our database
24+
cpantesters-schema fetch report --dist [email protected]
25+
2326
=head1 DESCRIPTION
2427
2528
This script works with L<DBIx::Class::Schema::Versioned> to prepare a new
@@ -54,7 +57,7 @@ L<DBIx::Class::Schema::Versioned>
5457
use v5.24;
5558
use warnings;
5659
use Pod::Usage;
57-
use Getopt::Long;
60+
use Getopt::Long qw( GetOptionsFromArray );
5861
use CPAN::Testers::Schema;
5962
use File::Share qw( dist_dir );
6063

@@ -108,3 +111,25 @@ sub upgrade {
108111
$schema->upgrade;
109112
}
110113

114+
sub fetch {
115+
my ( @args ) = @_;
116+
my $schema = CPAN::Testers::Schema->connect_from_config;
117+
GetOptionsFromArray( \my %opt, \@args,
118+
'dist|d=@s',
119+
);
120+
my @tables = @args;
121+
if ( !$opt{dist}->@* ) {
122+
die "Must specify one or more --dist options";
123+
}
124+
for my $dist_spec ( $opt{dist}->@* ) {
125+
my ( $dist, $version ) = split /\@/, $dist_spec;
126+
$schema->populate_from_api(
127+
{
128+
dist => $dist,
129+
version => $version,
130+
},
131+
@tables,
132+
);
133+
}
134+
}
135+

dist.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ Path::Tiny = 0.072 ; Fixes issues with File::Path
140140
SQL::Translator = 0.11018 ; Allows deploying the schema
141141
JSON::MaybeXS = 0
142142
Data::UUID = 0
143+
Mojolicious = 8
143144

144145
;-- Common prereqs with minimum version requirements
145146
;List::Util = 1.29 ; First version with pair* functions

lib/CPAN/Testers/Schema.pm

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ use File::Share qw( dist_dir );
3535
use Path::Tiny qw( path );
3636
use List::Util qw( uniq );
3737
use 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+
100243
1;

0 commit comments

Comments
 (0)