Merge branch 'feature-technical-debt-fix'

This commit is contained in:
Dmitry Khomutov 2017-12-14 19:16:57 +07:00
commit 0b71d79cd8
No known key found for this signature in database
GPG key ID: EC19426474B37AAC
3 changed files with 136 additions and 64 deletions

View file

@ -63,7 +63,7 @@ Plugins
* [PHP Unit](plugins/php_unit.md) - `php_unit` * [PHP Unit](plugins/php_unit.md) - `php_unit`
* [Shell](plugins/shell.md) - `shell` * [Shell](plugins/shell.md) - `shell`
* [Slack](plugins/slack_notify.md) - `slack_notify` * [Slack](plugins/slack_notify.md) - `slack_notify`
* [Technical Debt](plugins/technical_dept.md) - `technical_debt` * [Technical Debt](plugins/technical_debt.md) - `technical_debt`
* [Security Checker](plugins/security_checker.md) - SensioLabs Security Checker Plugin (`security_checker`). * [Security Checker](plugins/security_checker.md) - SensioLabs Security Checker Plugin (`security_checker`).
* [XMPP](plugins/xmpp.md) - `xmpp` * [XMPP](plugins/xmpp.md) - `xmpp`

View file

@ -1,4 +1,4 @@
Plugin Technical Dept Plugin Technical Debt
===================== =====================
Checks all files in your project for TODOs and other technical debt. Checks all files in your project for TODOs and other technical debt.

View file

