PK d^GMyު .travis.ymlnu W+A sudo: false
dist: trusty
language: php
matrix:
include:
- php: 5.5
env: 'COMPOSER_FLAGS="--prefer-stable --prefer-lowest"'
- php: 5.5
- php: 5.6
- php: 7.0
env: 'BOX=yes'
- php: 7.1
env: CHECKS=yes
- php: 7.1
env: SYMFONY_VERSION="^3.0"
- php: 7.2
env: SYMFONY_VERSION="^4.0" MIN_STABILITY=dev
cache:
directories:
- $HOME/.composer/cache
install:
- mkdir -p build/logs
- mv ${HOME}/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ${HOME}/xdebug.ini || return 0
- 'if [ "$MIN_STABILITY" != "" ]; then composer config minimum-stability $MIN_STABILITY; fi'
- 'if [ "$SYMFONY_VERSION" != "" ]; then sed -i "s/\"symfony\/\([^\"]*\)\": \"^2[^\"]*\"/\"symfony\/\1\": \"$SYMFONY_VERSION\"/g" composer.json; fi'
- travis_retry composer update ${COMPOSER_FLAGS} --no-interaction
- if [ "$CHECKS" = "yes" ]; then travis_retry composer install-dev-tools; fi;
script:
- cp ${HOME}/xdebug.ini ${HOME}/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini || return 0
- vendor/bin/phpunit -v
- rm ${HOME}/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini || return 0
- if [ "$CHECKS" = "yes" ]; then composer sca; fi;
after_success:
- bin/php-coveralls -v --exclude-no-stmt
before_deploy:
- if [ "${BOX}" = "yes" ]; then curl -LSs http://box-project.github.io/box2/installer.php | php; fi;
- if [ "${BOX}" = "yes" ]; then composer config platform.php 2> /dev/null || composer config platform.php 5.5.0; fi;
- if [ "${BOX}" = "yes" ]; then composer update --no-dev --no-interaction ${COMPOSER_FLAGS}; fi;
- if [ "${BOX}" = "yes" ]; then php -d phar.readonly=false box.phar build; fi;
deploy:
provider: releases
api_key:
secure: dNw8/urkXHRHzcI0F8NwYP63FjhcrpUqOO92uclAYESBjyVyhBzMuczBlGfwqdoxknwK+4wsDkr6TW7AtfeTa3d48acHdUD3ahWFFk9paC8jIVsh/H01UMsY3Xz4Z3KVWQDRFS5LIaDKk3jqPyvN+FiJpEQ8drIA+GDpm4VSQHc=
file: build/artifacts/php-coveralls.phar
skip_cleanup: true
on:
repo: php-coveralls/php-coveralls
tags: true
all_branches: true
condition: $BOX = yes
PK d^GMXU U build/config/phpmd.xmlnu W+A
My custom rule set that checks my code...
PK d^GM뚩 build/artifacts/.gitignorenu W+A *
!.gitignore
PK d^GM .* .* README.mdnu W+A php-coveralls
=============
[![Build Status](https://travis-ci.org/php-coveralls/php-coveralls.svg?branch=master)](https://travis-ci.org/php-coveralls/php-coveralls)
[![Coverage Status](https://coveralls.io/repos/php-coveralls/php-coveralls/badge.png?branch=master)](https://coveralls.io/r/php-coveralls/php-coveralls)
[![Latest Stable Version](https://poser.pugx.org/php-coveralls/php-coveralls/v/stable.png)](https://packagist.org/packages/php-coveralls/php-coveralls)
[![Total Downloads](https://poser.pugx.org/php-coveralls/php-coveralls/downloads.png)](https://packagist.org/packages/php-coveralls/php-coveralls)
PHP client library for [Coveralls](https://coveralls.io).
# Prerequisites
- PHP 5.5+ for 2.x or 5.3+ for 1.x
- On [GitHub](https://github.com/)
- Building on [Travis CI](http://travis-ci.org/), [CircleCI](https://circleci.com/), [Jenkins](http://jenkins-ci.org/) or [Codeship](https://www.codeship.io/)
- Testing by [PHPUnit](https://github.com/sebastianbergmann/phpunit/) or other testing framework that can generate clover style coverage report
# Installation
## Download phar file
We started to create a phar file, starting from the version 0.7.0
release. It is available at the URLs like:
```
https://github.com/php-coveralls/php-coveralls/releases/download/v2.1.0/php-coveralls.phar
```
Download the file and add exec permissions:
```sh
$ wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.1.0/php-coveralls.phar
$ chmod +x php-coveralls.phar
```
## Install by composer
To install php-coveralls with Composer, run the following command:
```sh
$ composer require --dev php-coveralls/php-coveralls
```
If you need support for PHP versions older than 5.5, you will need to use a 1.x version:
```sh
$ composer require --dev php-coveralls/php-coveralls '^2.1'
```
You can see this library on [Packagist](https://packagist.org/packages/php-coveralls/php-coveralls).
Composer installs autoloader at `./vendor/autoloader.php`. If you use
php-coveralls in your php script, add:
```php
require_once 'vendor/autoload.php';
```
If you use Symfony2, autoloader has to be detected automatically.
## Use it from your git clone
Or you can use git clone command:
```sh
# HTTP
$ git clone https://github.com/php-coveralls/php-coveralls.git
# SSH
$ git clone git@github.com:php-coveralls/php-coveralls.git
```
# Configuration
Currently php-coveralls supports clover style coverage report and collects coverage information from `clover.xml`.
## PHPUnit
Make sure that `phpunit.xml.dist` is configured to generate "coverage-clover" type log named `clover.xml` like the following configuration:
```xml
...
...
```
You can also use `--coverage-clover` CLI option.
```sh
phpunit --coverage-clover build/logs/clover.xml
```
### phpcov
Above settings are good for most projects if your test suite is executed once a build and is not divided into several parts. But if your test suite is configured as parallel tasks or generates multiple coverage reports through a build, you can use either `coverage_clover` configuration in `.coveralls.yml` ([see below coverage clover configuration section](#coverage-clover-configuration)) to specify multiple `clover.xml` files or `phpcov` for processing coverage reports.
#### composer.json
```json
"require-dev": {
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpcov": "^2.0"
},
```
#### phpunit configuration
Make sure that `phpunit.xml.dist` is configured to generate "coverage-php" type log:
```xml
...
...
```
You can also use `--coverage-php` CLI option.
```sh
# use --coverage-php option instead of --coverage-clover
phpunit --coverage-php build/cov/coverage-${component_name}.cov
```
#### phpcov configuration
And then, execute `phpcov.php` to merge `coverage.cov` logs.
```sh
# get information
php vendor/bin/phpcov.php --help
# merge coverage.cov logs under build/cov
php vendor/bin/phpcov.php merge --clover build/logs/clover.xml build/cov
# in case of memory exhausting error
php -d memory_limit=-1 vendor/bin/phpcov.php ...
```
### clover.xml
php-coveralls collects `count` attribute in a `line` tag from `clover.xml` if its `type` attribute equals to `stmt`. When `type` attribute equals to `method`, php-coveralls excludes its `count` attribute from coverage collection because abstract method in an abstract class is never counted though subclasses implement that method which is executed in test cases.
```xml
```
## Travis CI
Add `php php-coveralls.phar` or `php vendor/bin/php-coveralls` to your `.travis.yml` at `after_success`.
```yml
# .travis.yml
language: php
php:
- 5.5
- 5.4
- 5.3
matrix:
allow_failures:
- php: 5.5
install:
- curl -s http://getcomposer.org/installer | php
- php composer.phar install --dev --no-interaction
script:
- mkdir -p build/logs
- php vendor/bin/phpunit -c phpunit.xml.dist
after_success:
- travis_retry php vendor/bin/php-coveralls
# or enable logging
- travis_retry php vendor/bin/php-coveralls -v
```
## CircleCI
Enable Xdebug in your `circle.yml` at `dependencies` section since currently Xdebug extension is not pre-enabled. `composer` and `phpunit` are pre-installed but you can install them manually in this dependencies section. The following sample uses default ones.
```yml
machine:
php:
version: 5.4.10
## Customize dependencies
dependencies:
override:
- mkdir -p build/logs
- composer install --dev --no-interaction
- sed -i 's/^;//' ~/.phpenv/versions/$(phpenv global)/etc/conf.d/xdebug.ini
## Customize test commands
test:
override:
- phpunit -c phpunit.xml.dist
```
Add `COVERALLS_REPO_TOKEN` environment variable with your coveralls repo token on Web UI (Tweaks -> Environment Variable).
## Codeship
You can configure CI process for Coveralls by adding the following commands to the textarea on Web UI (Project settings > Test tab).
In the "Modify your Setup Commands" section:
```sh
curl -s http://getcomposer.org/installer | php
php composer.phar install --dev --no-interaction
mkdir -p build/logs
```
In the "Modify your Test Commands" section:
```sh
php vendor/bin/phpunit -c phpunit.xml.dist
php vendor/bin/php-coveralls
```
Next, open Project settings > Environment tab, you can set `COVERALLS_REPO_TOKEN` environment variable.
In the "Configure your environment variables" section:
```sh
COVERALLS_REPO_TOKEN=your_token
```
## From local environment
If you would like to call Coveralls API from your local environment, you can set `COVERALLS_RUN_LOCALLY` environment variable. This configuration requires `repo_token` to specify which project on Coveralls your project maps to. This can be done by configuring `.coveralls.yml` or `COVERALLS_REPO_TOKEN` environment variable.
```sh
$ export COVERALLS_RUN_LOCALLY=1
# either env var
$ export COVERALLS_REPO_TOKEN=your_token
# or .coveralls.yml configuration
$ vi .coveralls.yml
repo_token: your_token # should be kept secret!
```
php-coveralls set the following properties to `json_file` which is sent to Coveralls API (same behaviour as the Ruby library will do except for the service name).
- service_name: php-coveralls
- service_event_type: manual
## CLI options
You can get help information for `coveralls` with the `--help (-h)` option.
```sh
php vendor/bin/php-coveralls --help
```
- `--config (-c)`: Used to specify the path to `.coveralls.yml`. Default is `.coveralls.yml`
- `--verbose (-v)`: Used to show logs.
- `--dry-run`: Used not to send json_file to Coveralls Jobs API.
- `--exclude-no-stmt`: Used to exclude source files that have no executable statements.
- `--env (-e)`: Runtime environment name: test, dev, prod (default: "prod")
- `--coverage_clover (-x)`: Coverage clover xml files(allowing multiple values)
- `--json_path` (-o): Used to specify where to output json_file that will be
uploaded to Coveralls API. (default: `build/logs/coveralls-upload.json`)
- `--root_dir (-r)`: Root directory of the project. (default: ".")
## .coveralls.yml
php-coveralls can use optional `.coveralls.yml` file to configure options. This configuration file is usually at the root level of your repository, but you can specify other path by `--config (or -c)` CLI option. Following options are the same as Ruby library ([see reference on coveralls.io](https://coveralls.io/docs/ruby)).
- `repo_token`: Used to specify which project on Coveralls your project maps to. This is only needed for repos not using CI and should be kept secret
- `service_name`: Allows you to specify where Coveralls should look to find additional information about your builds. This can be any string, but using `travis-ci` or `travis-pro` will allow Coveralls to fetch branch data, comment on pull requests, and more.
Following options can be used for php-coveralls.
- `coverage_clover`: Used to specify the path to `clover.xml`. Default is `build/logs/clover.xml`
- `json_path`: Used to specify where to output `json_file` that will be uploaded to Coveralls API. Default is `build/logs/coveralls-upload.json`.
```yml
# .coveralls.yml example configuration
# same as Ruby lib
repo_token: your_token # should be kept secret!
service_name: travis-pro # travis-ci or travis-pro
# for php-coveralls
coverage_clover: build/logs/clover.xml
json_path: build/logs/coveralls-upload.json
```
### coverage clover configuration
You can specify multiple `clover.xml` logs at `coverage_clover`. This is useful for a project that has more than two test suites if all of the test results should be merged into one `json_file`.
```yml
#.coveralls.yml
# single file
coverage_clover: build/logs/clover.xml
# glob
coverage_clover: build/logs/clover-*.xml
# array
# specify files
coverage_clover:
- build/logs/clover-Auth.xml
- build/logs/clover-Db.xml
- build/logs/clover-Validator.xml
```
You can also use `--coverage_clover` (or `-x`) command line option as follows:
```
coveralls --coverage_clover=build/logs/my-clover.xml
```
### root_dir detection and override
This tool assume the current directory is the project root directory by default. You can override it with `--root_dir` command line option.
# Change log
[See changelog](CHANGELOG.md)
# Wiki
[See wiki](https://github.com/php-coveralls/php-coveralls/wiki)
PK d^GMVV
.gitignorenu W+A # eclipse
.buildpath
.project
.settings/
# PHP prj
build/
cache.properties
# composer
vendor/
composer.lock
# travis
travis/
# bin
composer.phar
php-cs-fixer.phar
.coveralls.yml
.php_cs
.php_cs.cache
phpunit.xml
box.phar
PK d^GM۔N . src/Component/System/SystemCommandExecutor.phpnu W+A
* @author Dariusz Rumiński
*
* @internal
*/
final class SystemCommandExecutor implements SystemCommandExecutorInterface
{
/**
* Execute command.
*
* @param string $command
*
* @throws \RuntimeException
*
* @return array
*/
public function execute($command)
{
exec($command, $result, $returnValue);
if ($returnValue === 0) {
return $result;
}
throw new \RuntimeException(sprintf('Failed to execute command: %s', $command), $returnValue);
}
}
PK d^GMh h 7 src/Component/System/SystemCommandExecutorInterface.phpnu W+A
*
* @internal
*/
interface SystemCommandExecutorInterface
{
/**
* Execute command.
*
* @param string $command
*
* @throws \RuntimeException
*
* @return array
*/
public function execute($command);
}
PK d^GMCp[ [ ' src/Component/System/Git/GitCommand.phpnu W+A
*/
class GitCommand
{
/**
* @var SystemCommandExecutorInterface
*/
private $executor;
public function __construct(SystemCommandExecutorInterface $executor = null)
{
$this->executor = $executor ? $executor : new SystemCommandExecutor();
}
/**
* Return branch names.
*
* @return array
*/
public function getBranches()
{
return $this->executor->execute('git branch');
}
/**
* Return HEAD commit.
*
* @return array
*/
public function getHeadCommit()
{
return $this->executor->execute("git log -1 --pretty=format:'%H%n%aN%n%ae%n%cN%n%ce%n%s'");
}
/**
* Return remote repositories.
*
* @return array
*/
public function getRemotes()
{
return $this->executor->execute('git remote -v');
}
}
PK d^GM[* * # src/Component/Log/ConsoleLogger.phpnu W+A
*/
class ConsoleLogger extends AbstractLogger
{
/**
* Output.
*
* @var \Symfony\Component\Console\Output\OutputInterface
*/
protected $output;
/**
* Constructor.
*
* @param OutputInterface $output
*/
public function __construct(OutputInterface $output)
{
$this->output = $output;
}
/**
* {@inheritdoc}
*
*
* @see \Psr\Log\LoggerInterface::log()
*/
public function log($level, $message, array $context = [])
{
$this->output->writeln($message);
}
}
PK d^GMB!T src/Component/File/Path.phpnu W+A
*/
class Path
{
/**
* Return whether the path is relative path.
*
* @param string $path path
*
* @return bool true if the path is relative path, false otherwise
*/
public function isRelativePath($path)
{
if (strlen($path) === 0) {
return true;
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
return !preg_match('/^[a-z]+\:\\\\/i', $path);
}
return strpos($path, DIRECTORY_SEPARATOR) !== 0;
}
/**
* Cat file path.
*
* @param string $path file path
* @param string $rootDir absolute path to project root directory
*
* @return false|string absolute path
*/
public function toAbsolutePath($path, $rootDir)
{
if (!is_string($path)) {
return false;
}
if ($this->isRelativePath($path)) {
return $rootDir . DIRECTORY_SEPARATOR . $path;
}
return $path;
}
/**
* Return real file path.
*
* @param string $path file path
* @param string $rootDir absolute path to project root directory
*
* @return false|string real path string if the path string is passed and real path exists, false otherwise
*/
public function getRealPath($path, $rootDir)
{
if (!is_string($path)) {
return false;
}
if ($this->isRelativePath($path)) {
return realpath($rootDir . DIRECTORY_SEPARATOR . $path);
}
return realpath($path);
}
/**
* Return real directory path.
*
* @param string $path path
* @param string $rootDir absolute path to project root directory
*
* @return false|string real directory path string if the path string is passed and real directory exists, false otherwise
*/
public function getRealDir($path, $rootDir)
{
if (!is_string($path)) {
return false;
}
if ($this->isRelativePath($path)) {
return realpath($rootDir . DIRECTORY_SEPARATOR . dirname($path));
}
return realpath(dirname($path));
}
/**
* Return real file path to write.
*
* @param string $path file path
* @param string $rootDir absolute path to project root directory
*
* @return false|string real file path string if the parent directory exists, false otherwise
*/
public function getRealWritingFilePath($path, $rootDir)
{
$realDir = $this->getRealDir($path, $rootDir);
if (!is_string($realDir)) {
return false;
}
return $realDir . DIRECTORY_SEPARATOR . basename($path);
}
/**
* Return whether the real path exists.
*
* @param bool|string $realpath real path
*
* @return bool true if the real path exists, false otherwise
*/
public function isRealPathExist($realpath)
{
return $realpath !== false && file_exists($realpath);
}
/**
* Return whether the real file path exists.
*
* @param bool|string $realpath real file path
*
* @return bool true if the real file path exists, false otherwise
*/
public function isRealFileExist($realpath)
{
return $this->isRealPathExist($realpath) && is_file($realpath);
}
/**
* Return whether the real file path is readable.
*
* @param bool|string $realpath real file path
*
* @return bool true if the real file path is readable, false otherwise
*/
public function isRealFileReadable($realpath)
{
return $this->isRealFileExist($realpath) && is_readable($realpath);
}
/**
* Return whether the real file path is writable.
*
* @param bool|string $realpath real file path
*
* @return bool true if the real file path is writable, false otherwise
*/
public function isRealFileWritable($realpath)
{
return $this->isRealFileExist($realpath) && is_writable($realpath);
}
/**
* Return whether the real directory exists.
*
* @param bool|string $realpath real directory path
*
* @return bool true if the real directory exists, false otherwise
*/
public function isRealDirExist($realpath)
{
return $this->isRealPathExist($realpath) && is_dir($realpath);
}
/**
* Return whether the real directory is writable.
*
* @param bool|string $realpath real directory path
*
* @return bool true if the real directory is writable, false otherwise
*/
public function isRealDirWritable($realpath)
{
return $this->isRealDirExist($realpath) && is_writable($realpath);
}
}
PK d^GMm>z z C src/Bundle/CoverallsBundle/Collector/CloverXmlCoverageCollector.phpnu W+A
*/
class CloverXmlCoverageCollector
{
/**
* JsonFile.
*
* @var \PhpCoveralls\Bundle\CoverallsBundle\Entity\JsonFile
*/
protected $jsonFile;
// API
/**
* Collect coverage from XML object.
*
* @param \SimpleXMLElement $xml clover XML object
* @param string $rootDir path to repository root directory
*
* @return \PhpCoveralls\Bundle\CoverallsBundle\Entity\JsonFile
*/
public function collect(\SimpleXMLElement $xml, $rootDir)
{
$root = rtrim($rootDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
if ($this->jsonFile === null) {
$this->jsonFile = new JsonFile();
}
// overwrite if run_at has already been set
$runAt = $this->collectRunAt($xml);
$this->jsonFile->setRunAt($runAt);
$xpaths = [
'/coverage/project/file',
'/coverage/project/package/file',
];
foreach ($xpaths as $xpath) {
foreach ($xml->xpath($xpath) as $file) {
$srcFile = $this->collectFileCoverage($file, $root);
if ($srcFile !== null) {
$this->jsonFile->addSourceFile($srcFile);
}
}
}
return $this->jsonFile;
}
// accessor
/**
* Return json file.
*
* @return \PhpCoveralls\Bundle\CoverallsBundle\Entity\JsonFile
*/
public function getJsonFile()
{
return $this->jsonFile;
}
// Internal method
/**
* Collect timestamp when the job ran.
*
* @param \SimpleXMLElement $xml clover XML object of a file
* @param string $format dateTime format
*
* @return string
*/
protected function collectRunAt(\SimpleXMLElement $xml, $format = 'Y-m-d H:i:s O')
{
$timestamp = $xml->project['timestamp'];
$runAt = new \DateTime('@' . $timestamp);
return $runAt->format($format);
}
/**
* Collect coverage data of a file.
*
* @param \SimpleXMLElement $file clover XML object of a file
* @param string $root path to src directory
*
* @return null|\PhpCoveralls\Bundle\CoverallsBundle\Entity\SourceFile
*/
protected function collectFileCoverage(\SimpleXMLElement $file, $root)
{
$absolutePath = realpath((string) ($file['path'] ?: $file['name']));
if (strpos($absolutePath, $root) === false) {
return;
}
$filename = $absolutePath;
if ($root !== DIRECTORY_SEPARATOR) {
$filename = str_replace($root, '', $absolutePath);
}
return $this->collectCoverage($file, $absolutePath, $filename);
}
/**
* Collect coverage data.
*
* @param \SimpleXMLElement $file clover XML object of a file
* @param string $path path to source file
* @param string $filename filename
*
* @return \PhpCoveralls\Bundle\CoverallsBundle\Entity\SourceFile
*/
protected function collectCoverage(\SimpleXMLElement $file, $path, $filename)
{
if ($this->jsonFile->hasSourceFile($path)) {
$srcFile = $this->jsonFile->getSourceFile($path);
} else {
$srcFile = new SourceFile($path, $filename);
}
foreach ($file->line as $line) {
if ((string) $line['type'] === 'stmt') {
$lineNum = (int) $line['num'];
if ($lineNum > 0) {
$srcFile->addCoverage($lineNum - 1, (int) $line['count']);
}
}
}
return $srcFile;
}
}
PK d^GMw 9 src/Bundle/CoverallsBundle/Collector/GitInfoCollector.phpnu W+A
*/
class GitInfoCollector
{
/**
* Git command.
*
* @var GitCommand
*/
protected $command;
/**
* Constructor.
*
* @param GitCommand $command Git command
*/
public function __construct(GitCommand $command)
{
$this->command = $command;
}
// API
/**
* Collect git repository info.
*
* @return \PhpCoveralls\Bundle\CoverallsBundle\Entity\Git\Git
*/
public function collect()
{
$branch = $this->collectBranch();
$commit = $this->collectCommit();
$remotes = $this->collectRemotes();
return new Git($branch, $commit, $remotes);
}
// accessor
/**
* Return git command.
*
* @return \PhpCoveralls\Component\System\Git\GitCommand
*/
public function getCommand()
{
return $this->command;
}
// internal method
/**
* Collect branch name.
*
* @throws \RuntimeException
*
* @return string
*/
protected function collectBranch()
{
$branchesResult = $this->command->getBranches();
foreach ($branchesResult as $result) {
if (strpos($result, '* ') === 0) {
$exploded = explode('* ', $result, 2);
return $exploded[1];
}
}
throw new \RuntimeException();
}
/**
* Collect commit info.
*
* @throws \RuntimeException
*
* @return \PhpCoveralls\Bundle\CoverallsBundle\Entity\Git\Commit
*/
protected function collectCommit()
{
$commitResult = $this->command->getHeadCommit();
if (count($commitResult) !== 6 || array_keys($commitResult) !== range(0, 5)) {
throw new \RuntimeException();
}
$commit = new Commit();
return $commit
->setId($commitResult[0])
->setAuthorName($commitResult[1])
->setAuthorEmail($commitResult[2])
->setCommitterName($commitResult[3])
->setCommitterEmail($commitResult[4])
->setMessage($commitResult[5]);
}
/**
* Collect remotes info.
*
* @throws \RuntimeException
*
* @return \PhpCoveralls\Bundle\CoverallsBundle\Entity\Git\Remote[]
*/
protected function collectRemotes()
{
$remotesResult = $this->command->getRemotes();
if (count($remotesResult) === 0) {
throw new \RuntimeException();
}
// parse command result
$results = [];
foreach ($remotesResult as $result) {
if (strpos($result, ' ') !== false) {
list($remote) = explode(' ', $result, 2);
$results[] = $remote;
}
}
// filter
$results = array_unique($results);
// create Remote instances
$remotes = [];
foreach ($results as $result) {
if (strpos($result, "\t") !== false) {
list($name, $url) = explode("\t", $result, 2);
$remote = new Remote();
$remotes[] = $remote->setName($name)->setUrl($url);
}
}
return $remotes;
}
}
PK d^GMM~!p p ; src/Bundle/CoverallsBundle/Collector/CiEnvVarsCollector.phpnu W+A
*/
class CiEnvVarsCollector
{
/**
* Configuration.
*
* @var Configuration
*/
protected $config;
/**
* Environment variables.
*
* Overwritten through collection process.
*
* @var array
*/
protected $env;
/**
* Read environment variables.
*
* @var array
*/
protected $readEnv;
/**
* Constructor.
*
* @param Configuration $config configuration
*/
public function __construct(Configuration $config)
{
$this->config = $config;
}
// API
/**
* Collect environment variables.
*
* @param array $env $_SERVER environment
*
* @return array
*/
public function collect(array $env)
{
$this->env = $env;
$this->readEnv = [];
$this
->fillTravisCi()
->fillCircleCi()
->fillAppVeyor()
->fillJenkins()
->fillLocal()
->fillRepoToken();
return $this->env;
}
// accessor
/**
* Return read environment variables.
*
* @return array
*/
public function getReadEnv()
{
return $this->readEnv;
}
// internal method
/**
* Fill Travis CI environment variables.
*
* "TRAVIS", "TRAVIS_JOB_ID" must be set.
*
* @return $this
*/
protected function fillTravisCi()
{
if (isset($this->env['TRAVIS']) && $this->env['TRAVIS'] && isset($this->env['TRAVIS_JOB_ID'])) {
$this->env['CI_JOB_ID'] = $this->env['TRAVIS_JOB_ID'];
if ($this->config->hasServiceName()) {
$this->env['CI_NAME'] = $this->config->getServiceName();
} else {
$this->env['CI_NAME'] = 'travis-ci';
}
// backup
$this->readEnv['TRAVIS'] = $this->env['TRAVIS'];
$this->readEnv['TRAVIS_JOB_ID'] = $this->env['TRAVIS_JOB_ID'];
$this->readEnv['CI_NAME'] = $this->env['CI_NAME'];
}
return $this;
}
/**
* Fill CircleCI environment variables.
*
* "CIRCLECI", "CIRCLE_BUILD_NUM" must be set.
*
* @return $this
*/
protected function fillCircleCi()
{
if (isset($this->env['CIRCLECI']) && $this->env['CIRCLECI'] && isset($this->env['CIRCLE_BUILD_NUM'])) {
$this->env['CI_BUILD_NUMBER'] = $this->env['CIRCLE_BUILD_NUM'];
$this->env['CI_NAME'] = 'circleci';
// backup
$this->readEnv['CIRCLECI'] = $this->env['CIRCLECI'];
$this->readEnv['CIRCLE_BUILD_NUM'] = $this->env['CIRCLE_BUILD_NUM'];
$this->readEnv['CI_NAME'] = $this->env['CI_NAME'];
}
return $this;
}
/**
* Fill AppVeyor environment variables.
*
* "APPVEYOR", "APPVEYOR_BUILD_NUMBER" must be set.
*
* @return $this
*/
protected function fillAppVeyor()
{
if (isset($this->env['APPVEYOR']) && $this->env['APPVEYOR'] && isset($this->env['APPVEYOR_BUILD_NUMBER'])) {
$this->env['CI_BUILD_NUMBER'] = $this->env['APPVEYOR_BUILD_NUMBER'];
$this->env['CI_JOB_ID'] = $this->env['APPVEYOR_JOB_NUMBER'];
$this->env['CI_BRANCH'] = $this->env['APPVEYOR_REPO_BRANCH'];
$this->env['CI_PULL_REQUEST'] = $this->env['APPVEYOR_PULL_REQUEST_NUMBER'];
$this->env['CI_NAME'] = 'AppVeyor';
// backup
$this->readEnv['APPVEYOR'] = $this->env['APPVEYOR'];
$this->readEnv['APPVEYOR_BUILD_NUMBER'] = $this->env['APPVEYOR_BUILD_NUMBER'];
$this->readEnv['APPVEYOR_JOB_NUMBER'] = $this->env['APPVEYOR_JOB_NUMBER'];
$this->readEnv['APPVEYOR_REPO_BRANCH'] = $this->env['APPVEYOR_REPO_BRANCH'];
$this->readEnv['APPVEYOR_PULL_REQUEST_NUMBER'] = $this->env['APPVEYOR_PULL_REQUEST_NUMBER'];
$this->readEnv['CI_NAME'] = $this->env['CI_NAME'];
}
return $this;
}
/**
* Fill Jenkins environment variables.
*
* "JENKINS_URL", "BUILD_NUMBER" must be set.
*
* @return $this
*/
protected function fillJenkins()
{
if (isset($this->env['JENKINS_URL']) && isset($this->env['BUILD_NUMBER'])) {
$this->env['CI_BUILD_NUMBER'] = $this->env['BUILD_NUMBER'];
$this->env['CI_BUILD_URL'] = $this->env['JENKINS_URL'];
$this->env['CI_NAME'] = 'jenkins';
// backup
$this->readEnv['BUILD_NUMBER'] = $this->env['BUILD_NUMBER'];
$this->readEnv['JENKINS_URL'] = $this->env['JENKINS_URL'];
$this->readEnv['CI_NAME'] = $this->env['CI_NAME'];
}
return $this;
}
/**
* Fill local environment variables.
*
* "COVERALLS_RUN_LOCALLY" must be set.
*
* @return $this
*/
protected function fillLocal()
{
if (isset($this->env['COVERALLS_RUN_LOCALLY']) && $this->env['COVERALLS_RUN_LOCALLY']) {
$this->env['CI_JOB_ID'] = null;
$this->env['CI_NAME'] = 'php-coveralls';
$this->env['COVERALLS_EVENT_TYPE'] = 'manual';
// backup
$this->readEnv['COVERALLS_RUN_LOCALLY'] = $this->env['COVERALLS_RUN_LOCALLY'];
$this->readEnv['COVERALLS_EVENT_TYPE'] = $this->env['COVERALLS_EVENT_TYPE'];
$this->readEnv['CI_NAME'] = $this->env['CI_NAME'];
}
return $this;
}
/**
* Fill repo_token for unsupported CI service.
*
* "COVERALLS_REPO_TOKEN" must be set.
*
* @return $this
*/
protected function fillRepoToken()
{
if ($this->config->hasRepoToken()) {
$this->env['COVERALLS_REPO_TOKEN'] = $this->config->getRepoToken();
}
// backup
if (isset($this->env['COVERALLS_REPO_TOKEN'])) {
$this->readEnv['COVERALLS_REPO_TOKEN'] = $this->env['COVERALLS_REPO_TOKEN'];
}
return $this;
}
}
PK d^GM֮~ ~ 8 src/Bundle/CoverallsBundle/Repository/JobsRepository.phpnu W+A
*/
class JobsRepository implements LoggerAwareInterface
{
/**
* Jobs API.
*
* @var \PhpCoveralls\Bundle\CoverallsBundle\Api\Jobs
*/
protected $api;
/**
* Configuration.
*
* @var \PhpCoveralls\Bundle\CoverallsBundle\Config\Configuration
*/
protected $config;
/**
* Logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructor.
*
* @param Jobs $api aPI
* @param Configuration $config configuration
*/
public function __construct(Jobs $api, Configuration $config)
{
$this->api = $api;
$this->config = $config;
}
// API
/**
* Persist coverage data to Coveralls.
*
* @return bool
*/
public function persist()
{
try {
return $this
->collectCloverXml()
->collectGitInfo()
->collectEnvVars()
->dumpJsonFile()
->send();
} catch (\PhpCoveralls\Bundle\CoverallsBundle\Entity\Exception\RequirementsNotSatisfiedException $e) {
$this->logger->error(sprintf('%s', $e->getHelpMessage()));
return false;
} catch (\Exception $e) {
$this->logger->error(sprintf("%s\n\n%s", $e->getMessage(), $e->getTraceAsString()));
return false;
}
}
// LoggerAwareInterface
/**
* {@inheritdoc}
*
*
* @see \Psr\Log\LoggerAwareInterface::setLogger()
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
// internal method
/**
* Collect clover XML into json_file.
*
* @return $this
*/
protected function collectCloverXml()
{
$this->logger->info('Load coverage clover log:');
foreach ($this->config->getCloverXmlPaths() as $path) {
$this->logger->info(sprintf(' - %s', $path));
}
$jsonFile = $this->api->collectCloverXml()->getJsonFile();
if ($jsonFile->hasSourceFiles()) {
$this->logCollectedSourceFiles($jsonFile);
}
return $this;
}
/**
* Collect git repository info into json_file.
*
* @return $this
*/
protected function collectGitInfo()
{
$this->logger->info('Collect git info');
$this->api->collectGitInfo();
return $this;
}
/**
* Collect environment variables.
*
* @return $this
*/
protected function collectEnvVars()
{
$this->logger->info('Read environment variables');
$this->api->collectEnvVars($_SERVER);
return $this;
}
/**
* Dump submitting json file.
*
* @return $this
*/
protected function dumpJsonFile()
{
$jsonPath = $this->config->getJsonPath();
$this->logger->info(sprintf('Dump submitting json file: %s', $jsonPath));
$this->api->dumpJsonFile();
$filesize = number_format(filesize($jsonPath) / 1024, 2); // kB
$this->logger->info(sprintf('File size: %s kB', $filesize));
return $this;
}
/**
* Send json_file to Jobs API.
*
* @return bool
*/
protected function send()
{
$this->logger->info(sprintf('Submitting to %s', Jobs::URL));
try {
$response = $this->api->send();
$message = $response
? sprintf('Finish submitting. status: %s %s', $response->getStatusCode(), $response->getReasonPhrase())
: 'Finish dry run';
$this->logger->info($message);
if ($response instanceof Response) {
$this->logResponse($response);
}
return true;
} catch (\GuzzleHttp\Exception\ConnectException $e) {
// connection error
$message = sprintf("Connection error occurred. %s\n\n%s", $e->getMessage(), $e->getTraceAsString());
} catch (\GuzzleHttp\Exception\ClientException $e) {
// 422 Unprocessable Entity
$response = $e->getResponse();
$message = sprintf('Client error occurred. status: %s %s', $response->getStatusCode(), $response->getReasonPhrase());
} catch (\GuzzleHttp\Exception\ServerException $e) {
// 500 Internal Server Error
// 503 Service Unavailable
$response = $e->getResponse();
$message = sprintf('Server error occurred. status: %s %s', $response->getStatusCode(), $response->getReasonPhrase());
}
$this->logger->error($message);
if (isset($response)) {
$this->logResponse($response);
}
return false;
}
// logging
/**
* Colorize coverage.
*
* * green 90% - 100%
* * yellow 80% - 90%
* * red 0% - 80%
*
* @param float $coverage coverage
* @param string $format format string to colorize
*
* @return string
*/
protected function colorizeCoverage($coverage, $format)
{
if ($coverage >= 90) {
return sprintf('%s', $format);
}
if ($coverage >= 80) {
return sprintf('%s', $format);
}
return sprintf('%s', $format);
}
/**
* Log collected source files.
*
* @param JsonFile $jsonFile json file
*/
protected function logCollectedSourceFiles(JsonFile $jsonFile)
{
$sourceFiles = $jsonFile->getSourceFiles();
$numFiles = count($sourceFiles);
$this->logger->info(sprintf('Found %s source file%s:', number_format($numFiles), $numFiles > 1 ? 's' : ''));
foreach ($sourceFiles as $sourceFile) {
/* @var $sourceFile \PhpCoveralls\Bundle\CoverallsBundle\Entity\SourceFile */
$coverage = $sourceFile->reportLineCoverage();
$template = ' - ' . $this->colorizeCoverage($coverage, '%6.2f%%') . ' %s';
$this->logger->info(sprintf($template, $coverage, $sourceFile->getName()));
}
$coverage = $jsonFile->reportLineCoverage();
$template = 'Coverage: ' . $this->colorizeCoverage($coverage, '%6.2f%% (%d/%d)');
$metrics = $jsonFile->getMetrics();
$this->logger->info(sprintf($template, $coverage, $metrics->getCoveredStatements(), $metrics->getStatements()));
}
/**
* Log response.
*
* @param Response $response aPI response
*/
protected function logResponse(Response $response)
{
$raw_body = (string) $response->getBody();
$body = json_decode($raw_body, true);
if ($body === null) {
// the response body is not in JSON format
$this->logger->error($raw_body);
} elseif (isset($body['error'])) {
if (isset($body['message'])) {
$this->logger->error($body['message']);
}
} else {
if (isset($body['message'])) {
$this->logger->info(sprintf('Accepted %s', $body['message']));
}
if (isset($body['url'])) {
$this->logger->info(sprintf('You can see the build on %s', $body['url']));
}
}
}
}
PK d^GMD &