Devel-Cover-Report-Coveralls

 view release on metacpan or  search on metacpan

lib/Devel/Cover/Report/Coveralls.pm  view on Meta::CPAN

    };
}

sub git_log {
    my $format = shift;

    my $text = '';

    my $command = "git log -1 --encoding=UTF-8 --pretty=format:'$format'";
    if (open(my $fh, '-|:encoding(UTF-8)', $command)) {
        $text = do { local $/; <$fh> };
        close $fh;
    }

    return $text;
}

sub get_git_info {
    my $git = {
        head => {
            id              => git_log('%H'),
            author_name     => git_log('%aN'),
            author_email    => git_log('%ae'),
            committer_name  => git_log('%cN'),
            committer_email => git_log('%ce'),
            message         => git_log('%s')
        },
        remotes => [
              map {
                  my ( $name, $url ) = split( " ", $_ );
                  +{ name => $name, url => $url }
              } split( "\n", `git remote -v` )
        ],
    };
    my ($branch,) = grep { /^\* / } split( "\n", `git branch` );
    $branch =~ s/^\* //;
    $git->{branch} = $branch;

    if ($ENV{GITHUB_REF} && $ENV{GITHUB_REF} =~ m![^/]+/[^/]+/(.+)$!) {
        $git->{branch} = $1;
    } elsif ($ENV{BUILD_SOURCEBRANCHNAME}) {
        $git->{branch} = $ENV{BUILD_SOURCEBRANCHNAME};
    }

    return $git;
}

sub get_config {
    my $config = {};
    if (-f $CONFIG_FILE) {
        $config = YAML::LoadFile($CONFIG_FILE);
    }

    my $json = {};
    $json->{repo_token} = $config->{repo_token} if $config->{repo_token};
    $json->{repo_token} = $ENV{COVERALLS_REPO_TOKEN} if $ENV{COVERALLS_REPO_TOKEN};
    $json->{flag_name} = $ENV{COVERALLS_FLAG_NAME} if $ENV{COVERALLS_FLAG_NAME};
    $json->{parallel} = \1 if $ENV{COVERALLS_PARALLEL};

    my $is_travis;
    my $endpoint = ($ENV{COVERALLS_ENDPOINT} || $API_ENDPOINT) . $API_ENDPOINT_STEM;
    if ($ENV{TRAVIS}) {
        $is_travis = 1;
        $json->{service_name} = $config->{service_name} || 'travis-ci';
        $json->{service_job_id} = $ENV{TRAVIS_JOB_ID};
        if($ENV{TRAVIS_PULL_REQUEST} && $ENV{TRAVIS_PULL_REQUEST} ne 'false'){
            $json->{service_pull_request} = $ENV{TRAVIS_PULL_REQUEST};
        }
    } elsif ($ENV{CIRCLECI}) {
        $json->{service_name} = 'circleci';
        $json->{service_number} = $ENV{CIRCLE_WORKFLOW_ID};
        # Unfortunately, circle-ci reports the url to PR..
    } elsif($ENV{DRONE}) {
        $json->{service_name} = 'drone';
        $json->{service_number} = $ENV{DRONE_BUILD_NUMBER};
        $json->{service_pull_request} = $ENV{DRONE_PULL_REQUEST} if $ENV{DRONE_PULL_REQUEST};
    } elsif ($ENV{SEMAPHORE}) {
        $json->{service_name} = 'semaphore';
        $json->{service_number} = $ENV{SEMAPHORE_BUILD_NUMBER} if $ENV{SEMAPHORE_BUILD_NUMBER};
        # Also support semaphore 2.x
        $json->{service_number} = $ENV{SEMAPHORE_WORKFLOW_ID} if $ENV{SEMAPHORE_WORKFLOW_ID};
        $json->{service_pull_request} = $ENV{SEMAPHORE_GIT_PR_NUMBER} if $ENV{SEMAPHORE_GIT_PR_NUMBER};
    } elsif ($ENV{JENKINS_URL}) {
        $json->{service_name} = 'jenkins';
        $json->{service_number} = $ENV{BUILD_NUM};
        # In jenkins, the PR number is not available as an env var..
    } elsif ($ENV{GITHUB_TOKEN}) {
        # from info as at 2020-11-07
        # https://github.com/coverallsapp/github-action/blob/master/src/run.ts
        # https://github.com/nickmerwin/node-coveralls/blob/master/lib/getOptions.js
        # we use GITHUB_TOKEN just to differentiate from still-working setup
        # in next option, but which requires a secret setting up
        $json->{service_name} = 'github';
        $json->{repo_token} = $ENV{GITHUB_TOKEN};
        $json->{service_job_id} = $ENV{GITHUB_RUN_ID};
        if (($ENV{GITHUB_EVENT_NAME}||'') eq 'pull_request') {
            if (open my $fh, '<:raw', $ENV{GITHUB_EVENT_PATH}) {
                local $/;
                my $text = <$fh>;
                my $pr = decode_json $text;
                if (my ($match) = ($pr->{number}||'') =~ /(\d+)$/) {
                    $json->{service_pull_request} = $match;
                }
            }
        }
    } elsif ($ENV{GITHUB_ACTIONS} && $ENV{GITHUB_SHA}) {
        $json->{service_name}   = 'github-actions';
        $json->{service_number} = substr($ENV{GITHUB_SHA}, 0, 9);
    } elsif ($ENV{SYSTEM_TEAMFOUNDATIONSERVERURI}) {
        $json->{service_name}   = 'azure-pipelines';
        $json->{service_number} = $ENV{BUILD_BUILDID};
    } else {
        $is_travis = 0;
        $json->{service_name} = $config->{service_name} || $SERVICE_NAME;
        $json->{service_event_type} = 'manual';
    }

    die "required repo_token in $CONFIG_FILE, make sure the environment var \"COVERALLS_REPO_TOKEN\" is set or launch via Travis" if !$json->{repo_token} && !$is_travis;

    if (exists $ENV{COVERALLS_PERL_SERVICE_NAME} && $ENV{COVERALLS_PERL_SERVICE_NAME}) {
        $json->{service_name} = $ENV{COVERALLS_PERL_SERVICE_NAME};
    }

    return ($json, $endpoint);
}

