Skip to content

Commit bf9e0f8

Browse files
committed
Added script which fetches and indexes river data
closes #460
1 parent e6043f7 commit bf9e0f8

File tree

4 files changed

+173
-1
lines changed

4 files changed

+173
-1
lines changed

lib/MetaCPAN/Document/Distribution.pm

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use namespace::autoclean;
77
use Moose;
88
use ElasticSearchX::Model::Document;
99

10-
use MetaCPAN::Types qw( ArrayRef BugSummary );
10+
use MetaCPAN::Types qw( ArrayRef BugSummary RiverSummary);
1111

1212
has name => (
1313
is => 'ro',
@@ -22,6 +22,13 @@ has bugs => (
2222
writer => '_set_bugs',
2323
);
2424

25+
has river => (
26+
is => 'ro',
27+
isa => RiverSummary,
28+
dynamic => 1,
29+
writer => '_set_river',
30+
);
31+
2532
sub releases {
2633
my $self = shift;
2734
return $self->index->type("release")

lib/MetaCPAN/Script/River.pm

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package MetaCPAN::Script::River;
2+
3+
use strict;
4+
use warnings;
5+
use namespace::autoclean;
6+
7+
use HTTP::Request::Common;
8+
use LWP::UserAgent;
9+
use Log::Contextual qw( :log :dlog );
10+
use Moose;
11+
use URI::Escape qw(uri_escape);
12+
use MetaCPAN::Types qw( ArrayRef Str );
13+
use JSON::MaybeXS qw( decode_json );
14+
15+
with 'MetaCPAN::Role::Script', 'MooseX::Getopt';
16+
17+
has river_url => (
18+
is => 'ro',
19+
required => 1,
20+
default => 'https://neilb.org/FIXME',
21+
);
22+
23+
has ua => (
24+
is => 'ro',
25+
default => sub { LWP::UserAgent->new },
26+
);
27+
28+
sub run {
29+
my $self = shift;
30+
my $summaries = $self->retrieve_river_summaries;
31+
$self->index_river_summaries($summaries);
32+
33+
return 1;
34+
}
35+
36+
sub index_river_summaries {
37+
my ( $self, $summaries ) = @_;
38+
$self->index->refresh;
39+
my $dists = $self->index->type('distribution');
40+
my $bulk = $self->index->bulk( size => 300 );
41+
for my $summary (@$summaries) {
42+
my $dist = delete $summary->{dist};
43+
my $doc = $dists->get($dist);
44+
$doc ||= $dists->new_document( { name => $dist } );
45+
$doc->_set_river($summary);
46+
$bulk->put($doc);
47+
}
48+
$bulk->commit;
49+
}
50+
51+
sub retrieve_river_summaries {
52+
my $self = shift;
53+
my $resp = $self->ua->request( GET $self->river_url );
54+
55+
$self->handle_error( $resp->status_line ) unless $resp->is_success;
56+
57+
return decode_json $resp->content;
58+
}
59+
60+
__PACKAGE__->meta->make_immutable;
61+
62+
1;
63+
64+
=pod
65+
66+
=head1 SYNOPSIS
67+
68+
# bin/metacpan river
69+
70+
=head1 DESCRIPTION
71+
72+
Retrieves the CPAN river data from its source and
73+
updates our ES information.
74+
75+
This can then be accessed here:
76+
77+
http://api.metacpan.org/distribution/Moose
78+
http://api.metacpan.org/distribution/HTTP-BrowserDetect
79+
80+
=cut
81+

lib/MetaCPAN/Types/Internal.pm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use MooseX::Types -declare => [
2727
PerlMongers
2828
Tests
2929
BugSummary
30+
RiverSummary
3031
)
3132
];
3233

@@ -105,6 +106,9 @@ subtype BugSummary,
105106
source => Str
106107
];
107108

109+
subtype RiverSummary,
110+
as Dict [ ( map { $_ => Optional [Int] } qw(total immediate bucket) ), ];
111+
108112
subtype Resources,
109113
as Dict [
110114
license => Optional [ ArrayRef [Str] ],

t/script/river.t

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use strict;
2+
use warnings;
3+
4+
use lib 't/lib';
5+
6+
use MetaCPAN::Script::River;
7+
use MetaCPAN::Script::Runner;
8+
use MetaCPAN::Server::Test;
9+
use MetaCPAN::TestHelpers;
10+
use Test::More;
11+
12+
my $config = MetaCPAN::Script::Runner::build_config;
13+
14+
#local @ARGV = ( '--dir', $config->{cpan} );
15+
16+
my $river = MetaCPAN::Script::River->new_with_options($config);
17+
18+
# structure from https://github.com/CPAN-API/cpan-api/issues/460
19+
my @summaries = (
20+
{
21+
dist => 'System-Command',
22+
total => 92,
23+
immediate => 4,
24+
bucket => 2,
25+
},
26+
{
27+
dist => 'Text-Markdown',
28+
total => 92,
29+
immediate => 56,
30+
bucket => 2,
31+
}
32+
);
33+
my %expect = (
34+
'System-Command' => {
35+
total => 92,
36+
immediate => 4,
37+
bucket => 2,
38+
},
39+
'Text-Markdown' => {
40+
total => 92,
41+
immediate => 56,
42+
bucket => 2,
43+
}
44+
);
45+
46+
# mock external service
47+
{
48+
no warnings 'redefine';
49+
*MetaCPAN::Script::River::retrieve_river_summaries = sub {
50+
return \@summaries;
51+
};
52+
}
53+
54+
ok $river->run, 'runs and returns true';
55+
56+
test_psgi app, sub {
57+
my $cb = shift;
58+
for my $dist ( keys %expect ) {
59+
my $test = $expect{$dist};
60+
subtest "Check $dist" => sub {
61+
my $url = "/distribution/$dist";
62+
ok( my $res = $cb->( GET $url), "GET $url" );
63+
64+
# TRAVIS 5.18
65+
is( $res->code, 200, "code 200" );
66+
is(
67+
$res->header('content-type'),
68+
'application/json; charset=utf-8',
69+
'Content-type'
70+
);
71+
my $json = decode_json_ok($res);
72+
73+
# TRAVIS 5.18
74+
is_deeply( $json->{river}, $test,
75+
"$dist river summary roundtrip" );
76+
};
77+
}
78+
};
79+
80+
done_testing();

0 commit comments

Comments
 (0)