More updates

This commit is contained in:
laf
2015-08-19 22:15:21 +00:00
parent 471c4bacf3
commit bc4f90877c
1250 changed files with 148061 additions and 0 deletions
@@ -0,0 +1,84 @@
<?php
namespace CodeClimate\Bundle\TestReporterBundle;
class ApiClient
{
protected $apiHost;
/**
* 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"];
}
}
/**
* 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 {
$error = error_get_last();
preg_match('/([0-9]{3})/', $error['message'], $match);
$errorCode = (isset($match[1])) ? $match[1] : 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 \stcClass 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;
}
}
@@ -0,0 +1,98 @@
<?php
namespace CodeClimate\Bundle\TestReporterBundle\Command;
use CodeClimate\Bundle\TestReporterBundle\CoverageCollector;
use CodeClimate\Bundle\TestReporterBundle\ApiClient;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Test reporter command
*/
class TestReporterCommand extends Command
{
/**
* 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.',
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;
}
}
@@ -0,0 +1,91 @@
<?php
namespace CodeClimate\Bundle\TestReporterBundle\Console;
use CodeClimate\Bundle\TestReporterBundle\Command\TestReporterCommand;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\Console\Input\InputInterface;
/**
* Coveralls API application.
*
* @author Kitamura Satoshi <with.no.parachute@gmail.com>
*/
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;
}
}
@@ -0,0 +1,66 @@
<?php
namespace CodeClimate\Bundle\TestReporterBundle;
use CodeClimate\Component\System\Git\GitCommand;
use CodeClimate\Bundle\TestReporterBundle\Entity\JsonFile;
use Contrib\Bundle\CoverallsV1Bundle\Api\Jobs;
use Contrib\Bundle\CoverallsV1Bundle\Config\Configuration;
class CoverageCollector
{
protected $api;
/**
* Array that holds list of relative paths to Clover XML files
* @var array
*/
protected $cloverPaths = array();
public function __construct($paths)
{
$rootDir = getcwd();
$config = new Configuration();
$config->setSrcDir($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;
}
}
@@ -0,0 +1,125 @@
<?php
namespace CodeClimate\Bundle\TestReporterBundle\Entity;
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["BUILDBOX"])) {
return $this->buildboxProperties();
}
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 buildboxProperties()
{
return array(
"name" => "buildbox",
"build_identifier" => $_SERVER["BUILDBOX_BUILD_ID"],
"build_url" => $_SERVER["BUILDBOX_BUILD_URL"],
"branch" => $_SERVER["BUILDBOX_BRANCH"],
"commit_sha" => $_SERVER["BUILDBOX_COMMIT"],
"pull_request" => $_SERVER["BUILDBOX_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"]
);
}
}
@@ -0,0 +1,82 @@
<?php
namespace CodeClimate\Bundle\TestReporterBundle\Entity;
use CodeClimate\Component\System\Git\GitCommand;
use CodeClimate\Bundle\TestReporterBundle\Entity\CiInfo;
use CodeClimate\Bundle\TestReporterBundle\Version;
use Contrib\Bundle\CoverallsV1Bundle\Entity\JsonFile as SatooshiJsonFile;
class JsonFile extends SatooshiJsonFile
{
public function toArray()
{
return array(
"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 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);
}
}
@@ -0,0 +1,15 @@
<?php
namespace CodeClimate\Bundle\TestReporterBundle;
/**
* TestReporterBundle version.
*/
final class Version
{
/**
* TestReporter version.
*
* @var string
*/
const VERSION = '0.1.2';
}
@@ -0,0 +1,37 @@
<?php
namespace CodeClimate\Component\System\Git;
use Contrib\Component\System\SystemCommand;
class GitCommand extends SystemCommand
{
protected $commandPath = 'git';
public function getHead()
{
$command = $this->createCommand("log -1 --pretty=format:'%H'");
return current($this->executeCommand($command));
}
public function getBranch()
{
$command = $this->createCommand("branch");
$branches = $this->executeCommand($command);
foreach ($branches as $branch) {
if ($branch[0] == "*") {
return str_replace("* ", "", $branch);
}
}
return null;
}
public function getCommittedAt()
{
$command = $this->createCommand("log -1 --pretty=format:'%ct'");
return (int)current($this->executeCommand($command));
}
}