From 4071b3b26443a83983740002f9aa8123fa72e522 Mon Sep 17 00:00:00 2001 From: Holger Woltersdorf Date: Tue, 19 Jul 2016 22:54:46 +0200 Subject: [PATCH 1/6] Use PSR-4-compatible namespaces --- .gitignore | 5 +- composer.json | 90 +++++++----- composer/bin/test-reporter | 46 +++--- src/Application.php | 85 +++++++++++ .../Bundle/TestReporterBundle/ApiClient.php | 123 ---------------- .../Command/TestReporterCommand.php | 98 ------------- .../Console/Application.php | 91 ------------ .../TestReporterBundle/CoverageCollector.php | 66 --------- .../TestReporterBundle/Entity/CiInfo.php | 125 ---------------- .../TestReporterBundle/Entity/JsonFile.php | 82 ----------- src/ConsoleCommands/TestReporterCommand.php | 100 +++++++++++++ .../Version.php | 3 +- .../Component => }/System/Git/GitCommand.php | 2 +- src/TestReporter/ApiClient.php | 135 ++++++++++++++++++ src/TestReporter/CoverageCollector.php | 72 ++++++++++ src/TestReporter/Entity/CiInfo.php | 133 +++++++++++++++++ src/TestReporter/Entity/JsonFile.php | 85 +++++++++++ .../Console/ApplicationTest.php | 57 -------- tests/Unit/ApplicationTest.php | 58 ++++++++ tests/bootstrap.php | 3 +- 20 files changed, 755 insertions(+), 704 deletions(-) create mode 100644 src/Application.php delete mode 100644 src/CodeClimate/Bundle/TestReporterBundle/ApiClient.php delete mode 100644 src/CodeClimate/Bundle/TestReporterBundle/Command/TestReporterCommand.php delete mode 100644 src/CodeClimate/Bundle/TestReporterBundle/Console/Application.php delete mode 100644 src/CodeClimate/Bundle/TestReporterBundle/CoverageCollector.php delete mode 100644 src/CodeClimate/Bundle/TestReporterBundle/Entity/CiInfo.php delete mode 100644 src/CodeClimate/Bundle/TestReporterBundle/Entity/JsonFile.php create mode 100644 src/ConsoleCommands/TestReporterCommand.php rename src/{CodeClimate/Bundle/TestReporterBundle => Constants}/Version.php (77%) rename src/{CodeClimate/Component => }/System/Git/GitCommand.php (94%) create mode 100644 src/TestReporter/ApiClient.php create mode 100644 src/TestReporter/CoverageCollector.php create mode 100644 src/TestReporter/Entity/CiInfo.php create mode 100644 src/TestReporter/Entity/JsonFile.php delete mode 100644 tests/CodeClimate/Bundle/TestReporterBundle/Console/ApplicationTest.php create mode 100644 tests/Unit/ApplicationTest.php diff --git a/.gitignore b/.gitignore index b6ba778..2fe8804 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ +.idea/ +.vagrant/ +Vagrantfile build/ vendor/ -box.phar -codeclimate-test-reporter.phar composer.lock composer.phar diff --git a/composer.json b/composer.json index 7192486..6b5efea 100644 --- a/composer.json +++ b/composer.json @@ -1,37 +1,57 @@ { - "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" - } - ], - "require": { - "php": ">=5.3", - "ext-curl": "*", - "satooshi/php-coveralls": "1.0.*", - "symfony/console": ">=2.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@stable", - "ext-xdebug": "*" - }, - "autoload": { - "psr-0": { - "CodeClimate\\Component": "src/", - "CodeClimate\\Bundle": "src/" - } - }, - "bin": ["composer/bin/test-reporter"], - "extra": { - "branch-alias": { - "dev-master": "0.3.x-dev" - } - } + "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" + } + ], + "require": { + "php": ">=5.3", + "ext-curl": "*", + "satooshi/php-coveralls": "^1.0", + "symfony/console": "^2.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@stable", + "ext-xdebug": "*", + "tm/tooly-composer-script": "^1.0" + }, + "autoload": { + "psr-4": { + "CodeClimate\\PhpTestReporter\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "CodeClimate\\PhpTestReporter\\Tests\\": "tests/" + } + }, + "bin": [ + "composer/bin/test-reporter" + ], + "scripts": { + "post-install-cmd": "Tooly\\ScriptHandler::installPharTools", + "post-update-cmd": "Tooly\\ScriptHandler::installPharTools" + }, + "extra": { + "branch-alias": { + "dev-master": "0.3.x-dev" + }, + "tools": { + "box": { + "url": "https://github.com/box-project/box2/releases/download/2.7.2/box-2.7.2.phar", + "only-dev": true + } + } + } } diff --git a/composer/bin/test-reporter b/composer/bin/test-reporter index 877de15..b8e2c72 100755 --- a/composer/bin/test-reporter +++ b/composer/bin/test-reporter @@ -1,33 +1,37 @@ #!/usr/bin/env php run(); diff --git a/src/Application.php b/src/Application.php new file mode 100644 index 0000000..c9a6776 --- /dev/null +++ b/src/Application.php @@ -0,0 +1,85 @@ + + */ +class Application extends BaseApplication +{ + /** + * Path to project root directory. + * @var string + */ + private $rootDir; + + /** + * Constructor. + * + * @param string $rootDir Path to project root directory. + * @param string $name The name of the application + * @param string $version The version of the application + */ + public function __construct( $rootDir, $name = 'UNKNOWN', $version = 'UNKNOWN' ) + { + $this->rootDir = $rootDir; + + parent::__construct( $name, $version ); + } + + // internal method + + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Application::getCommandName() + */ + protected function getCommandName( InputInterface $input ) + { + return 'test-reporter'; + } + + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Application::getDefaultCommands() + */ + 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->createTestReporterCommand(); + + return $defaultCommands; + } + + /** + * Create TestReporterCommand. + * @return TestReporterCommand + */ + protected function createTestReporterCommand() + { + $command = new TestReporterCommand(); + $command->setRootDir( $this->rootDir ); + + return $command; + } + + // accessor + + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Application::getDefinition() + */ + public function getDefinition() + { + $inputDefinition = parent::getDefinition(); + // clear out the normal first argument, which is the command name + $inputDefinition->setArguments(); + + return $inputDefinition; + } +} diff --git a/src/CodeClimate/Bundle/TestReporterBundle/ApiClient.php b/src/CodeClimate/Bundle/TestReporterBundle/ApiClient.php deleted file mode 100644 index 018f2e1..0000000 --- a/src/CodeClimate/Bundle/TestReporterBundle/ApiClient.php +++ /dev/null @@ -1,123 +0,0 @@ -apiHost = "https://codeclimate.com"; - - if (isset($_SERVER["CODECLIMATE_API_HOST"])) { - $this->apiHost = $_SERVER["CODECLIMATE_API_HOST"]; - } - - } - - /** - * Send the given JSON as a request to the CodeClimate Server - * - * @param object $json JSON data - * @return \stdClass Response object with (code, message, headers & body properties) - */ - public function send($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); - $raw_response = implode("\r\n", $meta['wrapper_data'])."\r\n\r\n".stream_get_contents($stream); - fclose($stream); - - if (!empty($raw_response)) { - $response = $this->buildResponse($response, $raw_response); - } - } 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); - $raw_response = curl_exec($curl); - - $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); - if (!empty($raw_response)) { - $response = $this->buildResponse($response, $raw_response); - } else { - $error = error_get_last(); - preg_match('/([0-9]{3})/', $error['message'], $match); - $errorCode = (isset($match[1])) ? $match[1] : ($status ? $status : 500); - - $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; - } -} diff --git a/src/CodeClimate/Bundle/TestReporterBundle/Command/TestReporterCommand.php b/src/CodeClimate/Bundle/TestReporterBundle/Command/TestReporterCommand.php deleted file mode 100644 index 4fd439d..0000000 --- a/src/CodeClimate/Bundle/TestReporterBundle/Command/TestReporterCommand.php +++ /dev/null @@ -1,98 +0,0 @@ -setName('test-reporter') - ->setDescription('Code Climate PHP Test Reporter') - ->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') - ); - } - - /** - * {@inheritdoc} - * - * @see \Symfony\Component\Console\Command\Command::execute() - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $ret = 0; - $collector = new CoverageCollector($input->getOption('coverage-report')); - $json = $collector->collectAsJson(); - - if ($input->getOption('stdout')) { - $output->writeln((string)$json); - } else { - $client = new ApiClient(); - $response = $client->send($json); - switch ($response->code) { - case 200: - $output->writeln("Test coverage data sent."); - break; - - case 401: - $output->writeln("Invalid CODECLIMATE_REPO_TOKEN."); - $ret = 1; - break; - - default: - $output->writeln("Unexpected response: ".$response->code." ".$response->message); - $output->writeln($response->body); - $ret = 1; - break; - } - } - - return $ret; - } - - // accessor - - /** - * Set root directory. - * - * @param string $rootDir Path to project root directory. - * - * @return void - */ - public function setRootDir($rootDir) - { - $this->rootDir = $rootDir; - } -} diff --git a/src/CodeClimate/Bundle/TestReporterBundle/Console/Application.php b/src/CodeClimate/Bundle/TestReporterBundle/Console/Application.php deleted file mode 100644 index f810645..0000000 --- a/src/CodeClimate/Bundle/TestReporterBundle/Console/Application.php +++ /dev/null @@ -1,91 +0,0 @@ - - */ -class Application extends BaseApplication -{ - /** - * Path to project root directory. - * - * @var string - */ - private $rootDir; - - /** - * Constructor. - * - * @param string $rootDir Path to project root directory. - * @param string $name The name of the application - * @param string $version The version of the application - */ - public function __construct($rootDir, $name = 'UNKNOWN', $version = 'UNKNOWN') - { - $this->rootDir = $rootDir; - - parent::__construct($name, $version); - } - - // internal method - - /** - * {@inheritdoc} - * - * @see \Symfony\Component\Console\Application::getCommandName() - */ - protected function getCommandName(InputInterface $input) - { - return 'test-reporter'; - } - - /** - * {@inheritdoc} - * - * @see \Symfony\Component\Console\Application::getDefaultCommands() - */ - 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->createTestReporterCommand(); - - return $defaultCommands; - } - - /** - * Create TestReporterCommand. - * - * @return \CodeClimate\Bundle\TestReporterBundle\Command\TestReporterCommand - */ - protected function createTestReporterCommand() - { - $command = new TestReporterCommand(); - $command->setRootDir($this->rootDir); - - return $command; - } - - // accessor - - /** - * {@inheritdoc} - * - * @see \Symfony\Component\Console\Application::getDefinition() - */ - public function getDefinition() - { - $inputDefinition = parent::getDefinition(); - // clear out the normal first argument, which is the command name - $inputDefinition->setArguments(); - - return $inputDefinition; - } -} diff --git a/src/CodeClimate/Bundle/TestReporterBundle/CoverageCollector.php b/src/CodeClimate/Bundle/TestReporterBundle/CoverageCollector.php deleted file mode 100644 index e35326e..0000000 --- a/src/CodeClimate/Bundle/TestReporterBundle/CoverageCollector.php +++ /dev/null @@ -1,66 +0,0 @@ -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 array $paths Array of relative paths to Clovers XML files - */ - public function setCloverPaths($paths) - { - $this->cloverPaths = $paths; - } - - /** - * Get a list of Clover XML paths - * @return array Array of relative Clover XML file locations - */ - public function getCloverPaths() - { - return $this->cloverPaths; - } - 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; - } -} diff --git a/src/CodeClimate/Bundle/TestReporterBundle/Entity/CiInfo.php b/src/CodeClimate/Bundle/TestReporterBundle/Entity/CiInfo.php deleted file mode 100644 index f44431d..0000000 --- a/src/CodeClimate/Bundle/TestReporterBundle/Entity/CiInfo.php +++ /dev/null @@ -1,125 +0,0 @@ -travisProperties(); - } - - if (isset($_SERVER["CIRCLECI"])) { - return $this->circleProperties(); - } - - if (isset($_SERVER["SEMAPHORE"])) { - return $this->semaphoreProperties(); - } - - if (isset($_SERVER["JENKINS_URL"])) { - return $this->jenkinsProperties(); - } - - if (isset($_SERVER["TDDIUM"])) { - return $this->tddiumProperties(); - } - - if (isset($_SERVER["CI_NAME"]) && preg_match('/codeship/i', $_SERVER["CI_NAME"])) { - return $this->codeshipProperties(); - } - - if (isset($_SERVER["BUILDKITE"])) { - return $this->buildkiteProperties(); - } - - if (isset($_SERVER["WERCKER"])) { - return $this->werckerProperties(); - } - - return array(); - } - - protected function travisProperties() - { - return array( - "name" => "travis-ci", - "branch" => $_SERVER["TRAVIS_BRANCH"], - "build_identifier" => $_SERVER["TRAVIS_JOB_ID"], - "pull_request" => $_SERVER["TRAVIS_PULL_REQUEST"] - ); - } - - protected function circleProperties() - { - return array( - "name" => "circleci", - "build_identifier" => $_SERVER["CIRCLE_BUILD_NUM"], - "branch" => $_SERVER["CIRCLE_BRANCH"], - "commit_sha" => $_SERVER["CIRCLE_SHA1"] - ); - } - - protected function semaphoreProperties() - { - return array( - "name" => "semaphore", - "branch" => $_SERVER["BRANCH_NAME"], - "build_identifier" => $_SERVER["SEMAPHORE_BUILD_NUMBER"] - ); - } - - protected function jenkinsProperties() - { - return array( - "name" => "jenkins", - "build_identifier" => $_SERVER["BUILD_NUMBER"], - "build_url" => $_SERVER["BUILD_URL"], - "branch" => $_SERVER["GIT_BRANCH"], - "commit_sha" => $_SERVER["GIT_COMMIT"] - ); - } - - protected function tddiumProperties() - { - return array( - "name" => "tddium", - "build_identifier" => $_SERVER["TDDIUM_SESSION_ID"], - "worker_id" => $_SERVER["TDDIUM_TID"] - ); - } - - protected function codeshipProperties() - { - 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"] - ); - } - - protected function buildkiteProperties() - { - 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"] - ); - } - - protected function werckerProperties() - { - 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"] - ); - } -} diff --git a/src/CodeClimate/Bundle/TestReporterBundle/Entity/JsonFile.php b/src/CodeClimate/Bundle/TestReporterBundle/Entity/JsonFile.php deleted file mode 100644 index c9ec0c8..0000000 --- a/src/CodeClimate/Bundle/TestReporterBundle/Entity/JsonFile.php +++ /dev/null @@ -1,82 +0,0 @@ - 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"]; - } - - protected function getEnvironment() - { - return array( - "pwd" => getcwd(), - "package_version" => Version::VERSION - ); - } - - protected function collectGitInfo() - { - $command = new GitCommand(); - - return array( - "head" => $command->getHead(), - "branch" => $command->getBranch(), - "committed_at" => $command->getCommittedAt() - ); - } - - protected function collectCiServiceInfo() - { - $ciInfo = new CiInfo(); - - return $ciInfo->toArray(); - } - - protected function collectSourceFiles() - { - $sourceFiles = array(); - - foreach ($this->getSourceFiles() as $sourceFile) { - array_push($sourceFiles, array( - "name" => $sourceFile->getName(), - "coverage" => json_encode($sourceFile->getCoverage()), - "blob_id" => $this->calculateBlobId($sourceFile) - )); - } - - return $sourceFiles; - } - - protected function calculateBlobId($sourceFile) - { - $content = file_get_contents($sourceFile->getPath()); - $header = "blob ".strlen($content)."\0"; - - return sha1($header.$content); - } -} diff --git a/src/ConsoleCommands/TestReporterCommand.php b/src/ConsoleCommands/TestReporterCommand.php new file mode 100644 index 0000000..ce923b1 --- /dev/null +++ b/src/ConsoleCommands/TestReporterCommand.php @@ -0,0 +1,100 @@ +setName( 'test-reporter' ) + ->setDescription( 'Code Climate PHP Test Reporter' ) + ->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.', + [ 'build/logs/clover.xml' ] + ); + } + + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Command\Command::execute() + */ + protected function execute( InputInterface $input, OutputInterface $output ) + { + $ret = 0; + $collector = new CoverageCollector( $input->getOption( 'coverage-report' ) ); + $json = $collector->collectAsJson(); + + if ( $input->getOption( 'stdout' ) ) + { + $output->writeln( (string)$json ); + } + else + { + $client = new ApiClient(); + $response = $client->send( $json ); + switch ( $response->code ) + { + case 200: + $output->writeln( "Test coverage data sent." ); + break; + + case 401: + $output->writeln( "Invalid CODECLIMATE_REPO_TOKEN." ); + $ret = 1; + break; + + default: + $output->writeln( "Unexpected response: " . $response->code . " " . $response->message ); + $output->writeln( $response->body ); + $ret = 1; + break; + } + } + + return $ret; + } + + // accessor + + /** + * Set root directory. + * + * @param string $rootDir Path to project root directory. + * + * @return void + */ + public function setRootDir( $rootDir ) + { + $this->rootDir = $rootDir; + } +} diff --git a/src/CodeClimate/Bundle/TestReporterBundle/Version.php b/src/Constants/Version.php similarity index 77% rename from src/CodeClimate/Bundle/TestReporterBundle/Version.php rename to src/Constants/Version.php index 103e7d8..b079856 100644 --- a/src/CodeClimate/Bundle/TestReporterBundle/Version.php +++ b/src/Constants/Version.php @@ -1,5 +1,6 @@ apiHost = "https://codeclimate.com"; + + if ( isset($_SERVER["CODECLIMATE_API_HOST"]) ) + { + $this->apiHost = $_SERVER["CODECLIMATE_API_HOST"]; + } + } + + /** + * Send the given JSON as a request to the CodeClimate Server + * + * @param object $json JSON data + * + * @return \stdClass Response object with (code, message, headers & body properties) + */ + public function send( $json ) + { + $response = new \stdClass; + $payload = (string)$json; + $options = [ + 'http' => [ + 'method' => 'POST', + 'header' => [ + '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 ); + $raw_response = implode( "\r\n", $meta['wrapper_data'] ) . "\r\n\r\n" . stream_get_contents( $stream ); + fclose( $stream ); + + if ( !empty($raw_response) ) + { + $response = $this->buildResponse( $response, $raw_response ); + } + } + 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, + [ + '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 ); + $raw_response = curl_exec( $curl ); + + $status = curl_getinfo( $curl, CURLINFO_HTTP_CODE ); + if ( !empty($raw_response) ) + { + $response = $this->buildResponse( $response, $raw_response ); + } + else + { + $error = error_get_last(); + preg_match( '/([0-9]{3})/', $error['message'], $match ); + $errorCode = (isset($match[1])) ? $match[1] : ($status ? $status : 500); + + $response->code = $errorCode; + $response->message = $error['message']; + $response->headers = [ ]; + $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; + } +} diff --git a/src/TestReporter/CoverageCollector.php b/src/TestReporter/CoverageCollector.php new file mode 100644 index 0000000..9ba39b2 --- /dev/null +++ b/src/TestReporter/CoverageCollector.php @@ -0,0 +1,72 @@ +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 array $paths Array of relative paths to Clovers XML files + */ + public function setCloverPaths( $paths ) + { + $this->cloverPaths = $paths; + } + + /** + * Get a list of Clover XML paths + * @return array Array of relative Clover XML file locations + */ + public function getCloverPaths() + { + return $this->cloverPaths; + } + + 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; + } +} diff --git a/src/TestReporter/Entity/CiInfo.php b/src/TestReporter/Entity/CiInfo.php new file mode 100644 index 0000000..3d5a7a8 --- /dev/null +++ b/src/TestReporter/Entity/CiInfo.php @@ -0,0 +1,133 @@ +travisProperties(); + } + + if ( isset($_SERVER["CIRCLECI"]) ) + { + return $this->circleProperties(); + } + + if ( isset($_SERVER["SEMAPHORE"]) ) + { + return $this->semaphoreProperties(); + } + + if ( isset($_SERVER["JENKINS_URL"]) ) + { + return $this->jenkinsProperties(); + } + + if ( isset($_SERVER["TDDIUM"]) ) + { + return $this->tddiumProperties(); + } + + if ( isset($_SERVER["CI_NAME"]) && preg_match( '/codeship/i', $_SERVER["CI_NAME"] ) ) + { + return $this->codeshipProperties(); + } + + if ( isset($_SERVER["BUILDKITE"]) ) + { + return $this->buildkiteProperties(); + } + + if ( isset($_SERVER["WERCKER"]) ) + { + return $this->werckerProperties(); + } + + return [ ]; + } + + protected function travisProperties() + { + return [ + "name" => "travis-ci", + "branch" => $_SERVER["TRAVIS_BRANCH"], + "build_identifier" => $_SERVER["TRAVIS_JOB_ID"], + "pull_request" => $_SERVER["TRAVIS_PULL_REQUEST"], + ]; + } + + protected function circleProperties() + { + return [ + "name" => "circleci", + "build_identifier" => $_SERVER["CIRCLE_BUILD_NUM"], + "branch" => $_SERVER["CIRCLE_BRANCH"], + "commit_sha" => $_SERVER["CIRCLE_SHA1"], + ]; + } + + protected function semaphoreProperties() + { + return [ + "name" => "semaphore", + "branch" => $_SERVER["BRANCH_NAME"], + "build_identifier" => $_SERVER["SEMAPHORE_BUILD_NUMBER"], + ]; + } + + protected function jenkinsProperties() + { + return [ + "name" => "jenkins", + "build_identifier" => $_SERVER["BUILD_NUMBER"], + "build_url" => $_SERVER["BUILD_URL"], + "branch" => $_SERVER["GIT_BRANCH"], + "commit_sha" => $_SERVER["GIT_COMMIT"], + ]; + } + + protected function tddiumProperties() + { + return [ + "name" => "tddium", + "build_identifier" => $_SERVER["TDDIUM_SESSION_ID"], + "worker_id" => $_SERVER["TDDIUM_TID"], + ]; + } + + protected function codeshipProperties() + { + return [ + "name" => "codeship", + "build_identifier" => $_SERVER["CI_BUILD_NUMBER"], + "build_url" => $_SERVER["CI_BUILD_URL"], + "branch" => $_SERVER["CI_BRANCH"], + "commit_sha" => $_SERVER["CI_COMMIT_ID"], + ]; + } + + protected function buildkiteProperties() + { + return [ + "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"], + ]; + } + + protected function werckerProperties() + { + return [ + "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"], + ]; + } +} diff --git a/src/TestReporter/Entity/JsonFile.php b/src/TestReporter/Entity/JsonFile.php new file mode 100644 index 0000000..a67bc45 --- /dev/null +++ b/src/TestReporter/Entity/JsonFile.php @@ -0,0 +1,85 @@ + 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"]; + } + + protected function getEnvironment() + { + return [ + "pwd" => getcwd(), + "package_version" => Version::VERSION, + ]; + } + + protected function collectGitInfo() + { + $command = new GitCommand(); + + return [ + "head" => $command->getHead(), + "branch" => $command->getBranch(), + "committed_at" => $command->getCommittedAt(), + ]; + } + + protected function collectCiServiceInfo() + { + $ciInfo = new CiInfo(); + + return $ciInfo->toArray(); + } + + protected function collectSourceFiles() + { + $sourceFiles = [ ]; + + foreach ( $this->getSourceFiles() as $sourceFile ) + { + array_push( + $sourceFiles, [ + "name" => $sourceFile->getName(), + "coverage" => json_encode( $sourceFile->getCoverage() ), + "blob_id" => $this->calculateBlobId( $sourceFile ), + ] + ); + } + + return $sourceFiles; + } + + protected function calculateBlobId( SourceFile $sourceFile ) + { + $content = file_get_contents( $sourceFile->getPath() ); + $header = "blob " . strlen( $content ) . "\0"; + + return sha1( $header . $content ); + } +} diff --git a/tests/CodeClimate/Bundle/TestReporterBundle/Console/ApplicationTest.php b/tests/CodeClimate/Bundle/TestReporterBundle/Console/ApplicationTest.php deleted file mode 100644 index b093f2c..0000000 --- a/tests/CodeClimate/Bundle/TestReporterBundle/Console/ApplicationTest.php +++ /dev/null @@ -1,57 +0,0 @@ -srcDir = realpath(__DIR__ . '/../../../../..'); - $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"; - } -} diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php new file mode 100644 index 0000000..e2c0a49 --- /dev/null +++ b/tests/Unit/ApplicationTest.php @@ -0,0 +1,58 @@ +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( [ '--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"; + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 727467f..1b84a5c 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,4 +1,3 @@ add('CodeClimate', __DIR__); +require(__DIR__ . '/../vendor/autoload.php'); From 0acd45a15c33d62700197c9c14f86f7a3f8b4995 Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Fri, 29 Jul 2016 11:54:12 -0400 Subject: [PATCH 2/6] Remove secure env var This is set via the web UI now. --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8251f0d..f36196c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,10 +9,6 @@ cache: directories: - $HOME/.composer/cache -env: - global: - secure: Yc+Xohkr/iEUU7FCQuSLXAE9ywNW9g6CfrM1Ki0Hl+fS15F3AXT7dFY8EyCJ4dP1/oI0dBmwrGWrltXV0XWIjGV1Ms3tefCgQpBBAqwT+hImzVP3RbpZW8Iyo2d0VgiDemQF1LWYD/pKu6d8WljTnv5D77NIMdEJjQ0uzeTLWdw= - before_install: - composer self-update From e3d61a19149c25c0cf8aa2428a7900130892e241 Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Fri, 29 Jul 2016 10:23:45 -0400 Subject: [PATCH 3/6] Configure CC --- .codeclimate.yml | 25 +++++++++++++++++++++++++ src/TestReporter/ApiClient.php | 14 +++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 .codeclimate.yml diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..b59b996 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,25 @@ +--- +engines: + duplication: + enabled: true + config: + languages: + - php + 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/ diff --git a/src/TestReporter/ApiClient.php b/src/TestReporter/ApiClient.php index 7291edb..d995521 100644 --- a/src/TestReporter/ApiClient.php +++ b/src/TestReporter/ApiClient.php @@ -49,13 +49,13 @@ public function send( $json ) if ( $stream = @fopen( $url, 'r', false, $context ) ) { - $meta = stream_get_meta_data( $stream ); - $raw_response = implode( "\r\n", $meta['wrapper_data'] ) . "\r\n\r\n" . stream_get_contents( $stream ); + $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($raw_response) ) + if ( !empty($rawResponse) ) { - $response = $this->buildResponse( $response, $raw_response ); + $response = $this->buildResponse( $response, $rawResponse ); } } else @@ -94,12 +94,12 @@ private function sendWithCurl( $url, $payload ) ); curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, 'POST' ); curl_setopt( $curl, CURLOPT_POSTFIELDS, $payload ); - $raw_response = curl_exec( $curl ); + $rawResponse = curl_exec( $curl ); $status = curl_getinfo( $curl, CURLINFO_HTTP_CODE ); - if ( !empty($raw_response) ) + if ( !empty($rawResponse) ) { - $response = $this->buildResponse( $response, $raw_response ); + $response = $this->buildResponse( $response, $rawResponse ); } else { From f6e892b6680a80aa2464d07ead34c273ffa82b3e Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Fri, 29 Jul 2016 13:50:04 -0400 Subject: [PATCH 4/6] Enable phpcodesniffer --- .codeclimate.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.codeclimate.yml b/.codeclimate.yml index b59b996..a986135 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -5,6 +5,8 @@ engines: config: languages: - php + phpcodesniffer: + enabled: true phpmd: enabled: true checks: From e4d1a339d7a8db0948939381cc1d4f7f6bd5b52c Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Fri, 29 Jul 2016 13:50:10 -0400 Subject: [PATCH 5/6] Tabs -> Spaces --- composer.json | 110 ++++----- composer/bin/test-reporter | 26 +- src/Application.php | 120 ++++----- src/ConsoleCommands/TestReporterCommand.php | 150 ++++++------ src/TestReporter/ApiClient.php | 230 +++++++++--------- src/TestReporter/CoverageCollector.php | 106 ++++---- src/TestReporter/Entity/CiInfo.php | 254 ++++++++++---------- src/TestReporter/Entity/JsonFile.php | 124 +++++----- tests/Unit/ApplicationTest.php | 98 ++++---- 9 files changed, 609 insertions(+), 609 deletions(-) diff --git a/composer.json b/composer.json index 6b5efea..9d7381e 100644 --- a/composer.json +++ b/composer.json @@ -1,57 +1,57 @@ { - "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" - } - ], - "require": { - "php": ">=5.3", - "ext-curl": "*", - "satooshi/php-coveralls": "^1.0", - "symfony/console": "^2.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@stable", - "ext-xdebug": "*", - "tm/tooly-composer-script": "^1.0" - }, - "autoload": { - "psr-4": { - "CodeClimate\\PhpTestReporter\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "CodeClimate\\PhpTestReporter\\Tests\\": "tests/" - } - }, - "bin": [ - "composer/bin/test-reporter" - ], - "scripts": { - "post-install-cmd": "Tooly\\ScriptHandler::installPharTools", - "post-update-cmd": "Tooly\\ScriptHandler::installPharTools" - }, - "extra": { - "branch-alias": { - "dev-master": "0.3.x-dev" - }, - "tools": { - "box": { - "url": "https://github.com/box-project/box2/releases/download/2.7.2/box-2.7.2.phar", - "only-dev": true - } - } - } + "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" + } + ], + "require": { + "php": ">=5.3", + "ext-curl": "*", + "satooshi/php-coveralls": "^1.0", + "symfony/console": "^2.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@stable", + "ext-xdebug": "*", + "tm/tooly-composer-script": "^1.0" + }, + "autoload": { + "psr-4": { + "CodeClimate\\PhpTestReporter\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "CodeClimate\\PhpTestReporter\\Tests\\": "tests/" + } + }, + "bin": [ + "composer/bin/test-reporter" + ], + "scripts": { + "post-install-cmd": "Tooly\\ScriptHandler::installPharTools", + "post-update-cmd": "Tooly\\ScriptHandler::installPharTools" + }, + "extra": { + "branch-alias": { + "dev-master": "0.3.x-dev" + }, + "tools": { + "box": { + "url": "https://github.com/box-project/box2/releases/download/2.7.2/box-2.7.2.phar", + "only-dev": true + } + } + } } diff --git a/composer/bin/test-reporter b/composer/bin/test-reporter index b8e2c72..d5a0cda 100755 --- a/composer/bin/test-reporter +++ b/composer/bin/test-reporter @@ -6,29 +6,29 @@ namespace CodeClimate\PhpTestReporter; use CodeClimate\PhpTestReporter\Constants\Version; $files = [ - __DIR__ . '/../../vendor/autoload.php', - __DIR__ . '/../../../../autoload.php', + __DIR__ . '/../../vendor/autoload.php', + __DIR__ . '/../../../../autoload.php', ]; foreach ( $files as $file ) { - if ( file_exists( $file ) ) - { - include_once $file; + if ( file_exists( $file ) ) + { + include_once $file; - define( 'PHP_TEST_REPORTER_COMPOSER_INSTALL', $file ); + define( 'PHP_TEST_REPORTER_COMPOSER_INSTALL', $file ); - break; - } + break; + } } if ( !defined( 'PHP_TEST_REPORTER_COMPOSER_INSTALL' ) ) { - die( - 'You need to set up the project dependencies using the following commands:' . PHP_EOL . - 'curl -s http://getcomposer.org/installer | php' . PHP_EOL . - 'php composer.phar install' . PHP_EOL - ); + die( + 'You need to set up the project dependencies using the following commands:' . PHP_EOL . + 'curl -s http://getcomposer.org/installer | php' . PHP_EOL . + 'php composer.phar install' . PHP_EOL + ); } $rootDir = realpath( dirname( PHP_TEST_REPORTER_COMPOSER_INSTALL ) . '/..' ); diff --git a/src/Application.php b/src/Application.php index c9a6776..aa377d1 100644 --- a/src/Application.php +++ b/src/Application.php @@ -11,75 +11,75 @@ */ class Application extends BaseApplication { - /** - * Path to project root directory. - * @var string - */ - private $rootDir; + /** + * Path to project root directory. + * @var string + */ + private $rootDir; - /** - * Constructor. - * - * @param string $rootDir Path to project root directory. - * @param string $name The name of the application - * @param string $version The version of the application - */ - public function __construct( $rootDir, $name = 'UNKNOWN', $version = 'UNKNOWN' ) - { - $this->rootDir = $rootDir; + /** + * Constructor. + * + * @param string $rootDir Path to project root directory. + * @param string $name The name of the application + * @param string $version The version of the application + */ + public function __construct( $rootDir, $name = 'UNKNOWN', $version = 'UNKNOWN' ) + { + $this->rootDir = $rootDir; - parent::__construct( $name, $version ); - } + parent::__construct( $name, $version ); + } - // internal method + // internal method - /** - * {@inheritdoc} - * @see \Symfony\Component\Console\Application::getCommandName() - */ - protected function getCommandName( InputInterface $input ) - { - return 'test-reporter'; - } + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Application::getCommandName() + */ + protected function getCommandName( InputInterface $input ) + { + return 'test-reporter'; + } - /** - * {@inheritdoc} - * @see \Symfony\Component\Console\Application::getDefaultCommands() - */ - 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->createTestReporterCommand(); + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Application::getDefaultCommands() + */ + 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->createTestReporterCommand(); - return $defaultCommands; - } + return $defaultCommands; + } - /** - * Create TestReporterCommand. - * @return TestReporterCommand - */ - protected function createTestReporterCommand() - { - $command = new TestReporterCommand(); - $command->setRootDir( $this->rootDir ); + /** + * Create TestReporterCommand. + * @return TestReporterCommand + */ + protected function createTestReporterCommand() + { + $command = new TestReporterCommand(); + $command->setRootDir( $this->rootDir ); - return $command; - } + return $command; + } - // accessor + // accessor - /** - * {@inheritdoc} - * @see \Symfony\Component\Console\Application::getDefinition() - */ - public function getDefinition() - { - $inputDefinition = parent::getDefinition(); - // clear out the normal first argument, which is the command name - $inputDefinition->setArguments(); + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Application::getDefinition() + */ + public function getDefinition() + { + $inputDefinition = parent::getDefinition(); + // clear out the normal first argument, which is the command name + $inputDefinition->setArguments(); - return $inputDefinition; - } + return $inputDefinition; + } } diff --git a/src/ConsoleCommands/TestReporterCommand.php b/src/ConsoleCommands/TestReporterCommand.php index ce923b1..f17c5cf 100644 --- a/src/ConsoleCommands/TestReporterCommand.php +++ b/src/ConsoleCommands/TestReporterCommand.php @@ -14,87 +14,87 @@ */ class TestReporterCommand extends Command { - /** - * Path to project root directory. - * @var string - */ - protected $rootDir; + /** + * Path to project root directory. + * @var string + */ + protected $rootDir; - /** - * {@inheritdoc} - * @see \Symfony\Component\Console\Command\Command::configure() - */ - protected function configure() - { - $this - ->setName( 'test-reporter' ) - ->setDescription( 'Code Climate PHP Test Reporter' ) - ->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.', - [ 'build/logs/clover.xml' ] - ); - } + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Command\Command::configure() + */ + protected function configure() + { + $this + ->setName( 'test-reporter' ) + ->setDescription( 'Code Climate PHP Test Reporter' ) + ->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.', + [ 'build/logs/clover.xml' ] + ); + } - /** - * {@inheritdoc} - * @see \Symfony\Component\Console\Command\Command::execute() - */ - protected function execute( InputInterface $input, OutputInterface $output ) - { - $ret = 0; - $collector = new CoverageCollector( $input->getOption( 'coverage-report' ) ); - $json = $collector->collectAsJson(); + /** + * {@inheritdoc} + * @see \Symfony\Component\Console\Command\Command::execute() + */ + protected function execute( InputInterface $input, OutputInterface $output ) + { + $ret = 0; + $collector = new CoverageCollector( $input->getOption( 'coverage-report' ) ); + $json = $collector->collectAsJson(); - if ( $input->getOption( 'stdout' ) ) - { - $output->writeln( (string)$json ); - } - else - { - $client = new ApiClient(); - $response = $client->send( $json ); - switch ( $response->code ) - { - case 200: - $output->writeln( "Test coverage data sent." ); - break; + if ( $input->getOption( 'stdout' ) ) + { + $output->writeln( (string)$json ); + } + else + { + $client = new ApiClient(); + $response = $client->send( $json ); + switch ( $response->code ) + { + case 200: + $output->writeln( "Test coverage data sent." ); + break; - case 401: - $output->writeln( "Invalid CODECLIMATE_REPO_TOKEN." ); - $ret = 1; - break; + case 401: + $output->writeln( "Invalid CODECLIMATE_REPO_TOKEN." ); + $ret = 1; + break; - default: - $output->writeln( "Unexpected response: " . $response->code . " " . $response->message ); - $output->writeln( $response->body ); - $ret = 1; - break; - } - } + default: + $output->writeln( "Unexpected response: " . $response->code . " " . $response->message ); + $output->writeln( $response->body ); + $ret = 1; + break; + } + } - return $ret; - } + return $ret; + } - // accessor + // accessor - /** - * Set root directory. - * - * @param string $rootDir Path to project root directory. - * - * @return void - */ - public function setRootDir( $rootDir ) - { - $this->rootDir = $rootDir; - } + /** + * Set root directory. + * + * @param string $rootDir Path to project root directory. + * + * @return void + */ + public function setRootDir( $rootDir ) + { + $this->rootDir = $rootDir; + } } diff --git a/src/TestReporter/ApiClient.php b/src/TestReporter/ApiClient.php index d995521..58e3399 100644 --- a/src/TestReporter/ApiClient.php +++ b/src/TestReporter/ApiClient.php @@ -5,131 +5,131 @@ class ApiClient { - protected $apiHost; + protected $apiHost; - /** - * Init the API client and set the hostname - */ - public function __construct() - { - $this->apiHost = "https://codeclimate.com"; + /** + * Init the API client and set the hostname + */ + public function __construct() + { + $this->apiHost = "https://codeclimate.com"; - if ( isset($_SERVER["CODECLIMATE_API_HOST"]) ) - { - $this->apiHost = $_SERVER["CODECLIMATE_API_HOST"]; - } - } + if ( isset($_SERVER["CODECLIMATE_API_HOST"]) ) + { + $this->apiHost = $_SERVER["CODECLIMATE_API_HOST"]; + } + } - /** - * Send the given JSON as a request to the CodeClimate Server - * - * @param object $json JSON data - * - * @return \stdClass Response object with (code, message, headers & body properties) - */ - public function send( $json ) - { - $response = new \stdClass; - $payload = (string)$json; - $options = [ - 'http' => [ - 'method' => 'POST', - 'header' => [ - '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'; + /** + * Send the given JSON as a request to the CodeClimate Server + * + * @param object $json JSON data + * + * @return \stdClass Response object with (code, message, headers & body properties) + */ + public function send( $json ) + { + $response = new \stdClass; + $payload = (string)$json; + $options = [ + 'http' => [ + 'method' => 'POST', + 'header' => [ + '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 ( $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 ); - } + if ( !empty($rawResponse) ) + { + $response = $this->buildResponse( $response, $rawResponse ); + } + } + else + { + $response = $this->sendWithCurl( $url, $payload ); + } - return $response; - } + 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, - [ - '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 ); + /** + * 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, + [ + '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( '/([0-9]{3})/', $error['message'], $match ); - $errorCode = (isset($match[1])) ? $match[1] : ($status ? $status : 500); + $status = curl_getinfo( $curl, CURLINFO_HTTP_CODE ); + if ( !empty($rawResponse) ) + { + $response = $this->buildResponse( $response, $rawResponse ); + } + else + { + $error = error_get_last(); + preg_match( '/([0-9]{3})/', $error['message'], $match ); + $errorCode = (isset($match[1])) ? $match[1] : ($status ? $status : 500); - $response->code = $errorCode; - $response->message = $error['message']; - $response->headers = [ ]; - $response->body = null; - } + $response->code = $errorCode; + $response->message = $error['message']; + $response->headers = [ ]; + $response->body = null; + } - return $response; - } + 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 ); + /** + * 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; - } + return $response; + } } diff --git a/src/TestReporter/CoverageCollector.php b/src/TestReporter/CoverageCollector.php index 9ba39b2..0072443 100644 --- a/src/TestReporter/CoverageCollector.php +++ b/src/TestReporter/CoverageCollector.php @@ -7,66 +7,66 @@ class CoverageCollector { - protected $api; + protected $api; - /** - * Array that holds list of relative paths to Clover XML files - * @var array - */ - protected $cloverPaths = [ ]; + /** + * Array that holds list of relative paths to Clover XML files + * @var array + */ + protected $cloverPaths = [ ]; - public function __construct( $paths ) - { - $rootDir = getcwd(); - $config = new Configuration(); - $config->setRootDir( $rootDir ); - $this->setCloverPaths( $paths ); - foreach ( $this->getCloverPaths() as $path ) - { - if ( file_exists( $path ) ) - { - $config->addCloverXmlPath( $path ); - } - else - { - $config->addCloverXmlPath( $rootDir . DIRECTORY_SEPARATOR . $path ); - } - } + public function __construct( $paths ) + { + $rootDir = getcwd(); + $config = new Configuration(); + $config->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 ); - } + $this->api = new Jobs( $config ); + } - /** - * Set a list of Clover XML paths - * - * @param array $paths Array of relative paths to Clovers XML files - */ - public function setCloverPaths( $paths ) - { - $this->cloverPaths = $paths; - } + /** + * Set a list of Clover XML paths + * + * @param array $paths Array of relative paths to Clovers XML files + */ + public function setCloverPaths( $paths ) + { + $this->cloverPaths = $paths; + } - /** - * Get a list of Clover XML paths - * @return array Array of relative Clover XML file locations - */ - public function getCloverPaths() - { - return $this->cloverPaths; - } + /** + * Get a list of Clover XML paths + * @return array Array of relative Clover XML file locations + */ + public function getCloverPaths() + { + return $this->cloverPaths; + } - public function collectAsJson() - { - $cloverJsonFile = $this->api->collectCloverXml()->getJsonFile(); + public function collectAsJson() + { + $cloverJsonFile = $this->api->collectCloverXml()->getJsonFile(); - $jsonFile = new JsonFile(); - $jsonFile->setRunAt( $cloverJsonFile->getRunAt() ); + $jsonFile = new JsonFile(); + $jsonFile->setRunAt( $cloverJsonFile->getRunAt() ); - foreach ( $cloverJsonFile->getSourceFiles() as $sourceFile ) - { - $jsonFile->addSourceFile( $sourceFile ); - } + foreach ( $cloverJsonFile->getSourceFiles() as $sourceFile ) + { + $jsonFile->addSourceFile( $sourceFile ); + } - return $jsonFile; - } + return $jsonFile; + } } diff --git a/src/TestReporter/Entity/CiInfo.php b/src/TestReporter/Entity/CiInfo.php index 3d5a7a8..502e22c 100644 --- a/src/TestReporter/Entity/CiInfo.php +++ b/src/TestReporter/Entity/CiInfo.php @@ -3,131 +3,131 @@ class CiInfo { - public function toArray() - { - if ( isset($_SERVER["TRAVIS"]) ) - { - return $this->travisProperties(); - } - - if ( isset($_SERVER["CIRCLECI"]) ) - { - return $this->circleProperties(); - } - - if ( isset($_SERVER["SEMAPHORE"]) ) - { - return $this->semaphoreProperties(); - } - - if ( isset($_SERVER["JENKINS_URL"]) ) - { - return $this->jenkinsProperties(); - } - - if ( isset($_SERVER["TDDIUM"]) ) - { - return $this->tddiumProperties(); - } - - if ( isset($_SERVER["CI_NAME"]) && preg_match( '/codeship/i', $_SERVER["CI_NAME"] ) ) - { - return $this->codeshipProperties(); - } - - if ( isset($_SERVER["BUILDKITE"]) ) - { - return $this->buildkiteProperties(); - } - - if ( isset($_SERVER["WERCKER"]) ) - { - return $this->werckerProperties(); - } - - return [ ]; - } - - protected function travisProperties() - { - return [ - "name" => "travis-ci", - "branch" => $_SERVER["TRAVIS_BRANCH"], - "build_identifier" => $_SERVER["TRAVIS_JOB_ID"], - "pull_request" => $_SERVER["TRAVIS_PULL_REQUEST"], - ]; - } - - protected function circleProperties() - { - return [ - "name" => "circleci", - "build_identifier" => $_SERVER["CIRCLE_BUILD_NUM"], - "branch" => $_SERVER["CIRCLE_BRANCH"], - "commit_sha" => $_SERVER["CIRCLE_SHA1"], - ]; - } - - protected function semaphoreProperties() - { - return [ - "name" => "semaphore", - "branch" => $_SERVER["BRANCH_NAME"], - "build_identifier" => $_SERVER["SEMAPHORE_BUILD_NUMBER"], - ]; - } - - protected function jenkinsProperties() - { - return [ - "name" => "jenkins", - "build_identifier" => $_SERVER["BUILD_NUMBER"], - "build_url" => $_SERVER["BUILD_URL"], - "branch" => $_SERVER["GIT_BRANCH"], - "commit_sha" => $_SERVER["GIT_COMMIT"], - ]; - } - - protected function tddiumProperties() - { - return [ - "name" => "tddium", - "build_identifier" => $_SERVER["TDDIUM_SESSION_ID"], - "worker_id" => $_SERVER["TDDIUM_TID"], - ]; - } - - protected function codeshipProperties() - { - return [ - "name" => "codeship", - "build_identifier" => $_SERVER["CI_BUILD_NUMBER"], - "build_url" => $_SERVER["CI_BUILD_URL"], - "branch" => $_SERVER["CI_BRANCH"], - "commit_sha" => $_SERVER["CI_COMMIT_ID"], - ]; - } - - protected function buildkiteProperties() - { - return [ - "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"], - ]; - } - - protected function werckerProperties() - { - return [ - "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"], - ]; - } + public function toArray() + { + if ( isset($_SERVER["TRAVIS"]) ) + { + return $this->travisProperties(); + } + + if ( isset($_SERVER["CIRCLECI"]) ) + { + return $this->circleProperties(); + } + + if ( isset($_SERVER["SEMAPHORE"]) ) + { + return $this->semaphoreProperties(); + } + + if ( isset($_SERVER["JENKINS_URL"]) ) + { + return $this->jenkinsProperties(); + } + + if ( isset($_SERVER["TDDIUM"]) ) + { + return $this->tddiumProperties(); + } + + if ( isset($_SERVER["CI_NAME"]) && preg_match( '/codeship/i', $_SERVER["CI_NAME"] ) ) + { + return $this->codeshipProperties(); + } + + if ( isset($_SERVER["BUILDKITE"]) ) + { + return $this->buildkiteProperties(); + } + + if ( isset($_SERVER["WERCKER"]) ) + { + return $this->werckerProperties(); + } + + return [ ]; + } + + protected function travisProperties() + { + return [ + "name" => "travis-ci", + "branch" => $_SERVER["TRAVIS_BRANCH"], + "build_identifier" => $_SERVER["TRAVIS_JOB_ID"], + "pull_request" => $_SERVER["TRAVIS_PULL_REQUEST"], + ]; + } + + protected function circleProperties() + { + return [ + "name" => "circleci", + "build_identifier" => $_SERVER["CIRCLE_BUILD_NUM"], + "branch" => $_SERVER["CIRCLE_BRANCH"], + "commit_sha" => $_SERVER["CIRCLE_SHA1"], + ]; + } + + protected function semaphoreProperties() + { + return [ + "name" => "semaphore", + "branch" => $_SERVER["BRANCH_NAME"], + "build_identifier" => $_SERVER["SEMAPHORE_BUILD_NUMBER"], + ]; + } + + protected function jenkinsProperties() + { + return [ + "name" => "jenkins", + "build_identifier" => $_SERVER["BUILD_NUMBER"], + "build_url" => $_SERVER["BUILD_URL"], + "branch" => $_SERVER["GIT_BRANCH"], + "commit_sha" => $_SERVER["GIT_COMMIT"], + ]; + } + + protected function tddiumProperties() + { + return [ + "name" => "tddium", + "build_identifier" => $_SERVER["TDDIUM_SESSION_ID"], + "worker_id" => $_SERVER["TDDIUM_TID"], + ]; + } + + protected function codeshipProperties() + { + return [ + "name" => "codeship", + "build_identifier" => $_SERVER["CI_BUILD_NUMBER"], + "build_url" => $_SERVER["CI_BUILD_URL"], + "branch" => $_SERVER["CI_BRANCH"], + "commit_sha" => $_SERVER["CI_COMMIT_ID"], + ]; + } + + protected function buildkiteProperties() + { + return [ + "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"], + ]; + } + + protected function werckerProperties() + { + return [ + "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"], + ]; + } } diff --git a/src/TestReporter/Entity/JsonFile.php b/src/TestReporter/Entity/JsonFile.php index a67bc45..f5453f4 100644 --- a/src/TestReporter/Entity/JsonFile.php +++ b/src/TestReporter/Entity/JsonFile.php @@ -8,78 +8,78 @@ class JsonFile extends SatooshiJsonFile { - public function toArray() - { - return [ - "partial" => 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 toArray() + { + return [ + "partial" => 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 getRunAt() + { + return strtotime( parent::getRunAt() ); + } - public function getRepoToken() - { - return $_SERVER["CODECLIMATE_REPO_TOKEN"]; - } + public function getRepoToken() + { + return $_SERVER["CODECLIMATE_REPO_TOKEN"]; + } - protected function getEnvironment() - { - return [ - "pwd" => getcwd(), - "package_version" => Version::VERSION, - ]; - } + protected function getEnvironment() + { + return [ + "pwd" => getcwd(), + "package_version" => Version::VERSION, + ]; + } - protected function collectGitInfo() - { - $command = new GitCommand(); + protected function collectGitInfo() + { + $command = new GitCommand(); - return [ - "head" => $command->getHead(), - "branch" => $command->getBranch(), - "committed_at" => $command->getCommittedAt(), - ]; - } + return [ + "head" => $command->getHead(), + "branch" => $command->getBranch(), + "committed_at" => $command->getCommittedAt(), + ]; + } - protected function collectCiServiceInfo() - { - $ciInfo = new CiInfo(); + protected function collectCiServiceInfo() + { + $ciInfo = new CiInfo(); - return $ciInfo->toArray(); - } + return $ciInfo->toArray(); + } - protected function collectSourceFiles() - { - $sourceFiles = [ ]; + protected function collectSourceFiles() + { + $sourceFiles = [ ]; - foreach ( $this->getSourceFiles() as $sourceFile ) - { - array_push( - $sourceFiles, [ - "name" => $sourceFile->getName(), - "coverage" => json_encode( $sourceFile->getCoverage() ), - "blob_id" => $this->calculateBlobId( $sourceFile ), - ] - ); - } + foreach ( $this->getSourceFiles() as $sourceFile ) + { + array_push( + $sourceFiles, [ + "name" => $sourceFile->getName(), + "coverage" => json_encode( $sourceFile->getCoverage() ), + "blob_id" => $this->calculateBlobId( $sourceFile ), + ] + ); + } - return $sourceFiles; - } + return $sourceFiles; + } - protected function calculateBlobId( SourceFile $sourceFile ) - { - $content = file_get_contents( $sourceFile->getPath() ); - $header = "blob " . strlen( $content ) . "\0"; + protected function calculateBlobId( SourceFile $sourceFile ) + { + $content = file_get_contents( $sourceFile->getPath() ); + $header = "blob " . strlen( $content ) . "\0"; - return sha1( $header . $content ); - } + return sha1( $header . $content ); + } } diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php index e2c0a49..3b8784c 100644 --- a/tests/Unit/ApplicationTest.php +++ b/tests/Unit/ApplicationTest.php @@ -6,53 +6,53 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase { - const PROJECT_DIR = "/tmp/php-test-reporter-example-project"; - - protected $srcDir; - - public function setUp() - { - $this->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( [ '--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"; - } + const PROJECT_DIR = "/tmp/php-test-reporter-example-project"; + + protected $srcDir; + + public function setUp() + { + $this->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( [ '--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"; + } } From 63aadd195c927b8d740e2f94178da5996f269471 Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Fri, 29 Jul 2016 13:59:16 -0400 Subject: [PATCH 6/6] Correct brace and parenthesis style - `(arg)`, not `( arg )` - `if {`, not `if\n{` --- composer/bin/test-reporter | 15 ++--- src/Application.php | 8 +-- src/ConsoleCommands/TestReporterCommand.php | 32 +++++----- src/TestReporter/ApiClient.php | 68 +++++++++------------ src/TestReporter/CoverageCollector.php | 31 ++++------ src/TestReporter/Entity/CiInfo.php | 24 +++----- src/TestReporter/Entity/JsonFile.php | 20 +++--- tests/Unit/ApplicationTest.php | 36 +++++------ 8 files changed, 103 insertions(+), 131 deletions(-) diff --git a/composer/bin/test-reporter b/composer/bin/test-reporter index d5a0cda..3a1e766 100755 --- a/composer/bin/test-reporter +++ b/composer/bin/test-reporter @@ -10,20 +10,17 @@ $files = [ __DIR__ . '/../../../../autoload.php', ]; -foreach ( $files as $file ) -{ - if ( file_exists( $file ) ) - { +foreach ($files as $file) { + if (file_exists($file)) { include_once $file; - define( 'PHP_TEST_REPORTER_COMPOSER_INSTALL', $file ); + define('PHP_TEST_REPORTER_COMPOSER_INSTALL', $file); break; } } -if ( !defined( 'PHP_TEST_REPORTER_COMPOSER_INSTALL' ) ) -{ +if (!defined('PHP_TEST_REPORTER_COMPOSER_INSTALL')) { die( 'You need to set up the project dependencies using the following commands:' . PHP_EOL . 'curl -s http://getcomposer.org/installer | php' . PHP_EOL . @@ -31,7 +28,7 @@ if ( !defined( 'PHP_TEST_REPORTER_COMPOSER_INSTALL' ) ) ); } -$rootDir = realpath( dirname( PHP_TEST_REPORTER_COMPOSER_INSTALL ) . '/..' ); +$rootDir = realpath(dirname(PHP_TEST_REPORTER_COMPOSER_INSTALL) . '/..'); -$app = new Application( $rootDir, 'Code Climate PHP Test Reporter', Version::VERSION ); +$app = new Application($rootDir, 'Code Climate PHP Test Reporter', Version::VERSION); $app->run(); diff --git a/src/Application.php b/src/Application.php index aa377d1..ccdc800 100644 --- a/src/Application.php +++ b/src/Application.php @@ -24,11 +24,11 @@ class Application extends BaseApplication * @param string $name The name of the application * @param string $version The version of the application */ - public function __construct( $rootDir, $name = 'UNKNOWN', $version = 'UNKNOWN' ) + public function __construct($rootDir, $name = 'UNKNOWN', $version = 'UNKNOWN') { $this->rootDir = $rootDir; - parent::__construct( $name, $version ); + parent::__construct($name, $version); } // internal method @@ -37,7 +37,7 @@ public function __construct( $rootDir, $name = 'UNKNOWN', $version = 'UNKNOWN' ) * {@inheritdoc} * @see \Symfony\Component\Console\Application::getCommandName() */ - protected function getCommandName( InputInterface $input ) + protected function getCommandName(InputInterface $input) { return 'test-reporter'; } @@ -63,7 +63,7 @@ protected function getDefaultCommands() protected function createTestReporterCommand() { $command = new TestReporterCommand(); - $command->setRootDir( $this->rootDir ); + $command->setRootDir($this->rootDir); return $command; } diff --git a/src/ConsoleCommands/TestReporterCommand.php b/src/ConsoleCommands/TestReporterCommand.php index f17c5cf..0db923a 100644 --- a/src/ConsoleCommands/TestReporterCommand.php +++ b/src/ConsoleCommands/TestReporterCommand.php @@ -27,8 +27,8 @@ class TestReporterCommand extends Command protected function configure() { $this - ->setName( 'test-reporter' ) - ->setDescription( 'Code Climate PHP Test Reporter' ) + ->setName('test-reporter') + ->setDescription('Code Climate PHP Test Reporter') ->addOption( 'stdout', null, @@ -48,34 +48,30 @@ protected function configure() * {@inheritdoc} * @see \Symfony\Component\Console\Command\Command::execute() */ - protected function execute( InputInterface $input, OutputInterface $output ) + protected function execute(InputInterface $input, OutputInterface $output) { $ret = 0; - $collector = new CoverageCollector( $input->getOption( 'coverage-report' ) ); + $collector = new CoverageCollector($input->getOption('coverage-report')); $json = $collector->collectAsJson(); - if ( $input->getOption( 'stdout' ) ) - { - $output->writeln( (string)$json ); - } - else - { + if ($input->getOption('stdout')) { + $output->writeln((string)$json); + } else { $client = new ApiClient(); - $response = $client->send( $json ); - switch ( $response->code ) - { + $response = $client->send($json); + switch ($response->code) { case 200: - $output->writeln( "Test coverage data sent." ); + $output->writeln("Test coverage data sent."); break; case 401: - $output->writeln( "Invalid CODECLIMATE_REPO_TOKEN." ); + $output->writeln("Invalid CODECLIMATE_REPO_TOKEN."); $ret = 1; break; default: - $output->writeln( "Unexpected response: " . $response->code . " " . $response->message ); - $output->writeln( $response->body ); + $output->writeln("Unexpected response: " . $response->code . " " . $response->message); + $output->writeln($response->body); $ret = 1; break; } @@ -93,7 +89,7 @@ protected function execute( InputInterface $input, OutputInterface $output ) * * @return void */ - public function setRootDir( $rootDir ) + public function setRootDir($rootDir) { $this->rootDir = $rootDir; } diff --git a/src/TestReporter/ApiClient.php b/src/TestReporter/ApiClient.php index 58e3399..e524163 100644 --- a/src/TestReporter/ApiClient.php +++ b/src/TestReporter/ApiClient.php @@ -14,8 +14,7 @@ public function __construct() { $this->apiHost = "https://codeclimate.com"; - if ( isset($_SERVER["CODECLIMATE_API_HOST"]) ) - { + if (isset($_SERVER["CODECLIMATE_API_HOST"])) { $this->apiHost = $_SERVER["CODECLIMATE_API_HOST"]; } } @@ -27,7 +26,7 @@ public function __construct() * * @return \stdClass Response object with (code, message, headers & body properties) */ - public function send( $json ) + public function send($json) { $response = new \stdClass; $payload = (string)$json; @@ -38,29 +37,25 @@ public function send( $json ) 'Host: codeclimate.com', 'Content-Type: application/json', 'User-Agent: Code Climate (PHP Test Reporter v' . Version::VERSION . ')', - 'Content-Length: ' . strlen( $payload ), + 'Content-Length: ' . strlen($payload), ], 'content' => $payload, "timeout" => 10, ], ]; - $context = stream_context_create( $options ); + $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 ($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 ); + if (!empty($rawResponse)) { + $response = $this->buildResponse($response, $rawResponse); } - } - else - { - $response = $this->sendWithCurl( $url, $payload ); + } else { + $response = $this->sendWithCurl($url, $payload); } return $response; @@ -75,13 +70,13 @@ public function send( $json ) * * @return \stdClass Response object with (code, message, headers & body properties) */ - private function sendWithCurl( $url, $payload ) + 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 = 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, @@ -89,22 +84,19 @@ private function sendWithCurl( $url, $payload ) 'Host: codeclimate.com', 'Content-Type: application/json', 'User-Agent: Code Climate (PHP Test Reporter v' . Version::VERSION . ')', - 'Content-Length: ' . strlen( $payload ), + 'Content-Length: ' . strlen($payload), ] ); - curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, 'POST' ); - curl_setopt( $curl, CURLOPT_POSTFIELDS, $payload ); - $rawResponse = curl_exec( $curl ); + 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 - { + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + if (!empty($rawResponse)) { + $response = $this->buildResponse($response, $rawResponse); + } else { $error = error_get_last(); - preg_match( '/([0-9]{3})/', $error['message'], $match ); + preg_match('/([0-9]{3})/', $error['message'], $match); $errorCode = (isset($match[1])) ? $match[1] : ($status ? $status : 500); $response->code = $errorCode; @@ -124,11 +116,11 @@ private function sendWithCurl( $url, $payload ) * * @return \stdClass Populated class object */ - private function buildResponse( $response, $body ) + 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 ); + 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; } diff --git a/src/TestReporter/CoverageCollector.php b/src/TestReporter/CoverageCollector.php index 0072443..6d15dd2 100644 --- a/src/TestReporter/CoverageCollector.php +++ b/src/TestReporter/CoverageCollector.php @@ -15,25 +15,21 @@ class CoverageCollector */ protected $cloverPaths = [ ]; - public function __construct( $paths ) + public function __construct($paths) { $rootDir = getcwd(); $config = new Configuration(); - $config->setRootDir( $rootDir ); - $this->setCloverPaths( $paths ); - foreach ( $this->getCloverPaths() as $path ) - { - if ( file_exists( $path ) ) - { - $config->addCloverXmlPath( $path ); - } - else - { - $config->addCloverXmlPath( $rootDir . DIRECTORY_SEPARATOR . $path ); + $config->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 ); + $this->api = new Jobs($config); } /** @@ -41,7 +37,7 @@ public function __construct( $paths ) * * @param array $paths Array of relative paths to Clovers XML files */ - public function setCloverPaths( $paths ) + public function setCloverPaths($paths) { $this->cloverPaths = $paths; } @@ -60,11 +56,10 @@ public function collectAsJson() $cloverJsonFile = $this->api->collectCloverXml()->getJsonFile(); $jsonFile = new JsonFile(); - $jsonFile->setRunAt( $cloverJsonFile->getRunAt() ); + $jsonFile->setRunAt($cloverJsonFile->getRunAt()); - foreach ( $cloverJsonFile->getSourceFiles() as $sourceFile ) - { - $jsonFile->addSourceFile( $sourceFile ); + foreach ($cloverJsonFile->getSourceFiles() as $sourceFile) { + $jsonFile->addSourceFile($sourceFile); } return $jsonFile; diff --git a/src/TestReporter/Entity/CiInfo.php b/src/TestReporter/Entity/CiInfo.php index 502e22c..12243c3 100644 --- a/src/TestReporter/Entity/CiInfo.php +++ b/src/TestReporter/Entity/CiInfo.php @@ -5,43 +5,35 @@ class CiInfo { public function toArray() { - if ( isset($_SERVER["TRAVIS"]) ) - { + if (isset($_SERVER["TRAVIS"])) { return $this->travisProperties(); } - if ( isset($_SERVER["CIRCLECI"]) ) - { + if (isset($_SERVER["CIRCLECI"])) { return $this->circleProperties(); } - if ( isset($_SERVER["SEMAPHORE"]) ) - { + if (isset($_SERVER["SEMAPHORE"])) { return $this->semaphoreProperties(); } - if ( isset($_SERVER["JENKINS_URL"]) ) - { + if (isset($_SERVER["JENKINS_URL"])) { return $this->jenkinsProperties(); } - if ( isset($_SERVER["TDDIUM"]) ) - { + if (isset($_SERVER["TDDIUM"])) { return $this->tddiumProperties(); } - if ( isset($_SERVER["CI_NAME"]) && preg_match( '/codeship/i', $_SERVER["CI_NAME"] ) ) - { + if (isset($_SERVER["CI_NAME"]) && preg_match('/codeship/i', $_SERVER["CI_NAME"])) { return $this->codeshipProperties(); } - if ( isset($_SERVER["BUILDKITE"]) ) - { + if (isset($_SERVER["BUILDKITE"])) { return $this->buildkiteProperties(); } - if ( isset($_SERVER["WERCKER"]) ) - { + if (isset($_SERVER["WERCKER"])) { return $this->werckerProperties(); } diff --git a/src/TestReporter/Entity/JsonFile.php b/src/TestReporter/Entity/JsonFile.php index f5453f4..8bd414a 100644 --- a/src/TestReporter/Entity/JsonFile.php +++ b/src/TestReporter/Entity/JsonFile.php @@ -23,7 +23,7 @@ public function toArray() public function getRunAt() { - return strtotime( parent::getRunAt() ); + return strtotime(parent::getRunAt()); } public function getRepoToken() @@ -61,13 +61,13 @@ protected function collectSourceFiles() { $sourceFiles = [ ]; - foreach ( $this->getSourceFiles() as $sourceFile ) - { + foreach ($this->getSourceFiles() as $sourceFile) { array_push( - $sourceFiles, [ + $sourceFiles, + [ "name" => $sourceFile->getName(), - "coverage" => json_encode( $sourceFile->getCoverage() ), - "blob_id" => $this->calculateBlobId( $sourceFile ), + "coverage" => json_encode($sourceFile->getCoverage()), + "blob_id" => $this->calculateBlobId($sourceFile), ] ); } @@ -75,11 +75,11 @@ protected function collectSourceFiles() return $sourceFiles; } - protected function calculateBlobId( SourceFile $sourceFile ) + protected function calculateBlobId(SourceFile $sourceFile) { - $content = file_get_contents( $sourceFile->getPath() ); - $header = "blob " . strlen( $content ) . "\0"; + $content = file_get_contents($sourceFile->getPath()); + $header = "blob " . strlen($content) . "\0"; - return sha1( $header . $content ); + return sha1($header . $content); } } diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php index 3b8784c..b0cb847 100644 --- a/tests/Unit/ApplicationTest.php +++ b/tests/Unit/ApplicationTest.php @@ -12,7 +12,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->srcDir = realpath( __DIR__ . '/../../../../CodeClimateTestReporter' ); + $this->srcDir = realpath(__DIR__ . '/../../../../CodeClimateTestReporter'); $this->setupProject(); $this->setupEnvironment(); } @@ -22,29 +22,29 @@ public function setUp() */ public function shouldExecuteSuccessfully() { - $app = new Application( $this->srcDir, 'PHP Test Reporter', '1.0.0' ); - $app->setAutoExit( false ); - $tester = new ApplicationTester( $app ); + $app = new Application($this->srcDir, 'PHP Test Reporter', '1.0.0'); + $app->setAutoExit(false); + $tester = new ApplicationTester($app); - $status = $tester->run( [ '--stdout' => true ] ); + $status = $tester->run([ '--stdout' => true ]); - $this->assertEquals( 0, $status ); + $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" ); + 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()