@ -30,12 +30,6 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
*/ */
protected $allowed_errors; protected $allowed_errors;
/**
* @var string, based on the assumption the root may not hold the code to be
* tested, extends the base path
*/
protected $path;
/** /**
* @var array - paths to ignore * @var array - paths to ignore
*/ */
@ -47,13 +41,78 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
protected $searches; protected $searches;
/** /**
* @return string * @var array - lines of . and X to visualize errors
*/ */
protected $errorPerFile = [];
/**
* @var int
*/
protected $currentLineSize = 0;
/**
* @var int
*/
protected $lineNumber = 0;
/**
* @var int
*/
protected $numberOfAnalysedFile = 0;
/**
* @return string
*/
public static function pluginName() public static function pluginName()
{ {
return 'technical_debt'; return 'technical_debt';
} }
/**
* Store the status of the file :
* . : checked no errors
* X : checked with one or more errors
*
* @param string $char
*/
protected function buildLogString($char)
{
if (isset($this->errorPerFile[$this->lineNumber])) {
$this->errorPerFile[$this->lineNumber] .= $char;
} else {
$this->errorPerFile[$this->lineNumber] = $char;
}
$this->currentLineSize++;
$this->numberOfAnalysedFile++;
if ($this->currentLineSize > 59) {
$this->currentLineSize = 0;
$this->lineNumber++;
}
}
/**
* Create a visual representation of file with Todo
* ...XX... 10/300 (10 %)
*
* @return string The visual representation
*/
protected function returnResult()
{
$string = '';
$fileNumber = 0;
foreach ($this->errorPerFile as $oneLine) {
$fileNumber += strlen($oneLine);
$string .= str_pad($oneLine, 60, ' ', STR_PAD_RIGHT);
$string .= str_pad($fileNumber, 4, ' ', STR_PAD_LEFT);
$string .= "/" . $this->numberOfAnalysedFile . " (" . floor($fileNumber * 100 / $this->numberOfAnalysedFile) . " %)\n";
}
$string .= "Checked {$fileNumber} files\n";
return $string;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -63,12 +122,15 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
$this->suffixes = ['php']; $this->suffixes = ['php'];
$this->directory = $this->builder->buildPath; $this->directory = $this->builder->buildPath;
$this->path = '';
$this->ignore = $this->builder->ignore; $this->ignore = $this->builder->ignore;
$this->allowed_errors = 0; $this->allowed_errors = 0;
$this->searches = ['TODO', 'FIXME', 'TO DO', 'FIX ME']; $this->searches = ['TODO', 'FIXME', 'TO DO', 'FIX ME'];
if (isset($options['searches']) && is_array($options['searches'])) { if (!empty($options['suffixes']) && is_array($options['suffixes'])) {
$this->suffixes = $options['suffixes'];
}
if (!empty($options['searches']) && is_array($options['searches'])) {
$this->searches = $options['searches']; $this->searches = $options['searches'];
} }
@ -81,11 +143,12 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
/** /**
* Handle this plugin's options. * Handle this plugin's options.
*
* @param $options * @param $options
*/ */
protected function setOptions($options) protected function setOptions($options)
{ {
foreach (array('directory', 'path', 'ignore', 'allowed_errors') as $key) { foreach (['directory', 'ignore', 'allowed_errors'] as $key) {
if (array_key_exists($key, $options)) { if (array_key_exists($key, $options)) {
$this->{$key} = $options[$key]; $this->{$key} = $options[$key];
} }
@ -95,10 +158,11 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
/** /**
* Check if this plugin can be executed. * Check if this plugin can be executed.
* *
* @param $stage * @param string $stage
* @param Builder $builder * @param Builder $builder
* @param Build $build * @param Build $build
* @return bool *
* @return boolean
*/ */
public static function canExecute($stage, Builder $builder, Build $build) public static function canExecute($stage, Builder $builder, Build $build)
{ {
@ -114,16 +178,14 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
*/ */
public function execute() public function execute()
{ {
$success = true; $success = true;
$this->builder->logExecOutput(false);
$errorCount = $this->getErrorList(); $errorCount = $this->getErrorList();
$this->builder->log("Found $errorCount instances of " . implode(', ', $this->searches)); $this->builder->log($this->returnResult() . "Found $errorCount instances of " . implode(', ', $this->searches));
$this->build->storeMeta('technical_debt-warnings', $errorCount); $this->build->storeMeta('technical_debt-warnings', $errorCount);
if ($this->allowed_errors != -1 && $errorCount > $this->allowed_errors) { if ($this->allowed_errors !== -1 && $errorCount > $this->allowed_errors) {
$success = false; $success = false;
} }
@ -133,65 +195,75 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface
/** /**
* Gets the number and list of errors returned from the search * Gets the number and list of errors returned from the search
* *
* @return array * @return integer
*/ */
public function getErrorList() protected function getErrorList()
{ {
$dirIterator = new \RecursiveDirectoryIterator($this->directory); $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory));
$iterator = new \RecursiveIteratorIterator($dirIterator, \RecursiveIteratorIterator::SELF_FIRST);
$files = [];
$ignores = $this->ignore; $this->builder->logDebug("Ignored path: ".json_encode($this->ignore, true));
$ignores[] = '.php-censor.yml'; $errorCount = 0;
$ignores[] = 'phpci.yml';
$ignores[] = '.phpci.yml';
/** @var \SplFileInfo $file */
foreach ($iterator as $file) { foreach ($iterator as $file) {
$filePath = $file->getRealPath(); $filePath = $file->getRealPath();
$skipFile = false; $extension = $file->getExtension();
foreach ($ignores as $ignore) {
if (stripos($filePath, $ignore) !== false) { $ignored = false;
$skipFile = true; foreach ($this->suffixes as $suffix) {
if ($suffix !== $extension) {
$ignored = true;
break; break;
} }
} }
// Ignore hidden files, else .git, .sass_cache, etc. all get looped over foreach ($this->ignore as $ignore) {
if (stripos($filePath, DIRECTORY_SEPARATOR . '.') !== false) { if ('/' === $ignore{0}) {
$skipFile = true; if (0 === strpos($filePath, $ignore)) {
$ignored = true;
break;
}
} else {
$ignoreReal = $this->directory . $ignore;
if (0 === strpos($filePath, $ignoreReal)) {
$ignored = true;
break;
}
}
} }
if ($skipFile === false) { if (!$ignored) {
$files[] = $file->getRealPath(); $handle = fopen($filePath, "r");
} $lineNumber = 1;
} $errorInFile = false;
while (false === feof($handle)) {
$line = fgets($handle);
$files = array_filter(array_unique($files)); foreach ($this->searches as $search) {
$errorCount = 0; if ($technicalDeptLine = trim(strstr($line, $search))) {
$fileName = str_replace($this->directory, '', $filePath);
foreach ($files as $file) { $this->build->reportError(
foreach ($this->searches as $search) { $this->builder,
$fileContent = file_get_contents($file); 'technical_debt',
$allLines = explode(PHP_EOL, $fileContent); $technicalDeptLine,
$beforeString = strstr($fileContent, $search, true); PHPCensor\Model\BuildError::SEVERITY_LOW,
$fileName,
$lineNumber
);
if (false !== $beforeString) { $errorInFile = true;
$lines = explode(PHP_EOL, $beforeString); $errorCount++;
$lineNumber = count($lines); }
$content = trim($allLines[$lineNumber - 1]); }
$lineNumber++;
}
fclose ($handle);
$errorCount++; if ($errorInFile === true) {
$this->buildLogString('X');
$fileName = str_replace($this->directory, '', $file); } else {
$this->buildLogString('.');
$this->build->reportError(
$this->builder,
'technical_debt',
$content,
PHPCensor\Model\BuildError::SEVERITY_LOW,
$fileName,
$lineNumber
);
} }
} }
} }