This commit is contained in:
OxGroup 2016-11-23 21:36:40 +00:00 committed by GitHub
commit fa66a20a9c
23 changed files with 452 additions and 2914 deletions

3
.gitignore vendored
View file

@ -1,5 +1,7 @@
/composer.lock
.idea
vendor/
.gitignore
composer.phar
config.php
.DS_Store
@ -9,7 +11,6 @@ config.php
.htaccess
PHPCI/config.yml
cache
/loggerconfig.php
/pluginconfig.php
PHPCI/Model/Migration.php
PHPCI/Model/Base/MigrationBase.php

View file

@ -104,7 +104,7 @@ class Application extends b8\Application
$this->response->setContent($view->render());
}
if ($this->response->hasLayout() && $this->controller->layout) {
if (!empty($this->response->hasLayout()) && isset($this->controller->layout)) {
$this->setLayoutVariables($this->controller->layout);
$this->controller->layout->content = $this->response->getContent();

View file

@ -246,7 +246,7 @@ class Builder implements LoggerAwareInterface
// Clean up:
$this->buildLogger->log(Lang::get('removing_build'));
$this->build->removeBuildDirectory();
//$this->build->removeBuildDirectory();
$this->store->save($this->build);
}

View file

@ -74,14 +74,7 @@ class RunCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->output = $output;
// For verbose mode we want to output all informational and above
// messages to the symphony output interface.
if ($input->hasOption('verbose') && $input->getOption('verbose')) {
$this->logger->pushHandler(
new OutputLogHandler($this->output, Logger::INFO)
);
}
$this->logger->pushHandler(new OutputLogHandler($output));
$running = $this->validateRunningBuilds();

View file

@ -12,7 +12,6 @@ namespace PHPCI\Controller;
use b8;
use b8\Store;
use Exception;
use PHPCI\BuildFactory;
use PHPCI\Model\Project;
use PHPCI\Service\BuildService;
use PHPCI\Store\BuildStore;
@ -60,7 +59,7 @@ class WebhookController extends \b8\Controller
/** Handle the action, Ensuring to return a JsonResponse.
*
* @param string $action
* @param mixed $actionParams
* @param mixed $actionParams
*
* @return \b8\Http\Response
*/
@ -78,6 +77,7 @@ class WebhookController extends \b8\Controller
$response->setResponseCode(500);
$response->setContent(array('status' => 'failed', 'error' => $ex->getMessage()));
}
return $response;
}
@ -216,8 +216,8 @@ class WebhookController extends \b8\Controller
/**
* Handle the payload when Github sends a commit webhook.
*
* @param Project $project
* @param array $payload
* @param Project $project
* @param array $payload
* @param b8\Http\Response\JsonResponse $response
*
* @return b8\Http\Response\JsonResponse
@ -256,6 +256,7 @@ class WebhookController extends \b8\Controller
$results[$commit['id']] = array('status' => 'failed', 'error' => $ex->getMessage());
}
}
return array('status' => $status, 'commits' => $results);
}
@ -264,6 +265,7 @@ class WebhookController extends \b8\Controller
$branch = str_replace('refs/tags/', 'Tag: ', $payload['ref']);
$committer = $payload['pusher']['email'];
$message = $payload['head_commit']['message'];
return $this->createBuild($project, $payload['after'], $branch, $committer, $message);
}
@ -274,7 +276,7 @@ class WebhookController extends \b8\Controller
* Handle the payload when Github sends a Pull Request webhook.
*
* @param Project $project
* @param array $payload
* @param array $payload
*/
protected function githubPullRequest(Project $project, array $payload)
{
@ -290,10 +292,17 @@ class WebhookController extends \b8\Controller
$headers[] = 'Authorization: token ' . $token;
}
$url = $payload['pull_request']['commits_url'];
$http = new \b8\HttpClient();
$url = $payload['pull_request']['commits_url'];
$http = new \b8\HttpClient();
$http->setHeaders($headers);
$response = $http->get($url);
//for large pull requests, allow grabbing more then the default number of commits
$custom_per_page = \b8\Config::getInstance()->get('phpci.github.per_page');
$params = [];
if ($custom_per_page) {
$params["per_page"] = $custom_per_page;
}
$response = $http->get($url, $params);
// Check we got a success response:
if (!$response['success']) {
@ -379,6 +388,7 @@ class WebhookController extends \b8\Controller
$results[$commit['id']] = array('status' => 'failed', 'error' => $ex->getMessage());
}
}
return array('status' => $status, 'commits' => $results);
}
@ -389,11 +399,11 @@ class WebhookController extends \b8\Controller
* Wrapper for creating a new build.
*
* @param Project $project
* @param string $commitId
* @param string $branch
* @param string $committer
* @param string $commitMessage
* @param array $extra
* @param string $commitId
* @param string $branch
* @param string $committer
* @param string $commitMessage
* @param array $extra
*
* @return array
*
@ -406,7 +416,8 @@ class WebhookController extends \b8\Controller
$committer,
$commitMessage,
array $extra = null
) {
)
{
// Check if a build already exists for this commit ID:
$builds = $this->buildStore->getByProjectAndCommit($project->getId(), $commitId);
@ -426,7 +437,7 @@ class WebhookController extends \b8\Controller
/**
* Fetch a project and check its type.
*
* @param int $projectId
* @param int $projectId
* @param array|string $expectedType
*
* @return Project

View file

@ -37,7 +37,7 @@ class Lang
return call_user_func_array('sprintf', $vars);
}
return '%%MISSING STRING: ' . $string . '%%';
return $string;
}
/**

View file

@ -438,7 +438,6 @@ PHPCI',
'php_unit' => 'PHP Unit',
'php_cpd' => 'PHP Copy/Paste Detector',
'php_docblock_checker' => 'PHP Docblock Checker',
'behat' => 'Behat',
'technical_debt' => 'Technical Debt',
'php_lint' => 'PHP Lint',
);

View file

@ -98,8 +98,8 @@ PHPCI',
'gitlab' => 'GitLab',
'remote' => 'Внешний URL',
'local' => 'Локальный путь',
'hg' => 'Mercurial',
'svn' => 'Subversion',
'hg' => 'Mercurial',
'svn' => 'Subversion',
'where_hosted' => 'Расположение проекта',
'choose_github' => 'Выберите GitHub репозиторий:',
@ -148,11 +148,12 @@ PHPCI',
Services</a> вашего Bitbucket репозитория.',
// View Build
'build_x_not_found' => 'Сборки с ID %d не существует.',
'errors' => 'Ошибки',
'information' => 'Информация',
'build_x_not_found' => 'Сборки с ID %d не существует.',
'build_n' => 'Сборка %d',
'rebuild_now' => 'Пересобрать сейчас',
'committed_by_x' => 'Отправил %s',
'commit_id_x' => 'Коммит: %s',
@ -164,6 +165,7 @@ PHPCI',
'noncomment_lines' => 'Строк некомментариев',
'logical_lines' => 'Строк логики',
'lines_of_code' => 'Строк кода',
'structure' => 'Структура',
'build_log' => 'Лог сборки',
'quality_trend' => 'Тенденция качества',
'codeception_errors' => 'Ошибки Codeception',
@ -205,8 +207,8 @@ PHPCI',
'build_created' => 'Сборка создана',
'build_started' => 'Сборка запущена',
'build_finished' => 'Сборка окончена',
'test_message' => 'Message',
'test_no_message' => 'No message',
'test_message' => 'Сообщение',
'test_no_message' => 'Нет сообщений',
'test_success' => 'Успешно: %d',
'test_fail' => 'Провалено: %d',
'test_skipped' => 'Пропущено: %d',
@ -268,8 +270,8 @@ PHPCI',
'5_mins' => '5 минут',
'15_mins' => '15 минут',
'30_mins' => '30 минут',
'1_hour' => '1 часа',
'3_hours' => '3 часов',
'1_hour' => '1 час',
'3_hours' => '3 часа',
// Plugins
'cannot_update_composer' => 'PHPCI не может обновить composer.json, если он недоступен на запись.',
@ -293,11 +295,11 @@ PHPCI',
'duration' => 'Продолжительность',
'plugin' => 'Плагин',
'stage_setup' => 'Установка',
'stage_test' => 'тестирование',
'stage_complete' => 'Завершение',
'stage_success' => 'Успешное завершение',
'stage_failure' => 'Провал',
'stage_broken' => 'Поломка',
'stage_test' => 'Тестирование',
'stage_complete' => 'Завершено',
'stage_success' => 'Успешно',
'stage_failure' => 'Провалено',
'stage_broken' => 'Поломка',
'stage_fixed' => 'Исправление',
// Installer
@ -408,5 +410,19 @@ PHPCI',
'build_file_missing' => 'Указанного файла сборки не существует.',
'property_file_missing' => 'Указанного файла сборки не существует.',
'could_not_process_report' => 'Невозможно обработать отчет этой утилиты.',
'shell_not_enabled' => 'Плагин shell не включен. Пожалуйста, включите его в файле config.yml.'
'shell_not_enabled' => 'Плагин shell не включен. Пожалуйста, включите его в файле config.yml.',
// Error Levels:
'critical' => 'Критическая',
'high' => 'Высокий',
'normal' => 'Обычный',
'low' => 'Низкий',
// Plugins that generate errors:
'php_mess_detector' => 'PHP Mess Detector',
'php_code_sniffer' => 'PHP Code Sniffer',
'php_unit' => 'PHP Unit',
'php_cpd' => 'PHP Copy/Paste Detector',
'php_docblock_checker' => 'PHP Docblock Checker',
'php_lint' => 'PHP Lint'
);

View file

@ -10,40 +10,82 @@
namespace PHPCI\Logging;
use Monolog\Handler\AbstractProcessingHandler;
use Psr\Log\LogLevel;
use Monolog\Logger;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class OutputLogHandler outputs the build log to the terminal.
*
* @package PHPCI\Logging
*/
class OutputLogHandler extends AbstractProcessingHandler
{
/**
* @var array
*/
protected static $levels = array(
OutputInterface::VERBOSITY_QUIET => Logger::ERROR,
OutputInterface::VERBOSITY_NORMAL => Logger::WARNING,
OutputInterface::VERBOSITY_VERBOSE => Logger::NOTICE,
OutputInterface::VERBOSITY_VERY_VERBOSE => Logger::INFO,
OutputInterface::VERBOSITY_DEBUG => Logger::DEBUG,
);
/**
* @var array
*/
protected static $colors = array(
Logger::ERROR => 'red',
Logger::WARNING => 'yellow',
Logger::NOTICE => 'green',
Logger::INFO => 'white'
);
/**
* @var OutputInterface
*/
protected $output;
/**
* OutputLogHandler constructor.
*
* @param OutputInterface $output
* @param bool|string $level
* @param bool $bubble
*/
public function __construct(
OutputInterface $output,
$level = LogLevel::INFO,
$bubble = true
) {
parent::__construct($level, $bubble);
public function __construct(OutputInterface $output)
{
parent::__construct(static::$levels[$output->getVerbosity()]);
$this->output = $output;
$this->pushProcessor(array($this, 'addConsoleColor'));
}
public function addConsoleColor($record)
{
foreach (static::$colors as $level => $color) {
if ($record['level'] >= $level) {
break;
}
}
$record['message'] = sprintf('<fg=%s>%s</fg=%s>', $color, rtrim($record['message']), $color);
return $record;
}
/**
* Write a log entry to the terminal.
*
* @param array $record
*/
protected function write(array $record)
{
$this->output->writeln((string)$record['formatted']);
if ($record['level'] >= Logger::ERROR && $this->output instanceof ConsoleOutputInterface) {
$output = $this->output->getErrorOutput();
} else {
$output = $this->output;
}
$output->write($record['formatted']);
}
}

View file

@ -15,6 +15,7 @@ use PHPCI\Model\Build;
/**
* PHP Loc - Allows PHP Copy / Lines of Code testing.
*
* @author Johan van der Heide <info@japaveh.nl>
* @package PHPCI
* @subpackage Plugins
@ -30,11 +31,18 @@ class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
*/
protected $phpci;
/**
* @var Build
*/
protected $build;
/**
* Check if this plugin can be executed.
* @param $stage
*
* @param $stage
* @param Builder $builder
* @param Build $build
* @param Build $build
*
* @return bool
*/
public static function canExecute($stage, Builder $builder, Build $build)
@ -48,14 +56,15 @@ class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
/**
* Set up the plugin, configure options, etc.
*
* @param Builder $phpci
* @param Build $build
* @param array $options
* @param Build $build
* @param array $options
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->phpci = $phpci;
$this->build = $build;
$this->directory = $phpci->buildPath;
if (isset($options['directory'])) {
@ -82,17 +91,30 @@ class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$phploc = $this->phpci->findBinary('phploc');
$success = $this->phpci->executeCommand($phploc . ' %s "%s"', $ignore, $this->directory);
$output = $this->phpci->getLastOutput();
$output = $this->phpci->getLastOutput();
if (preg_match_all('/\((LOC|CLOC|NCLOC|LLOC)\)\s+([0-9]+)/', $output, $matches)) {
if (preg_match_all('/\((LOC|CLOC|NCLOC|LLOC)\)\s+([0-9]+)/', $output, $matches2)) {
$data = array();
foreach ($matches[1] as $k => $v) {
$data[$v] = (int)$matches[2][$k];
foreach ($matches2[1] as $k => $v) {
$data[$v] = (int) $matches2[2][$k];
}
$this->build->storeMeta('phploc', $data);
}
if (preg_match_all('/(Namespaces|Interfaces|Classes|Methods)\s+([0-9]+)/', $output, $matches)) {
$key = $matches[1];
$val = $matches[2];
$data = array(
$key[1] => (int) $val[1],
$key[2] => (int) $val[2],
$key[3] => (int) $val[3],
$key[6] => (int) $val[6],
);
$this->build->storeMeta('phploc-structure', $data);
}
return $success;
}
}

View file

@ -2,32 +2,37 @@
namespace PHPCI\Plugin\Util;
use Pimple\Container;
/**
* Plugin Factory - Loads Plugins and passes required dependencies.
*
* @package PHPCI\Plugin\Util
*/
class Factory
{
const TYPE_ARRAY = "array";
const TYPE_CALLABLE = "callable";
const TYPE_ARRAY = "array";
const TYPE_CALLABLE = "callable";
const INTERFACE_PHPCI_PLUGIN = '\PHPCI\Plugin';
private $currentPluginOptions;
/**
* @var \Pimple
* @var Container
*/
private $container;
/**
* @param \Pimple $container
* Factory constructor.
*
* @param Container|null $container
*/
public function __construct(\Pimple $container = null)
public function __construct(Container $container = null)
{
if ($container) {
$this->container = $container;
} else {
$this->container = new \Pimple();
$this->container = new Container();
}
$self = $this;
@ -46,6 +51,7 @@ class Factory
* This enables the config file to call any public methods.
*
* @param $configPath
*
* @return bool - true if the function exists else false.
*/
public function addConfigFromFile($configPath)
@ -56,14 +62,17 @@ class Factory
$configFunction = require($configPath);
if (is_callable($configFunction)) {
$configFunction($this);
return true;
}
}
return false;
}
/**
* Get most recently used factory options.
*
* @return mixed
*/
public function getLastOptions()
@ -75,8 +84,9 @@ class Factory
* Builds an instance of plugin of class $className. $options will
* be passed along with any resources registered with the factory.
*
* @param $className
* @param $className
* @param array|null $options
*
* @throws \InvalidArgumentException if $className doesn't represent a valid plugin
* @return \PHPCI\Plugin
*/
@ -108,9 +118,10 @@ class Factory
}
/**
* @param callable $loader
* @param callable $loader
* @param string|null $name
* @param string|null $type
*
* @throws \InvalidArgumentException
* @internal param mixed $resource
*/
@ -118,7 +129,8 @@ class Factory
$loader,
$name = null,
$type = null
) {
)
{
if ($name === null && $type === null) {
throw new \InvalidArgumentException(
"Type or Name must be specified"
@ -138,20 +150,24 @@ class Factory
/**
* Get an internal resource ID.
*
* @param null $type
* @param null $name
*
* @return string
*/
private function getInternalID($type = null, $name = null)
{
$type = $type ? : "";
$name = $name ? : "";
$type = $type ?: "";
$name = $name ?: "";
return $type . "-" . $name;
}
/**
* @param string $type
* @param string $name
*
* @return mixed
*/
public function getResourceFor($type = null, $name = null)
@ -176,6 +192,7 @@ class Factory
/**
* @param \ReflectionParameter $param
*
* @return null|string
*/
private function getParamType(\ReflectionParameter $param)
@ -193,8 +210,9 @@ class Factory
}
/**
* @param $existingArgs
* @param $existingArgs
* @param \ReflectionParameter $param
*
* @return array
* @throws \DomainException
*/

View file

@ -9,7 +9,7 @@
<?php Lang::out('edit_project'); ?>
</a>
<a class="btn btn-danger" href="javascript:confirmDelete('<?php print PHPCI_URL . 'project/delete/' . $project->getId(); ?>', '<?php print Lang::out('project'); ?>', true)">
<a class="btn btn-danger" href="javascript:;" onclick="confirmDelete('<?php print PHPCI_URL . 'project/delete/' . $project->getId(); ?>', '<?php print Lang::out('project'); ?>', true)">
<?php Lang::out('delete_project'); ?>
</a>

View file

@ -31,6 +31,7 @@
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/class.js"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/sprintf.js"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/moment.min.js"></script>

View file

@ -1,79 +0,0 @@
{
"name" : "block8/phpci",
"description" : "Simple continuous integration for PHP projects.",
"minimum-stability": "stable",
"type" : "library",
"keywords" : ["php", "phpci", "ci", "continuous", "integration", "testing", "phpunit", "continuous integration", "jenkins", "travis"],
"homepage" : "http://www.phptesting.org/",
"license" : "BSD-2-Clause",
"authors": [
{
"name" : "Dan Cryer",
"email" : "dan.cryer@block8.co.uk",
"homepage": "http://www.block8.co.uk",
"role" : "Developer"
}
],
"support": {
"email" : "hello+phpci@block8.co.uk",
"issues": "https://github.com/Block8/PHPCI/issues",
"source": "https://github.com/Block8/PHPCI"
},
"autoload": {
"psr-4": {
"PHPCI\\": "PHPCI"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\PHPCI\\": "Tests/PHPCI/"
}
},
"require": {
"php": ">=5.3.8",
"ext-pdo": "*",
"ext-pdo_mysql": "*",
"block8/b8framework": "~1.0",
"ircmaxell/password-compat": "~1.0",
"swiftmailer/swiftmailer": "~5.0",
"symfony/yaml": "~2.1",
"symfony/console": "~2.1",
"psr/log": "~1.0",
"monolog/monolog": "~1.6",
"pimple/pimple": "~1.1",
"robmorgan/phinx": "~0.4",
"sensiolabs/ansi-to-html": "~1.1",
"pda/pheanstalk": "~3.1",
"maknz/slack": "~1.7",
"hipchat/hipchat-php": "~1.4",
"mremi/flowdock": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.5",
"phpmd/phpmd": "~2.0",
"squizlabs/php_codesniffer": "~2.3",
"block8/php-docblock-checker": "~1.0",
"phploc/phploc": "~2.0",
"jakub-onderka/php-parallel-lint": "0.8.*"
},
"suggest": {
"block8/php-docblock-checker": "PHP Docblock Checker",
"phpmd/phpmd": "PHP Mess Detector",
"sebastian/phpcpd": "PHP Copy/Paste Detector",
"squizlabs/php_codesniffer": "PHP Code Sniffer",
"phpspec/phpspec": "PHP Spec",
"fabpot/php-cs-fixer": "PHP Coding Standards Fixer",
"phploc/phploc": "PHP Lines of Code",
"atoum/atoum": "Atoum",
"jakub-onderka/php-parallel-lint": "Parallel Linting Tool",
"behat/behat": "Behat BDD Testing",
"phptal/phptal": "PHPTAL templating engine"
}
}

2740
composer.lock generated

File diff suppressed because it is too large Load diff

0
errors.log Normal file
View file

View file

@ -0,0 +1,72 @@
var composerSecurityCheck = ActiveBuild.UiPlugin.extend({
id: 'build-composer-security-check-errors',
css: 'col-lg-6 col-md-6 col-sm-6 col-xs-6',
title: Lang.get('Composer Security'),
lastData: null,
displayOnUpdate: false,
box: true,
rendered: false,
register: function() {
var self = this;
var query = ActiveBuild.registerQuery('composer-security-check-errors', -1, {key: 'composer-security-check-errors'})
$(window).on('composer-security-check-errors', function(data) {
self.onUpdate(data);
});
$(window).on('build-updated', function() {
if (!self.rendered) {
self.displayOnUpdate = true;
query();
}
});
},
render: function() {
return $('<div class="table-responsive"><table class="table" id="composer-security-check-data">' +
'<thead>' +
'<tr>' +
' <th>'+Lang.get('Resultats')+'</th>' +
'</tr>' +
'</thead><tbody></tbody></table></div>');
},
onUpdate: function(e) {
if (!e.queryData) {
$('#build-composer-security-check-errors').hide();
return;
}
this.rendered = true;
this.lastData = e.queryData;
var results = this.lastData[0].meta_value;
var tbody = $('#composer-security-check-data tbody');
tbody.empty();
if (results.length == 0) {
$('#build-composer-security-check-errors').hide();
return;
}
console.log(results);
for (var i in results) {
var lib = results[i];
var head = '<tr><th>'+i + ' ' + lib.version+'</th></tr>'
tbody.append(head);
console.log(lib);
for (var j in lib.advisories) {
var advise = lib.advisories[j]
console.log(advise);
var row = '<tr><td><a href="'+advise.link+'" target="_blank">'+advise.title+'</a></TD></tr>'
tbody.append(row);
}
}
$('#build-composer-security-check-errors').show();
}
});
ActiveBuild.registerPlugin(new composerSecurityCheck());

View file

@ -1,6 +1,6 @@
var locPlugin = ActiveBuild.UiPlugin.extend({
id: 'build-lines-chart',
css: 'col-xs-12',
css: 'col-xs-6',
title: Lang.get('lines_of_code'),
lastData: null,
displayOnUpdate: false,

View file

@ -0,0 +1,106 @@
var locPlugin2 = ActiveBuild.UiPlugin.extend({
id: 'build-lines-chart-structure',
css: 'col-xs-6',
title: Lang.get('structure'),
lastData: null,
displayOnUpdate: false,
rendered: false,
chartData: null,
register: function() {
var self = this;
var query = ActiveBuild.registerQuery('phploc-structure', -1, {num_builds: 10, key: 'phploc-structure'})
$(window).on('phploc-structure', function(data) {
self.onUpdate(data);
});
$(window).on('build-updated', function(data) {
if (data.queryData.status > 1 && !self.rendered) {
query();
}
});
},
render: function() {
var self = this;
var container = $('<div id="phploc-structure" style="width: 100%; height: 300px"></div>');
container.append('<canvas id="phploc-structure-chart" style="width: 100%; height: 300px"></canvas>');
$(document).on('shown.bs.tab', function () {
$('#build-lines-chart-structure').hide();
self.drawChart();
});
return container;
},
onUpdate: function(e) {
this.lastData = e.queryData;
this.displayChart();
},
displayChart: function() {
var self = this;
var builds = this.lastData;
self.rendered = true;
self.chartData = {
labels: [],
datasets: [
{
label: "Namespaces",
strokeColor: "rgba(60,141,188,1)",
pointColor: "rgba(60,141,188,1)",
data: []
},
{
label: "Interfaces",
strokeColor: "rgba(245,105,84,1)",
pointColor: "rgba(245,105,84,1)",
data: []
},
{
label: "Classes",
strokeColor: "rgba(0,166,90,1)",
pointColor: "rgba(0,166,90,1)",
data: []
},
{
label: "Methods",
strokeColor: "rgba(0,192,239,1)",
pointColor: "rgba(0,192,239,1)",
data: []
}
]
};
for (var i in builds) {
self.chartData.labels.push('Build ' + builds[i].build_id);
self.chartData.datasets[0].data.push(builds[i].meta_value.Namespaces);
self.chartData.datasets[1].data.push(builds[i].meta_value.Interfaces);
self.chartData.datasets[2].data.push(builds[i].meta_value.Classes);
self.chartData.datasets[3].data.push(builds[i].meta_value.Methods);
}
self.drawChart();
},
drawChart: function () {
var self = this;
if ($('#information').hasClass('active') && self.chartData && self.lastData) {
$('#build-lines-chart-structure').show();
var ctx = $("#phploc-structure-chart").get(0).getContext("2d");
var phpLocChart = new Chart(ctx);
phpLocChart.Line(self.chartData, {
datasetFill: false,
multiTooltipTemplate: "<%=datasetLabel%>: <%= value %>"
});
}
}
});
ActiveBuild.registerPlugin(new locPlugin2());

View file

@ -1,6 +1,6 @@
var SummaryPlugin = ActiveBuild.UiPlugin.extend({
id: 'build-summary',
css: 'col-xs-12',
css: 'col-xs-6',
title: Lang.get('build-summary'),
box: true,
statusIcons: [ 'fa-clock-o', 'fa-cogs', 'fa-check', 'fa-remove' ],

View file

@ -1,6 +1,6 @@
var warningsPlugin = ActiveBuild.UiPlugin.extend({
id: 'build-warnings-chart',
css: 'col-xs-12',
css: 'col-xs-6',
title: Lang.get('quality_trend'),
keys: {
'codeception-errors': Lang.get('codeception_errors'),

View file

@ -6,7 +6,7 @@ var Build = Class.extend({
queries: {},
updateInterval: null,
init: function(build) {
init: function (build) {
var self = this;
self.buildId = build;
},
@ -18,7 +18,7 @@ var Build = Class.extend({
self.registerQuery('build-updated', 10);
$(window).on('build-updated', function(data) {
$(window).on('build-updated', function (data) {
self.buildData = data.queryData;
@ -68,12 +68,12 @@ var Build = Class.extend({
});
},
registerQuery: function(name, seconds, query) {
registerQuery: function (name, seconds, query) {
var self = this;
var uri = 'build/meta/' + self.buildId;
var query = query || {};
var cb = function() {
var cb = function () {
var fullUri = window.PHPCI_URL + uri;
if (name == 'build-updated') {
@ -84,7 +84,7 @@ var Build = Class.extend({
dataType: "json",
url: fullUri,
data: query,
success: function(data) {
success: function (data) {
$(window).trigger({type: name, queryData: data});
},
error: handleFailedAjax
@ -102,7 +102,7 @@ var Build = Class.extend({
clearInterval(this.queries[name]);
},
registerPlugin: function(plugin) {
registerPlugin: function (plugin) {
this.plugins[plugin.id] = plugin;
plugin.register();
},
@ -110,14 +110,14 @@ var Build = Class.extend({
storePluginOrder: function () {
var renderOrder = [];
$('.ui-plugin > div').each(function() {
$('.ui-plugin > div').each(function () {
renderOrder.push($(this).attr('id'));
});
localStorage.setItem('phpci-plugin-order', JSON.stringify(renderOrder));
},
renderPlugins: function() {
renderPlugins: function () {
var self = this;
var rendered = [];
var renderOrder = localStorage.getItem('phpci-plugin-order');
@ -155,7 +155,7 @@ var Build = Class.extend({
$(window).trigger({type: 'build-updated', queryData: self.buildData});
},
renderPlugin: function(plugin) {
renderPlugin: function (plugin) {
var output = plugin.render();
if (!plugin.box) {
@ -167,26 +167,102 @@ var Build = Class.extend({
content.addClass('box box-default');
if (plugin.title) {
content.prepend('<div class="box-header"><h3 class="box-title">'+plugin.title+'</h3></div>');
content.prepend('<div class="box-header"><h3 class="box-title">' + plugin.title + '</h3></div>');
}
this.toggleWidget(content);
container.append(content);
$('#plugins').append(container);
},
toggleWidget: function ($box) {
var self = this;
var id = $box.attr('id');
var $header = $box.find('.box-header');
var $content = $header.next();
// Add widget toggler
var $toggle = $('<i class="box-tools fa pull-right fa-angle-down"></i>');
if (self.isWidgetHidden(id)) {
$content.addClass('hidden');
$toggle.toggleClass('fa-angle-down fa-angle-left');
}
$toggle.appendTo($header).click(function () {
$content.toggleClass('hidden');
if ($content.hasClass('hidden')) {
self.hideWidget(id);
} else {
self.showWidget(id);
}
$(this).toggleClass('fa-angle-down fa-angle-left');
});
},
isWidgetHidden: function (id) {
var settings = this._getSettings('hidden_widgets');
return (settings.indexOf(id) != -1);
},
hideWidget: function (id) {
var settings = this._getSettings('hidden_widgets');
var index = settings.indexOf(id);
if (index == -1) {
settings.push(id);
this._storeSettings('hidden_widgets', settings);
}
},
showWidget: function (id) {
var settings = this._getSettings('hidden_widgets');
var index = settings.indexOf(id);
if (index != -1) {
settings.splice(index, 1);
this._storeSettings('hidden_widgets', settings);
}
},
_getSettings: function (setting) {
var settingsArray = [];
var settingsString = $.cookie(setting);
if (settingsString) {
settingsArray = settingsString.split(',');
}
return settingsArray;
},
_storeSettings: function (setting, value) {
$.cookie(setting, value.toString());
},
UiPlugin: Class.extend({
id: null,
css: 'col-lg-4 col-md-6 col-sm-12 col-xs-12',
box: false,
init: function(){
init: function () {
},
register: function() {
register: function () {
var self = this;
$(window).on('build-updated', function(data) {
$(window).on('build-updated', function (data) {
self.onUpdate(data);
});
},