21 my @opt = <<'=back' =~ /B<--(\S+)>/g;
25 Defaults to 7. Is translated to
27 now() - interval 'N days'
33 =item B<--minpostdate=s>
35 Looks like an integer but stands for a month in the format YYYYMM.
36 Actual DB range is 199908 to, at the time of this writing, 202202.
37 Used to generate where clauses such as
39 ... where postdate >= $dbh->quote($Opt{minpostdate}) ...
43 B<Note: this should be changed to be a moving value similar to days> (once we are satisfied with the alpha version)
47 Provide relevant URLs and parts of URLs after each line
61 use lib
"$FindBin::Bin/../lib";
67 use File
::Basename
qw(dirname);
68 use File
::Path
qw(mkpath);
74 use Hash
::Util
qw(lock_keys);
75 use List
::AllUtils
qw(any);
78 lock_keys
%Opt, map { /([^=|!]+)/ } @opt;
85 $Opt{minpostdate
} = '202104';
89 use lib
"$FindBin::Bin/../CPAN-Blame/lib";
90 use CPAN
::Blame
::Config
::Cnntp
;
92 my $ann = "/home/andreas/src/analysis-cpantesters-annotate/annotate.txt"; # !!! needs config support
93 open my $fh, $ann or die "Could not open $ann: $!";
94 my(%Annotations,%HalfAnnotations);
96 my($d,$r) = /(\S+)\s+(.+)/;
97 $Annotations{$d} = $r;
98 $d =~ s/-v?[\d\._]+//;
99 $HalfAnnotations{$d} = $r;
104 use CPAN
::DistnameInfo
;
105 use List
::AllUtils
qw(reduce);
108 my $ua = LWP
::UserAgent
->new();
109 my $jsonxs = JSON
::XS
->new->indent(0);
113 my $pgdbh = DBI
->connect("dbi:Pg:dbname=analysis") or die "Could not connect to 'analysis': $DBI::err";
114 my $sth0 = $pgdbh->prepare("create temporary table x as (select dist, version, sum(case when state='pass' then cnt else 0 end) passes, sum(case when state='fail' then cnt else 0 end) fails from (select dist, version, state, count(*) cnt from cpanstats where postdate >= ? AND fulldate < now() - interval '$Opt{days} days' group by dist, version, state) x group by dist, version)");
115 my $sth0i = $pgdbh->prepare("CREATE INDEX xdv ON x (dist, version)");
116 my $sth1 = $pgdbh->prepare("select passes, fails from x where dist=? AND version=?");
117 my $sth2 = $pgdbh->prepare("select version, passes, fails from x where dist=? order by version");
118 my $sth3 = $pgdbh->prepare("select dist, version, state, fulldate, tester, perl, guid from cpanstats where (postdate >= ?) AND (fulldate > (now() - interval '$Opt{days} days')) order by fulldate"); # ignoring race between two values of now()
119 my $sth4 = $pgdbh->prepare("update x set passes=? where dist=? AND version=?");
120 my $sth5 = $pgdbh->prepare("update x set fails=? where dist=? AND version=?");
121 my $sth6 = $pgdbh->prepare("INSERT INTO x values (?,?,0,0)");
125 $sth0->execute($Opt{minpostdate
});
127 $sth3->execute($Opt{minpostdate
});
130 my $total = $sth3->rows;
132 ROW
: while (my($dist,$version,$state,$fulldate,$tester,$perl,$guid) = $sth3->fetchrow_array) {
134 $sth1->execute($dist, $version);
135 if ($sth1->rows == 0) {
136 $sth6->execute($dist, $version);
137 $sth1->execute($dist, $version);
139 my($passes, $fails) = $sth1->fetchrow_array;
140 if ($state eq 'pass') {
142 $sth4->execute($passes, $dist, $version);
144 } elsif ($state eq 'fail') {
146 $cand{$dist}{$version}=1;
149 $sth5->execute($fails, $dist, $version);
153 next ROW
unless $passes;
154 next ROW
unless $cand{$dist};
155 next ROW
unless any
{ $fails==$_ } 1, 2, 3;
156 my $short_tester = length($tester) < 40 ?
$tester : substr($tester,0,40);
157 $fulldate =~ s/:00\+00$//;
158 printf "%6d %-39s %-16s %-11s %5d %2d %s %s %s\n", $i, $dist, $version, $perl, $passes, $fails, $fulldate, $guid, $short_tester;
160 my $distv = sprintf "%s-%s", $dist, $version;
162 my %w = ( distv
=> $distv, version
=> $version ); # work from metacpanapiquery, maybe not needed
163 my $query = sprintf "http://fastapi.metacpan.org/v1/release/_search?q=distribution:%s&fields=name,date,status,version,author,archive&size=400&_source=tests", $dist;
164 my $resp = $ua->get($query);
165 unless ($resp->is_success) {
166 warn sprintf "No success visiting '%s': %s; sleeping %.3f\n",
171 my $jsontxt = $resp->decoded_content;
172 my $j = eval { $jsonxs->decode($jsontxt); };
174 my $err = $@
|| "unknown error";
175 die "Error while decoding '$jsontxt': $err";
177 my $hits = $j->{hits
}{hits
};
178 my($matchingrelease) = grep { $_->{fields
}{name
} eq $distv } @
$hits;
179 unless ($matchingrelease) {
180 warn "Did not find release for $distv\n";
183 my($releasedate) = $matchingrelease->{fields
}{date
};
184 my($archive) = $matchingrelease->{fields
}{archive
};
185 print " releasedate: $releasedate\n";
186 my($author) = $matchingrelease->{fields
}{author
};
187 print "$author/$archive\n";
189 # warn "x $matchingrelease";
190 my $report_url = sprintf "http://www.cpantesters.org/cpan/report/$guid";
191 print "$report_url\n";
195 my $displayallcands = 0;
196 if ($displayallcands) {
197 DIST
: for my $dist (sort keys %cand) {
198 printf "%4d %s\n", ++$i, $dist;
199 $sth2->execute($dist);
201 VERSION
: while (my($version, $passes, $fails) = $sth2->fetchrow_array) {
202 next VERSION
unless $cand{$dist}{$version};
203 my $anno_comment = "";
204 if (my $anno = $Annotations{sprintf "%s-%s", $dist, $version}) {
205 $anno_comment = " anno: $anno";
207 elsif (my $half_anno = $HalfAnnotations{$dist}) {
208 $anno_comment .= " hanno: $half_anno";
210 printf " %4d %-20s %8d %8d%s\n", ++$j, $version, $passes, $fails, $anno_comment;
214 $pgdbh->do("DROP TABLE x");
219 # cperl-indent-level: 4