Adding Technical Debt plugin.
This commit is contained in:
parent
8ba9738add
commit
6be867a517
|
@ -183,6 +183,7 @@ PHPCI',
|
|||
'phpmd' => 'PHP Mess Detector',
|
||||
'phpspec' => 'PHP Spec',
|
||||
'phpunit' => 'PHP Unit',
|
||||
'technical_debt' => 'Technical Debt',
|
||||
|
||||
'file' => 'File',
|
||||
'line' => 'Line',
|
||||
|
|
183
PHPCI/Plugin/TechnicalDebt.php
Executable file
183
PHPCI/Plugin/TechnicalDebt.php
Executable file
|
@ -0,0 +1,183 @@
|
|||
<?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\Plugin;
|
||||
|
||||
use PHPCI;
|
||||
use PHPCI\Builder;
|
||||
use PHPCI\Model\Build;
|
||||
|
||||
/**
|
||||
* Technical Debt Plugin - Checks for existence of "TODO", "FIXME", etc.
|
||||
*
|
||||
* @author James Inman <james@jamesinman.co.uk>
|
||||
* @package PHPCI
|
||||
* @subpackage Plugins
|
||||
*/
|
||||
class TechnicalDebt implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
|
||||
{
|
||||
/**
|
||||
* @var \PHPCI\Builder
|
||||
*/
|
||||
protected $phpci;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $suffixes;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $directory;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $allowed_errors;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $allowed_warnings;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
protected $ignore;
|
||||
|
||||
/**
|
||||
* @var array - terms to search for
|
||||
*/
|
||||
protected $searches;
|
||||
|
||||
public static function canExecute($stage, Builder $builder, Build $build)
|
||||
{
|
||||
if ($stage == 'test') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PHPCI\Builder $phpci
|
||||
* @param \PHPCI\Model\Build $build
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(Builder $phpci, Build $build, array $options = array())
|
||||
{
|
||||
$this->phpci = $phpci;
|
||||
$this->build = $build;
|
||||
$this->suffixes = array('php');
|
||||
$this->directory = $phpci->buildPath;
|
||||
$this->path = '';
|
||||
$this->ignore = $this->phpci->ignore;
|
||||
$this->allowed_warnings = 0;
|
||||
$this->allowed_errors = 0;
|
||||
$this->searches = array('TODO', 'FIXME', 'TO DO', 'FIX ME');
|
||||
|
||||
if (isset($options['searches']) && is_array($options['searches'])) {
|
||||
$this->searches = $options['searches'];
|
||||
}
|
||||
|
||||
if (isset($options['zero_config']) && $options['zero_config']) {
|
||||
$this->allowed_warnings = -1;
|
||||
$this->allowed_errors = -1;
|
||||
}
|
||||
}
|
||||
|
||||
protected function setOptions($options)
|
||||
{
|
||||
foreach (array('directory', 'path', 'ignore', 'allowed_warnings', 'allowed_errors') as $key) {
|
||||
if (array_key_exists($key, $options)) {
|
||||
$this->{$key} = $options[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs in a specified directory, to a specified standard.
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$this->phpci->logExecOutput(false);
|
||||
|
||||
$ignores = $this->ignore;
|
||||
$ignores[] = 'phpci.yml';
|
||||
|
||||
$dirIterator = new \RecursiveDirectoryIterator($this->directory);
|
||||
$iterator = new \RecursiveIteratorIterator($dirIterator, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$files = [];
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
$filePath = $file->getRealPath();
|
||||
$skipFile = false;
|
||||
foreach ($ignores as $ignore) {
|
||||
if (stripos($filePath, $ignore) !== false) {
|
||||
$skipFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore hidden files, else .git, .sass_cache, etc. all get looped over
|
||||
if (stripos($filePath, '/.') !== false) {
|
||||
$skipFile = true;
|
||||
}
|
||||
|
||||
if ($skipFile == false) {
|
||||
$files[] = $file->getRealPath();
|
||||
}
|
||||
}
|
||||
|
||||
$files = array_filter(array_unique($files));
|
||||
$errorCount = 0;
|
||||
$data = array();
|
||||
|
||||
foreach ($files as $file) {
|
||||
foreach ($this->searches as $search) {
|
||||
$fileContent = file_get_contents($file);
|
||||
$allLines = explode(PHP_EOL, $fileContent);
|
||||
$beforeString = strstr($fileContent, $search, true);
|
||||
|
||||
if (false !== $beforeString) {
|
||||
$lines = explode(PHP_EOL, $beforeString);
|
||||
$lineNumber = count($lines);
|
||||
$content = trim($allLines[$lineNumber - 1]);
|
||||
|
||||
$errorCount++;
|
||||
$this->phpci->log("Found $search on line $lineNumber of $file:\n$content");
|
||||
$data[] = array(
|
||||
'file' => str_replace($this->directory, '', $file),
|
||||
'line' => $lineNumber,
|
||||
'message' => $content
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->phpci->log("Found $errorCount instances of " . implode(', ', $this->searches));
|
||||
|
||||
$this->build->storeMeta('technical_debt-warnings', $errorCount);
|
||||
$this->build->storeMeta('technical_debt-data', $data);
|
||||
|
||||
if ($this->allowed_errors != -1 && $errorCount > $this->allowed_errors) {
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
|
79
public/assets/js/build-plugins/technical_debt.js
Executable file
79
public/assets/js/build-plugins/technical_debt.js
Executable file
|
@ -0,0 +1,79 @@
|
|||
var TechnicalDebtPlugin = ActiveBuild.UiPlugin.extend({
|
||||
id: 'build-technical_debt',
|
||||
css: 'col-lg-6 col-md-12 col-sm-12 col-xs-12',
|
||||
title: Lang.get('technical_debt'),
|
||||
lastData: null,
|
||||
box: true,
|
||||
rendered: false,
|
||||
|
||||
register: function() {
|
||||
var self = this;
|
||||
var query = ActiveBuild.registerQuery('technical_debt-data', -1, {key: 'technical_debt-data'})
|
||||
|
||||
$(window).on('technical_debt-data', function(data) {
|
||||
self.onUpdate(data);
|
||||
});
|
||||
|
||||
$(window).on('build-updated', function() {
|
||||
if (!self.rendered) {
|
||||
query();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return $('<div class="table-responsive"><table class="table" id="technical_debt-data">' +
|
||||
'<thead>' +
|
||||
'<tr>' +
|
||||
' <th>'+Lang.get('file')+'</th>' +
|
||||
' <th>'+Lang.get('line')+'</th>' +
|
||||
' <th>'+Lang.get('message')+'</th>' +
|
||||
'</tr>' +
|
||||
'</thead><tbody></tbody></table></div>');
|
||||
},
|
||||
|
||||
onUpdate: function(e) {
|
||||
if (!e.queryData) {
|
||||
$('#build-technical_debt').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
this.rendered = true;
|
||||
this.lastData = e.queryData;
|
||||
|
||||
var errors = this.lastData[0].meta_value;
|
||||
var tbody = $('#technical_debt-data tbody');
|
||||
tbody.empty();
|
||||
|
||||
if (errors.length == 0) {
|
||||
$('#build-technical_debt').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i in errors) {
|
||||
var file = errors[i].file;
|
||||
|
||||
if (ActiveBuild.fileLinkTemplate) {
|
||||
var fileLink = ActiveBuild.fileLinkTemplate.replace('{FILE}', file);
|
||||
fileLink = fileLink.replace('{LINE}', errors[i].line);
|
||||
|
||||
file = '<a target="_blank" href="'+fileLink+'">' + file + '</a>';
|
||||
}
|
||||
|
||||
var row = $('<tr class="warning">' +
|
||||
'<td>'+file+'</td>' +
|
||||
'<td>'+errors[i].line+'</td>' +
|
||||
'<td>'+errors[i].message+'</td></tr>');
|
||||
|
||||
if (errors[i].type == 'ERROR') {
|
||||
row.addClass('danger');
|
||||
}
|
||||
|
||||
tbody.append(row);
|
||||
}
|
||||
|
||||
$('#build-technical_debt').show();
|
||||
}
|
||||
});
|
||||
|
||||
ActiveBuild.registerPlugin(new TechnicalDebtPlugin());
|
Loading…
Reference in a new issue