Compare commits
1 commit
master
...
dc/github-
Author | SHA1 | Date | |
---|---|---|---|
f2db45277c |
92
PHPCI/Command/RebuildCommand.php
Normal file
92
PHPCI/Command/RebuildCommand.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPCI - Continuous Integration for PHP
|
||||||
|
*
|
||||||
|
* @copyright Copyright 2014, Block 8 Limited.
|
||||||
|
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||||
|
* @link https://www.phptesting.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPCI\Command;
|
||||||
|
|
||||||
|
use b8\Store\Factory;
|
||||||
|
use Monolog\Logger;
|
||||||
|
use PHPCI\Service\BuildService;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-runs the last run build.
|
||||||
|
* @author Dan Cryer <dan@block8.co.uk>
|
||||||
|
* @package PHPCI
|
||||||
|
* @subpackage Console
|
||||||
|
*/
|
||||||
|
class RebuildCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Logger
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var OutputInterface
|
||||||
|
*/
|
||||||
|
protected $output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $run;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $sleep;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Monolog\Logger $logger
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
|
public function __construct(Logger $logger, $name = null)
|
||||||
|
{
|
||||||
|
parent::__construct($name);
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('phpci:rebuild')
|
||||||
|
->setDescription('Re-runs the last run build.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loops through running.
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$runner = new RunCommand($this->logger);
|
||||||
|
$runner->setMaxBuilds(1);
|
||||||
|
$runner->setDaemon(false);
|
||||||
|
|
||||||
|
/** @var \PHPCI\Store\BuildStore $store */
|
||||||
|
$store = Factory::getStore('Build');
|
||||||
|
$service = new BuildService($store);
|
||||||
|
|
||||||
|
$lastBuild = array_shift($store->getLatestBuilds(null, 1));
|
||||||
|
$service->createDuplicateBuild($lastBuild);
|
||||||
|
|
||||||
|
$runner->run(new ArgvInput(array()), $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when log entries are made in Builder / the plugins.
|
||||||
|
* @see \PHPCI\Builder::log()
|
||||||
|
*/
|
||||||
|
public function logCallback($log)
|
||||||
|
{
|
||||||
|
$this->output->writeln($log);
|
||||||
|
}
|
||||||
|
}
|
58
PHPCI/Helper/Diff.php
Normal file
58
PHPCI/Helper/Diff.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPCI - Continuous Integration for PHP
|
||||||
|
*
|
||||||
|
* @copyright Copyright 2015, Block 8 Limited.
|
||||||
|
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||||
|
* @link https://www.phptesting.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPCI\Helper;
|
||||||
|
|
||||||
|
use b8\Cache;
|
||||||
|
use b8\Config;
|
||||||
|
use b8\HttpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides some basic diff processing functionality.
|
||||||
|
* @package PHPCI\Helper
|
||||||
|
*/
|
||||||
|
class Diff
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Take a diff
|
||||||
|
* @param string $diff
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getLinePositions($diff)
|
||||||
|
{
|
||||||
|
$rtn = array();
|
||||||
|
|
||||||
|
$diffLines = explode(PHP_EOL, $diff);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
$line = array_shift($diffLines);
|
||||||
|
|
||||||
|
if (substr($line, 0, 2) == '@@') {
|
||||||
|
array_unshift($diffLines, $line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$lineNumber = 0;
|
||||||
|
$position = 0;
|
||||||
|
|
||||||
|
foreach ($diffLines as $diffLine) {
|
||||||
|
if (preg_match('/@@\s+\-[0-9]+\,[0-9]+\s+\+([0-9]+)\,([0-9]+)/', $diffLine, $matches)) {
|
||||||
|
$lineNumber = (int)$matches[1] - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rtn[$lineNumber] = $position;
|
||||||
|
|
||||||
|
$lineNumber++;
|
||||||
|
$position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rtn;
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,4 +108,74 @@ class Github
|
||||||
|
|
||||||
return $rtn;
|
return $rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a comment on a specific file (and commit) in a Github Pull Request.
|
||||||
|
* @param $repo
|
||||||
|
* @param $pullId
|
||||||
|
* @param $commitId
|
||||||
|
* @param $file
|
||||||
|
* @param $line
|
||||||
|
* @param $comment
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function createPullRequestComment($repo, $pullId, $commitId, $file, $line, $comment)
|
||||||
|
{
|
||||||
|
$token = Config::getInstance()->get('phpci.github.token');
|
||||||
|
|
||||||
|
if (!$token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = '/repos/' . strtolower($repo) . '/pulls/' . $pullId . '/comments';
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'body' => $comment,
|
||||||
|
'commit_id' => $commitId,
|
||||||
|
'path' => $file,
|
||||||
|
'position' => $line,
|
||||||
|
);
|
||||||
|
|
||||||
|
$http = new HttpClient('https://api.github.com');
|
||||||
|
$http->setHeaders(array(
|
||||||
|
'Content-Type: application/x-www-form-urlencoded',
|
||||||
|
'Authorization: Basic ' . base64_encode($token . ':x-oauth-basic'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$http->post($url, json_encode($params));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a comment on a Github commit.
|
||||||
|
* @param $repo
|
||||||
|
* @param $commitId
|
||||||
|
* @param $file
|
||||||
|
* @param $line
|
||||||
|
* @param $comment
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
public function createCommitComment($repo, $commitId, $file, $line, $comment)
|
||||||
|
{
|
||||||
|
$token = Config::getInstance()->get('phpci.github.token');
|
||||||
|
|
||||||
|
if (!$token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = '/repos/' . strtolower($repo) . '/commits/' . $commitId . '/comments';
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'body' => $comment,
|
||||||
|
'path' => $file,
|
||||||
|
'position' => $line,
|
||||||
|
);
|
||||||
|
|
||||||
|
$http = new HttpClient('https://api.github.com');
|
||||||
|
$http->setHeaders(array(
|
||||||
|
'Content-Type: application/x-www-form-urlencoded',
|
||||||
|
'Authorization: Basic ' . base64_encode($token . ':x-oauth-basic'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$http->post($url, json_encode($params));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,4 +204,17 @@ class Build extends BuildBase
|
||||||
|
|
||||||
return $rtn;
|
return $rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows specific build types (e.g. Github) to report violations back to their respective services.
|
||||||
|
* @param Builder $builder
|
||||||
|
* @param $file
|
||||||
|
* @param $line
|
||||||
|
* @param $message
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function reportError(Builder $builder, $file, $line, $message)
|
||||||
|
{
|
||||||
|
return array($builder, $file, $line, $message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
namespace PHPCI\Model\Build;
|
namespace PHPCI\Model\Build;
|
||||||
|
|
||||||
use PHPCI\Builder;
|
use PHPCI\Builder;
|
||||||
|
use PHPCI\Helper\Diff;
|
||||||
|
use PHPCI\Helper\Github;
|
||||||
use PHPCI\Model\Build\RemoteGitBuild;
|
use PHPCI\Model\Build\RemoteGitBuild;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,4 +169,56 @@ class GithubBuild extends RemoteGitBuild
|
||||||
|
|
||||||
return $success;
|
return $success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function reportError(Builder $builder, $file, $line, $message)
|
||||||
|
{
|
||||||
|
$diffLineNumber = $this->getDiffLineNumber($builder, $file, $line);
|
||||||
|
|
||||||
|
if (!is_null($diffLineNumber)) {
|
||||||
|
$helper = new Github();
|
||||||
|
|
||||||
|
$repo = $this->getProject()->getReference();
|
||||||
|
$prNumber = $this->getExtra('pull_request_number');
|
||||||
|
$commit = $this->getCommitId();
|
||||||
|
|
||||||
|
if (!empty($prNumber)) {
|
||||||
|
$helper->createPullRequestComment($repo, $prNumber, $commit, $file, $diffLineNumber, $message);
|
||||||
|
} else {
|
||||||
|
$helper->createCommitComment($repo, $commit, $file, $diffLineNumber, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses git diff to figure out what the diff line position is, based on the error line number.
|
||||||
|
* @param Builder $builder
|
||||||
|
* @param $file
|
||||||
|
* @param $line
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
protected function getDiffLineNumber(Builder $builder, $file, $line)
|
||||||
|
{
|
||||||
|
$builder->logExecOutput(false);
|
||||||
|
|
||||||
|
$prNumber = $this->getExtra('pull_request_number');
|
||||||
|
$path = $builder->buildPath;
|
||||||
|
|
||||||
|
if (!empty($prNumber)) {
|
||||||
|
$builder->executeCommand('cd %s && git diff origin/%s "%s"', $path, $this->getBranch(), $file);
|
||||||
|
} else {
|
||||||
|
$builder->executeCommand('cd %s && git diff %s^! "%s"', $path, $this->getCommitId(), $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder->logExecOutput(true);
|
||||||
|
|
||||||
|
$diff = $builder->getLastOutput();
|
||||||
|
|
||||||
|
$helper = new Diff();
|
||||||
|
$lines = $helper->getLinePositions($diff);
|
||||||
|
|
||||||
|
return $lines[$line];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ class Behat implements \PHPCI\Plugin
|
||||||
|
|
||||||
$errorCount = 0;
|
$errorCount = 0;
|
||||||
$storeFailures = false;
|
$storeFailures = false;
|
||||||
$data = [];
|
$data = array();
|
||||||
|
|
||||||
foreach ($lines as $line) {
|
foreach ($lines as $line) {
|
||||||
$line = trim($line);
|
$line = trim($line);
|
||||||
|
@ -119,6 +119,8 @@ class Behat implements \PHPCI\Plugin
|
||||||
'file' => $lineParts[0],
|
'file' => $lineParts[0],
|
||||||
'line' => $lineParts[1]
|
'line' => $lineParts[1]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->build->reportError($this->phpci, $lineParts[0], $lineParts[1], 'Behat scenario failed.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,8 @@ class PhpCodeSniffer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
|
||||||
$fileName = str_replace($this->phpci->buildPath, '', $fileName);
|
$fileName = str_replace($this->phpci->buildPath, '', $fileName);
|
||||||
|
|
||||||
foreach ($file['messages'] as $message) {
|
foreach ($file['messages'] as $message) {
|
||||||
|
$this->build->reportError($this->phpci, $fileName, $message['line'], 'PHPCS: ' . $message['message']);
|
||||||
|
|
||||||
$rtn[] = array(
|
$rtn[] = array(
|
||||||
'file' => $fileName,
|
'file' => $fileName,
|
||||||
'line' => $message['line'],
|
'line' => $message['line'],
|
||||||
|
|
|
@ -140,6 +140,17 @@ class PhpCpd implements \PHPCI\Plugin
|
||||||
'line_end' => (int) $file['line'] + (int) $duplication['lines'],
|
'line_end' => (int) $file['line'] + (int) $duplication['lines'],
|
||||||
'code' => (string) $duplication->codefragment
|
'code' => (string) $duplication->codefragment
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$message = <<<CPD
|
||||||
|
Copy and paste detected:
|
||||||
|
|
||||||
|
```
|
||||||
|
{$duplication->codefragment}
|
||||||
|
```
|
||||||
|
CPD;
|
||||||
|
|
||||||
|
$this->build->reportError($this->phpci, $fileName, $file['line'], $message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$warnings++;
|
$warnings++;
|
||||||
|
|
|
@ -143,12 +143,13 @@ class PhpDocblockChecker implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
|
||||||
// Re-enable exec output logging:
|
// Re-enable exec output logging:
|
||||||
$this->phpci->logExecOutput(true);
|
$this->phpci->logExecOutput(true);
|
||||||
|
|
||||||
$output = json_decode($this->phpci->getLastOutput());
|
$output = json_decode($this->phpci->getLastOutput(), true);
|
||||||
$errors = count($output);
|
$errors = count($output);
|
||||||
$success = true;
|
$success = true;
|
||||||
|
|
||||||
$this->build->storeMeta('phpdoccheck-warnings', $errors);
|
$this->build->storeMeta('phpdoccheck-warnings', $errors);
|
||||||
$this->build->storeMeta('phpdoccheck-data', $output);
|
$this->build->storeMeta('phpdoccheck-data', $output);
|
||||||
|
$this->reportErrors($output);
|
||||||
|
|
||||||
if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) {
|
if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) {
|
||||||
$success = false;
|
$success = false;
|
||||||
|
@ -156,4 +157,21 @@ class PhpDocblockChecker implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
|
||||||
|
|
||||||
return $success;
|
return $success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report all of the errors we've encountered line-by-line.
|
||||||
|
* @param $output
|
||||||
|
*/
|
||||||
|
protected function reportErrors($output)
|
||||||
|
{
|
||||||
|
foreach ($output as $error) {
|
||||||
|
$message = 'Class ' . $error['class'] . ' does not have a Docblock comment.';
|
||||||
|
|
||||||
|
if ($error['type'] == 'method') {
|
||||||
|
$message = 'Method ' . $error['class'] . '::' . $error['method'] . ' does not have a Docblock comment.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->build->reportError($this->phpci, $error['file'], $error['line'], $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,7 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
|
||||||
'message' => (string)$violation,
|
'message' => (string)$violation,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->build->reportError($this->phpci, $fileName, (int)$violation['beginline'], (string)$violation);
|
||||||
$data[] = $warning;
|
$data[] = $warning;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,11 +194,16 @@ class TechnicalDebt implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
|
||||||
|
|
||||||
$errorCount++;
|
$errorCount++;
|
||||||
$this->phpci->log("Found $search on line $lineNumber of $file:\n$content");
|
$this->phpci->log("Found $search on line $lineNumber of $file:\n$content");
|
||||||
|
|
||||||
|
$fileName = str_replace($this->directory, '', $file);
|
||||||
$data[] = array(
|
$data[] = array(
|
||||||
'file' => str_replace($this->directory, '', $file),
|
'file' => $fileName,
|
||||||
'line' => $lineNumber,
|
'line' => $lineNumber,
|
||||||
'message' => $content
|
'message' => $content
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->build->reportError($this->phpci, $fileName, $lineNumber, $content);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,11 +76,11 @@ class Factory
|
||||||
* be passed along with any resources registered with the factory.
|
* be passed along with any resources registered with the factory.
|
||||||
*
|
*
|
||||||
* @param $className
|
* @param $className
|
||||||
* @param array $options
|
* @param array|null $options
|
||||||
* @throws \InvalidArgumentException if $className doesn't represent a valid plugin
|
* @throws \InvalidArgumentException if $className doesn't represent a valid plugin
|
||||||
* @return \PHPCI\Plugin
|
* @return \PHPCI\Plugin
|
||||||
*/
|
*/
|
||||||
public function buildPlugin($className, array $options = array())
|
public function buildPlugin($className, $options = array())
|
||||||
{
|
{
|
||||||
$this->currentPluginOptions = $options;
|
$this->currentPluginOptions = $options;
|
||||||
|
|
||||||
|
|
2
console
2
console
|
@ -13,6 +13,7 @@ define('PHPCI_IS_CONSOLE', true);
|
||||||
require('bootstrap.php');
|
require('bootstrap.php');
|
||||||
|
|
||||||
use PHPCI\Command\RunCommand;
|
use PHPCI\Command\RunCommand;
|
||||||
|
use PHPCI\Command\RebuildCommand;
|
||||||
use PHPCI\Command\GenerateCommand;
|
use PHPCI\Command\GenerateCommand;
|
||||||
use PHPCI\Command\UpdateCommand;
|
use PHPCI\Command\UpdateCommand;
|
||||||
use PHPCI\Command\InstallCommand;
|
use PHPCI\Command\InstallCommand;
|
||||||
|
@ -25,6 +26,7 @@ use b8\Store\Factory;
|
||||||
$application = new Application();
|
$application = new Application();
|
||||||
|
|
||||||
$application->add(new RunCommand($loggerConfig->getFor('RunCommand')));
|
$application->add(new RunCommand($loggerConfig->getFor('RunCommand')));
|
||||||
|
$application->add(new RebuildCommand($loggerConfig->getFor('RunCommand')));
|
||||||
$application->add(new InstallCommand);
|
$application->add(new InstallCommand);
|
||||||
$application->add(new UpdateCommand($loggerConfig->getFor('UpdateCommand')));
|
$application->add(new UpdateCommand($loggerConfig->getFor('UpdateCommand')));
|
||||||
$application->add(new GenerateCommand);
|
$application->add(new GenerateCommand);
|
||||||
|
|
Loading…
Reference in a new issue