sub _parse_line ($) {
    my $c = shift;

    return sub {
        my $l = $c->location(shift);

        return $l unless $l;

        if ($l->[0]->uncoverable) {
            return undef;
        } else {
            return $l->[0]->covered;
        }
    };
}

sub report {
    my ($pkg, $db, $options) = @_;

    my $cover = $db->cover;

    my @sfs;

    for my $file (@{$options->{file}}) {
        my $f = $cover->file($file);
        my $c = $f->statement();

        push @sfs, get_source( $file, _parse_line $c );
    }

    my ($json, $endpoint) = get_config();
    $json->{git} = eval { get_git_info() } || {};
    $json->{source_files} = \@sfs;

    my $coder = JSON::PP->new->ascii;

    my $response = HTTP::Tiny->new( verify_SSL => 1 )
        ->post_form( $endpoint, { json => $coder->encode($json) } );

    my $res = eval { decode_json $response->{content} };


    print("- Report::Coveralls --------\n");
    if(exists($json->{service_number})){
        print "My build number: ". $json->{service_number} ."\n";
    }
    if ($@) {
        print "error: " . $response->{content};
    } elsif ($response->{success}) {
        print "register: " . $res->{url} . "\n";
    } else {
        print "error: " . $res->{message} . "\n";
    }
    if($ENV{COVERALLS_PARALLEL}){
        print "Parallel mode: True". "\n"
    }
    print("----------------------------\n");
}


1;
__END__

=encoding utf-8

=head1 NAME

Devel::Cover::Report::Coveralls - coveralls backend for Devel::Cover

=head1 USAGE

=head2 GitHub Actions

1. Add your repo to coveralls. L<https://coveralls.io/repos/new>

2. Add settings to one of your GitHub workflows. Here assuming you're
calling it F<.github/workflows/ci.yml>:

  jobs:
    ubuntu:
      runs-on: ${{ matrix.os }}
      strategy:
        fail-fast: false
        matrix:
          os: [ubuntu-latest]
          perl-version: ['5.10', '5.14', '5.20']
          include:
            - perl-version: '5.30'
              os: ubuntu-latest
              release-test: true
              coverage: true
      container: perl:${{ matrix.perl-version }}
      steps:
        - uses: actions/checkout@v2
        # do other stuff like installing external deps here
        - run: cpanm -n --installdeps .
        - run: perl -V
        - name: Run release tests # before others as may install useful stuff



( run in 1.614 second using v1.01-cache-2.11-cpan-8dfa8b56332 )