App-GHGen
view release on metacpan or search on metacpan
scripts/generate_index.pl view on Meta::CPAN
.badge-good { background-color: #4CAF50; }
.badge-warn { background-color: #FFC107; }
.badge-bad { background-color: #F44336; }
.summary-row {
font-weight: bold;
background-color: #f0f0f0;
}
td.positive { color: green; font-weight: bold; }
td.negative { color: red; font-weight: bold; }
td.neutral { color: gray; }
/* Show cursor points on the headers to show that they are clickable */
th { background-color: #f2f2f2; cursor: pointer; }
th.sortable {
cursor: pointer;
user-select: none;
white-space: nowrap;
}
th .arrow {
color: #aaa; /* dimmed for inactive */
font-weight: normal;
}
th .arrow.active {
color: #000; /* dark for active */
font-weight: bold;
}
.sparkline {
display: inline-block;
vertical-align: middle;
}
tr.cpan-fail td {
background-color: #fdd;
}
tr.cpan-unknown td {
background-color: #eee;
color: #666;
}
tr.cpan-na td {
background-color: #ffffde;
color: #666;
}
.new-failure {
background: #c00;
color: #fff;
font-weight: bold;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.85em;
}
.notice {
padding: 8px 12px;
margin: 10px 0;
border-radius: 4px;
font-size: 0.95em;
}
.notice strong {
font-weight: bold;
}
.notice.perl-version-cliff {
background-color: #fff3cd; /* soft amber */
border: 1px solid #ffeeba;
color: #856404;
}
.notice.perl-version-cliff a {
color: #533f03;
text-decoration: underline;
}
.notice.perl-version-cliff a:hover {
text-decoration: none;
}
.notice.locale-cliff {
border-left: 4px solid #d97706;
background: #fffbeb;
padding: 0.5em 1em;
}
.notice.rt-issues {
background: #fff6e5;
border-left: 4px solid #d9822b;
}
table.root-causes {
border-collapse: collapse;
width: 100%;
margin-bottom: 1.5em;
}
table.root-causes th,
table.root-causes td {
border: 1px solid #ccc;
padding: 8px;
vertical-align: top;
}
table.root-causes tr.high {
background-color: #dfd;
}
table.root-causes tr.med {
background-color: #ffd;
}
table.root-causes tr.low {
background-color: #fdd;
}
</style>
</head>
<body>
<div class="badges">
<a href="https://github.com/$config{github_user}/$config{github_repo}">
<img src="https://img.shields.io/github/stars/$config{github_user}/$config{github_repo}?style=social" alt="GitHub stars">
</a>
<img src="$coverage_badge_url" alt="Coverage badge">
</div>
<h1>$config{package_name}</h1><h2>Coverage Report</h2>
<table data-sort-col="0" data-sort-order="asc">
<!-- Make the column headers clickable -->
<thead>
<tr>
<th class="sortable" onclick="sortTable(this, 0)"><span class="label">File</span> <span class="arrow active">▲</span></th>
<th class="sortable" onclick="sortTable(this, 1)"><span class="label">Stmt</span> <span class="arrow">▲</span></th>
<th class="sortable" onclick="sortTable(this, 2)"><span class="label">Branch</span> <span class="arrow">▲</span></th>
<th class="sortable" onclick="sortTable(this, 3)"><span class="label">Cond</span> <span class="arrow">▲</span></th>
<th class="sortable" onclick="sortTable(this, 4)"><span class="label">Sub</span> <span class="arrow">▲</span></th>
<th class="sortable" onclick="sortTable(this, 5)"><span class="label">Total</span> <span class="arrow">▲</span></th>
<th class="sortable" onclick="sortTable(this, 6)"><span class="label">Δ</span> <span class="arrow">▲</span></th>
</tr>
</thead>
scripts/generate_index.pl view on Meta::CPAN
<th>Report</th>
</tr>
</thead>
<tbody>
HTML
my %best;
for my $r (@fail_reports) {
my $key = make_key($r);
if(!exists $best{$key} || (!$best{$key}{guid} && $r->{guid})) {
$best{$key} = $r;
}
}
my @deduped = values %best;
my %prev_fail_set;
for my $r (@prev_fail_reports) {
my $key = make_key($r);
$prev_fail_set{$key} = 1;
}
for my $r (@deduped) {
my $date = $r->{date} // '';
my $perl = $r->{perl} // '';
my $os = $r->{osname} // '';
my $grade = lc($r->{grade} // 'unknown');
my $row_class = "cpan-$grade"; # cpan-fail or cpan-unknown
my $reporter = $r->{reporter} // '';
$reporter =~ s/"//g;
$reporter =~ s/<.+>//g;
$reporter =~ s/\s+$//g;
my $guid = $r->{guid} // '';
my $url = $guid ? "https://www.cpantesters.org/cpan/report/$guid" : '#';
my $is_new = !$prev_fail_set{make_key($r)};
my $new_html = $is_new ? '<span class="new-failure">NEW</span>' : '';
push @html, sprintf(
qq{<tr class="%s"><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td>
<td><a href="%s" target="_blank">View</a></td></tr>},
$row_class,
$date,
$os,
$perl,
$reporter,
$new_html,
$url
);
}
push @html, '</tbody></table>';
} else {
# @fail_reports is empty
push @html, "<p>No <A HREF=\"https://fast2-matrix.cpantesters.org/?dist=$dist_name+$version\">CPAN Testers</A> failures reported for $dist_name $version</p>";
}
} elsif($res->{status} == 404) { # 404 means no fail reports
# push @html, "<A HREF=\"$cpan_api\">$cpan_api</A>";
push @html, "<p>No CPAN Testers failures reported for $dist_name $version.</p>";
} else {
push @html, "<a href=\"$cpan_api\">$cpan_api</a>: $res->{status} $res->{reason}";
}
my $timestamp = 'Unknown';
if (my $stat = stat($config{cover_db})) {
$timestamp = strftime('%Y-%m-%d %H:%M:%S', localtime($stat->mtime));
}
push @html, <<"HTML";
<footer>
<p>Project: <a href="https://github.com/$config{github_user}/$config{github_repo}">$config{github_repo}</a></p>
<p><em>Last updated: $timestamp - <a href="$commit_url">commit <code>$short_sha</code></a></em></p>
</footer>
</body>
</html>
HTML
# Write to index.html
write_file($config{output}, join("\n", @html));
# Safe git command execution
sub run_git {
my @cmd = @_;
my ($out, $err);
run3 ['git', @cmd], \undef, \$out, \$err;
return unless $? == 0;
chomp $out;
return $out;
}
sub js_escape {
my $str = $_[0];
$str =~ s/\\/\\\\/g;
$str =~ s/"/\\"/g;
$str =~ s/\n/\\n/g;
return $str;
}
sub fetch_reports_by_grades {
my ($dist, $version, @grades) = @_;
my %seen;
my @reports;
for my $grade (@grades) {
my $url = 'https://api.cpantesters.org/v3/summary/'
. uri_escape($dist)
. '/' . uri_escape($version)
. "?grade=$grade";
my $res = $http->get($url);
next unless $res->{success};
my $arr = eval { decode_json($res->{content}) };
next unless ref $arr eq 'ARRAY';
( run in 1.298 second using v1.01-cache-2.11-cpan-39bf76dae61 )