File Coverage

blib/lib/Badge/Depot/Plugin/Coverage.pm
Criterion Covered Total %
statement 56 74 75.6
branch 5 18 27.7
condition n/a
subroutine 17 17 100.0
pod 0 4 0.0
total 78 113 69.0


line stmt bran cond sub pod time code
1 1     1   103538 use 5.10.0;
  1         13  
2 1     1   6 use strict;
  1         2  
  1         20  
3 1     1   4 use warnings;
  1         11  
  1         37  
4 1     1   6 use feature qw/say/;
  1         2  
  1         182  
5              
6             package Badge::Depot::Plugin::Coverage;
7              
8 1     1   562 use Moose;
  1         476384  
  1         7  
9 1     1   8099 use namespace::autoclean;
  1         8332  
  1         4  
10 1     1   592 use MooseX::AttributeShortcuts;
  1         498136  
  1         4  
11 1     1   137673 use Types::Standard qw/Str Bool Num/;
  1         76187  
  1         11  
12 1     1   1599 use Types::URI qw/Uri/;
  1         103904  
  1         14  
13 1     1   938 use JSON::MaybeXS 'decode_json';
  1         4213  
  1         61  
14 1     1   8 use Path::Tiny;
  1         2  
  1         47  
15 1     1   888 use DateTime;
  1         451766  
  1         57  
16 1     1   612 use DateTime::Format::RFC3339;
  1         1282  
  1         670  
