use strict;
use warnings;
use MetaCPAN::API;
use Text::Diff;
use XML::Feed;
use DateTime::Format::ISO8601;
use DateTime;
use HTML::Escape 'escape_html';
my $api = MetaCPAN::API->new();
sub get_recent_releases {
my $now = DateTime->now;
my $yesterday = $now->clone->subtract(hours=>3);
my $recent = $api->post(
'release/_search',
{
size => 500,
from => 0,
query => {
range => { date => {
from => $yesterday->iso8601,
include_lower => 1,
} },
},
sort => [ { 'date' => { order => "desc" } } ],
fields => [qw(distribution name date author abstract)],
},
);
$recent=$recent->{hits}{hits};
return $recent;
}
sub get_changelog_diff {
my ($release) = @_;
my $dist_name = $release->{distribution};
my $release_name = $release->{name};
my $release_author = $release->{author};
my $release_date = $release->{date};
my $prev_release = $api->post(
'release/_search',
{
size => 1,
from => 0,
query => {
filtered => {
query => {
range => { date => {
to => $release_date,
include_upper => 0,
} },
},
filter => {
and => [ {
term => {
'release.distribution' => $dist_name,
},
} ]
}
}
},
sort => [ { date => 'desc' } ],
fields => [qw(name author)],
},
);
($prev_release)=@{$prev_release->{hits}{hits}};
return if !$prev_release;
my $prev_release_name = $prev_release->{fields}{name};
my $prev_release_author = $prev_release->{fields}{author};
my $files = $api->post(
'file/_search',
{
size => 30,
query => {
filtered => {
query => { match_all => {} },
filter => {
and => [
{ term => { level => 0 } },
{ term => { release => $release_name } },
{
or => [
{ prefix => { name => 'Change' } },
{ prefix => { name => 'change' } },
{ prefix => { name => 'CHANGE' } },
],
},
],
},
},
},
fields => [qw(name)],
}
);
my ($changelog_name) = grep {
/^change(s|log)$/i
} map { $_->{fields}{name} } @{$files->{hits}{hits}};
return unless $changelog_name;
my $this_changelog = $api->ua->get(
join '/',$api->base_url,'source',
$release_author,$release_name,$changelog_name
)->{content};
my $prev_changelog = $api->ua->get(
join '/',$api->base_url,'source',
$prev_release_author,$prev_release_name,$changelog_name
)->{content};
my $diff = diff \$prev_changelog,\$this_changelog;
return $diff;
}
sub build_feed {
my $feed = XML::Feed->new('Atom');
$feed->title('Recent CPAN uploads with Changelog diff');
$feed->link('http://metacpan.org');
return $feed;
}
sub build_entry {
my ($release,$diff) = @_;
my $e = XML::Feed::Entry->new('RSS');
$e->title( $release->{name} );
$e->link(
join( '/',
'http://metacpan.org', 'release',
$release->{author}, $release->{name} )
);
$e->author( $release->{author} );
$e->issued( DateTime::Format::ISO8601->parse_datetime( $release->{date} ) );
$e->content( sprintf '<p>%s</p><pre>%s</pre>',
escape_html($release->{abstract}),
escape_html($diff//'') );
return $e;
}
my $recent = get_recent_releases();
my $feed = build_feed();
for my $rel (@{$recent}) {
my $release = $rel->{fields};
my $diff = get_changelog_diff($release);
$feed->add_entry(build_entry($release,$diff));
}
print $feed->as_xml;