├── t ├── data │ ├── libexec │ │ ├── hg.bat │ │ ├── git.bat │ │ ├── git │ │ └── hg │ ├── git.tar.bz2 │ ├── hg.tar.bz2 │ ├── sample.pl │ ├── proj │ │ ├── lib │ │ │ └── Example │ │ │ │ ├── Add.pm │ │ │ │ └── Div.pm │ │ └── t │ │ │ ├── 00_compile.t │ │ │ ├── 10_add.t │ │ │ ├── 10_div.t │ │ │ └── Util.pm │ └── proj_blib │ │ ├── lib │ │ └── Example │ │ │ ├── Add.pm │ │ │ └── Div.pm │ │ ├── blib │ │ └── lib │ │ │ └── Example │ │ │ ├── Add.pm │ │ │ └── Div.pm │ │ └── t │ │ ├── 00_compile.t │ │ ├── 10_add.t │ │ ├── Util.pm │ │ └── 10_div.t ├── codecov │ ├── 000_compile.t │ ├── service │ │ ├── git │ │ │ ├── fallback.t │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ ├── mercurial │ │ │ ├── fallback.t │ │ │ ├── configuration.t │ │ │ └── detect.t │ │ ├── drone │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ ├── gitlab │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ ├── bitrise │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ ├── travis │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ ├── semaphore │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ ├── appveyor │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ ├── shippable │ │ │ ├── detect.t │ │ │ └── configuration.t │ │ └── wercker │ │ │ ├── detect.t │ │ │ └── configuration.t │ ├── get_file_lines.t │ ├── get_request_url.t │ ├── get_file_realpath.t │ ├── get_query.t │ ├── get_codecov_json.t │ ├── get_services.t │ ├── get_line_coverage.t │ ├── send_report_once.t │ ├── get_file_coverage.t │ ├── report.t │ └── send_report.t └── Util.pm ├── .proverc ├── .gitignore ├── .envrc ├── minil.toml ├── xt ├── codecov │ └── 000_lint.t └── perlcriticrc ├── Build.PL ├── lib └── Devel │ └── Cover │ └── Report │ ├── Codecov │ └── Service │ │ ├── Codeship.pm │ │ ├── Drone.pm │ │ ├── Semaphore.pm │ │ ├── Shippable.pm │ │ ├── AppVeyor.pm │ │ ├── Wercker.pm │ │ ├── GitLab.pm │ │ ├── Travis.pm │ │ ├── Mercurial.pm │ │ ├── Bitrise.pm │ │ ├── Git.pm │ │ └── Circle.pm │ └── Codecov.pm ├── script └── dev │ └── create-perlcriticrc.pl ├── appveyor.yml ├── LICENSE ├── cpanfile ├── .travis.yml ├── Changes ├── README.md └── META.json /t/data/libexec/hg.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | perl "%~dp0\hg" %* 4 | -------------------------------------------------------------------------------- /.proverc: -------------------------------------------------------------------------------- 1 | --lib 2 | --timer 3 | --color 4 | --failures 5 | --trap 6 | -------------------------------------------------------------------------------- /t/data/libexec/git.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | perl "%~dp0\git" %* 4 | -------------------------------------------------------------------------------- /t/data/git.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codecov/codecov-perl/HEAD/t/data/git.tar.bz2 -------------------------------------------------------------------------------- /t/data/hg.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codecov/codecov-perl/HEAD/t/data/hg.tar.bz2 -------------------------------------------------------------------------------- /t/data/sample.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | use utf8; 6 | use feature qw/say/; 7 | 8 | say 'Hello World!'; 9 | 10 | __END__ 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | *.swo 4 | 5 | /local/ 6 | cpanfile.snapshot 7 | 8 | cover_db/ 9 | 10 | /Devel-Cover-Report-Codecov-* 11 | 12 | # for Test::Requires::Git 13 | .test.requires.git.lock 14 | -------------------------------------------------------------------------------- /t/data/proj/lib/Example/Add.pm: -------------------------------------------------------------------------------- 1 | package Example::Add; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub add { 7 | my ($class, $lhs, $rhs) = @_; 8 | return $lhs + $rhs; 9 | } 10 | 11 | 1; 12 | -------------------------------------------------------------------------------- /t/data/proj/t/00_compile.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | 8 | use_ok $_ for qw( 9 | Example::Add 10 | Example::Div 11 | ); 12 | 13 | done_testing; 14 | -------------------------------------------------------------------------------- /t/data/proj_blib/lib/Example/Add.pm: -------------------------------------------------------------------------------- 1 | package Example::Add; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub add { 7 | my ($class, $lhs, $rhs) = @_; 8 | return $lhs + $rhs; 9 | } 10 | 11 | 1; 12 | -------------------------------------------------------------------------------- /t/data/proj_blib/blib/lib/Example/Add.pm: -------------------------------------------------------------------------------- 1 | package Example::Add; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub add { 7 | my ($class, $lhs, $rhs) = @_; 8 | return $lhs + $rhs; 9 | } 10 | 11 | 1; 12 | -------------------------------------------------------------------------------- /t/data/proj_blib/t/00_compile.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | 8 | use_ok $_ for qw( 9 | Example::Add 10 | Example::Div 11 | ); 12 | 13 | done_testing; 14 | -------------------------------------------------------------------------------- /t/codecov/000_compile.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Module::Find; 6 | 7 | use lib '.'; 8 | use t::Util; 9 | 10 | use_ok $_ for findallmod 'Devel::Cover::Report::Codecov'; 11 | 12 | done_testing; 13 | 14 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NEW_PATH=`carton exec -- sh -c 'echo $PATH'` 4 | if [ $? -ne 0 ]; then exit 1; fi 5 | 6 | NEW_PERL5LIB=`carton exec -- sh -c 'echo $PERL5LIB'` 7 | if [ $? -ne 0 ]; then exit 1; fi 8 | 9 | export PATH=$NEW_PATH 10 | export PERL5LIB=$NEW_PERL5LIB 11 | -------------------------------------------------------------------------------- /t/data/proj/t/10_add.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Example::Add; 8 | 9 | subtest add => sub { 10 | can_ok 'Example::Add', qw/add/; 11 | is( Example::Add->add(3, 5), 8 ); 12 | }; 13 | 14 | done_testing; 15 | -------------------------------------------------------------------------------- /t/data/proj_blib/t/10_add.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Example::Add; 8 | 9 | subtest add => sub { 10 | can_ok 'Example::Add', qw/add/; 11 | is( Example::Add->add(3, 5), 8 ); 12 | }; 13 | 14 | done_testing; 15 | -------------------------------------------------------------------------------- /minil.toml: -------------------------------------------------------------------------------- 1 | authority = "cpan:PINE" 2 | authors = ["Pine Mizune"] 3 | badges = ["travis"] 4 | license = "mit" 5 | markdown_maker = "Pod::Markdown::Github" 6 | module_maker = "ModuleBuildTiny" 7 | name = "Devel-Cover-Report-Codecov" 8 | 9 | 10 | [ReleaseTest] 11 | MinimumVersion = false 12 | -------------------------------------------------------------------------------- /t/data/libexec/git: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | sub main { 4 | my $branch = grep { $_ =~ /abbrev-ref/ } @ARGV; 5 | 6 | print $branch ? 'master' : '3713ace1c825f6626e439e3cb72e2ce37f0cd63e'; 7 | print "\n"; 8 | } 9 | 10 | main unless caller; 11 | 12 | # vim: se et ts=4 sw=4 sts=4 ft=perl : 13 | -------------------------------------------------------------------------------- /t/data/libexec/hg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | sub main { 4 | my $branch = grep { $_ =~ /branch/ } @ARGV; 5 | 6 | print $branch ? 'default' : 'a42207909e7bdfc81dde25f307e9076ba71e04bf'; 7 | print "\n"; 8 | } 9 | 10 | main unless caller; 11 | 12 | # vim: se et ts=4 sw=4 sts=4 ft=perl : 13 | -------------------------------------------------------------------------------- /xt/codecov/000_lint.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | 8 | eval { 9 | require Test::Perl::Critic; 10 | Test::Perl::Critic->import( -profile => 'xt/perlcriticrc', -severity => 1 ); 11 | }; 12 | 13 | all_critic_ok('lib', 't'); 14 | -------------------------------------------------------------------------------- /t/data/proj/t/10_div.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Example::Div; 8 | 9 | subtest div => sub { 10 | can_ok 'Example::Div', qw/div/; 11 | is( Example::Div->div(9, 3), 3); 12 | is( Example::Div->div(10, 3), 3); 13 | }; 14 | 15 | done_testing; 16 | -------------------------------------------------------------------------------- /t/data/proj_blib/t/Util.pm: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use Exporter 'import'; 6 | 7 | use Test::More; 8 | use Test::Deep; 9 | use Test::Exception; 10 | 11 | our @EXPORT = ( 12 | @Test::More::EXPORT, 13 | @Test::Deep::EXPORT, 14 | @Test::Exception::EXPORT, 15 | ); 16 | 17 | 1; 18 | -------------------------------------------------------------------------------- /t/codecov/service/git/fallback.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Git; 8 | 9 | 10 | subtest basic => sub { 11 | ok( Devel::Cover::Report::Codecov::Service::Git->fallback ); 12 | }; 13 | 14 | done_testing; 15 | -------------------------------------------------------------------------------- /t/data/proj_blib/t/10_div.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Example::Div; 8 | 9 | subtest div => sub { 10 | can_ok 'Example::Div', qw/div/; 11 | is( Example::Div->div(9, 3), 3); 12 | is( Example::Div->div(10, 3), 3); 13 | }; 14 | 15 | done_testing; 16 | -------------------------------------------------------------------------------- /t/data/proj/lib/Example/Div.pm: -------------------------------------------------------------------------------- 1 | package Example::Div; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub div { 7 | my ($class, $lhs, $rhs) = @_; 8 | 9 | if ($rhs == 0) { 10 | return; 11 | } 12 | 13 | return do { 14 | use integer; 15 | return $lhs / $rhs; 16 | }; 17 | } 18 | 19 | 1; 20 | -------------------------------------------------------------------------------- /t/data/proj/t/Util.pm: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib qw(lib); 6 | 7 | use Exporter 'import'; 8 | 9 | use Test::More; 10 | use Test::Deep; 11 | use Test::Exception; 12 | 13 | our @EXPORT = ( 14 | @Test::More::EXPORT, 15 | @Test::Deep::EXPORT, 16 | @Test::Exception::EXPORT, 17 | ); 18 | 19 | 1; 20 | -------------------------------------------------------------------------------- /t/codecov/service/mercurial/fallback.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Mercurial; 8 | 9 | 10 | subtest basic => sub { 11 | ok( Devel::Cover::Report::Codecov::Service::Mercurial->fallback ); 12 | }; 13 | 14 | done_testing; 15 | -------------------------------------------------------------------------------- /t/data/proj_blib/lib/Example/Div.pm: -------------------------------------------------------------------------------- 1 | package Example::Div; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub div { 7 | my ($class, $lhs, $rhs) = @_; 8 | 9 | if ($rhs == 0) { 10 | return; 11 | } 12 | 13 | return do { 14 | use integer; 15 | return $lhs / $rhs; 16 | }; 17 | } 18 | 19 | 1; 20 | -------------------------------------------------------------------------------- /t/data/proj_blib/blib/lib/Example/Div.pm: -------------------------------------------------------------------------------- 1 | package Example::Div; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub div { 7 | my ($class, $lhs, $rhs) = @_; 8 | 9 | if ($rhs == 0) { 10 | return; 11 | } 12 | 13 | return do { 14 | use integer; 15 | return $lhs / $rhs; 16 | }; 17 | } 18 | 19 | 1; 20 | -------------------------------------------------------------------------------- /Build.PL: -------------------------------------------------------------------------------- 1 | # ========================================================================= 2 | # THIS FILE IS AUTOMATICALLY GENERATED BY MINILLA. 3 | # DO NOT EDIT DIRECTLY. 4 | # ========================================================================= 5 | 6 | use 5.008_001; 7 | use strict; 8 | 9 | use Module::Build::Tiny 0.035; 10 | 11 | Build_PL(); 12 | 13 | -------------------------------------------------------------------------------- /t/codecov/get_file_lines.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov; 8 | 9 | sub get_file_lines { 10 | Devel::Cover::Report::Codecov::get_file_lines(@_); 11 | } 12 | 13 | subtest basic => sub { 14 | is get_file_lines('t/data/sample.pl'), 10; 15 | }; 16 | 17 | done_testing; 18 | -------------------------------------------------------------------------------- /t/codecov/get_request_url.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Test::MockObject; 6 | 7 | use lib '.'; 8 | use t::Util; 9 | use Devel::Cover::Report::Codecov; 10 | 11 | sub get_request_url { 12 | Devel::Cover::Report::Codecov::get_request_url(@_); 13 | } 14 | 15 | subtest basic => sub { 16 | is 17 | get_request_url('http://example.com/path', { key => 'value' }), 18 | 'http://example.com/path?key=value'; 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /t/codecov/service/drone/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Drone; 8 | 9 | sub drone { 'Devel::Cover::Report::Codecov::Service::Drone' } 10 | 11 | subtest 'if drone' => sub { 12 | local $ENV{DRONE} = 'true'; 13 | ok( drone->detect ); 14 | }; 15 | 16 | subtest 'if not drone' => sub { 17 | local %ENV; 18 | ok( not drone->detect ); 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /t/codecov/service/gitlab/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::GitLab; 8 | 9 | sub gitlab { 'Devel::Cover::Report::Codecov::Service::GitLab' } 10 | 11 | subtest 'if gitlab' => sub { 12 | local $ENV{GITLAB_CI} = 1; 13 | ok(gitlab->detect); 14 | }; 15 | 16 | subtest 'if not gitlasb' => sub { 17 | local $ENV{GITLAB_CI} = 0; 18 | ok(not gitlab->detect); 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /t/codecov/service/bitrise/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Bitrise; 8 | 9 | subtest 'if bitrise' => sub { 10 | local $ENV{BITRISE_IO} = 1; 11 | is(Devel::Cover::Report::Codecov::Service::Bitrise->detect, 1); 12 | }; 13 | 14 | subtest 'if not bitrise' => sub { 15 | local %ENV; 16 | is(Devel::Cover::Report::Codecov::Service::Bitrise->detect, 0); 17 | }; 18 | 19 | done_testing; 20 | -------------------------------------------------------------------------------- /t/codecov/service/travis/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Travis; 8 | 9 | sub travis { 'Devel::Cover::Report::Codecov::Service::Travis' } 10 | 11 | subtest 'if travis' => sub { 12 | local $ENV{TRAVIS} = 1; 13 | ok( travis->detect ); 14 | }; 15 | 16 | subtest 'if not travis' => sub { 17 | local $ENV{TRAVIS} = 0; 18 | ok( not travis->detect ); 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /t/codecov/service/semaphore/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Semaphore; 8 | 9 | sub semaphore { 'Devel::Cover::Report::Codecov::Service::Semaphore' } 10 | 11 | subtest 'if semaphore' => sub { 12 | local $ENV{SEMAPHORE} = 1; 13 | ok( semaphore->detect ); 14 | }; 15 | 16 | subtest 'if not semaphore' => sub { 17 | local %ENV; 18 | ok( not semaphore->detect ); 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /t/codecov/service/appveyor/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::AppVeyor; 8 | 9 | sub appveyor { 'Devel::Cover::Report::Codecov::Service::AppVeyor' } 10 | 11 | subtest 'if appveyor' => sub { 12 | local $ENV{APPVEYOR} = 1; 13 | ok( appveyor->detect ); 14 | }; 15 | 16 | subtest 'if not appveyor' => sub { 17 | local $ENV{APPVEYOR} = 0; 18 | ok( not appveyor->detect ); 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /t/codecov/service/shippable/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Shippable; 8 | 9 | sub detect { 10 | return Devel::Cover::Report::Codecov::Service::Shippable->detect(@_); 11 | } 12 | 13 | subtest 'if Shippable' => sub { 14 | local %ENV = ( SHIPPABLE => 1 ); 15 | ok( detect ); 16 | }; 17 | 18 | subtest 'if not Shippable' => sub { 19 | local %ENV; 20 | ok( not detect ); 21 | }; 22 | 23 | done_testing; 24 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Codeship.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Codeship; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return defined $ENV{CI_NAME} && $ENV{CI_NAME} eq 'codeship'; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'codeship', 13 | build => $ENV{CI_BUILD_NUMBER}, 14 | build_url => $ENV{CI_BUILD_URL}, 15 | commit => $ENV{CI_COMMIT_ID}, 16 | branch => $ENV{CI_BRANCH}, 17 | }; 18 | } 19 | 20 | 1; 21 | __END__ 22 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Drone.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Drone; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{DRONE}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'drone.io', 13 | build => $ENV{DRONE_BUILD_NUMBER}, 14 | commit => $ENV{DRONE_COMMIT}, 15 | build_url => $ENV{DRONE_BUILD_URL}, 16 | branch => $ENV{DRONE_BRANCH}, 17 | tag => $ENV{DRONE_TAG}, 18 | }; 19 | } 20 | 21 | 1; 22 | __END__ 23 | -------------------------------------------------------------------------------- /t/codecov/service/wercker/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Wercker; 8 | 9 | sub wercker { 'Devel::Cover::Report::Codecov::Service::Wercker' } 10 | 11 | subtest 'if wercker' => sub { 12 | local $ENV{WERCKER_MAIN_PIPELINE_STARTED} = 1; 13 | ok( wercker->detect ); 14 | }; 15 | 16 | subtest 'if not wercker' => sub { 17 | local $ENV{WERCKER_MAIN_PIPELINE_STARTED} = 0; 18 | ok( not wercker->detect ); 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Semaphore.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Semaphore; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{SEMAPHORE}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'semaphore', 13 | build => $ENV{SEMAPHORE_BUILD_NUMBER} . '.' . $ENV{SEMAPHORE_CURRENT_THREAD}, 14 | commit => $ENV{REVISION}, 15 | branch => $ENV{BRANCH_NAME}, 16 | slug => $ENV{SEMAPHORE_REPO_SLUG}, 17 | }; 18 | } 19 | 20 | 1; 21 | __END__ 22 | -------------------------------------------------------------------------------- /t/codecov/get_file_realpath.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Cwd::Guard qw/cwd_guard/; 6 | 7 | use lib '.'; 8 | use t::Util; 9 | use Devel::Cover::Report::Codecov; 10 | 11 | sub get_file_realpath { 12 | Devel::Cover::Report::Codecov::get_file_realpath(@_); 13 | } 14 | 15 | subtest basic => sub { 16 | my $guard = cwd_guard('t/data/proj_blib'); 17 | is get_file_realpath('blib/lib/Example/Add.pm'), 'lib/Example/Add.pm'; 18 | is get_file_realpath('lib/Example/Div.pm'), 'lib/Example/Div.pm'; 19 | }; 20 | 21 | done_testing; 22 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Shippable.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Shippable; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{SHIPPABLE}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'shippable', 13 | build => $ENV{BUILD_NUMBER}, 14 | build_url => $ENV{BUILD_URL}, 15 | pull_request => $ENV{PULL_REQUEST}, 16 | slug => $ENV{REPO_NAME}, 17 | commit => $ENV{COMMIT}, 18 | }; 19 | } 20 | 21 | 1; 22 | __END__ 23 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/AppVeyor.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::AppVeyor; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{APPVEYOR}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'appveyor', 13 | commit => $ENV{APPVEYOR_REPO_COMMIT}, 14 | branch => $ENV{APPVEYOR_REPO_BRANCH}, 15 | job => $ENV{APPVEYOR_ACCOUNT_NAME} . '/' . $ENV{APPVEYOR_PROJECT_SLUG} . '/' . $ENV{APPVEYOR_BUILD_VERSION}, 16 | build => $ENV{APPVEYOR_JOB_ID}, 17 | slug => $ENV{APPVEYOR_REPO_NAME}, 18 | }; 19 | } 20 | 21 | 1; 22 | __END__ 23 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Wercker.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Wercker; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{WERCKER_MAIN_PIPELINE_STARTED}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'wercker', 13 | build => $ENV{WERCKER_MAIN_PIPELINE_STARTED}, 14 | commit => $ENV{WERCKER_GIT_COMMIT}, 15 | build_url => $ENV{WERCKER_BUILD_URL}, 16 | branch => $ENV{WERCKER_GIT_BRANCH}, 17 | owner => $ENV{WERCKER_GIT_OWNER}, 18 | repo => $ENV{WERCKER_GIT_REPOSITORY}, 19 | }; 20 | } 21 | 22 | 1; 23 | __END__ 24 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/GitLab.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::GitLab; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{GITLAB_CI}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'gitlab', 13 | commit => $ENV{CI_BUILD_REF}, 14 | build => $ENV{CI_BUILD_ID}, 15 | build_url => "$ENV{CI_PROJECT_URL}/builds/$ENV{CI_BUILD_ID}", 16 | job => $ENV{CI_PIPELINE_ID}, 17 | branch => $ENV{CI_BUILD_REF_NAME}, 18 | tag => $ENV{CI_BUILD_TAG}, 19 | slug => $ENV{CI_PROJECT_PATH}, 20 | }; 21 | } 22 | 23 | 1; 24 | __END__ 25 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Travis.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Travis; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{TRAVIS}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'travis', 13 | commit => $ENV{TRAVIS_COMMIT}, 14 | build => $ENV{TRAVIS_JOB_NUMBER}, 15 | branch => $ENV{TRAVIS_BRANCH}, 16 | job => $ENV{TRAVIS_JOB_ID}, 17 | pull_request => $ENV{TRAVIS_PULL_REQUEST}, 18 | slug => $ENV{TRAVIS_REPO_SLUG}, 19 | tag => $ENV{TRAVIS_TAG}, 20 | }; 21 | } 22 | 23 | 1; 24 | __END__ 25 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Mercurial.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Mercurial; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | require Capture::Tiny; 8 | Capture::Tiny->import('capture'); 9 | 10 | my (undef, undef, $r) = capture(sub { 11 | system('hg root'); 12 | }); 13 | 14 | return $r == 0; 15 | } 16 | 17 | sub configuration { 18 | my $branch = `hg branch`; 19 | my $commit = `hg id -i --debug`; 20 | 21 | chomp $branch; 22 | chomp $commit; 23 | 24 | $commit =~ s/x//; 25 | 26 | return { 27 | branch => $branch, 28 | commit => $commit, 29 | }; 30 | } 31 | 32 | sub fallback { 1 } 33 | 34 | 1; 35 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Bitrise.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Bitrise; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{BITRISE_IO} ? 1 : 0; 8 | } 9 | 10 | sub configuration { 11 | # http://devcenter.bitrise.io/faq/available-environment-variables/ 12 | return { 13 | service => 'bitrise', 14 | branch => $ENV{BITRISE_GIT_BRANCH}, 15 | build => $ENV{BITRISE_BUILD_NUMBER}, 16 | build_url => $ENV{BITRISE_BUILD_URL}, 17 | pr => $ENV{BITRISE_PULL_REQUEST}, 18 | $ENV{GIT_CLONE_COMMIT_HASH} ? 19 | (commit => $ENV{GIT_CLONE_COMMIT_HASH}) : (), 20 | }; 21 | } 22 | 23 | 1; 24 | __END__ 25 | -------------------------------------------------------------------------------- /t/Util.pm: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use utf8; 4 | 5 | use lib qw( 6 | lib 7 | t/data/proj/lib 8 | ); 9 | 10 | use Exporter 'import'; 11 | 12 | use Test::More; 13 | use Test::Deep; 14 | use Test::Exception; 15 | 16 | use Archive::Tar; 17 | use Cwd qw/abs_path/; 18 | use Cwd::Guard qw/cwd_guard/; 19 | 20 | our @EXPORT = ( 21 | @Test::More::EXPORT, 22 | @Test::Deep::EXPORT, 23 | @Test::Exception::EXPORT, 24 | 25 | qw/extract_tar/, 26 | ); 27 | 28 | sub extract_tar { 29 | my ($filepath, $outdir) = @_; 30 | 31 | my $abs_path = abs_path($filepath); 32 | my $guard = cwd_guard($outdir); 33 | 34 | my $tar = Archive::Tar->new; 35 | $tar->read($abs_path); 36 | $tar->extract; 37 | } 38 | 39 | 1; 40 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Git.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Git; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | require Capture::Tiny; 8 | Capture::Tiny->import('capture'); 9 | 10 | my (undef, undef, $r) = capture(sub { 11 | system('git rev-parse --is-inside-work-tree'); 12 | }); 13 | 14 | return $r == 0; 15 | } 16 | 17 | sub configuration { 18 | my $branch = `git rev-parse --abbrev-ref HEAD`; 19 | my $commit = `git rev-parse HEAD`; 20 | 21 | chomp $branch; 22 | chomp $commit; 23 | 24 | return { 25 | branch => $branch eq 'HEAD' ? 'master' : $branch, 26 | commit => $commit, 27 | }; 28 | } 29 | 30 | sub fallback { 1 } 31 | 32 | 1; 33 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov/Service/Circle.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov::Service::Circle; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | 6 | sub detect { 7 | return $ENV{CIRCLECI}; 8 | } 9 | 10 | sub configuration { 11 | return { 12 | service => 'circleci', 13 | build => $ENV{CIRCLE_BUILD_NUM} . '.' . $ENV{CIRCLE_NODE_INDEX}, 14 | job => $ENV{CIRCLE_BUILD_NUM} . '.' . $ENV{CIRCLE_NODE_INDEX}, 15 | commit => $ENV{CIRCLE_SHA1}, 16 | branch => $ENV{CIRCLE_BRANCH}, 17 | pull_request => $ENV{CIRCLE_PR_NUMBER}, 18 | owner => $ENV{CIRCLE_PROJECT_USERNAME}, 19 | repo => $ENV{CIRCLE_PROJECT_REPONAME}, 20 | }; 21 | } 22 | 23 | 1; 24 | __END__ 25 | -------------------------------------------------------------------------------- /t/codecov/get_query.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Test::MockObject; 6 | 7 | use lib '.'; 8 | use t::Util; 9 | use Devel::Cover::Report::Codecov; 10 | 11 | sub get_query { 12 | Devel::Cover::Report::Codecov::get_query(@_); 13 | } 14 | 15 | sub _make_service { 16 | my $service = Test::MockObject->new; 17 | $service->mock(detect => sub { 1 }); 18 | $service->mock(configuration => sub { { key => 'value' } }); 19 | 20 | return $service; 21 | } 22 | 23 | subtest 'if has token' => sub { 24 | local $ENV{CODECOV_TOKEN} = 'token'; 25 | 26 | cmp_deeply 27 | get_query(_make_service), 28 | { key => 'value', token => 'token' }; 29 | }; 30 | 31 | subtest 'if has not token' => sub { 32 | local %ENV = (); 33 | 34 | cmp_deeply 35 | get_query(_make_service), 36 | { key => 'value' }; 37 | }; 38 | 39 | done_testing; 40 | -------------------------------------------------------------------------------- /t/codecov/service/drone/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Drone; 8 | 9 | sub drone { 'Devel::Cover::Report::Codecov::Service::Drone' } 10 | 11 | subtest basic => sub { 12 | local %ENV = ( 13 | DRONE_BUILD_NUMBER => 'build_number', 14 | DRONE_COMMIT => 'commit', 15 | DRONE_BUILD_URL => 'build_url', 16 | DRONE_BRANCH => 'branch', 17 | DRONE_TAG => 'tag', 18 | ); 19 | 20 | cmp_deeply 21 | drone->configuration, 22 | { 23 | service => 'drone.io', 24 | build => 'build_number', 25 | commit => 'commit', 26 | build_url => 'build_url', 27 | branch => 'branch', 28 | tag => 'tag', 29 | }; 30 | }; 31 | 32 | done_testing; 33 | -------------------------------------------------------------------------------- /t/codecov/service/semaphore/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Semaphore; 8 | 9 | sub semaphore { 'Devel::Cover::Report::Codecov::Service::Semaphore' } 10 | 11 | subtest basic => sub { 12 | local %ENV = ( 13 | SEMAPHORE_BUILD_NUMBER => 'build_number', 14 | SEMAPHORE_CURRENT_THREAD => 'thread', 15 | REVISION => 'revision', 16 | BRANCH_NAME => 'branch_name', 17 | SEMAPHORE_REPO_SLUG => 'slug', 18 | ); 19 | 20 | cmp_deeply 21 | semaphore->configuration, 22 | { 23 | service => 'semaphore', 24 | build => 'build_number.thread', 25 | commit => 'revision', 26 | branch => 'branch_name', 27 | slug => 'slug', 28 | }; 29 | }; 30 | 31 | done_testing; 32 | -------------------------------------------------------------------------------- /script/dev/create-perlcriticrc.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use Module::Find; 4 | use Data::Section::Simple qw/get_data_section/; 5 | use Text::MicroTemplate qw/render_mt/; 6 | 7 | sub find_all_policies { 8 | my $namespace = 'Perl::Critic::Policy'; 9 | my @modules = findallmod($namespace); 10 | return [ map { substr($_, length($namespace) + 2) } @modules ]; 11 | } 12 | 13 | sub filter_policies { 14 | return $_[0]; 15 | } 16 | 17 | sub policies_to_string { 18 | my $policies = shift; 19 | return join ', ', @$policies; 20 | } 21 | 22 | sub load_template { 23 | return get_data_section('perlcriticrc'); 24 | } 25 | 26 | sub main { 27 | my $policies = filter_policies(find_all_policies); 28 | my $template = load_template; 29 | print render_mt($template, policies_to_string($policies)); 30 | print "\n"; 31 | } 32 | 33 | main unless caller; 34 | 35 | __DATA__ 36 | @@ perlcriticrc 37 | only = 1 38 | include = 39 | -------------------------------------------------------------------------------- /t/codecov/service/shippable/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Shippable; 8 | 9 | sub configuration { 10 | return Devel::Cover::Report::Codecov::Service::Shippable->configuration(@_); 11 | } 12 | 13 | subtest basic => sub { 14 | local %ENV = ( 15 | BUILD_NUMBER => 'build_number', 16 | BUILD_URL => 'build_url', 17 | PULL_REQUEST => 'pull_request', 18 | REPO_NAME => 'slug', 19 | COMMIT => 'commit', 20 | ); 21 | 22 | cmp_deeply 23 | configuration, 24 | { 25 | service => 'shippable', 26 | build => 'build_number', 27 | build_url => 'build_url', 28 | pull_request => 'pull_request', 29 | slug => 'slug', 30 | commit => 'commit', 31 | }; 32 | }; 33 | 34 | done_testing; 35 | -------------------------------------------------------------------------------- /t/codecov/service/gitlab/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::GitLab; 8 | 9 | sub gitlab { 'Devel::Cover::Report::Codecov::Service::GitLab' } 10 | 11 | subtest basic => sub { 12 | local $ENV{CI_BUILD_REF} = 'commit'; 13 | local $ENV{CI_BUILD_ID} = 'build_id'; 14 | local $ENV{CI_BUILD_REF_NAME} = 'branch'; 15 | local $ENV{CI_BUILD_TAG} = 'tag'; 16 | local $ENV{CI_PIPELINE_ID} = 'job_id'; 17 | local $ENV{CI_PROJECT_PATH} = 'repo_slug'; 18 | local $ENV{CI_PROJECT_URL} = 'repo_url'; 19 | 20 | cmp_deeply 21 | gitlab->configuration, 22 | { 23 | service => 'gitlab', 24 | commit => 'commit', 25 | build => 'build_id', 26 | build_url => 'repo_url/builds/build_id', 27 | job => 'job_id', 28 | branch => 'branch', 29 | tag => 'tag', 30 | slug => 'repo_slug', 31 | }; 32 | }; 33 | 34 | done_testing; 35 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | only: 3 | - master 4 | 5 | init: 6 | - git config --global core.autocrlf false 7 | 8 | install: 9 | # - rmdir /s /q C:\projects\codecov-perl\local\ 10 | - ps: Invoke-WebRequest -Uri http://strawberryperl.com/download/5.26.1.1/strawberry-perl-5.26.1.1-64bit.msi -OutFile strawberry-perl-64bit.msi 11 | - ps: Start-Process msiexec.exe -ArgumentList @("/package", "strawberry-perl-64bit.msi", "/qn", "INSTALLDIR=C:\strawberry") -Wait 12 | - SET PATH=C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH% 13 | - cpanm --notest --quiet Carton 14 | - carton install --without develop 15 | 16 | build: off 17 | 18 | test_script: 19 | - carton exec prove --norc --rc=.proverc -r t/codecov 20 | 21 | - SET HARNESS_PERL_SWITCHES="-MDevel::Cover=+ignore,^t/Util.pm|^t/data/proj/t/|^local/" 22 | - carton exec prove -r t/data/proj/t 23 | 24 | - SET PERL5LIB=%CD%\lib 25 | - SET PATH=%CD%\local\bin;%PATH% 26 | - carton exec cover -report codecov 27 | 28 | cache: 29 | - local 30 | 31 | shallow_clone: true 32 | -------------------------------------------------------------------------------- /t/codecov/service/appveyor/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::AppVeyor; 8 | 9 | sub appveyor { 'Devel::Cover::Report::Codecov::Service::AppVeyor' } 10 | 11 | subtest basic => sub { 12 | local $ENV{APPVEYOR_ACCOUNT_NAME} = 'name'; 13 | local $ENV{APPVEYOR_PROJECT_SLUG} = 'slug'; 14 | local $ENV{APPVEYOR_REPO_COMMIT} = 'commit'; 15 | local $ENV{APPVEYOR_REPO_BRANCH} = 'branch'; 16 | local $ENV{APPVEYOR_BUILD_VERSION} = 'build_version'; 17 | local $ENV{APPVEYOR_JOB_ID} = 'job_id'; 18 | local $ENV{APPVEYOR_REPO_NAME} = 'repo_name'; 19 | 20 | cmp_deeply 21 | appveyor->configuration, 22 | { 23 | service => 'appveyor', 24 | commit => 'commit', 25 | branch => 'branch', 26 | job => 'name/slug/build_version', 27 | build => 'job_id', 28 | slug => 'repo_name', 29 | }; 30 | }; 31 | 32 | done_testing; 33 | -------------------------------------------------------------------------------- /t/codecov/service/wercker/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Wercker; 8 | 9 | sub wercker { 'Devel::Cover::Report::Codecov::Service::Wercker' } 10 | 11 | subtest basic => sub { 12 | local $ENV{WERCKER_MAIN_PIPELINE_STARTED} = 'build'; 13 | local $ENV{WERCKER_GIT_COMMIT} = 'commit'; 14 | local $ENV{WERCKER_BUILD_URL} = 'build_url'; 15 | local $ENV{WERCKER_GIT_BRANCH} = 'branch'; 16 | local $ENV{WERCKER_GIT_OWNER} = 'owner'; 17 | local $ENV{WERCKER_GIT_REPOSITORY} = 'repo'; 18 | 19 | cmp_deeply 20 | wercker->configuration, 21 | { 22 | service => 'wercker', 23 | build => 'build', 24 | commit => 'commit', 25 | build_url => 'build_url', 26 | branch => 'branch', 27 | owner => 'owner', 28 | repo => 'repo', 29 | }; 30 | }; 31 | 32 | done_testing; 33 | -------------------------------------------------------------------------------- /t/codecov/service/travis/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Travis; 8 | 9 | subtest basic => sub { 10 | local $ENV{TRAVIS_COMMIT} = 'commit'; 11 | local $ENV{TRAVIS_JOB_NUMBER} = 'job_number'; 12 | local $ENV{TRAVIS_BRANCH} = 'branch'; 13 | local $ENV{TRAVIS_JOB_ID} = 'job_id'; 14 | local $ENV{TRAVIS_PULL_REQUEST} = 'pull_request'; 15 | local $ENV{TRAVIS_REPO_SLUG} = 'repo_slug'; 16 | local $ENV{TRAVIS_TAG} = 'tag'; 17 | 18 | my $configuration = Devel::Cover::Report::Codecov::Service::Travis->configuration; 19 | cmp_deeply 20 | $configuration, 21 | { 22 | service => 'travis', 23 | commit => 'commit', 24 | build => 'job_number', 25 | branch => 'branch', 26 | job => 'job_id', 27 | pull_request => 'pull_request', 28 | slug => 'repo_slug', 29 | tag => 'tag', 30 | }; 31 | }; 32 | 33 | done_testing; 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Pine Mizune 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /t/codecov/get_codecov_json.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use JSON::XS; 6 | use Test::Mock::Guard; 7 | 8 | use lib '.'; 9 | use t::Util; 10 | use Devel::Cover::Report::Codecov; 11 | 12 | sub get_codecov_json { 13 | Devel::Cover::Report::Codecov::get_codecov_json(@_); 14 | } 15 | 16 | subtest basic => sub { 17 | my $guard = mock_guard( 18 | 'Devel::Cover::Report::Codecov', 19 | { 20 | get_file_coverage => sub { 21 | my ($file, $db) = @_; 22 | 23 | like $file, qr/lib\/Test\/(Foo|Bar)\.pm/, $file; 24 | is $db, 'db'; 25 | 26 | return $file => [ undef, 1, 0, 5 ] if $file =~ qr/Foo/; 27 | return $file => [ undef, 2, 3, 8 ]; 28 | }, 29 | }); 30 | 31 | my $files = [ 'lib/Test/Foo.pm', 'lib/Test/Bar.pm' ]; 32 | 33 | cmp_deeply 34 | decode_json(get_codecov_json($files, 'db')), 35 | { 36 | coverage => { 37 | 'lib/Test/Foo.pm' => [ undef, 1, 0, 5 ], 38 | 'lib/Test/Bar.pm' => [ undef, 2, 3, 8 ], 39 | }, 40 | messages => {}, 41 | }; 42 | }; 43 | 44 | done_testing; 45 | -------------------------------------------------------------------------------- /t/codecov/service/mercurial/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Config; 6 | use Cwd qw/abs_path/; 7 | use File::Temp qw/tempdir/; 8 | use File::Which qw/which/; 9 | use Cwd::Guard qw/cwd_guard/; 10 | 11 | use lib '.'; 12 | use t::Util; 13 | use Devel::Cover::Report::Codecov::Service::Mercurial; 14 | 15 | sub configuration { 16 | Devel::Cover::Report::Codecov::Service::Mercurial->configuration(@_); 17 | } 18 | 19 | if (which 'hg') { 20 | subtest hg => sub { 21 | my $dir = tempdir; 22 | extract_tar('t/data/hg.tar.bz2', $dir); 23 | my $guard = cwd_guard("$dir/hg"); 24 | 25 | cmp_deeply 26 | configuration, 27 | { 28 | branch => 'default', 29 | commit => 'a42207909e7bdfc81dde25f307e9076ba71e04bf', 30 | }; 31 | }; 32 | } 33 | 34 | subtest mock => sub { 35 | local $ENV{PATH} = 36 | abs_path('t/data/libexec') . $Config::Config{path_sep} . $ENV{PATH}; 37 | 38 | cmp_deeply 39 | configuration, 40 | { 41 | branch => 'default', 42 | commit => 'a42207909e7bdfc81dde25f307e9076ba71e04bf', 43 | }; 44 | }; 45 | 46 | done_testing; 47 | -------------------------------------------------------------------------------- /t/codecov/service/git/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | our $SYSTEM; 6 | BEGIN { 7 | $SYSTEM = sub { CORE::system(@_) }; 8 | *CORE::GLOBAL::system = sub { goto $SYSTEM }; 9 | } 10 | 11 | use File::Temp qw/tempdir/; 12 | use File::Which qw/which/; 13 | 14 | use lib '.'; 15 | use t::Util; 16 | use Devel::Cover::Report::Codecov::Service::Git; 17 | sub detect { Devel::Cover::Report::Codecov::Service::Git->detect(@_) } 18 | 19 | if (which 'git') { 20 | subtest integrated => sub { 21 | subtest 'is inside worktree' => sub { 22 | my $dir = tempdir; 23 | extract_tar('t/data/git.tar.bz2', $dir); 24 | my $guard = cwd_guard("$dir/git"); 25 | 26 | ok detect; 27 | }; 28 | 29 | subtest 'is not inside worktree' => sub { 30 | my $dir = tempdir; 31 | my $guard = cwd_guard($dir); 32 | 33 | ok not detect; 34 | }; 35 | }; 36 | } 37 | 38 | subtest mock => sub { 39 | subtest 'is inside worktree' => sub { 40 | local $SYSTEM = sub { 0 }; 41 | ok detect; 42 | }; 43 | 44 | subtest 'is not inside worktree' => sub { 45 | local $SYSTEM = sub { 1 }; 46 | ok not detect; 47 | }; 48 | }; 49 | 50 | done_testing; 51 | -------------------------------------------------------------------------------- /t/codecov/service/mercurial/detect.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | our $SYSTEM; 6 | BEGIN { 7 | $SYSTEM = sub { CORE::system(@_) }; 8 | *CORE::GLOBAL::system = sub { goto $SYSTEM }; 9 | } 10 | 11 | use File::Temp qw/tempdir/; 12 | use File::Which qw/which/; 13 | 14 | use lib '.'; 15 | use t::Util; 16 | use Devel::Cover::Report::Codecov::Service::Mercurial; 17 | sub detect { Devel::Cover::Report::Codecov::Service::Mercurial->detect(@_) } 18 | 19 | if (which 'hg') { 20 | subtest integrated => sub { 21 | subtest 'is inside worktree' => sub { 22 | my $dir = tempdir; 23 | extract_tar('t/data/hg.tar.bz2', $dir); 24 | my $guard = cwd_guard("$dir/hg"); 25 | 26 | ok detect; 27 | }; 28 | 29 | subtest 'is not inside worktree' => sub { 30 | my $dir = tempdir; 31 | my $guard = cwd_guard($dir); 32 | 33 | ok not detect; 34 | }; 35 | }; 36 | } 37 | 38 | subtest mock => sub { 39 | subtest 'is inside worktree' => sub { 40 | local $SYSTEM = sub { 0 }; 41 | ok detect; 42 | }; 43 | 44 | subtest 'is not inside worktree' => sub { 45 | local $SYSTEM = sub { 1 }; 46 | ok not detect; 47 | }; 48 | }; 49 | 50 | done_testing; 51 | -------------------------------------------------------------------------------- /t/codecov/get_services.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Test::MockObject; 6 | use Test::Mock::Guard; 7 | 8 | use lib '.'; 9 | use t::Util; 10 | use Devel::Cover::Report::Codecov; 11 | 12 | sub get_services { 13 | Devel::Cover::Report::Codecov::get_services(@_); 14 | } 15 | 16 | subtest basic => sub { 17 | my $guard = mock_guard('Devel::Cover::Report::Codecov', { 18 | # Module::Find 19 | findallmod => sub { 20 | my $pkg = shift; 21 | is $pkg, 'Devel::Cover::Report::Codecov::Service'; 22 | 23 | my $default1 = Test::MockObject->new; 24 | $default1->set_isa('Default'); 25 | 26 | my $default2 = Test::MockObject->new; 27 | $default2->set_isa('Default'); 28 | $default2->mock(fallback => sub { 0 }); 29 | 30 | my $fallback = Test::MockObject->new; 31 | $fallback->mock(fallback => sub { 1 }); 32 | $fallback->set_isa('Fallback'); 33 | 34 | return ($default1, $fallback, $default2); 35 | }, 36 | }); 37 | 38 | my @services = get_services('Devel::Cover::Report::Codecov'); 39 | 40 | is @services, 3; 41 | ok $services[0]->isa('Default'); 42 | ok $services[1]->isa('Default'); 43 | ok $services[2]->isa('Fallback'); 44 | }; 45 | 46 | done_testing; 47 | -------------------------------------------------------------------------------- /t/codecov/service/bitrise/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use lib '.'; 6 | use t::Util; 7 | use Devel::Cover::Report::Codecov::Service::Bitrise; 8 | 9 | subtest 'without commit hash' => sub { 10 | local $ENV{BITRISE_GIT_BRANCH} = 'branch'; 11 | local $ENV{BITRISE_BUILD_NUMBER} = 'build'; 12 | local $ENV{BITRISE_BUILD_URL} = 'build_url'; 13 | local $ENV{BITRISE_PULL_REQUEST} = 'pr'; 14 | 15 | cmp_deeply( 16 | Devel::Cover::Report::Codecov::Service::Bitrise->configuration, 17 | { 18 | service => 'bitrise', 19 | branch => 'branch', 20 | build => 'build', 21 | build_url => 'build_url', 22 | pr => 'pr', 23 | }); 24 | }; 25 | 26 | subtest 'with commit hash' => sub { 27 | local $ENV{BITRISE_GIT_BRANCH} = 'branch'; 28 | local $ENV{BITRISE_BUILD_NUMBER} = 'build'; 29 | local $ENV{BITRISE_BUILD_URL} = 'build_url'; 30 | local $ENV{BITRISE_PULL_REQUEST} = 'pr'; 31 | local $ENV{GIT_CLONE_COMMIT_HASH} = 'commit'; 32 | 33 | cmp_deeply( 34 | Devel::Cover::Report::Codecov::Service::Bitrise->configuration, 35 | { 36 | service => 'bitrise', 37 | branch => 'branch', 38 | build => 'build', 39 | build_url => 'build_url', 40 | pr => 'pr', 41 | commit => 'commit', 42 | }); 43 | }; 44 | 45 | done_testing; 46 | -------------------------------------------------------------------------------- /cpanfile: -------------------------------------------------------------------------------- 1 | requires 'perl', '5.008001'; 2 | 3 | requires 'Devel::Cover'; 4 | 5 | requires 'Capture::Tiny', '0.30'; 6 | requires 'Furl', '3.07'; 7 | requires 'IO::Socket::SSL', '2.016'; 8 | requires 'JSON::XS', '3.01'; 9 | requires 'Module::Find', '0.13'; 10 | requires 'Sub::Retry', '0.06'; 11 | requires 'URI', '1.60'; 12 | 13 | on 'test' => sub { 14 | requires 'Test::More', '1.001014'; 15 | requires 'Test::Deep', '0.117'; 16 | requires 'Test::Exception', '0.40'; 17 | requires 'Test::Mock::Guard', '0.10'; 18 | requires 'Test::Mock::Time', '0.1.6'; 19 | requires 'Test::MockObject', '1.20150527'; 20 | requires 'Test::Requires::Git', '1.003'; 21 | 22 | requires 'Test::Perl::Critic', '1.03'; 23 | requires 'Perl::Critic', '1.125'; 24 | 25 | requires 'Devel::Cover', '1.20'; 26 | requires 'Capture::Tiny', '0.30'; 27 | requires 'Cwd', '3.47'; 28 | requires 'Cwd::Guard', '0.04'; 29 | requires 'File::Which', '1.19'; 30 | requires 'Archive::Tar', '2.04'; 31 | requires 'File::Temp', '0.2304'; 32 | }; 33 | 34 | on 'develop' => sub { 35 | requires 'Data::Dumper', '2.154'; 36 | requires 'Data::Section::Simple', '0.07'; 37 | requires 'Text::MicroTemplate', '0.24'; 38 | 39 | requires 'CPAN::Uploader', '0.103012'; 40 | requires 'Minilla', '3.0.1'; 41 | requires 'Software::License::MIT', '0.103011'; 42 | requires 'Test::CPAN::Meta', '0.25'; 43 | requires 'Test::MinimumVersion::Fast', '0.04'; 44 | requires 'Test::PAUSE::Permissions', '0.05'; 45 | requires 'Test::Spellunker', '0.4.0'; 46 | requires 'Version::Next', '1.000'; 47 | requires 'Pod::Markdown::Github', '0.02'; 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /t/codecov/get_line_coverage.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Test::MockObject; 6 | 7 | use lib '.'; 8 | use t::Util; 9 | use Devel::Cover::Report::Codecov; 10 | 11 | sub get_line_coverage { 12 | Devel::Cover::Report::Codecov::get_line_coverage(@_); 13 | } 14 | 15 | subtest 'if false' => sub { 16 | is get_line_coverage(undef, undef), undef; 17 | }; 18 | 19 | subtest statement => sub { 20 | subtest 'if uncoverable' => sub { 21 | my $statement = Test::MockObject->new; 22 | $statement->mock(uncoverable => sub { 1 }); 23 | $statement->mock(covered => sub { 0 }); 24 | 25 | is get_line_coverage([ $statement ]), undef; 26 | }; 27 | 28 | subtest 'if covered' => sub { 29 | my $statement = Test::MockObject->new; 30 | $statement->mock(uncoverable => sub { 0 }); 31 | $statement->mock(covered => sub { 1024 }); 32 | 33 | is get_line_coverage([ $statement ]), 1024; 34 | }; 35 | }; 36 | 37 | subtest branch => sub { 38 | my $statement = Test::MockObject->new; 39 | $statement->mock(uncoverable => sub { 0 }); 40 | $statement->mock(covered => sub { 8 }); 41 | 42 | my $branch = Test::MockObject->new; 43 | $branch->mock(covered => sub { 5 }); 44 | $branch->mock(total => sub { 10 }); 45 | $branch->mock(error => sub { 5 }); 46 | 47 | is get_line_coverage([ $statement ], [ $branch ]), '5/10'; 48 | 49 | subtest 'if uncoverable' => sub { 50 | my $branch = Test::MockObject->new; 51 | $branch->mock(covered => sub { 5 }); 52 | $branch->mock(total => sub { 10 }); 53 | $branch->mock(error => sub { 0 }); 54 | 55 | is get_line_coverage([ $statement ], [ $branch ]), '10/10'; 56 | }; 57 | 58 | }; 59 | 60 | done_testing; 61 | -------------------------------------------------------------------------------- /t/codecov/service/git/configuration.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Config; 6 | use Cwd qw/abs_path/; 7 | use Cwd::Guard qw/cwd_guard/; 8 | use File::Temp qw/tempdir/; 9 | use Capture::Tiny qw/capture/; 10 | use Test::Requires::Git; 11 | 12 | use lib '.'; 13 | use t::Util; 14 | use Devel::Cover::Report::Codecov::Service::Git; 15 | 16 | sub configuration { 17 | Devel::Cover::Report::Codecov::Service::Git->configuration(@_); 18 | } 19 | 20 | SKIP: { 21 | test_requires_git version_ge => '1.6.3', skip => 2; 22 | 23 | subtest integrated => sub { 24 | my $dir = tempdir; 25 | extract_tar('t/data/git.tar.bz2', $dir); 26 | my $guard = cwd_guard("$dir/git"); 27 | local $ENV{GIT_DIR} = "$dir/git/.git"; 28 | 29 | subtest master => sub { 30 | capture { `git reset --hard master` }; 31 | 32 | cmp_deeply 33 | configuration, 34 | { 35 | branch => 'master', 36 | commit => '3713ace1c825f6626e439e3cb72e2ce37f0cd63e', 37 | }; 38 | }; 39 | 40 | subtest HEAD => sub { 41 | capture { `git checkout HEAD~` }; 42 | 43 | cmp_deeply 44 | configuration, 45 | { 46 | branch => 'master', 47 | commit => '8074326f663b7929608b9748ae0728fc3971acca', 48 | }; 49 | }; 50 | }; 51 | } 52 | 53 | subtest mock => sub { 54 | local $ENV{PATH} = 55 | abs_path('t/data/libexec') . $Config::Config{path_sep} . $ENV{PATH}; 56 | 57 | cmp_deeply 58 | configuration, 59 | { 60 | branch => 'master', 61 | commit => '3713ace1c825f6626e439e3cb72e2ce37f0cd63e', 62 | }; 63 | }; 64 | 65 | done_testing; 66 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: perl 2 | sudo: false 3 | 4 | perl: 5 | - "5.8" 6 | - "5.10" 7 | - "5.12" 8 | - "5.14" 9 | - "5.16" 10 | - "5.18" 11 | - "5.20" 12 | - "5.22" 13 | - "5.24" 14 | - "5.26" 15 | - "5.28" 16 | - "5.30" 17 | 18 | before_install: 19 | - git clone git://github.com/travis-perl/helpers ~/travis-perl-helpers 20 | - source ~/travis-perl-helpers/init 21 | - build-perl 22 | - perl -V 23 | 24 | install: 25 | - cpan-install --deps 26 | # Install the right version of Devel::Cover, but no actual report module 27 | - COVERAGE=1 cpan-install --coverage 28 | 29 | script: 30 | # unit tests 31 | - prove -r t/codecov 32 | - prove -r xt/codecov 33 | 34 | # integration tests 35 | - cd $TRAVIS_BUILD_DIR/t/data/proj 36 | - |- 37 | HARNESS_PERL_SWITCHES="-MDevel::Cover=+ignore,^t|^local/" \ 38 | prove -r t 39 | - PERL5LIB=$TRAVIS_BUILD_DIR/lib travis_retry cover -report codecov 40 | 41 | - cd $TRAVIS_BUILD_DIR/t/data/proj_blib 42 | - |- 43 | HARNESS_PERL_SWITCHES="-MDevel::Cover=+ignore,^t|^local/" \ 44 | prove --blib -r t 45 | - PERL5LIB=$TRAVIS_BUILD_DIR/lib travis_retry cover -report codecov 46 | 47 | notifications: 48 | slack: 49 | - secure: "LiypVOGzfJoeTmdzkz2szBQIrflXFZZ4HFdVcaxeWe4bt1VT/f5l2sNd+lCcCarUjzKHfvqBvYOMusOJ2BuzA/6XIfwT7fN/QTkTwl9ARSC2Dk9xtjPeNFl97feCWirSlRVRALryO6oQOwaFO1ksGaCE4YVr1U0YqdLSvvCnebXN04o0o15QRHqGJJYLjwe/2y6rwVuKlCH9bRNZA6OUfv7W3noEHLJ4BnhC0DAZ9qR+anq7vgvIFyy4OadMMBMFcyymt3C1FA4MXI/X3UzmUbmUSKbXXvmeTYo8y0TS8Gtv46dOYCKxiGgODa/v6i6glPCY1KQvwVCsOq+z7xXPgK5HrfcZ/+tlLi40vhXWcroH0w8vlKMnsRKQ59Vg2pOM03vIXuM4T9s7i+KrLLW6M9DlESQeaCdENsUzBGeN9SffBJYR9Wy8rEJADShY2EKM4xaQjGGixX+Rx9m6j27O7WfSVEIcR7u+f8Kuzo5yCdeKUV198A+DdPm63LJoB3P8ccKbXsgF4tUUsGRPUOtARNzrInhrsG1tcQlV3XKKyJOiv0B/zADQO/dggfUh/Emv4heLCtapcihb3XYnUOGVywcBiNTsjk1GOMjzQSSsVxw+UhGWXrz1PPIWa6cbalem1YVBvwA3lh5tZEZkl7jsOrIrJGEiiTVw2Cbk3sBKMkk=" 50 | 51 | -------------------------------------------------------------------------------- /t/codecov/send_report_once.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Test::MockObject; 6 | use Test::Mock::Guard; 7 | 8 | use lib '.'; 9 | use t::Util; 10 | use Devel::Cover::Report::Codecov; 11 | 12 | sub send_report { 13 | Devel::Cover::Report::Codecov::send_report_once(@_); 14 | } 15 | 16 | sub _make_furl { 17 | my $res = shift; 18 | 19 | my $furl = Test::MockObject->new; 20 | $furl->mock(post => sub { 21 | my ($class, $url, $headers, $json) = @_; 22 | 23 | is $url, 'http://www.example.com'; 24 | cmp_deeply $headers, ['Accept' => 'application/json']; 25 | is $json, '{"test":1}'; 26 | 27 | return $res; 28 | }); 29 | 30 | return $furl; 31 | } 32 | 33 | subtest 'if 200' => sub { 34 | my $res = Test::MockObject->new; 35 | my $furl = _make_furl($res); 36 | 37 | $res->mock(code => sub { 200 }); 38 | $res->mock(message => sub { 'OK' }); 39 | $res->mock(content => sub { '{"message":"OK","url":"http://www.example.net/ok"}' }); 40 | 41 | my $guard = mock_guard('Furl', { new => sub { $furl } }); 42 | 43 | my $message = < 1, message => $message }; 52 | }; 53 | 54 | subtest 'if not 200' => sub { 55 | my $res = Test::MockObject->new; 56 | my $furl = _make_furl($res); 57 | 58 | $res->mock(code => sub { 400 }); 59 | $res->mock(message => sub { 'Bad Request' }); 60 | $res->mock(content => sub { '{"message":"ERROR"}' }); 61 | 62 | my $guard = mock_guard('Furl', { new => sub { $furl } }); 63 | 64 | my $message = < 0, message => $message }; 72 | }; 73 | 74 | done_testing; 75 | -------------------------------------------------------------------------------- /t/codecov/get_file_coverage.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Test::MockObject; 6 | use Test::Mock::Guard; 7 | 8 | use lib '.'; 9 | use t::Util; 10 | use Devel::Cover::Report::Codecov; 11 | 12 | sub get_file_coverage { 13 | Devel::Cover::Report::Codecov::get_file_coverage(@_); 14 | } 15 | 16 | subtest basic => sub { 17 | my $guard = mock_guard( 18 | 'Devel::Cover::Report::Codecov', 19 | { 20 | get_file_lines => sub { 21 | my $file = shift; 22 | is $file, 'lib/Test/File.pm'; 23 | return 3; 24 | }, 25 | get_line_coverage => sub { 26 | my ($statement, $branch) = @_; 27 | is $branch, undef; 28 | return $statement; 29 | }, 30 | }); 31 | 32 | my $db = Test::MockObject->new; 33 | my $cover = Test::MockObject->new; 34 | my $file = Test::MockObject->new; 35 | my $stmt = Test::MockObject->new; 36 | my $branch = Test::MockObject->new; 37 | 38 | $db->mock(cover => sub { $cover }); 39 | $cover->mock(file => sub { $file }); 40 | $file->mock(statement => sub { $stmt }); 41 | $file->mock(branch => sub { $branch }); 42 | $stmt->mock(location => sub { 43 | my (undef, $n) = @_; 44 | return [ undef, 0, undef, 5 ]->[$n]; 45 | }); 46 | $branch->mock(location => sub { undef }); 47 | 48 | cmp_deeply 49 | { get_file_coverage('lib/Test/File.pm', $db) }, 50 | { 'lib/Test/File.pm' => [ undef, 0, undef, 5 ] }; 51 | 52 | is $guard->call_count('Devel::Cover::Report::Codecov', 'get_file_lines'), 1; 53 | is $guard->call_count('Devel::Cover::Report::Codecov', 'get_line_coverage'), 3; 54 | 55 | ok $db->called('cover'); 56 | ok $cover->called('file'); 57 | ok $file->called('statement'); 58 | ok $file->called('branch'); 59 | ok $stmt->called('location'); 60 | ok $branch->called('location'); 61 | }; 62 | 63 | done_testing; 64 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | Revision history for Perl extension Devel-Cover-Report-Codecov 2 | 3 | {{$NEXT}} 4 | 5 | 0.25 2019-05-23T05:50:46Z 6 | - support `tag` query for travis & drone.io 7 | 8 | 9 | 0.24 2018-08-29T15:01:51Z 10 | - good bye Magnum CI 11 | 12 | 0.23 2018-08-28T16:31:09Z 13 | - use https endpoint 14 | 15 | 0.22 2018-01-16T17:38:24Z 16 | - support perl 5.8.1 or later 17 | 18 | 0.21 2017-10-01T05:36:04Z 19 | - fix retry bugs 20 | 21 | 0.20 2017-09-29T12:32:54Z 22 | - good bye snap ci 23 | - add retry logics 24 | 25 | 0.19 2017-08-31T14:43:49Z 26 | - support uncoverable branches 27 | 28 | 0.18 2017-05-16T15:15:30Z 29 | - support perl 5.26.x & good bye perl 5.8.x 30 | 31 | 0.17 2016-12-15T09:13:52Z 32 | - fix support CI list in the readme 33 | 34 | 0.16 2016-12-15T03:19:15Z 35 | - fix bugs that file name is invalid 36 | 37 | 0.15 2016-12-15T03:14:55Z 38 | - support GitLab CI (thank you @melo) 39 | 40 | 0.14 2016-05-01T18:09:10Z 41 | - fix a bug that can't parse Codecov's response 42 | 43 | 0.13 2016-03-04T13:58:51Z 44 | - support branch 45 | 46 | 0.12 2016-01-01T00:30:58Z 47 | - update documents 48 | 49 | 0.11 2015-12-20T12:45:28Z 50 | - fix tests 51 | 52 | 0.10 2015-09-27T08:56:26Z 53 | - fix tests 54 | 55 | 0.09 2015-08-24T15:04:21Z 56 | - support Shippable 57 | 58 | 0.08 2015-08-23T09:42:01Z 59 | - support local git and mercurial repository 60 | - add Devel::Cover to dependencies 61 | 62 | 0.07 2015-08-15T14:16:59Z 63 | - support Magnum CI 64 | - fix API parameters from CI environment variables 65 | 66 | 0.06 2015-08-15T04:37:07Z 67 | - support blib directory 68 | 69 | 0.05 2015-08-12T16:42:59Z 70 | - fix bugs that doesn't work in Perl 5.8.x 71 | 72 | 0.04 2015-08-08T07:36:33Z 73 | - support Snap CI 74 | - support Semaphore 75 | 76 | 0.03 2015-08-05T15:34:50Z 77 | - fix tests 78 | 79 | 0.02 2015-08-01T15:56:27Z 80 | - fix documents 81 | 82 | 0.01 2015-08-01T15:03:15Z 83 | - original version 84 | 85 | -------------------------------------------------------------------------------- /t/codecov/report.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use JSON::XS; 6 | use Test::MockObject; 7 | use Test::Mock::Guard; 8 | use Capture::Tiny qw/capture_stdout/; 9 | 10 | use lib '.'; 11 | use t::Util; 12 | use Devel::Cover::Report::Codecov; 13 | 14 | sub report { 15 | Devel::Cover::Report::Codecov::report(@_); 16 | } 17 | 18 | subtest 'if service found' => sub { 19 | my $db = Test::MockObject->new; 20 | my $service = Test::MockObject->new; 21 | $service->mock(detect => sub { 1 }); 22 | $service->mock(configuration => sub { { key => 'value' } }); 23 | 24 | my $guard = mock_guard('Devel::Cover::Report::Codecov', 25 | { 26 | get_codecov_json => sub { 27 | my ($file, $_db) = @_; 28 | is $db, $_db; 29 | cmp_deeply $file, [ 'lib/Foo.pm', 'lib/Foo/Bar.pm' ]; 30 | return '{"coverage":[]}'; 31 | }, 32 | 33 | get_request_url => sub { 34 | my ($url, $query) = @_; 35 | is $url, 'https://codecov.io/upload/v2'; 36 | cmp_deeply $query, { key => 'value' }; 37 | return 'http://www.example.com'; 38 | }, 39 | 40 | send_report => sub { 41 | my ($url, $json) = @_; 42 | is $url, 'http://www.example.com'; 43 | cmp_deeply decode_json($json), { coverage => [] }; 44 | return { ok => 1, message => 'send_report' }; 45 | }, 46 | 47 | get_query => sub { 48 | my $service = shift; 49 | return $service->configuration; 50 | }, 51 | 52 | get_services => sub { 53 | my $pkg = shift; 54 | is $pkg, 'Devel::Cover::Report::Codecov'; 55 | return ($service); 56 | }, 57 | }); 58 | 59 | my $options = { 60 | file => [ 'lib/Foo.pm', 'lib/Foo/Bar.pm' ], 61 | }; 62 | 63 | my ($stdout) = capture_stdout { 64 | report('Devel::Cover::Report::Codecov', $db, $options); 65 | }; 66 | is $stdout, "send_report\n"; 67 | 68 | my $pkg = 'Devel::Cover::Report::Codecov'; 69 | is $guard->call_count($pkg, 'get_codecov_json'), 1; 70 | is $guard->call_count($pkg, 'get_request_url'), 1; 71 | is $guard->call_count($pkg, 'send_report'), 1; 72 | is $guard->call_count($pkg, 'get_services'), 1; 73 | }; 74 | 75 | subtest 'if service not found' => sub { 76 | dies_ok { 77 | report('Unknown::Namespace', undef, {}); 78 | }; 79 | }; 80 | 81 | done_testing; 82 | -------------------------------------------------------------------------------- /t/codecov/send_report.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings FATAL => 'all'; 3 | use utf8; 4 | 5 | use Test::Mock::Guard; 6 | use Test::Mock::Time; 7 | use Test::MockObject; 8 | 9 | use lib '.'; 10 | use t::Util; 11 | use Devel::Cover::Report::Codecov; 12 | 13 | subtest 'without retry' => sub { 14 | my $url = Test::MockObject->new; 15 | my $res = Test::MockObject->new; 16 | my $ok = { ok => 1 }; 17 | 18 | my $guard = mock_guard('Devel::Cover::Report::Codecov', { 19 | send_report_once => sub { 20 | is $_[0], $url; 21 | is $_[1], $res; 22 | return $ok; 23 | }, 24 | }); 25 | 26 | subtest 'n_times = 0' => sub { 27 | local $Devel::Cover::Report::Codecov::RETRY_TIMES = 0; 28 | my $result = Devel::Cover::Report::Codecov::send_report($url, $res); 29 | is $result, $ok; 30 | is $guard->call_count('Devel::Cover::Report::Codecov', 'send_report_once'), 1; 31 | }; 32 | 33 | subtest 'n_times = 1' => sub { 34 | local $Devel::Cover::Report::Codecov::RETRY_TIMES = 1; 35 | my $result = Devel::Cover::Report::Codecov::send_report($url, $res); 36 | is $result, $ok; 37 | is $guard->call_count('Devel::Cover::Report::Codecov', 'send_report_once'), 1 + 1; 38 | }; 39 | 40 | subtest 'n_times = 5' => sub { 41 | local $Devel::Cover::Report::Codecov::RETRY_TIMES = 5; 42 | my $result = Devel::Cover::Report::Codecov::send_report($url, $res); 43 | is $result, $ok; 44 | is $guard->call_count('Devel::Cover::Report::Codecov', 'send_report_once'), 1 + 1 + 1; 45 | }; 46 | }; 47 | 48 | subtest 'with retry' => sub { 49 | my $url = Test::MockObject->new; 50 | my $res = Test::MockObject->new; 51 | my $ok = { ok => 1 }; 52 | my $ng = { ok => 0 }; 53 | 54 | my $count = 0; 55 | my $guard = mock_guard('Devel::Cover::Report::Codecov', { 56 | send_report_once => sub { 57 | is $_[0], $url; 58 | is $_[1], $res; 59 | 60 | $count++; 61 | return $count < 5 ? $ng : $ok; 62 | }, 63 | }); 64 | 65 | subtest 'n_times = 0' => sub { 66 | local $Devel::Cover::Report::Codecov::RETRY_TIMES = 0; 67 | 68 | my $result = Devel::Cover::Report::Codecov::send_report($url, $res); 69 | is $result, $ng; 70 | is $guard->call_count('Devel::Cover::Report::Codecov', 'send_report_once'), 1; 71 | }; 72 | 73 | $count = 0; 74 | subtest 'n_times = 3' => sub { 75 | local $Devel::Cover::Report::Codecov::RETRY_TIMES = 3; 76 | 77 | my $result = Devel::Cover::Report::Codecov::send_report($url, $res); 78 | is $result, $ng; 79 | is $guard->call_count('Devel::Cover::Report::Codecov', 'send_report_once'), 1 + 3; 80 | }; 81 | 82 | $count = 0; 83 | subtest 'n_times = 5' => sub { 84 | local $Devel::Cover::Report::Codecov::RETRY_TIMES = 5; 85 | 86 | my $result = Devel::Cover::Report::Codecov::send_report($url, $res); 87 | is $result, $ok; 88 | is $guard->call_count('Devel::Cover::Report::Codecov', 'send_report_once'), 1 + 3 + 5; 89 | }; 90 | }; 91 | 92 | done_testing; 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 🚨🚨 Deprecation Notice 🚨🚨 2 | 3 | This uploader is being deprecated by the Codecov team. We recommend migrating to our [new uploader](https://docs.codecov.com/docs/codecov-uploader) as soon as possible to prevent any lapses in coverage. [The new uploader is open source](https://github.com/codecov/uploader), and we highly encourage submitting Issues and Pull Requests. 4 | 5 | You can visit our blog post to learn more about our [deprecation plan](https://about.codecov.io/blog/codecov-uploader-deprecation-plan/) 6 | 7 | **On February 1, 2022 this uploader will be completely deprecated and will no longer be able to upload coverage to Codecov.** 8 | 9 | [![Build Status](https://travis-ci.org/codecov/codecov-perl.svg?branch=master)](https://travis-ci.org/codecov/codecov-perl) 10 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-perl.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-perl?ref=badge_shield) 11 | # NAME 12 | 13 | Devel::Cover::Report::Codecov - Backend for Codecov reporting of coverage statistics 14 | 15 | # SYNOPSIS 16 | 17 | ``` 18 | $ cover -report codecov 19 | ``` 20 | 21 | # DESCRIPTION 22 | 23 | Devel::Cover::Report::Codecov is coverage reporter for [Codecov](https://codecov.io). 24 | 25 | ## CI Companies Supported 26 | 27 | Many CI services supported. 28 | You must set CODECOV\_TOKEN environment variables if you don't use Travis CI, Circle CI and AppVeyor. 29 | 30 | - [Travis CI](https://travis-ci.org/) 31 | - [Circle CI](https://circleci.com/) 32 | - [Codeship](https://codeship.com/) 33 | - [Semaphore](https://semaphoreci.com/) 34 | - [drone.io](https://drone.io/) 35 | - [AppVeyor](https://www.appveyor.com/) 36 | - [Wercker](https://wercker.com/) 37 | - [Shippable](https://www.shippable.com/) 38 | - [GitLab CI](https://about.gitlab.com/gitlab-ci/) 39 | - [Bitrise](https://www.bitrise.io/) 40 | 41 | There are example Codecov CI settings in [example-perl](https://github.com/codecov/example-perl). 42 | 43 | # SEE ALSO 44 | 45 | - [Devel::Cover](https://metacpan.org/pod/Devel::Cover) 46 | 47 | # LICENSE 48 | 49 | The MIT License (MIT) 50 | 51 | Copyright (c) 2015-2019 Pine Mizune 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a copy 54 | of this software and associated documentation files (the "Software"), to deal 55 | in the Software without restriction, including without limitation the rights 56 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 57 | copies of the Software, and to permit persons to whom the Software is 58 | furnished to do so, subject to the following conditions: 59 | 60 | The above copyright notice and this permission notice shall be included in 61 | all copies or substantial portions of the Software. 62 | 63 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 66 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 67 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 68 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 69 | THE SOFTWARE. 70 | 71 | 72 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-perl.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-perl?ref=badge_large) 73 | 74 | # AUTHOR 75 | 76 | Pine Mizune 77 | -------------------------------------------------------------------------------- /META.json: -------------------------------------------------------------------------------- 1 | { 2 | "abstract" : "Backend for Codecov reporting of coverage statistics", 3 | "author" : [ 4 | "Pine Mizune" 5 | ], 6 | "dynamic_config" : 0, 7 | "generated_by" : "Minilla/v3.1.4, CPAN::Meta::Converter version 2.150010", 8 | "license" : [ 9 | "mit" 10 | ], 11 | "meta-spec" : { 12 | "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", 13 | "version" : 2 14 | }, 15 | "name" : "Devel-Cover-Report-Codecov", 16 | "no_index" : { 17 | "directory" : [ 18 | "t", 19 | "xt", 20 | "inc", 21 | "share", 22 | "eg", 23 | "examples", 24 | "author", 25 | "builder" 26 | ] 27 | }, 28 | "prereqs" : { 29 | "configure" : { 30 | "requires" : { 31 | "Module::Build::Tiny" : "0.035" 32 | } 33 | }, 34 | "develop" : { 35 | "requires" : { 36 | "CPAN::Uploader" : "0.103012", 37 | "Data::Dumper" : "2.154", 38 | "Data::Section::Simple" : "0.07", 39 | "Minilla" : "v3.0.1", 40 | "Pod::Markdown::Github" : "0.02", 41 | "Software::License::MIT" : "0.103011", 42 | "Test::CPAN::Meta" : "0.25", 43 | "Test::MinimumVersion::Fast" : "0.04", 44 | "Test::PAUSE::Permissions" : "0.05", 45 | "Test::Pod" : "1.41", 46 | "Test::Spellunker" : "v0.4.0", 47 | "Text::MicroTemplate" : "0.24", 48 | "Version::Next" : "1.000" 49 | } 50 | }, 51 | "runtime" : { 52 | "requires" : { 53 | "Capture::Tiny" : "0.30", 54 | "Devel::Cover" : "0", 55 | "Furl" : "3.07", 56 | "IO::Socket::SSL" : "2.016", 57 | "JSON::XS" : "3.01", 58 | "Module::Find" : "0.13", 59 | "Sub::Retry" : "0.06", 60 | "URI" : "1.60", 61 | "perl" : "5.008001" 62 | } 63 | }, 64 | "test" : { 65 | "requires" : { 66 | "Archive::Tar" : "2.04", 67 | "Capture::Tiny" : "0.30", 68 | "Cwd" : "3.47", 69 | "Cwd::Guard" : "0.04", 70 | "Devel::Cover" : "1.20", 71 | "File::Temp" : "0.2304", 72 | "File::Which" : "1.19", 73 | "Perl::Critic" : "1.125", 74 | "Test::Deep" : "0.117", 75 | "Test::Exception" : "0.40", 76 | "Test::Mock::Guard" : "0.10", 77 | "Test::Mock::Time" : "v0.1.6", 78 | "Test::MockObject" : "1.20150527", 79 | "Test::More" : "1.001014", 80 | "Test::Perl::Critic" : "1.03", 81 | "Test::Requires::Git" : "1.003" 82 | } 83 | } 84 | }, 85 | "release_status" : "unstable", 86 | "resources" : { 87 | "bugtracker" : { 88 | "web" : "https://github.com/codecov/codecov-perl/issues" 89 | }, 90 | "homepage" : "https://github.com/codecov/codecov-perl", 91 | "repository" : { 92 | "type" : "git", 93 | "url" : "git://github.com/codecov/codecov-perl.git", 94 | "web" : "https://github.com/codecov/codecov-perl" 95 | } 96 | }, 97 | "version" : "0.25", 98 | "x_authority" : "cpan:PINE", 99 | "x_contributors" : [ 100 | "Dagfinn Ilmari Mannsåker ", 101 | "M Somerville ", 102 | "Pedro Melo ", 103 | "Pine Mizune ", 104 | "stevepeak ", 105 | "Álvaro Castellano Vela " 106 | ], 107 | "x_serialization_backend" : "JSON::PP version 2.97001", 108 | "x_static_install" : 1 109 | } 110 | -------------------------------------------------------------------------------- /xt/perlcriticrc: -------------------------------------------------------------------------------- 1 | only = 1 2 | include = Objects::ProhibitIndirectSyntax, References::ProhibitDoubleSigils, Variables::ProtectPrivateVars, Variables::ProhibitPunctuationVars, Variables::RequireNegativeIndices, Variables::ProhibitAugmentedAssignmentInDeclaration, Variables::ProhibitReusedNames, Variables::ProhibitMatchVars, Variables::ProhibitUnusedVariables, Variables::RequireLexicalLoopIterators, Variables::RequireLocalizedPunctuationVars, Variables::ProhibitPackageVars, Variables::ProhibitEvilVariables, Variables::ProhibitConditionalDeclarations, Variables::ProhibitPerl4PackageNames, Variables::ProhibitLocalVars, Variables::RequireInitializationForLocalVars, Modules::ProhibitConditionalUseStatements, Modules::RequireEndWithOne, Modules::RequireFilenameMatchesPackage, Modules::RequireVersionVar, Modules::RequireBarewordIncludes, Modules::ProhibitEvilModules, Modules::ProhibitMultiplePackages, Modules::ProhibitAutomaticExportation, Modules::RequireNoMatchVarsWithUseEnglish, Modules::RequireExplicitPackage, Modules::ProhibitExcessMainComplexity, Miscellanea::ProhibitFormats, Miscellanea::ProhibitTies, Miscellanea::ProhibitUnrestrictedNoCritic, Miscellanea::ProhibitUselessNoCritic, RegularExpressions::ProhibitEscapedMetacharacters, RegularExpressions::ProhibitEnumeratedClasses, RegularExpressions::RequireExtendedFormatting, RegularExpressions::RequireBracesForMultiline, RegularExpressions::ProhibitSingleCharAlternation, RegularExpressions::ProhibitCaptureWithoutTest, RegularExpressions::ProhibitUnusedCapture, RegularExpressions::RequireDotMatchAnything, RegularExpressions::ProhibitUselessTopic, RegularExpressions::ProhibitUnusualDelimiters, RegularExpressions::ProhibitFixedStringMatches, RegularExpressions::ProhibitComplexRegexes, RegularExpressions::RequireLineBoundaryMatching, Subroutines::ProhibitManyArgs, Subroutines::ProhibitBuiltinHomonyms, Subroutines::ProhibitSubroutinePrototypes, Subroutines::ProhibitAmpersandSigils, Subroutines::ProhibitExcessComplexity, Subroutines::ProhibitNestedSubs, Subroutines::ProhibitUnusedPrivateSubroutines, Subroutines::ProhibitReturnSort, Subroutines::RequireFinalReturn, Subroutines::RequireArgUnpacking, Subroutines::ProhibitExplicitReturnUndef, Subroutines::ProtectPrivateSubs, InputOutput::ProhibitBarewordFileHandles, InputOutput::RequireBriefOpen, InputOutput::ProhibitExplicitStdin, InputOutput::RequireBracedFileHandleWithPrint, InputOutput::RequireCheckedClose, InputOutput::RequireCheckedSyscalls, InputOutput::RequireEncodingWithUTF8Layer, InputOutput::ProhibitInteractiveTest, InputOutput::ProhibitBacktickOperators, InputOutput::ProhibitOneArgSelect, InputOutput::ProhibitJoinedReadline, InputOutput::ProhibitTwoArgOpen, InputOutput::RequireCheckedOpen, InputOutput::ProhibitReadlineInForLoop, NamingConventions::ProhibitAmbiguousNames, NamingConventions::Capitalization, CodeLayout::ProhibitTrailingWhitespace, CodeLayout::RequireTrailingCommas, CodeLayout::ProhibitQuotedWordLists, CodeLayout::RequireTidyCode, CodeLayout::RequireConsistentNewlines, CodeLayout::ProhibitHardTabs, CodeLayout::ProhibitParensWithBuiltins, BuiltinFunctions::ProhibitComplexMappings, BuiltinFunctions::ProhibitVoidMap, BuiltinFunctions::ProhibitUniversalCan, BuiltinFunctions::RequireBlockGrep, BuiltinFunctions::ProhibitReverseSortBlock, BuiltinFunctions::ProhibitStringyEval, BuiltinFunctions::ProhibitVoidGrep, BuiltinFunctions::ProhibitUniversalIsa, BuiltinFunctions::ProhibitBooleanGrep, BuiltinFunctions::ProhibitUselessTopic, BuiltinFunctions::ProhibitLvalueSubstr, BuiltinFunctions::ProhibitStringySplit, BuiltinFunctions::RequireSimpleSortBlock, BuiltinFunctions::RequireGlobFunction, BuiltinFunctions::RequireBlockMap, BuiltinFunctions::ProhibitSleepViaSelect, ClassHierarchies::ProhibitAutoloading, ClassHierarchies::ProhibitExplicitISA, ClassHierarchies::ProhibitOneArgBless, TestingAndDebugging::ProhibitNoWarnings, TestingAndDebugging::ProhibitProlongedStrictureOverride, TestingAndDebugging::RequireTestLabels, TestingAndDebugging::ProhibitNoStrict, TestingAndDebugging::RequireUseWarnings, TestingAndDebugging::RequireUseStrict, ErrorHandling::RequireCheckingReturnValueOfEval, ErrorHandling::RequireCarping, Documentation::PodSpelling, Documentation::RequirePackageMatchesPodName, Documentation::RequirePodAtEnd, Documentation::RequirePodLinksIncludeText, Documentation::RequirePodSections, ControlStructures::ProhibitUnreachableCode, ControlStructures::ProhibitDeepNests, ControlStructures::ProhibitCascadingIfElse, ControlStructures::ProhibitUntilBlocks, ControlStructures::ProhibitPostfixControls, ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions, ControlStructures::ProhibitLabelsWithSpecialBlockNames, ControlStructures::ProhibitCStyleForLoops, ControlStructures::ProhibitMutatingListFunctions, ControlStructures::ProhibitUnlessBlocks, ValuesAndExpressions::RequireNumberSeparators, ValuesAndExpressions::RequireUpperCaseHeredocTerminator, ValuesAndExpressions::ProhibitConstantPragma, ValuesAndExpressions::ProhibitMagicNumbers, ValuesAndExpressions::RequireConstantVersion, ValuesAndExpressions::ProhibitComplexVersion, ValuesAndExpressions::ProhibitEscapedCharacters, ValuesAndExpressions::ProhibitInterpolationOfLiterals, ValuesAndExpressions::RequireQuotedHeredocTerminator, ValuesAndExpressions::ProhibitSpecialLiteralHeredocTerminator, ValuesAndExpressions::ProhibitLongChainsOfMethodCalls, ValuesAndExpressions::ProhibitEmptyQuotes, ValuesAndExpressions::ProhibitMismatchedOperators, ValuesAndExpressions::ProhibitNoisyQuotes, ValuesAndExpressions::ProhibitCommaSeparatedStatements, ValuesAndExpressions::ProhibitVersionStrings, ValuesAndExpressions::ProhibitImplicitNewlines, ValuesAndExpressions::ProhibitMixedBooleanOperators, ValuesAndExpressions::ProhibitLeadingZeros, ValuesAndExpressions::RequireInterpolationOfMetachars, ValuesAndExpressions::ProhibitQuotesAsQuotelikeOperatorDelimiters 3 | 4 | -------------------------------------------------------------------------------- /lib/Devel/Cover/Report/Codecov.pm: -------------------------------------------------------------------------------- 1 | package Devel::Cover::Report::Codecov; 2 | use strict; 3 | use warnings; 4 | use utf8; 5 | our $VERSION = '0.25'; 6 | 7 | use URI; 8 | use Furl; 9 | use JSON::XS; 10 | use Sub::Retry; 11 | 12 | use Module::Find; 13 | useall 'Devel::Cover::Report::Codecov::Service'; 14 | 15 | 16 | our $API_ENDPOINT = 'https://codecov.io/upload/v2'; 17 | our $RETRY_TIMES = 5; 18 | our $RETRY_DELAY = 1; # sec 19 | 20 | sub report { 21 | my ($pkg, $db, $options) = @_; 22 | 23 | my @services = get_services($pkg); 24 | my ($service) = grep { $_->detect } @services; 25 | die 'unknown service. could not get configuration' unless $service; 26 | 27 | my $query = get_query($service); 28 | my $url = get_request_url($API_ENDPOINT, $query); 29 | my $json = get_codecov_json($options->{file}, $db); 30 | my $res = send_report($url, $json); 31 | 32 | if ($res->{ok}) { 33 | print $res->{message} . "\n"; 34 | } 35 | 36 | else { 37 | die $res->{message} . "\n"; 38 | } 39 | } 40 | 41 | sub get_services { 42 | my $pkg = shift; 43 | 44 | my @services = findallmod "${pkg}::Service"; 45 | return sort { 46 | defined $a->can('fallback') && $a->fallback ? 1 : 47 | defined $b->can('fallback') && $b->fallback ? -1 : 0 48 | } @services; 49 | } 50 | 51 | sub get_file_lines { 52 | my ($file) = @_; 53 | 54 | my $lines = 0; 55 | 56 | open my $fp, '<', $file; 57 | $lines++ while <$fp>; 58 | close $fp; 59 | 60 | return $lines; 61 | } 62 | 63 | sub get_file_coverage { 64 | my ($filepath, $db) = @_; 65 | 66 | my $realpath = get_file_realpath($filepath); 67 | my $lines = get_file_lines($realpath); 68 | my $file = $db->cover->file($filepath); 69 | my $statements = $file->statement; 70 | my $branches = $file->branch; 71 | my @coverage = (undef); 72 | 73 | for (my $i = 1; $i <= $lines; $i++) { 74 | my $statement = $statements->location($i); 75 | my $branch = defined $branches ? $branches->location($i) : undef; 76 | push @coverage, get_line_coverage($statement, $branch); 77 | } 78 | 79 | return $realpath => \@coverage; 80 | } 81 | 82 | sub get_line_coverage { 83 | my ($statement, $branch) = @_; 84 | 85 | # If all branches covered or uncoverable, report as all covered 86 | return $branch->[0]->total.'/'.$branch->[0]->total if $branch && !$branch->[0]->error; 87 | return $branch->[0]->covered.'/'.$branch->[0]->total if $branch; 88 | return $statement unless $statement; 89 | return if $statement->[0]->uncoverable; 90 | return $statement->[0]->covered; 91 | } 92 | 93 | sub get_file_realpath { 94 | my $file = shift; 95 | 96 | if (-d 'blib') { 97 | my $realpath = $file; 98 | $realpath =~ s/blib\/lib/lib/; 99 | 100 | return $realpath if -f $realpath; 101 | } 102 | 103 | return $file; 104 | } 105 | 106 | sub get_codecov_json { 107 | my ($files, $db) = @_; 108 | 109 | my %coverages = map { get_file_coverage($_, $db) } @$files; 110 | my $request = { coverage => \%coverages, messages => {} }; 111 | 112 | return encode_json($request); 113 | } 114 | 115 | sub get_request_url { 116 | my ($base_url, $query) = @_; 117 | 118 | my $url = URI->new($base_url); 119 | $url->query_form($query); 120 | 121 | return $url->canonical; 122 | } 123 | 124 | sub get_query { 125 | my ($service) = @_; 126 | 127 | my $query = $service->configuration; 128 | 129 | if (defined $ENV{CODECOV_TOKEN}) { 130 | $query->{token} = lc $ENV{CODECOV_TOKEN}; 131 | } 132 | 133 | return $query; 134 | } 135 | 136 | sub send_report { 137 | my ($url, $json) = @_; 138 | 139 | my $n_times = $RETRY_TIMES > 0 ? $RETRY_TIMES : 1; 140 | 141 | # evaluate in list context 142 | my $result; 143 | { 144 | no warnings 'void'; 145 | [ retry $n_times, $RETRY_DELAY, 146 | sub { $result = send_report_once($url, $json) }, 147 | sub { $_[0]->{ok} ? 0 : 1 } ]; 148 | }; 149 | 150 | return $result; 151 | } 152 | 153 | sub send_report_once { 154 | my ($url, $json) = @_; 155 | 156 | my $furl = Furl->new; 157 | my $headers = [ 'Accept' => 'application/json' ]; 158 | my $res = $furl->post($url, $headers, $json); 159 | 160 | my ($message, $ok); 161 | 162 | if ($res->code == 200) { 163 | my $content = decode_json($res->content); 164 | 165 | $ok = 1; 166 | $message = <code]} @{[$res->message]} 168 | @{[$content->{message}]} 169 | @{[$content->{url}]} 170 | EOF 171 | } 172 | 173 | else { 174 | $ok = 0; 175 | $message = <code]} @{[$res->message]} 177 | @{[$res->content]} 178 | EOF 179 | } 180 | 181 | return { 182 | ok => $ok, 183 | message => $message, 184 | }; 185 | } 186 | 187 | 1; 188 | __END__ 189 | 190 | =encoding utf-8 191 | 192 | =head1 NAME 193 | 194 | Devel::Cover::Report::Codecov - Backend for Codecov reporting of coverage statistics 195 | 196 | =head1 SYNOPSIS 197 | 198 | $ cover -report codecov 199 | 200 | =head1 DESCRIPTION 201 | 202 | Devel::Cover::Report::Codecov is coverage reporter for L. 203 | 204 | =head2 CI Companies Supported 205 | 206 | Many CI services supported. 207 | You must set CODECOV_TOKEN environment variables if you don't use Travis CI, Circle CI and AppVeyor. 208 | 209 | =over 4 210 | 211 | =item * L 212 | 213 | =item * L 214 | 215 | =item * L 216 | 217 | =item * L 218 | 219 | =item * L 220 | 221 | =item * L 222 | 223 | =item * L 224 | 225 | =item * L 226 | 227 | =item * L 228 | 229 | =item * L 230 | 231 | =back 232 | 233 | There are example Codecov CI settings in L. 234 | 235 | =head1 SEE ALSO 236 | 237 | =over 4 238 | 239 | =item * L 240 | 241 | =back 242 | 243 | =head1 LICENSE 244 | 245 | The MIT License (MIT) 246 | 247 | Copyright (c) 2015-2019 Pine Mizune 248 | 249 | Permission is hereby granted, free of charge, to any person obtaining a copy 250 | of this software and associated documentation files (the "Software"), to deal 251 | in the Software without restriction, including without limitation the rights 252 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 253 | copies of the Software, and to permit persons to whom the Software is 254 | furnished to do so, subject to the following conditions: 255 | 256 | The above copyright notice and this permission notice shall be included in 257 | all copies or substantial portions of the Software. 258 | 259 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 260 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 261 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 262 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 263 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 264 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 265 | THE SOFTWARE. 266 | 267 | =head1 AUTHOR 268 | 269 | Pine Mizune Epinemz@gmail.comE 270 | 271 | =cut 272 | 273 | --------------------------------------------------------------------------------