17             with 'Badge::Depot';
18              
19             # ABSTRACT: Code coverage plugin for Badge::Depot
20             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
21             our $VERSION = '0.0102';
22              
23             has coverage => (
24             is => 'ro',
25             isa => Num,
26             required => 0,
27             predicate => 1,
28             );
29             has custom_image_url => (
30             is => 'ro',
31             isa => Uri,
32             coerce => 1,
33             default => 'https://img.shields.io/badge/%s-%s-%s.svg',
34             );
35             has text => (
36             is => 'ro',
37             isa => Str,
38             default => 'coverage',
39             );
40             has max_age => (
41             is => 'ro',
42             isa => 'Int',
43             default => '60',
44             documentation => q{Include coverage badge if the latest cover run was done less than 'max_age' minutes ago},
45             );
46              
47              
48             sub BUILD {
49 2     2 0 4 my $self = shift;
50              
51 2         7 my $coverage = $self->determine_coverage;
52 2 100       11 if($coverage == -1) {
53 1         4 $self->log('! Could not determine coverage, skips Coverage badge');
54 1         41 return;
55             }
56              
57 1         15 $coverage = sprintf '%.1f', $coverage;
58 1         6 my $color = $self->determine_color($coverage);
59 1         38 $self->image_url(sprintf $self->custom_image_url, $self->text, $coverage.'%25', $color);
60 1         210 $self->image_alt(sprintf '%s %s', $self->text, $coverage.'%');
61 1         23 $self->log("Adds coverage badge ($coverage%)");
62             }
63              
64              
65             sub determine_coverage {
66 2     2 0 5 my $self = shift;
67 2 50       78 return $self->coverage if $self->has_coverage;
68              
69 0         0 my $log_file = path(qw/. .coverhistory.json/);
70              
71 0 0       0 if(!$log_file->exists) {
72 0         0 $self->log('! Could not find cover history file (.coverhistory.json), no coverage to add');
73 0         0 return -1;
74             }
75              
76 0         0 my $history = decode_json($log_file->slurp);
77              
78 0 0       0 if(!scalar @$history) {
79 0         0 $self->log('! No coverage history in .coverhistory.json, nothing to add');
80 0         0 return -1;
81             }
82              
83 0         0 my $summary = $history->[-1];
84 0         0 my $created_at = DateTime::Format::RFC3339->parse_datetime($summary->{'created_at'});
85 0         0 my $since = DateTime->now - $created_at;
86              
87 0         0 my $minutes = $since->years * 1440 * 365
88             + $since->months * 1440 * 30
89             + $since->days * 1440
90             + $since->hours * 60
91             + $since->minutes
92             + $since->seconds / 60;
93              
94 0 0       0 if($minutes > $self->max_age) {
95 0         0 $self->log("! Latest coverage was run @{[ sprintf '%.1f', $minutes ]} minutes ago, maximum allowed age is @{[ $self->max_age ]} minutes, wont add coverage");
  0         0  
  0         0  
96 0         0 return -1;
97             }
98 0         0 return $summary->{'total'};
99             }
100             sub determine_color {
101 1     1 0 3 my $self = shift;
102 1         2 my $coverage = shift;
103              
104 1 0       8 return $coverage < 75 ? 'red'
    0          
    50          
    50          
105             : $coverage < 90 ? 'orange'
106             : $coverage < 100 ? 'yellow'
107             : $coverage == 100 ? 'brightgreen'
108             : 'blue'
109             ;
110             }
111             sub log {
112 2     2 0 4 my $self = shift;
113 2         5 my $text = shift;
114              
115 2         148 say "[Badge/Coverage] $text";
116              
117             };
118              
119             __PACKAGE__->meta->make_immutable;
120              
121             1;
122              
123             __END__
124              
125             =pod
126              
127             =encoding UTF-8
128              
129             =head1 NAME
130              
131             Badge::Depot::Plugin::Coverage - Code coverage plugin for Badge::Depot
132              
133             =head1 VERSION
134              
135             Version 0.0102, released 2020-12-26.
136              
137             =head1 SYNOPSIS
138              
139             Used standalone:
140              
141             use Badge::Depot::Plugin::Coverage;
142              
143             my $badge = Badge::Depot::Plugin::Coverage->new(coverage => 87);
144              
145             print $badge->to_html;
146              
147             Used together with L<Pod::Weaver::Section::Badges>, in weaver.ini:
148              
149             [Badges]
150             ; other settings
151             badge = Coverage
152              
153             =head1 DESCRIPTION
154              
155             This L<Badge::Depot> badge is meant to be used together with L<Dist::Zilla::App::Command::coverh> (or standalone, as per the synopsis) and creates a coverage badge:
156              
157             =for HTML <p><img src="https://img.shields.io/badge/coverage-87%25-orange.svg" /></p>
158              
159             =for markdown ![Coverage 87%](https://img.shields.io/badge/coverage-87%25-orange.svg)
160              
161             =head1 ATTRIBUTES
162              
163             =head2 coverage
164              
165             Set the code coverage percentage manually. Should only be used when L<Dist::Zilla::App::Command::coverh> is B<not> used.
166              
167             =head2 custom_image_url
168              
169             Default: C<https://img.shields.io/badge/%s-%s-%s.svg>
170              
171             Override the default image url. It is expected to have three C<sprintf> placeholders: Text, coverage percentage and color.
172              
173             =head2 max_age
174              
175             Default: C<60>
176              
177             When used together with L<Dist::Zilla::App::Command::coverh>, only include the badge if the latest coverage run was less than C<max_age> minutes ago.
178              
179             =head2 text
180              
181             Default: C<coverage>
182              
183             Set a different coverage percentage. The percentage sign will be appended.
184              
185             =head1 SEE ALSO
186              
187             =over 4
188              
189             =item *
190              
191             L<Badge::Depot>
192              
193             =item *
194              
195             L<Task::Badge::Depot>
196              
197             =back
198              
199             =head1 SOURCE
200              
201             L<https://github.com/Csson/p5-Badge-Depot-Plugin-Coverage>
202              
203             =head1 HOMEPAGE
204              
205             L<https://metacpan.org/release/Badge-Depot-Plugin-Coverage>
206              
207             =head1 AUTHOR
208              
209             Erik Carlsson <info@code301.com>
210              
211             =head1 COPYRIGHT AND LICENSE
212              
213             This software is copyright (c) 2016 by Erik Carlsson.
214              
215             This is free software; you can redistribute it and/or modify it under
216             the same terms as the Perl 5 programming language system itself.
217              
218             =cut