PK )%AV,X phpunit.xml.distnu W+A
./tests/
./src
./composer
./tests
./vendor
PK )%AVN N .travis/travis.shnu W+A #!/usr/bin/env bash
# The problem is that we do not want to remove the configuration file, just disable it for a few tasks, then enable it
#
# For reference, see
#
# - https://docs.travis-ci.com/user/languages/php#Disabling-preinstalled-PHP-extensions
# - https://docs.travis-ci.com/user/languages/php#Custom-PHP-configuration
config="/home/travis/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini"
function xdebug-disable() {
if [[ -f $config ]]; then
mv $config "$config.bak"
fi
}
function xdebug-enable() {
if [[ -f "$config.bak" ]]; then
mv "$config.bak" $config
fi
}
function run-tests() {
if [[ "$WITH_COVERAGE" == "true" ]]; then
xdebug-enable
vendor/bin/phpunit --coverage-clover=build/logs/clover.xml
xdebug-disable
else
vendor/bin/phpunit
fi
}
PK )%AVNV& LICENSEnu W+A Copyright (c) 2014 Code Climate LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
This package includes code by Kitamura Satoshi, distributed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
PK )%AVԛk k phar/bin/main.phpnu W+A
*/
namespace CodeClimate\PhpTestReporter;
use CodeClimate\PhpTestReporter\ConsoleCommands\RollbackCommand;
use CodeClimate\PhpTestReporter\ConsoleCommands\SelfUpdateCommand;
use CodeClimate\PhpTestReporter\ConsoleCommands\UploadCommand;
use Symfony\Component\Console\Application;
require __DIR__ . '/../../vendor/autoload.php';
try {
$app = new Application('Code Climate PHP Test Reporter', '@package_version@');
$app->addCommands(
array(
new UploadCommand('upload'),
new SelfUpdateCommand('self-update'),
new RollbackCommand('rollback'),
)
);
$code = $app->run();
exit($code);
} catch (\Exception $e) {
echo 'Uncaught Exception ' . get_class($e) . ' with message: ' . $e->getMessage() . PHP_EOL;
echo $e->getTraceAsString();
exit(1);
}
PK )%AVĭ .travis.ymlnu W+A language: php
sudo: false
matrix:
include:
- php: 5.3
env: WITH_LOWEST=true
- php: 5.3
env: WITH_HIGHEST=true WITH_CS=true WITH_PHAR=true
- php: 5.4
env: WITH_LOWEST=true
- php: 5.4
env: WITH_HIGHEST=true
- php: 5.5
env: WITH_LOWEST=true
- php: 5.5
env: WITH_HIGHEST=true
- php: 5.6
env: WITH_LOWEST=true
- php: 5.6
env: WITH_HIGHEST=true
- php: 7.0
env: WITH_LOWEST=true
- php: 7.0
env: WITH_HIGHEST=true
- php: 7.1
env: WITH_LOWEST=true
- php: 7.1
env: WITH_HIGHEST=true WITH_COVERAGE=true
cache:
directories:
- $HOME/.composer/cache
- $HOME/.php-cs-fixer
before_install:
- source .travis/travis.sh
- xdebug-disable
- composer self-update
- composer validate
install:
- if [[ "$WITH_LOWEST" == "true" ]]; then composer update --prefer-lowest --prefer-dist; else composer install --prefer-dist; fi
before_script:
- git config --global user.email "travis-ci@codeclimate.com"
- git config --global user.name "Travis CI"
- mkdir -p "$HOME/.php-cs-fixer"
script:
- if [[ "$WITH_CS" == "true" ]]; then vendor/bin/php-cs-fixer fix --config=.php_cs --verbose --diff --dry-run; fi
- run-tests
after_success:
- if [[ "$WITH_COVERAGE" == "true" ]]; then php composer/bin/test-reporter; fi
deploy:
provider: releases
api_key: $GITHUB_API_KEY
file: build/codeclimate-test-reporter.phar
skip_cleanup: true
on:
tags: true
php: 5.3
condition: "$WITH_HIGHEST == true && $WITH_PHAR == true"
PK )%AVy y .php_csnu W+A in(__DIR__);
$cacheDir = getenv('TRAVIS') ? getenv('HOME') . '/.php-cs-fixer' : __DIR__;
return PhpCsFixer\Config::create()
->setCacheFile($cacheDir . '/.php_cs.cache')
->setFinder($finder)
->setRules(array(
'@PSR2' => true,
'array_syntax' => array(
'syntax' => 'long',
),
));
PK )%AVcF .github/CONTRIBUTING.mdnu W+A # CONTRIBUTING
We're using [Travis CI](https://travis-ci.com) as a continuous integration system.
For details, see [`.travis.yml`](../.travis.yml).
## Tests
We're using [`phpunit/phpunit`](https://github.com/sebastianbergmann/phpunit) to drive the development.
Run
```
$ composer test
```
to run all the tests.
## Coding Standards
We are using [`friendsofphp/php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to enforce coding standards.
Run
```
$ composer cs
```
to automatically fix coding standard violations.
PK )%AVq[l l .github/ISSUE_TEMPLATE.mdnu W+A #### Steps required to reproduce the problem
1.
2.
3.
#### Expected Result
*
#### Actual Result
*
PK )%AVQёj j .github/PULL_REQUEST_TEMPLATE.mdnu W+A This PR
* [ ]
* [ ] has tests
* [ ] updates changelog if appropriate
Follows #.
Related to #.
Fixes #.
PK )%AVR[ composer/bin/test-reporternu W+A #!/usr/bin/env php
run();
PK )%AVWky7 7 box.jsonnu W+A {
"chmod": "0755",
"compression": "GZ",
"alias": "codeclimate-test-reporter.phar",
"directories": [
"src"
],
"compactors": [
"Herrera\\Box\\Compactor\\Php"
],
"extract": false,
"intercept": true,
"files": [
"LICENSE"
],
"finder": [
{
"name": [
"*.php",
"*.pem"
],
"exclude": [
"bin",
"tests",
"Tests"
],
"in": [
"vendor"
]
}
],
"git-version": "package_version",
"main": "phar/bin/main.php",
"metadata": "The code climate php test reporter",
"output": "build/codeclimate-test-reporter.phar",
"shebang": "#!/usr/bin/env php",
"stub": true
}
PK )%AV
composer.jsonnu W+A {
"name": "codeclimate/php-test-reporter",
"description": "PHP client for reporting test coverage to Code Climate",
"keywords": [
"codeclimate",
"coverage"
],
"homepage": "https://github.com/codeclimate/php-test-reporter",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Code Climate",
"email": "hello@codeclimate.com",
"homepage": "https://codeclimate.com"
}
],
"config": {
"sort-packages": true
},
"require": {
"php": "^5.3 || ^7.0",
"ext-curl": "*",
"padraic/phar-updater": "^1.0",
"psr/log": "^1.0",
"satooshi/php-coveralls": "^1.0",
"symfony/console": "^2.0 || ^3.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.0.0",
"phpunit/phpunit": "^4.8.31"
},
"autoload": {
"psr-4": {
"CodeClimate\\PhpTestReporter\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"CodeClimate\\PhpTestReporter\\Tests\\": "tests/"
}
},
"bin": [
"composer/bin/test-reporter"
],
"scripts": {
"box": [
"composer install --no-dev --prefer-dist",
"curl -LSs https://box-project.github.io/box2/installer.php | php",
"php box.phar --version",
"php box.phar build -v"
],
"cs": [
"composer install --prefer-dist",
"php-cs-fixer fix --config=.php_cs --verbose --diff"
],
"test": [
"composer install --prefer-dist",
"phpunit --configuration=phpunit.xml.dist"
]
},
"extra": {
"branch-alias": {
"dev-master": "0.3.x-dev"
}
}
}
PK )%AV֖&\ CHANGELOG.mdnu W+A # Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a CHANGELOG](http://keepachangelog.com).
## [Unreleased](https://github.com/codeclimate/php-test-reporter/compare/v0.4.4...HEAD)
(add details here)
## [v0.4.4](https://github.com/codeclimate/php-test-reporter/compare/v0.4.3...v0.4.4)
### Fixed
- Format Gitlab CI payloads in the same way as we do in other test reporters ([#116](https://github.com/codeclimate/php-test-reporter/pull/116))
## [v0.4.3](https://github.com/codeclimate/php-test-reporter/compare/v0.4.2...v0.4.3)
### Added
- Added support for Gitlab CI ([#113](https://github.com/codeclimate/php-test-reporter/pull/113))
### Fixed
- Restore compatibility with PHP 5.3 ([@localheinz])
## [v0.4.2](https://github.com/codeclimate/php-test-reporter/compare/v0.4.1...v0.4.2)
### Fixed
- Fix bug in payload structure ([@localheinz])
## [v0.4.1](https://github.com/codeclimate/php-test-reporter/compare/v0.4.0...v0.4.1)
- Internal fixes to code, documentation, and packaging ([@localheinz])
## v0.4.0
### Added
- Executable .phar file for download
- `upload` command (PHAR only) - same as calling the tool without a command when installed via composer.
- `self-update` / `selfupdate` command (PHAR only)
- `rollback` command (PHAR only)
- [Installation / Usage](./README.md) / [Distribution instructions](./DEVELOPING.md) for the PHAR tool
[@localheinz]: https://github.com/localheinz
PK )%AVT{
DEVELOPING.mdnu W+A # Developing
## Get the source
$ git clone https://github.com/codeclimate/php-test-reporter
## Install dependencies
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar update -o -v
## Run the tests
$ ./vendor/bin/phpunit
### With HTML coverage output:
$ ./vendor/bin/phpunit --coverage-html=build/logs/coverage
## Build the PHAR tool
# Create a new git tag (optional)
$ git tag v1.x.x -m 'Version 1.x.x'
# Build the PHAR using box project
$ ./vendor/bin/box build
## Distribute the PHAR tool
### With verification and compatibility for phar.io / PhiVE
* [Create a GPG key](https://phar.io/howto/generate-gpg-key.html) (Should be the repositoy's maintainer one)
* [Create a signature and upload to Github](https://phar.io/howto/sign-and-upload-to-github.html)
### Without verification
* Go to the [releases section on Github](https://github.com/codeclimate/php-test-reporter/releases)
* Click "Edit" on the latest tag/release
* Add the `codeclimate-test-reporter.phar` in the "Attach binaries..." section
* Click "Update release"
## Contribute
* Submit PRs to: https://github.com/codeclimate/php-test-reporter
* *Note*: all changes and fixes must have appropriate test coverage.
PK )%AVܽ tests/files/clover.xmlnu W+A
PK )%AV5fh h tests/files/test.phpnu W+A message = 'hoge';
}
}
PK )%AVCD D - tests/Unit/TestReporter/Entity/CiInfoTest.phpnu W+A 'bar',
);
$info = new CiInfo($server);
$expected = array();
$this->assertSame($expected, $info->toArray());
}
public function testToArrayReturnsTravisCiProperties()
{
$branch = 'fix/test';
$buildIdentifier = 9000;
$pullRequest = false;
$server = array(
'TRAVIS' => true,
'TRAVIS_BRANCH' => $branch,
'TRAVIS_JOB_ID' => $buildIdentifier,
'TRAVIS_PULL_REQUEST' => $pullRequest,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'travis-ci',
'branch' => $branch,
'build_identifier' => $buildIdentifier,
'pull_request' => $pullRequest,
);
$this->assertEquals($expected, $info->toArray());
}
public function testToArrayReturnsSemaphoreProperties()
{
$branch = 'fix/test';
$buildIdentifier = 9000;
$server = array(
'SEMAPHORE' => true,
'BRANCH_NAME' => $branch,
'SEMAPHORE_BUILD_NUMBER' => $buildIdentifier,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'semaphore',
'branch' => $branch,
'build_identifier' => $buildIdentifier,
);
$this->assertEquals($expected, $info->toArray());
}
public function testToArrayReturnsJenkinsProperties()
{
$branch = 'fix/test';
$buildIdentifier = 9000;
$buildUrl = 'http://example.orf/foo/bar';
$commitSha = \sha1('foo');
$server = array(
'JENKINS_URL' => 'http://example.org',
'BUILD_NUMBER' => $buildIdentifier,
'BUILD_URL' => $buildUrl,
'GIT_BRANCH' => $branch,
'GIT_COMMIT' => $commitSha,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'jenkins',
'branch' => $branch,
'build_identifier' => $buildIdentifier,
'build_url' => $buildUrl,
'commit_sha' => $commitSha,
);
$this->assertEquals($expected, $info->toArray());
}
public function testToArrayReturnsTddiumProperties()
{
$sessionId = 9000;
$workerId = 12;
$server = array(
'TDDIUM' => true,
'TDDIUM_SESSION_ID' => $sessionId,
'TDDIUM_TID' => $workerId,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'tddium',
'build_identifier' => $sessionId,
'worker_id' => $workerId,
);
$this->assertEquals($expected, $info->toArray());
}
/**
* @dataProvider providerCodeshipName
*/
public function testToArrayReturnsCodeshipProperties($ciName)
{
$branch = 'fix/test';
$buildIdentifier = 9000;
$buildUrl = 'http://example.orf/foo/bar';
$commitSha = \sha1('foo');
$server = array(
'CI_NAME' => $ciName,
'CI_BRANCH' => $branch,
'CI_COMMIT_ID' => $commitSha,
'CI_BUILD_NUMBER' => $buildIdentifier,
'CI_BUILD_URL' => $buildUrl,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'codeship',
'build_identifier' => $buildIdentifier,
'build_url' => $buildUrl,
'branch' => $branch,
'commit_sha' => $commitSha,
);
$this->assertEquals($expected, $info->toArray());
}
/**
* @return array
*/
public function providerCodeshipName()
{
$names = array(
'codeship',
'CODESHIP',
'best-codeship-3000',
'best-CODESHIP-3000',
);
return \array_map(function ($name) {
return array(
$name,
);
}, $names);
}
public function testToArrayReturnsBuildkiteProperties()
{
$branch = 'fix/test';
$buildIdentifier = 9000;
$buildUrl = 'http://example.orf/foo/bar';
$commitSha = \sha1('foo');
$pullRequest = false;
$server = array(
'BUILDKITE' => true,
'BUILDKITE_BRANCH' => $branch,
'BUILDKITE_BUILD_ID' => $buildIdentifier,
'BUILDKITE_BUILD_URL' => $buildUrl,
'BUILDKITE_COMMIT' => $commitSha,
'BUILDKITE_PULL_REQUEST' => $pullRequest,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'buildkite',
'build_identifier' => $buildIdentifier,
'build_url' => $buildUrl,
'branch' => $branch,
'commit_sha' => $commitSha,
'pull_request' => $pullRequest,
);
$this->assertEquals($expected, $info->toArray());
}
public function testToArrayReturnsGitlabCiProperties()
{
$branch = 'fix/test';
$buildIdentifier = 9000;
$commitSha = \sha1('foo');
$server = array(
'CI' => true,
'GITLAB_CI' => true,
'CI_BUILD_REF' => $commitSha,
'CI_BUILD_REF_NAME' => $branch,
'CI_BUILD_ID' => $buildIdentifier,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'gitlab-ci',
'build_identifier' => $buildIdentifier,
'branch' => $branch,
'commit_sha' => $commitSha,
);
$this->assertEquals($expected, $info->toArray());
}
public function testToArrayReturnsWerckerProperties()
{
$branch = 'fix/test';
$buildIdentifier = 9000;
$buildUrl = 'http://example.orf/foo/bar';
$commitSha = \sha1('foo');
$server = array(
'WERCKER' => true,
'WERCKER_BUILD_ID' => $buildIdentifier,
'WERCKER_BUILD_URL' => $buildUrl,
'WERCKER_GIT_BRANCH' => $branch,
'WERCKER_GIT_COMMIT' => $commitSha,
);
$info = new CiInfo($server);
$expected = array(
'name' => 'wercker',
'build_identifier' => $buildIdentifier,
'build_url' => $buildUrl,
'branch' => $branch,
'commit_sha' => $commitSha,
);
$this->assertEquals($expected, $info->toArray());
}
}
PK )%AVE E tests/Unit/ApplicationTest.phpnu W+A srcDir = realpath(__DIR__ . '/../../../../CodeClimateTestReporter');
$this->setupProject();
$this->setupEnvironment();
}
/**
* @test
*/
public function shouldExecuteSuccessfully()
{
$app = new Application($this->srcDir, 'PHP Test Reporter', '1.0.0');
$app->setAutoExit(false);
$tester = new ApplicationTester($app);
$status = $tester->run(array( '--stdout' => true ));
$this->assertEquals(0, $status);
}
private function setupProject()
{
shell_exec("rm -rf " . static::PROJECT_DIR);
mkdir(static::PROJECT_DIR . "/build/logs", 0755, true);
copy("tests/files/test.php", static::PROJECT_DIR . "/test.php");
copy("tests/files/test.php", static::PROJECT_DIR . "/test2.php");
copy("tests/files/clover.xml", static::PROJECT_DIR . "/build/logs/clover.xml");
chdir(static::PROJECT_DIR);
shell_exec("git init");
shell_exec("git add test.php test2.php");
shell_exec("git commit -m 'Initial commit'");
shell_exec("git remote add origin git@github.com:foo/bar.git");
}
private function setupEnvironment()
{
$_SERVER["CODECLIMATE_REPO_TOKEN"] = 'abc123';
$_SERVER["TRAVIS"] = "1";
$_SERVER["TRAVIS_BRANCH"] = "master";
$_SERVER["TRAVIS_JOB_ID"] = "1";
$_SERVER["TRAVIS_PULL_REQUEST"] = "fb-feature";
}
}
PK )%AV .codeclimate.ymlnu W+A ---
engines:
duplication:
enabled: true
config:
languages:
- php
phpcodesniffer:
enabled: true
phpmd:
enabled: true
checks:
CleanCode/ElseExpression:
enabled: false
Controversial/Superglobals:
enabled: false
exclude_fingerprints:
# High complexity in CiInfo#toArray()
- 8f1ff5077ea52a5fee818bde73a0dbb7
- efc665f3aa41cbbd0bbd0ec9c945a453
ratings:
paths:
- "**.inc"
- "**.module"
- "**.php"
exclude_paths:
- tests/
PK )%AVZ
_ _
.gitignorenu W+A .idea/
.vagrant/
Vagrantfile
build/
vendor/
.php_cs.cache
box.phar
composer.lock
composer.phar
PK )%AVd README.mdnu W+A [![Build Status](https://travis-ci.org/codeclimate/php-test-reporter.svg?branch=master)](https://travis-ci.org/codeclimate/php-test-reporter)
[![Code Climate](https://codeclimate.com/github/codeclimate/php-test-reporter.svg)](https://codeclimate.com/github/codeclimate/php-test-reporter)
[![Test Coverage](https://codeclimate.com/github/codeclimate/php-test-reporter/badges/coverage.svg)](https://codeclimate.com/github/codeclimate/php-test-reporter/coverage)
# codeclimate-test-reporter
Collects test coverage data from your PHP test suite and sends it to
Code Climate's hosted, automated code review service.
Code Climate - https://codeclimate.com
**Important:** If you encounter an error involving SSL certificates, see the **Known Issue: SSL Certificate Error** section below.
# Important FYIs
Across the many different testing frameworks, setups, and environments, there are lots of variables at play. Before setting up test coverage, it's important to understand what we do and do not currently support:
* **Single payload:** We currently only support a single test coverage payload per commit. If you run your tests in multiple steps, or via parallel tests, Code Climate will only process the first payload that we receive. If you are using a CI, be sure to check if you are running your tests in a parallel mode.
**Note:** There is one exception to this rule. We've specifically built an integration with [Solano Labs](https://www.solanolabs.com/) to support parallel tests.
**Note:** If you've configured Code Climate to analyze multiple languages in the same repository (e.g., Ruby and JavaScript), we can nonetheless only process test coverage information for one of these languages. We'll process the first payload that we receive.
* **Invalid File Paths:** By default, our test reporters expect your application to exist at the root of your repository. If this is not the case, the file paths in your test coverage payload will not match the file paths that Code Climate expects.
## Requirements
There are several requirements you'll need in order to use the PHP test reporter on your system:
- [PHPUnit](http://phpunit.de)
- [Xdebug](http://xdebug.org)
- [Composer](http://getcomposer.org)
The test reporter uses the [PHPUnit](http://phpunit.de) testing tool to generate [code coverage](http://en.wikipedia.org/wiki/Code_coverage) information. These results show how much of your application's code is being executed by your unit tests. PHPUnit can't generate this information on its own though - it needs another tool, [Xdebug](http://xdebug.org). This is *not* included as a part of the PHPUnit (or PHP) install by default so you'll need to install it yourself.
Xdebug is installed as an extension to PHP, not a library. You can find more information about installing the tool via PECL [on the project website](http://xdebug.org/docs/install).
If you execute your PHPUnit tests with the `--coverage-clover` option and receive the message "The Xdebug extension is not loaded. No code coverage will be generated." you will need to visit the Xdebug website and install the extension. If you do not, you'll most likely get an error something like this:
```
PHP Warning: simplexml_load_file(): I/O warning : failed to load external entity "[...]/build/logs/clover.xml" in [...]/vendor/satooshi/php-coveralls/src/Contrib/Bundle/CoverallsV1Bundle/Api/Jobs.php on line 52
```
## Installation
This package requires a user, but not necessarily a paid account, on
Code Climate, so if you don't have one the first step is to signup at:
https://codeclimate.com.
### Via composer
To install php-test-reporter with Composer run the following command.
```shell
$ composer require codeclimate/php-test-reporter --dev
```
This will get you the latest version of the reporter and install it. If you do want the master, untagged, version you may use the command below:
```shell
$ composer require codeclimate/php-test-reporter:@dev --dev
```
### As PHAR tool
Checkout the [latest release here](https://github.com/codeclimate/php-test-reporter/releases) and replace `X.X.X` with the latest version.
```shell
$ RELEASE=X.X.X
$ wget -c "https://github.com/codeclimate/php-test-reporter/releases/download/$RELEASE/codeclimate-test-reporter.phar"
```
## Usage
- Generate coverage data to `build/logs/clover.xml`
Add the following to phpunit.xml.dist:
```xml
...
...
```
Or invoke `phpunit` as follows:
```shell
$ phpunit --coverage-clover build/logs/clover.xml
```
- Specifying your repo token as an environment variable, invoke the
test-reporter:
```shell
$ CODECLIMATE_REPO_TOKEN="..." vendor/bin/test-reporter
# ... or via PHAR ...
$ CODECLIMATE_REPO_TOKEN="..." codeclimate-test-reporter.phar upload
```
The `CODECLIMATE_REPO_TOKEN` value is provided after you add your repo
to your Code Climate account by clicking on "Setup Test Coverage" on the
right hand side of your feed.
Please contact hello@codeclimate.com if you need any assistance setting
this up.
## Troubleshooting
If you're having trouble setting up or working with our test coverage feature, [see our detailed help doc](http://docs.codeclimate.com/article/220-help-im-having-trouble-with-test-coverage), which covers the most common issues encountered.
## Known Issue: SSL Certificate Error
If you encounter an error involving SSL certificates when trying to report
coverage data from your CI server, you can work around it by manually posting
the data via `curl`:
```yaml
after_script:
- CODECLIMATE_REPO_TOKEN="..." bin/test-reporter --stdout > codeclimate.json
- "curl -X POST -d @codeclimate.json -H 'Content-Type: application/json' -H 'User-Agent: Code Climate (PHP Test Reporter v0.1.1)' https://codeclimate.com/test_reports"
```
**Note:** In the command above, you may need to change `bin/test-reporter` to `vendor/bin/test-reporter`, depending on your project's directory structure.
More details can be found in [this issue][issue].
[issue]: https://github.com/codeclimate/php-test-reporter/issues/3
## Contributions
Patches, bug fixes, feature requests, and pull requests are welcome on
the GitHub page for this project:
https://github.com/codeclimate/php-test-reporter
This package is maintained by Bryan Helmkamp (bryan@codeclimate.com).
For more details, see [`CONTRIBUTING.md`](.github/CONTRIBUTING.md).
## Copyright
See LICENSE.txt
Portions of the implementation were inspired by the php-coveralls
project.
PK )%AV% f src/Constants/Version.phpnu W+A setRootDir($rootDir);
$this->setCloverPaths($paths);
foreach ($this->getCloverPaths() as $path) {
if (file_exists($path)) {
$config->addCloverXmlPath($path);
} else {
$config->addCloverXmlPath($rootDir . DIRECTORY_SEPARATOR . $path);
}
}
$this->api = new Jobs($config);
}
/**
* Set a list of Clover XML paths
*
* @param string[] $paths Array of relative paths to Clovers XML files
*/
public function setCloverPaths($paths)
{
$this->cloverPaths = $paths;
}
/**
* Get a list of Clover XML paths
* @return string[] Array of relative Clover XML file locations
*/
public function getCloverPaths()
{
return $this->cloverPaths;
}
/**
* @return JsonFile
*/
public function collectAsJson()
{
$cloverJsonFile = $this->api->collectCloverXml()->getJsonFile();
$jsonFile = new JsonFile();
$jsonFile->setRunAt($cloverJsonFile->getRunAt());
foreach ($cloverJsonFile->getSourceFiles() as $sourceFile) {
$jsonFile->addSourceFile($sourceFile);
}
return $jsonFile;
}
}
PK )%AV
J J src/TestReporter/ApiClient.phpnu W+A apiHost = $_SERVER["CODECLIMATE_API_HOST"];
}
}
/**
* Send the given JSON as a request to the CodeClimate Server
*
* @param Entity\JsonFile $json JSON data
*
* @return \stdClass Response object with (code, message, headers & body properties)
*/
public function send(Entity\JsonFile $json)
{
$response = new \stdClass;
$payload = (string)$json;
$options = array(
'http' => array(
'method' => 'POST',
'header' => array(
'Host: codeclimate.com',
'Content-Type: application/json',
'User-Agent: Code Climate (PHP Test Reporter v' . Version::VERSION . ')',
'Content-Length: ' . strlen($payload),
),
'content' => $payload,
"timeout" => 10,
),
);
$context = stream_context_create($options);
$url = $this->apiHost . '/test_reports';
if ($stream = @fopen($url, 'r', false, $context)) {
$meta = stream_get_meta_data($stream);
$rawResponse = implode("\r\n", $meta['wrapper_data']) . "\r\n\r\n" . stream_get_contents($stream);
fclose($stream);
if (!empty($rawResponse)) {
$response = $this->buildResponse($response, $rawResponse);
}
} else {
$response = $this->sendWithCurl($url, $payload);
}
return $response;
}
/**
* Send the given JSON as a request to the CodeClimate Server using cURL.
* Added as a backup if PHP Streams method fails (e.g. if allow_url_fopen is disabled).
*
* @param string $url The API end-point URL
* @param string $payload The request payload as a JSON-encoded string
*
* @return \stdClass Response object with (code, message, headers & body properties)
*/
private function sendWithCurl($url, $payload)
{
$response = new \stdClass;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt(
$curl,
CURLOPT_HTTPHEADER,
array(
'Host: codeclimate.com',
'Content-Type: application/json',
'User-Agent: Code Climate (PHP Test Reporter v' . Version::VERSION . ')',
'Content-Length: ' . strlen($payload),
)
);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
$rawResponse = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if (!empty($rawResponse)) {
$response = $this->buildResponse($response, $rawResponse);
} else {
$error = error_get_last();
preg_match('/(\d{3})/', $error['message'], $match);
$errorCode = 500;
if (isset($match[1])) {
$errorCode = $match[1];
} elseif ($status) {
$errorCode = $status;
}
$response->code = $errorCode;
$response->message = $error['message'];
$response->headers = array( );
$response->body = null;
}
return $response;
}
/**
* Build the response object from the HTTP results
*
* @param \stdClass $response Standard object
* @param string $body HTTP response contents
*
* @return \stdClass Populated class object
*/
private function buildResponse($response, $body)
{
list($response->headers, $response->body) = explode("\r\n\r\n", $body, 2);
$response->headers = explode("\r\n", $response->headers);
list(, $response->code, $response->message) = explode(' ', $response->headers[0], 3);
return $response;
}
}
PK )%AV
0n $ src/TestReporter/Entity/JsonFile.phpnu W+A false,
"run_at" => $this->getRunAt(),
"repo_token" => $this->getRepoToken(),
"environment" => $this->getEnvironment(),
"git" => $this->collectGitInfo(),
"ci_service" => $this->collectCiServiceInfo(),
"source_files" => $this->collectSourceFiles(),
);
}
public function getRunAt()
{
return strtotime(parent::getRunAt());
}
public function getRepoToken()
{
return $_SERVER["CODECLIMATE_REPO_TOKEN"];
}
/**
* @return array
*/
protected function getEnvironment()
{
return array(
"pwd" => getcwd(),
"package_version" => Version::VERSION,
);
}
/**
* @return array
*/
protected function collectGitInfo()
{
$command = new GitCommand();
return array(
"head" => $command->getHead(),
"branch" => $command->getBranch(),
"committed_at" => $command->getCommittedAt(),
);
}
/**
* @return array
*/
protected function collectCiServiceInfo()
{
$ciInfo = new CiInfo($_SERVER);
return $ciInfo->toArray();
}
/**
* @return array
*/
protected function collectSourceFiles()
{
$data = array();
foreach ($this->getSourceFiles() as $sourceFile) {
$data[] = array(
"name" => $sourceFile->getName(),
"coverage" => json_encode($sourceFile->getCoverage()),
"blob_id" => $this->calculateBlobId($sourceFile),
);
}
return $data;
}
/**
* @param SourceFile $sourceFile
* @return string
*/
protected function calculateBlobId(SourceFile $sourceFile)
{
$content = file_get_contents($sourceFile->getPath());
$header = "blob " . strlen($content) . "\0";
return sha1($header . $content);
}
}
PK )%AV] " src/TestReporter/Entity/CiInfo.phpnu W+A info = $this->infoFrom($server);
}
/**
* @return array
*/
public function toArray()
{
return $this->info;
}
/**
* @param array $server
* @return array
*/
private function infoFrom(array $server)
{
if (isset($server["TRAVIS"])) {
return $this->travisProperties($server);
}
if (isset($server["CIRCLECI"])) {
return $this->circleProperties($server);
}
if (isset($server["SEMAPHORE"])) {
return $this->semaphoreProperties($server);
}
if (isset($server["JENKINS_URL"])) {
return $this->jenkinsProperties($server);
}
if (isset($server["TDDIUM"])) {
return $this->tddiumProperties($server);
}
if (isset($server["CI_NAME"]) && false !== stripos($server["CI_NAME"], 'codeship')) {
return $this->codeshipProperties($server);
}
if (isset($server["BUILDKITE"])) {
return $this->buildkiteProperties($server);
}
if (isset($server["WERCKER"])) {
return $this->werckerProperties($server);
}
if (isset($server["GITLAB_CI"])) {
return $this->gitlabCiProperties($server);
}
return array();
}
/**
* @param array $server
* @return array
*/
protected function travisProperties(array $server)
{
return array(
"name" => "travis-ci",
"branch" => $server["TRAVIS_BRANCH"],
"build_identifier" => $server["TRAVIS_JOB_ID"],
"pull_request" => $server["TRAVIS_PULL_REQUEST"],
);
}
/**
* @param array $server
* @return array
*/
protected function circleProperties(array $server)
{
return array(
"name" => "circleci",
"build_identifier" => $server["CIRCLE_BUILD_NUM"],
"branch" => $server["CIRCLE_BRANCH"],
"commit_sha" => $server["CIRCLE_SHA1"],
);
}
/**
* @param array $server
* @return array
*/
protected function semaphoreProperties(array $server)
{
return array(
"name" => "semaphore",
"branch" => $server["BRANCH_NAME"],
"build_identifier" => $server["SEMAPHORE_BUILD_NUMBER"],
);
}
/**
* @param array $server
* @return array
*/
protected function jenkinsProperties(array $server)
{
return array(
"name" => "jenkins",
"build_identifier" => $server["BUILD_NUMBER"],
"build_url" => $server["BUILD_URL"],
"branch" => $server["GIT_BRANCH"],
"commit_sha" => $server["GIT_COMMIT"],
);
}
/**
* @param array $server
* @return array
*/
protected function tddiumProperties(array $server)
{
return array(
"name" => "tddium",
"build_identifier" => $server["TDDIUM_SESSION_ID"],
"worker_id" => $server["TDDIUM_TID"],
);
}
/**
* @param array $server
* @return array
*/
protected function codeshipProperties(array $server)
{
return array(
"name" => "codeship",
"build_identifier" => $server["CI_BUILD_NUMBER"],
"build_url" => $server["CI_BUILD_URL"],
"branch" => $server["CI_BRANCH"],
"commit_sha" => $server["CI_COMMIT_ID"],
);
}
/**
* @param array $server
* @return array
*/
protected function buildkiteProperties(array $server)
{
return array(
"name" => "buildkite",
"build_identifier" => $server["BUILDKITE_BUILD_ID"],
"build_url" => $server["BUILDKITE_BUILD_URL"],
"branch" => $server["BUILDKITE_BRANCH"],
"commit_sha" => $server["BUILDKITE_COMMIT"],
"pull_request" => $server["BUILDKITE_PULL_REQUEST"],
);
}
/**
* @param array $server
* @return array
*/
protected function werckerProperties(array $server)
{
return array(
"name" => "wercker",
"build_identifier" => $server["WERCKER_BUILD_ID"],
"build_url" => $server["WERCKER_BUILD_URL"],
"branch" => $server["WERCKER_GIT_BRANCH"],
"commit_sha" => $server["WERCKER_GIT_COMMIT"],
);
}
/**
* @param array $server
* @return array
*/
protected function gitlabCiProperties(array $server)
{
return array(
"name" => "gitlab-ci",
"build_identifier" => $server["CI_BUILD_ID"],
"branch" => $server["CI_BUILD_REF_NAME"],
"commit_sha" => $server["CI_BUILD_REF"],
);
}
}
PK )%AVI; src/System/Git/GitCommand.phpnu W+A createCommand("log -1 --pretty=format:'%H'");
return current($this->executeCommand($command));
}
/**
* @return string|null
*/
public function getBranch()
{
$command = $this->createCommand("branch");
$branches = $this->executeCommand($command);
foreach ($branches as $branch) {
if ($branch[0] == "*") {
return str_replace("* ", "", $branch);
}
}
return null;
}
/**
* @return int
*/
public function getCommittedAt()
{
$command = $this->createCommand("log -1 --pretty=format:'%ct'");
return (int)current($this->executeCommand($command));
}
}
PK )%AV. src/Application.phpnu W+A
*/
class Application extends BaseApplication
{
// internal method
protected function getCommandName(InputInterface $input)
{
return 'upload';
}
protected function getDefaultCommands()
{
// Keep the core default commands to have the HelpCommand
// which is used when using the --help option
$defaultCommands = parent::getDefaultCommands();
$defaultCommands[] = $this->createUploadCommand();
return $defaultCommands;
}
/**
* Create UploadCommand.
* @return UploadCommand
*/
protected function createUploadCommand()
{
return new UploadCommand('upload');
}
// accessor
public function getDefinition()
{
$inputDefinition = parent::getDefinition();
// clear out the normal first argument, which is the command name
$inputDefinition->setArguments();
return $inputDefinition;
}
}
PK )%AV$a a ' src/ConsoleCommands/RollbackCommand.phpnu W+A setDescription('Rolls back this PHAR to the previous version.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$input->validate();
$logger = new ConsoleLogger($output);
$updater = new Updater(null, false, Updater::STRATEGY_GITHUB);
/** @var GithubStrategy $strategy */
$strategy = $updater->getStrategy();
$strategy->setPackageName(PharTool::PACKAGE_NAME);
$strategy->setPharName(PharTool::PHAR_NAME);
$strategy->setCurrentLocalVersion('@package_version@');
if ($updater->rollback()) {
$logger->info('Roll back successful!');
} else {
$logger->alert('Roll back failed.');
}
return 0;
}
}
PK )%AV/mR
R
) src/ConsoleCommands/SelfUpdateCommand.phpnu W+A setAliases(array( 'selfupdate' ));
$this->setDescription('Updates this PHAR to latest version.');
$this->addOption(
'stability',
's',
InputOption::VALUE_OPTIONAL,
sprintf(
'Specify the stability (%s, %s or %s)',
GithubStrategy::STABLE,
GithubStrategy::UNSTABLE,
GithubStrategy::ANY
),
GithubStrategy::STABLE
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = new ConsoleLogger($output);
$updater = new Updater(null, false, Updater::STRATEGY_GITHUB);
/** @var GithubStrategy $strategy */
$strategy = $updater->getStrategy();
$strategy->setPackageName(PharTool::PACKAGE_NAME);
$strategy->setPharName(PharTool::PHAR_NAME);
$strategy->setCurrentLocalVersion('@package_version@');
$stability = $input->getOption('stability');
$strategy->setStability($stability);
try {
if ($updater->hasUpdate()) {
$newVersion = $updater->getNewVersion();
$logger->info(sprintf('The current stable version available is: %s', $newVersion));
$logger->info('Updating...');
if ($updater->update()) {
$logger->info(sprintf('Successful! You now have version %s installed', $newVersion));
}
} elseif (false === $updater->getNewVersion()) {
$logger->alert('There is no stable version available.');
} else {
$logger->info('@package_version@ is the latest stable version.');
}
return 0;
} catch (HttpRequestException $e) {
$logger->alert('Error fetching current version from remote repository.');
return 1;
}
}
}
PK )%AVWYMe % src/ConsoleCommands/UploadCommand.phpnu W+A setDescription('Uploads test report to code climate')
->addOption(
'stdout',
null,
InputOption::VALUE_NONE,
'Do not upload, print JSON payload to stdout'
)
->addOption(
'coverage-report',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Location of clover style CodeCoverage report, as produced by PHPUnit\'s --coverage-clover option.',
array( 'build/logs/clover.xml' )
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$collector = new CoverageCollector($input->getOption('coverage-report'));
$json = $collector->collectAsJson();
if ($input->getOption('stdout')) {
$output->writeln((string)$json);
return 0;
}
$client = new ApiClient();
$response = $client->send($json);
if ($response->code == 200) {
$output->writeln("Test coverage data sent.");
return 0;
}
if ($response->code == 401) {
$output->writeln("Invalid CODECLIMATE_REPO_TOKEN.");
return 1;
}
$output->writeln("Unexpected response: " . $response->code . " " . $response->message);
$output->writeln($response->body);
return 1;
}
}
PK )%AV,X phpunit.xml.distnu W+A PK )%AVN N .travis/travis.shnu W+A PK )%AVNV& LICENSEnu W+A PK )%AVԛk k phar/bin/main.phpnu W+A PK )%AVĭ I .travis.ymlnu W+A PK )%AVy y .php_csnu W+A PK )%AVcF L .github/CONTRIBUTING.mdnu W+A PK )%AVq[l l .github/ISSUE_TEMPLATE.mdnu W+A PK )%AVQёj j c .github/PULL_REQUEST_TEMPLATE.mdnu W+A PK )%AVR[ composer/bin/test-reporternu W+A PK )%AVWky7 7 j# box.jsonnu W+A PK )%AV
&