Merge remote-tracking branch 'block8/master'

This commit is contained in:
Frank Laszlo 2016-04-11 09:18:58 -04:00
commit 538fbb295a
898 changed files with 165012 additions and 19556 deletions

View file

@ -8,6 +8,7 @@ build_settings:
- "PHPCI/Migrations" # Ignore the migrations directory, as both PHPMD and PHPCS can't cope with them.
- "PHPCI/Model/Base" # These files are auto-generated, and sometimes hit PHPMD complexity thresholds.
- "PHPCI/Languages" # PHPCS fails on character counts for non-Latin languages
- "public/assets" # If there are any PHP files in here, we didn't write them.
setup:
composer:
@ -32,7 +33,7 @@ test:
php_docblock_checker:
allowed_warnings: 0
failure:
broken:
email:
committer: true
cc: ["php-ci@googlegroups.com"]

View file

@ -303,8 +303,7 @@ class Builder implements LoggerAwareInterface
*/
protected function setupBuild()
{
$this->buildPath = $this->build->getBuildPath() . '/';
$this->build->currentBuildPath = $this->buildPath;
$this->buildPath = $this->build->getBuildPath();
$this->interpolator->setupInterpolationVars(
$this->build,

View file

@ -16,6 +16,7 @@ use b8\Config;
use b8\Store\Factory;
use PHPCI\Helper\Lang;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\DialogHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@ -46,6 +47,9 @@ class InstallCommand extends Command
->addOption('admin-pass', null, InputOption::VALUE_OPTIONAL, Lang::get('admin_pass'))
->addOption('admin-mail', null, InputOption::VALUE_OPTIONAL, Lang::get('admin_email'))
->addOption('config-path', null, InputOption::VALUE_OPTIONAL, Lang::get('config_path'), $defaultPath)
->addOption('queue-disabled', null, InputOption::VALUE_NONE, 'Don\'t ask for queue details')
->addOption('queue-server', null, InputOption::VALUE_OPTIONAL, 'Beanstalkd queue server hostname')
->addOption('queue-name', null, InputOption::VALUE_OPTIONAL, 'Beanstalkd queue name')
->setDescription(Lang::get('install_phpci'));
}
@ -229,10 +233,37 @@ class InstallCommand extends Command
}
$phpci['url'] = $url;
$phpci['worker'] = $this->getQueueInformation($input, $output, $dialog);
return $phpci;
}
/**
* If the user wants to use a queue, get the necessary details.
* @param InputInterface $input
* @param OutputInterface $output
* @param DialogHelper $dialog
* @return array
*/
protected function getQueueInformation(InputInterface $input, OutputInterface $output, DialogHelper $dialog)
{
if ($input->getOption('queue-disabled')) {
return null;
}
$rtn = [];
if (!$rtn['host'] = $input->getOption('queue-server')) {
$rtn['host'] = $dialog->ask($output, 'Enter your beanstalkd hostname [localhost]: ', 'localhost');
}
if (!$rtn['queue'] = $input->getOption('queue-name')) {
$rtn['queue'] = $dialog->ask($output, 'Enter the queue (tube) name to use [phpci]: ', 'phpci');
}
return $rtn;
}
/**
* Load configuration for DB form CLI options or ask info to user.
*

View file

@ -0,0 +1,85 @@
<?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\Command;
use b8\Config;
use b8\Store\Factory;
use Monolog\Logger;
use PHPCI\BuildFactory;
use PHPCI\Helper\Lang;
use PHPCI\Logging\OutputLogHandler;
use PHPCI\Service\BuildService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Dan Cryer <dan@block8.co.uk>
* @package PHPCI
* @subpackage Console
*/
class RebuildQueueCommand extends Command
{
/**
* @var OutputInterface
*/
protected $output;
/**
* @var Logger
*/
protected $logger;
/**
* @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-queue')
->setDescription('Rebuilds the PHPCI worker queue.');
}
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)
);
}
$store = Factory::getStore('Build');
$result = $store->getByStatus(0);
$this->logger->addInfo(Lang::get('found_n_builds', count($result['items'])));
$buildService = new BuildService($store);
while (count($result['items'])) {
$build = array_shift($result['items']);
$build = BuildFactory::getBuild($build);
$this->logger->addInfo('Added build #' . $build->getId() . ' to queue.');
$buildService->addBuildToQueue($build);
}
}
}

View file

@ -63,24 +63,42 @@ class BuildController extends \PHPCI\Controller
$this->view->plugins = $this->getUiPlugins();
$this->view->build = $build;
$this->view->data = json_encode($this->getBuildData($build));
$this->view->data = $this->getBuildData($build);
$this->layout->title = Lang::get('build_n', $buildId);
$this->layout->subtitle = $build->getProjectTitle();
$nav = array(
'title' => Lang::get('build_n', $buildId),
'icon' => 'cog',
'links' => array(
'build/rebuild/' . $build->getId() => Lang::get('rebuild_now'),
),
);
switch ($build->getStatus()) {
case 0:
$this->layout->skin = 'blue';
break;
if ($this->currentUserIsAdmin()) {
$nav['links']['build/delete/' . $build->getId()] = Lang::get('delete_build');
case 1:
$this->layout->skin = 'yellow';
break;
case 2:
$this->layout->skin = 'green';
break;
case 3:
$this->layout->skin = 'red';
break;
}
$this->layout->nav = $nav;
$rebuild = Lang::get('rebuild_now');
$rebuildLink = PHPCI_URL . 'build/rebuild/' . $build->getId();
$delete = Lang::get('delete_build');
$deleteLink = PHPCI_URL . 'build/delete/' . $build->getId();
$actions = "<a class=\"btn btn-default\" href=\"{$rebuildLink}\">{$rebuild}</a> ";
if ($this->currentUserIsAdmin()) {
$actions .= " <a class=\"btn btn-danger\" href=\"{$deleteLink}\">{$delete}</a>";
}
$this->layout->actions = $actions;
}
/**
@ -144,7 +162,7 @@ class BuildController extends \PHPCI\Controller
/**
* Get build data from database and json encode it:
*/
protected function getBuildData($build)
protected function getBuildData(Build $build)
{
$data = array();
$data['status'] = (int)$build->getStatus();
@ -152,6 +170,19 @@ class BuildController extends \PHPCI\Controller
$data['created'] = !is_null($build->getCreated()) ? $build->getCreated()->format('Y-m-d H:i:s') : null;
$data['started'] = !is_null($build->getStarted()) ? $build->getStarted()->format('Y-m-d H:i:s') : null;
$data['finished'] = !is_null($build->getFinished()) ? $build->getFinished()->format('Y-m-d H:i:s') : null;
$data['duration'] = $build->getDuration();
/** @var \PHPCI\Store\BuildErrorStore $errorStore */
$errorStore = b8\Store\Factory::getStore('BuildError');
$errors = $errorStore->getErrorsForBuild($build->getId(), $this->getParam('since', null));
$errorView = new b8\View('Build/errors');
$errorView->build = $build;
$errorView->errors = $errors;
$data['errors'] = count($errors);
$data['error_html'] = $errorView->render();
$data['since'] = (new \DateTime())->format('Y-m-d H:i:s');
return $data;
}

View file

@ -444,7 +444,7 @@ class SettingsController extends Controller
$field->setClass('form-control');
$field->setContainerClass('form-group');
$field->setOptions(Lang::getLanguageOptions());
$field->setValue('en');
$field->setValue(Lang::getLanguage());
$form->addField($field);

View file

@ -39,7 +39,7 @@ PHPCI',
'reset_email_title' => 'PHPCI Passwort zurücksetzen für %s',
'reset_invalid' => 'Fehlerhafte Anfrage für das Zurücksetzen eines Passwortes',
'email_address' => 'Emailadresse',
'login' => 'Login / Email Address',
'login' => 'Login / Emailadresse',
'password' => 'Passwort',
'log_in' => 'Einloggen',
@ -103,7 +103,7 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
'local' => 'Lokaler Pfad',
'hg' => 'Mercurial',
'svn' => 'Subversion',
'where_hosted' => 'Wo wird Ihr Projekt gehostet?',
'choose_github' => 'Wählen Sie ein GitHub Repository:',
@ -115,8 +115,8 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
(falls Sie Ihrem Projektrepository kein phpci.yml hinzufügen können)',
'default_branch' => 'Name des Standardbranches',
'allow_public_status' => 'Öffentliche Statusseite und -bild für dieses Projekt einschalten?',
'archived' => 'Archived',
'archived_menu' => 'Archived',
'archived' => 'Archiviert',
'archived_menu' => 'Archiviert',
'save_project' => 'Projekt speichern',
'error_mercurial' => 'Mercurial Repository-URL muss mit http://, oder https:// beginnen',
@ -130,7 +130,7 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
'all_branches' => 'Alle Branches',
'builds' => 'Builds',
'id' => 'ID',
'date' => 'Date',
'date' => 'Datum',
'project' => 'Projekt',
'commit' => 'Commit',
'branch' => 'Branch',
@ -151,6 +151,9 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
'webhooks_help_bitbucket' => 'Um für dieses Projekt automatisch einen Build zu starten, wenn neue Commits gepushed werden, fügen Sie die untenstehende URL als "POST" Service in der <a href="https://bitbucket.org/%s/admin/services">Services</a>-Sektion Ihres Bitbucket Repositories hinzu.',
// View Build
'errors' => 'Fehler',
'information' => 'Information',
'build_x_not_found' => 'Build mit ID %d existiert nicht.',
'build_n' => 'Build %d',
'rebuild_now' => 'Build neu starten',
@ -192,8 +195,8 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
'codeception_suite' => 'Suite',
'codeception_time' => 'Zeit',
'codeception_synopsis' => '<strong>%1$d</strong> Tests in <strong>%2$f</strong> Sekunden ausgeführt.
<strong>%3$d</strong> Fehler.',
<strong>%3$d</strong> Fehler.',
'file' => 'Datei',
'line' => 'Zeile',
'class' => 'Klasse',
@ -209,14 +212,14 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
'build_created' => 'Build erstellt',
'build_started' => 'Build gestartet',
'build_finished' => 'Build abgeschlossen',
'test_message' => 'Message',
'test_no_message' => 'No message',
'test_success' => 'Successful: %d',
'test_fail' => 'Failures: %d',
'test_skipped' => 'Skipped: %d',
'test_error' => 'Errors: %d',
'test_message' => 'Nachricht',
'test_no_message' => 'Keine Nachricht',
'test_success' => 'Erfolgreich: %d',
'test_fail' => 'Fehlschläge: %d',
'test_skipped' => 'Übersprungen: %d',
'test_error' => 'Fehler: %d',
'test_todo' => 'Todos: %d',
'test_total' => '%d test(s)',
'test_total' => '%d Test(s)',
// Users
'name' => 'Name',
@ -292,6 +295,19 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
'search_packagist_for_more' => 'Packagist nach mehr Packages durchsuchen',
'search' => 'Suchen &raquo;',
// Summary plugin
'build-summary' => 'Zusammenfassung',
'stage' => 'Abschnitt',
'duration' => 'Dauer',
'plugin' => 'Plugin',
'stage_setup' => 'Vorbereitung',
'stage_test' => 'Test',
'stage_complete' => 'Vollständig',
'stage_success' => 'Erfolg',
'stage_failure' => 'Fehlschlag',
'stage_broken' => 'Defekt',
'stage_fixed' => 'Behoben',
// Installer
'installation_url' => 'PHPCI Installations-URL',
'db_host' => 'Datenbankserver',
@ -400,5 +416,18 @@ generiert. Um es zu verwenden, fügen Sie einfach den folgenden Public Key im Ab
'build_file_missing' => 'Angegebene Builddatei existiert nicht.',
'property_file_missing' => 'Angegebene Eigenschaftsdatei existiert nicht.',
'could_not_process_report' => 'Konnte den von diesem Tool erstellten Bericht nicht verarbeiten.',
'shell_not_enabled' => 'Das Shell-Plugin ist nicht aktiviert. Bitte aktivieren Sie es via config.yml.'
'shell_not_enabled' => 'Das Shell-Plugin ist nicht aktiviert. Bitte aktivieren Sie es via config.yml.',
// Error Levels:
'critical' => 'Kritisch',
'high' => 'Hoch',
'normal' => 'Normal',
'low' => 'Niedrig',
// 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',
);

View file

@ -154,6 +154,9 @@ PHPCI',
Services</a> section of your Bitbucket repository.',
// View Build
'errors' => 'Errors',
'information' => 'Information',
'build_x_not_found' => 'Build with ID %d does not exist.',
'build_n' => 'Build %d',
'rebuild_now' => 'Rebuild Now',
@ -417,5 +420,22 @@ PHPCI',
'build_file_missing' => 'Specified build file does not exist.',
'property_file_missing' => 'Specified property file does not exist.',
'could_not_process_report' => 'Could not process the report generated by this tool.',
'shell_not_enabled' => 'The shell plugin is not enabled. Please enable it via config.yml.'
'shell_not_enabled' => 'The shell plugin is not enabled. Please enable it via config.yml.',
// Error Levels:
'critical' => 'Critical',
'high' => 'High',
'normal' => 'Normal',
'low' => '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',
'behat' => 'Behat',
'technical_debt' => 'Technical Debt',
);

View file

@ -130,7 +130,7 @@ od wybranego kodu źródłowego platformy hostingowej.',
'all_branches' => 'Wszystkie Gałęzie',
'builds' => 'Budowania',
'id' => 'ID',
'date' => 'Date',
'date' => 'Data',
'project' => 'Projekt',
'commit' => 'Commit',
'branch' => 'Gałąź',
@ -206,14 +206,14 @@ Services</a> repozytoria Bitbucket.',
'build_created' => 'Budowanie Stworzone',
'build_started' => 'Budowanie Rozpoczęte',
'build_finished' => 'Budowanie Zakończone',
'test_message' => 'Message',
'test_no_message' => 'No message',
'test_success' => 'Successful: %d',
'test_fail' => 'Failures: %d',
'test_skipped' => 'Skipped: %d',
'test_error' => 'Errors: %d',
'test_todo' => 'Todos: %d',
'test_total' => '%d test(s)',
'test_message' => 'Wiadomość',
'test_no_message' => 'Brak wiadomości',
'test_success' => 'Powodzenie: %d',
'test_fail' => 'Niepowodzenia: %d',
'test_skipped' => 'Pominęte: %d',
'test_error' => 'Błędy: %d',
'test_todo' => 'Do zrobienia: %d',
'test_total' => '%d test(ów)',
// Users
'name' => 'Nazwa',
@ -344,10 +344,10 @@ Przejrzyj powyższą listę błędów przed kontynuowaniem.',
'incorrect_format' => 'Niepoprawny format',
// Create Build Command
'create_build_project' => 'Create a build for a project',
'project_id_argument' => 'A project ID',
'commit_id_option' => 'Commit ID to build',
'branch_name_option' => 'Branch to build',
'create_build_project' => 'Utwórz budowanie dla projektu',
'project_id_argument' => 'ID projektu',
'commit_id_option' => 'ID Commita do budowania',
'branch_name_option' => 'Gałąź do budowania',
// Run Command
'run_all_pending' => 'Uruchom wszystkie oczekujące budowy w PHPCI',

View file

@ -0,0 +1,24 @@
<?php
use Phinx\Migration\AbstractMigration;
use Phinx\Db\Adapter\MysqlAdapter;
class ErrorsTable extends AbstractMigration
{
public function change()
{
$table = $this->table('build_error');
$table->addColumn('build_id', 'integer', array('signed' => true));
$table->addColumn('plugin', 'string', array('limit' => 100));
$table->addColumn('file', 'string', array('limit' => 250, 'null' => true));
$table->addColumn('line_start', 'integer', array('signed' => false, 'null' => true));
$table->addColumn('line_end', 'integer', array('signed' => false, 'null' => true));
$table->addColumn('severity', 'integer', array('signed' => false, 'limit' => MysqlAdapter::INT_TINY));
$table->addColumn('message', 'string', array('limit' => 250));
$table->addColumn('created_date', 'datetime');
$table->addIndex(array('build_id', 'created_date'), array('unique' => false));
$table->addForeignKey('build_id', 'build', 'id', array('delete'=> 'CASCADE', 'update' => 'CASCADE'));
$table->save();
}
}

View file

@ -0,0 +1,183 @@
<?php
use Phinx\Migration\AbstractMigration;
use PHPCI\Model\BuildMeta;
use PHPCI\Model\BuildError;
class ConvertErrors extends AbstractMigration
{
/**
* @var \PHPCI\Store\BuildMetaStore
*/
protected $metaStore;
/**
* @var \PHPCI\Store\BuildErrorStore
*/
protected $errorStore;
public function change()
{
$count = 100;
$this->metaStore = \b8\Store\Factory::getStore('BuildMeta');
$this->errorStore = \b8\Store\Factory::getStore('BuildError');
while ($count == 100) {
$data = $this->metaStore->getErrorsForUpgrade(100);
$count = count($data);
/** @var \PHPCI\Model\BuildMeta $meta */
foreach ($data as $meta) {
try {
switch ($meta->getMetaKey()) {
case 'phpmd-data':
$this->processPhpMdMeta($meta);
break;
case 'phpcs-data':
$this->processPhpCsMeta($meta);
break;
case 'phpdoccheck-data':
$this->processPhpDocCheckMeta($meta);
break;
case 'phpcpd-data':
$this->processPhpCpdMeta($meta);
break;
case 'technicaldebt-data':
$this->processTechnicalDebtMeta($meta);
break;
}
} catch (\Exception $ex) {}
$this->metaStore->delete($meta);
}
}
}
protected function processPhpMdMeta(BuildMeta $meta)
{
$data = json_decode($meta->getMetaValue(), true);
if (is_array($data) && count($data)) {
foreach ($data as $error) {
$buildError = new BuildError();
$buildError->setBuildId($meta->getBuildId());
$buildError->setPlugin('php_mess_detector');
$buildError->setCreatedDate(new \DateTime());
$buildError->setFile($error['file']);
$buildError->setLineStart($error['line_start']);
$buildError->setLineEnd($error['line_end']);
$buildError->setSeverity(BuildError::SEVERITY_HIGH);
$buildError->setMessage($error['message']);
$this->errorStore->save($buildError);
}
}
}
protected function processPhpCsMeta(BuildMeta $meta)
{
$data = json_decode($meta->getMetaValue(), true);
if (is_array($data) && count($data)) {
foreach ($data as $error) {
$buildError = new BuildError();
$buildError->setBuildId($meta->getBuildId());
$buildError->setPlugin('php_code_sniffer');
$buildError->setCreatedDate(new \DateTime());
$buildError->setFile($error['file']);
$buildError->setLineStart($error['line']);
$buildError->setLineEnd($error['line']);
$buildError->setMessage($error['message']);
switch ($error['type']) {
case 'ERROR':
$buildError->setSeverity(BuildError::SEVERITY_HIGH);
break;
case 'WARNING':
$buildError->setSeverity(BuildError::SEVERITY_LOW);
break;
}
$this->errorStore->save($buildError);
}
}
}
protected function processPhpDocCheckMeta(BuildMeta $meta)
{
$data = json_decode($meta->getMetaValue(), true);
if (is_array($data) && count($data)) {
foreach ($data as $error) {
$buildError = new BuildError();
$buildError->setBuildId($meta->getBuildId());
$buildError->setPlugin('php_docblock_checker');
$buildError->setCreatedDate(new \DateTime());
$buildError->setFile($error['file']);
$buildError->setLineStart($error['line']);
$buildError->setLineEnd($error['line']);
switch ($error['type']) {
case 'method':
$buildError->setMessage($error['class'] . '::' . $error['method'] . ' is missing a docblock.');
$buildError->setSeverity(BuildError::SEVERITY_NORMAL);
break;
case 'class':
$buildError->setMessage('Class ' . $error['class'] . ' is missing a docblock.');
$buildError->setSeverity(BuildError::SEVERITY_LOW);
break;
}
$this->errorStore->save($buildError);
}
}
}
protected function processPhpCpdMeta(BuildMeta $meta)
{
$data = json_decode($meta->getMetaValue(), true);
if (is_array($data) && count($data)) {
foreach ($data as $error) {
$buildError = new BuildError();
$buildError->setBuildId($meta->getBuildId());
$buildError->setPlugin('php_cpd');
$buildError->setCreatedDate(new \DateTime());
$buildError->setFile($error['file']);
$buildError->setLineStart($error['line_start']);
$buildError->setLineEnd($error['line_end']);
$buildError->setSeverity(BuildError::SEVERITY_NORMAL);
$buildError->setMessage('Copy and paste detected.');
$this->errorStore->save($buildError);
}
}
}
protected function processTechnicalDebtMeta(BuildMeta $meta)
{
$data = json_decode($meta->getMetaValue(), true);
if (is_array($data) && count($data)) {
foreach ($data as $error) {
$buildError = new BuildError();
$buildError->setBuildId($meta->getBuildId());
$buildError->setPlugin('technical_debt');
$buildError->setCreatedDate(new \DateTime());
$buildError->setFile($error['file']);
$buildError->setLineStart($error['line']);
$buildError->setSeverity(BuildError::SEVERITY_NORMAL);
$buildError->setMessage($error['message']);
$this->errorStore->save($buildError);
}
}
}
}

View file

@ -621,6 +621,18 @@ class BuildBase extends Model
return $this->setProjectId($value->getId());
}
/**
* Get BuildError models by BuildId for this Build.
*
* @uses \PHPCI\Store\BuildErrorStore::getByBuildId()
* @uses \PHPCI\Model\BuildError
* @return \PHPCI\Model\BuildError[]
*/
public function getBuildBuildErrors()
{
return Factory::getStore('BuildError', 'PHPCI')->getByBuildId($this->getId());
}
/**
* Get BuildMeta models by BuildId for this Build.
*

View file

@ -0,0 +1,503 @@
<?php
/**
* BuildError base model for table: build_error
*/
namespace PHPCI\Model\Base;
use PHPCI\Model;
use b8\Store\Factory;
/**
* BuildError Base Model
*/
class BuildErrorBase extends Model
{
/**
* @var array
*/
public static $sleepable = array();
/**
* @var string
*/
protected $tableName = 'build_error';
/**
* @var string
*/
protected $modelName = 'BuildError';
/**
* @var array
*/
protected $data = array(
'id' => null,
'build_id' => null,
'plugin' => null,
'file' => null,
'line_start' => null,
'line_end' => null,
'severity' => null,
'message' => null,
'created_date' => null,
);
/**
* @var array
*/
protected $getters = array(
// Direct property getters:
'id' => 'getId',
'build_id' => 'getBuildId',
'plugin' => 'getPlugin',
'file' => 'getFile',
'line_start' => 'getLineStart',
'line_end' => 'getLineEnd',
'severity' => 'getSeverity',
'message' => 'getMessage',
'created_date' => 'getCreatedDate',
// Foreign key getters:
'Build' => 'getBuild',
);
/**
* @var array
*/
protected $setters = array(
// Direct property setters:
'id' => 'setId',
'build_id' => 'setBuildId',
'plugin' => 'setPlugin',
'file' => 'setFile',
'line_start' => 'setLineStart',
'line_end' => 'setLineEnd',
'severity' => 'setSeverity',
'message' => 'setMessage',
'created_date' => 'setCreatedDate',
// Foreign key setters:
'Build' => 'setBuild',
);
/**
* @var array
*/
public $columns = array(
'id' => array(
'type' => 'int',
'length' => 11,
'primary_key' => true,
'auto_increment' => true,
'default' => null,
),
'build_id' => array(
'type' => 'int',
'length' => 11,
'default' => null,
),
'plugin' => array(
'type' => 'varchar',
'length' => 100,
'default' => null,
),
'file' => array(
'type' => 'varchar',
'length' => 250,
'nullable' => true,
'default' => null,
),
'line_start' => array(
'type' => 'int',
'length' => 11,
'nullable' => true,
'default' => null,
),
'line_end' => array(
'type' => 'int',
'length' => 11,
'nullable' => true,
'default' => null,
),
'severity' => array(
'type' => 'tinyint',
'length' => 3,
'default' => null,
),
'message' => array(
'type' => 'varchar',
'length' => 250,
'default' => null,
),
'created_date' => array(
'type' => 'datetime',
'default' => null,
),
);
/**
* @var array
*/
public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'build_id' => array('columns' => 'build_id, created_date'),
);
/**
* @var array
*/
public $foreignKeys = array(
'build_error_ibfk_1' => array(
'local_col' => 'build_id',
'update' => 'CASCADE',
'delete' => 'CASCADE',
'table' => 'build',
'col' => 'id'
),
);
/**
* Get the value of Id / id.
*
* @return int
*/
public function getId()
{
$rtn = $this->data['id'];
return $rtn;
}
/**
* Get the value of BuildId / build_id.
*
* @return int
*/
public function getBuildId()
{
$rtn = $this->data['build_id'];
return $rtn;
}
/**
* Get the value of Plugin / plugin.
*
* @return string
*/
public function getPlugin()
{
$rtn = $this->data['plugin'];
return $rtn;
}
/**
* Get the value of File / file.
*
* @return string
*/
public function getFile()
{
$rtn = $this->data['file'];
return $rtn;
}
/**
* Get the value of LineStart / line_start.
*
* @return int
*/
public function getLineStart()
{
$rtn = $this->data['line_start'];
return $rtn;
}
/**
* Get the value of LineEnd / line_end.
*
* @return int
*/
public function getLineEnd()
{
$rtn = $this->data['line_end'];
return $rtn;
}
/**
* Get the value of Severity / severity.
*
* @return int
*/
public function getSeverity()
{
$rtn = $this->data['severity'];
return $rtn;
}
/**
* Get the value of Message / message.
*
* @return string
*/
public function getMessage()
{
$rtn = $this->data['message'];
return $rtn;
}
/**
* Get the value of CreatedDate / created_date.
*
* @return \DateTime
*/
public function getCreatedDate()
{
$rtn = $this->data['created_date'];
if (!empty($rtn)) {
$rtn = new \DateTime($rtn);
}
return $rtn;
}
/**
* Set the value of Id / id.
*
* Must not be null.
* @param $value int
*/
public function setId($value)
{
$this->_validateNotNull('Id', $value);
$this->_validateInt('Id', $value);
if ($this->data['id'] === $value) {
return;
}
$this->data['id'] = $value;
$this->_setModified('id');
}
/**
* Set the value of BuildId / build_id.
*
* Must not be null.
* @param $value int
*/
public function setBuildId($value)
{
$this->_validateNotNull('BuildId', $value);
$this->_validateInt('BuildId', $value);
if ($this->data['build_id'] === $value) {
return;
}
$this->data['build_id'] = $value;
$this->_setModified('build_id');
}
/**
* Set the value of Plugin / plugin.
*
* Must not be null.
* @param $value string
*/
public function setPlugin($value)
{
$this->_validateNotNull('Plugin', $value);
$this->_validateString('Plugin', $value);
if ($this->data['plugin'] === $value) {
return;
}
$this->data['plugin'] = $value;
$this->_setModified('plugin');
}
/**
* Set the value of File / file.
*
* @param $value string
*/
public function setFile($value)
{
$this->_validateString('File', $value);
if ($this->data['file'] === $value) {
return;
}
$this->data['file'] = $value;
$this->_setModified('file');
}
/**
* Set the value of LineStart / line_start.
*
* @param $value int
*/
public function setLineStart($value)
{
$this->_validateInt('LineStart', $value);
if ($this->data['line_start'] === $value) {
return;
}
$this->data['line_start'] = $value;
$this->_setModified('line_start');
}
/**
* Set the value of LineEnd / line_end.
*
* @param $value int
*/
public function setLineEnd($value)
{
$this->_validateInt('LineEnd', $value);
if ($this->data['line_end'] === $value) {
return;
}
$this->data['line_end'] = $value;
$this->_setModified('line_end');
}
/**
* Set the value of Severity / severity.
*
* Must not be null.
* @param $value int
*/
public function setSeverity($value)
{
$this->_validateNotNull('Severity', $value);
$this->_validateInt('Severity', $value);
if ($this->data['severity'] === $value) {
return;
}
$this->data['severity'] = $value;
$this->_setModified('severity');
}
/**
* Set the value of Message / message.
*
* Must not be null.
* @param $value string
*/
public function setMessage($value)
{
$this->_validateNotNull('Message', $value);
$this->_validateString('Message', $value);
if ($this->data['message'] === $value) {
return;
}
$this->data['message'] = $value;
$this->_setModified('message');
}
/**
* Set the value of CreatedDate / created_date.
*
* Must not be null.
* @param $value \DateTime
*/
public function setCreatedDate($value)
{
$this->_validateNotNull('CreatedDate', $value);
$this->_validateDate('CreatedDate', $value);
if ($this->data['created_date'] === $value) {
return;
}
$this->data['created_date'] = $value;
$this->_setModified('created_date');
}
/**
* Get the Build model for this BuildError by Id.
*
* @uses \PHPCI\Store\BuildStore::getById()
* @uses \PHPCI\Model\Build
* @return \PHPCI\Model\Build
*/
public function getBuild()
{
$key = $this->getBuildId();
if (empty($key)) {
return null;
}
$cacheKey = 'Cache.Build.' . $key;
$rtn = $this->cache->get($cacheKey, null);
if (empty($rtn)) {
$rtn = Factory::getStore('Build', 'PHPCI')->getById($key);
$this->cache->set($cacheKey, $rtn);
}
return $rtn;
}
/**
* Set Build - Accepts an ID, an array representing a Build or a Build model.
*
* @param $value mixed
*/
public function setBuild($value)
{
// Is this an instance of Build?
if ($value instanceof \PHPCI\Model\Build) {
return $this->setBuildObject($value);
}
// Is this an array representing a Build item?
if (is_array($value) && !empty($value['id'])) {
return $this->setBuildId($value['id']);
}
// Is this a scalar value representing the ID of this foreign key?
return $this->setBuildId($value);
}
/**
* Set Build - Accepts a Build model.
*
* @param $value \PHPCI\Model\Build
*/
public function setBuildObject(\PHPCI\Model\Build $value)
{
return $this->setBuildId($value->getId());
}
}

View file

@ -107,7 +107,7 @@ class UserBase extends Model
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'idx_email' => array('unique' => true, 'columns' => 'email'),
'email' => array('unique' => true, 'columns' => 'email'),
'name' => array('unique' => true, 'columns' => 'name'),
'name' => array('columns' => 'name'),
);
/**

View file

@ -28,7 +28,7 @@ class Build extends BuildBase
const STATUS_SUCCESS = 2;
const STATUS_FAILED = 3;
public $currentBuildPath = null;
public $currentBuildPath;
/**
* Get link to commit from another source (i.e. Github)
@ -213,14 +213,36 @@ class Build extends BuildBase
/**
* Allows specific build types (e.g. Github) to report violations back to their respective services.
* @param Builder $builder
* @param $file
* @param $line
* @param $plugin
* @param $message
* @return mixed
* @param int $severity
* @param null $file
* @param null $lineStart
* @param null $lineEnd
* @return BuildError
*/
public function reportError(Builder $builder, $file, $line, $message)
{
return array($builder, $file, $line, $message);
public function reportError(
Builder $builder,
$plugin,
$message,
$severity = BuildError::SEVERITY_NORMAL,
$file = null,
$lineStart = null,
$lineEnd = null
) {
unset($builder);
$error = new BuildError();
$error->setBuild($this);
$error->setCreatedDate(new \DateTime());
$error->setPlugin($plugin);
$error->setMessage($message);
$error->setSeverity($severity);
$error->setFile($file);
$error->setLineStart($lineStart);
$error->setLineEnd($lineEnd);
return Factory::getStore('BuildError')->save($error);
}
/**
@ -233,7 +255,13 @@ class Build extends BuildBase
if (!$this->getId()) {
return null;
}
return PHPCI_BUILD_ROOT_DIR . $this->getId() . '_' . substr(md5(microtime(true)), 0, 5);
if (empty($this->currentBuildPath)) {
$buildDirectory = $this->getId() . '_' . substr(md5(microtime(true)), 0, 5);
$this->currentBuildPath = PHPCI_BUILD_ROOT_DIR . $buildDirectory . DIRECTORY_SEPARATOR;
}
return $this->currentBuildPath;
}
/**
@ -249,4 +277,25 @@ class Build extends BuildBase
exec(sprintf(IS_WIN ? 'rmdir /S /Q "%s"' : 'rm -Rf "%s"', $buildPath));
}
/**
* Get the number of seconds a build has been running for.
* @return int
*/
public function getDuration()
{
$start = $this->getStarted();
if (empty($start)) {
return 0;
}
$end = $this->getFinished();
if (empty($end)) {
$end = new \DateTime();
}
return $end->getTimestamp() - $start->getTimestamp();
}
}

View file

@ -151,7 +151,7 @@ class GithubBuild extends RemoteGitBuild
$link = 'https://github.com/' . $reference . '/';
$link .= 'blob/' . $branch . '/';
$link .= '{FILE}';
$link .= '#L{LINE}';
$link .= '#L{LINE}-L{LINE_END}';
return $link;
}
@ -190,9 +190,16 @@ class GithubBuild extends RemoteGitBuild
/**
* @inheritDoc
*/
public function reportError(Builder $builder, $file, $line, $message)
{
$diffLineNumber = $this->getDiffLineNumber($builder, $file, $line);
public function reportError(
Builder $builder,
$plugin,
$message,
$severity = BuildError::SEVERITY_NORMAL,
$file = null,
$lineStart = null,
$lineEnd = null
) {
$diffLineNumber = $this->getDiffLineNumber($builder, $file, $lineStart);
if (!is_null($diffLineNumber)) {
$helper = new Github();
@ -207,6 +214,8 @@ class GithubBuild extends RemoteGitBuild
$helper->createCommitComment($repo, $commit, $file, $diffLineNumber, $message);
}
}
return parent::reportError($builder, $plugin, $message, $severity, $file, $lineStart, $lineEnd);
}
/**

View file

@ -0,0 +1,63 @@
<?php
/**
* BuildError model for table: build_error
*/
namespace PHPCI\Model;
use PHPCI\Model\Base\BuildErrorBase;
/**
* BuildError Model
* @uses PHPCI\Model\Base\BuildErrorBase
*/
class BuildError extends BuildErrorBase
{
const SEVERITY_CRITICAL = 0;
const SEVERITY_HIGH = 1;
const SEVERITY_NORMAL = 2;
const SEVERITY_LOW = 3;
/**
* Get the language string key for this error's severity level.
* @return string
*/
public function getSeverityString()
{
switch ($this->getSeverity()) {
case self::SEVERITY_CRITICAL:
return 'critical';
case self::SEVERITY_HIGH:
return 'high';
case self::SEVERITY_NORMAL:
return 'normal';
case self::SEVERITY_LOW:
return 'low';
}
}
/**
* Get the class to apply to HTML elements representing this error.
* @return string
*/
public function getSeverityClass()
{
switch ($this->getSeverity()) {
case self::SEVERITY_CRITICAL:
return 'danger';
case self::SEVERITY_HIGH:
return 'warning';
case self::SEVERITY_NORMAL:
return 'info';
case self::SEVERITY_LOW:
return 'default';
}
}
}

View file

@ -12,6 +12,7 @@ namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Helper\Lang;
use PHPCI\Model\Build;
use PHPCI\Model\BuildError;
/**
* Behat BDD Plugin
@ -119,7 +120,14 @@ class Behat implements \PHPCI\Plugin
'line' => $lineParts[1]
);
$this->build->reportError($this->phpci, $lineParts[0], $lineParts[1], 'Behat scenario failed.');
$this->build->reportError(
$this->phpci,
'behat',
'Behat scenario failed.',
BuildError::SEVERITY_HIGH,
$lineParts[0],
$lineParts[1]
);
}
}

View file

@ -38,19 +38,19 @@ class Campfire implements \PHPCI\Plugin
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->message = $options['message'];
$this->phpci = $phpci;
$this->build = $build;
$this->message = $options['message'];
$this->userAgent = "PHPCI/1.0 (+http://www.phptesting.org/)";
$this->cookie = "phpcicookie";
$this->cookie = "phpcicookie";
$buildSettings = $phpci->getConfig('build_settings');
if (isset($buildSettings['campfire'])) {
$campfire = $buildSettings['campfire'];
$this->url = $campfire['url'];
$campfire = $buildSettings['campfire'];
$this->url = $campfire['url'];
$this->authToken = $campfire['authToken'];
$this->roomId = $campfire['roomId'];
$this->roomId = $campfire['roomId'];
} else {
throw new \Exception(Lang::get('no_campfire_settings'));
}
@ -63,7 +63,7 @@ class Campfire implements \PHPCI\Plugin
*/
public function execute()
{
$url = PHPCI_URL."build/view/".$this->build->getId();
$url = PHPCI_URL . "build/view/" . $this->build->getId();
$message = str_replace("%buildurl%", $url, $this->message);
$this->joinRoom($this->roomId);
$status = $this->speak($message, $this->roomId);
@ -101,6 +101,7 @@ class Campfire implements \PHPCI\Plugin
public function speak($message, $roomId, $isPaste = false)
{
$page = '/room/'.$roomId.'/speak.json';
if ($isPaste) {
$type = 'PasteMessage';
} else {
@ -143,10 +144,12 @@ class Campfire implements \PHPCI\Plugin
// We tend to get one space with an otherwise blank response
$output = trim($output);
if (strlen($output)) {
/* Responses are JSON. Decode it to a data structure */
return json_decode($output);
}
// Simple 200 OK response (such as for joining a room)
return true;
}

View file

@ -39,9 +39,9 @@ class CleanBuild implements \PHPCI\Plugin
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->remove = isset($options['remove']) && is_array($options['remove']) ? $options['remove'] : array();
$this->phpci = $phpci;
$this->build = $build;
$this->remove = isset($options['remove']) && is_array($options['remove']) ? $options['remove'] : array();
}
/**
@ -57,7 +57,7 @@ class CleanBuild implements \PHPCI\Plugin
$this->phpci->executeCommand($cmd, $this->phpci->buildPath . 'composer.lock');
$success = true;
foreach ($this->remove as $file) {
$ok = $this->phpci->executeCommand($cmd, $this->phpci->buildPath . $file);

View file

@ -83,7 +83,7 @@ class Codeception implements \PHPCI\Plugin, \PHPCI\ZeroConfigPlugin
{
$this->phpci = $phpci;
$this->build = $build;
$this->path = 'tests/_output/';
$this->path = 'tests' . DIRECTORY_SEPARATOR . '_output' . DIRECTORY_SEPARATOR;
if (empty($options['config'])) {
$this->ymlConfigFile = self::findConfigFile($this->phpci->buildPath);
@ -148,9 +148,9 @@ class Codeception implements \PHPCI\Plugin, \PHPCI\ZeroConfigPlugin
$output = $parser->parse();
$meta = array(
'tests' => $parser->getTotalTests(),
'tests' => $parser->getTotalTests(),
'timetaken' => $parser->getTotalTimeTaken(),
'failures' => $parser->getTotalFailures()
'failures' => $parser->getTotalFailures()
);
$this->build->storeMeta('codeception-meta', $meta);

View file

@ -38,7 +38,7 @@ class Composer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
*/
public static function canExecute($stage, Builder $builder, Build $build)
{
$path = $builder->buildPath . '/composer.json';
$path = $builder->buildPath . DIRECTORY_SEPARATOR . 'composer.json';
if (file_exists($path) && $stage == 'setup') {
return true;
@ -55,16 +55,16 @@ class Composer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$path = $phpci->buildPath;
$this->phpci = $phpci;
$this->build = $build;
$this->directory = $path;
$this->action = 'install';
$path = $phpci->buildPath;
$this->phpci = $phpci;
$this->build = $build;
$this->directory = $path;
$this->action = 'install';
$this->preferDist = false;
$this->nodev = false;
$this->nodev = false;
if (array_key_exists('directory', $options)) {
$this->directory = $path . '/' . $options['directory'];
$this->directory = $path . DIRECTORY_SEPARATOR . $options['directory'];
}
if (array_key_exists('action', $options)) {

View file

@ -35,12 +35,12 @@ class CopyBuild implements \PHPCI\Plugin
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$path = $phpci->buildPath;
$this->phpci = $phpci;
$this->build = $build;
$this->directory = isset($options['directory']) ? $options['directory'] : $path;
$this->wipe = isset($options['wipe']) ? (bool)$options['wipe'] : false;
$this->ignore = isset($options['respect_ignore']) ? (bool)$options['respect_ignore'] : false;
$path = $phpci->buildPath;
$this->phpci = $phpci;
$this->build = $build;
$this->directory = isset($options['directory']) ? $options['directory'] : $path;
$this->wipe = isset($options['wipe']) ? (bool)$options['wipe'] : false;
$this->ignore = isset($options['respect_ignore']) ? (bool)$options['respect_ignore'] : false;
}
/**

View file

@ -23,6 +23,7 @@ class Deployer implements \PHPCI\Plugin
{
protected $webhookUrl;
protected $reason;
protected $updateOnly;
/**
* Set up the plugin, configure options, etc.
@ -43,6 +44,8 @@ class Deployer implements \PHPCI\Plugin
if (isset($options['reason'])) {
$this->reason = $options['reason'];
}
$this->updateOnly = isset($options['update_only']) ? (bool) $options['update_only'] : true;
}
/**
@ -61,6 +64,8 @@ class Deployer implements \PHPCI\Plugin
'reason' => $this->phpci->interpolate($this->reason),
'source' => 'PHPCI',
'url' => $this->phpci->interpolate('%BUILD_URI%'),
'branch' => $this->phpci->interpolate('%BRANCH%'),
'update_only' => $this->updateOnly
));
return $response['success'];

View file

@ -52,9 +52,9 @@ class Email implements \PHPCI\Plugin
Build $build,
array $options = array()
) {
$this->phpci = $phpci;
$this->build = $build;
$this->options = $options;
$this->phpci = $phpci;
$this->build = $build;
$this->options = $options;
}
/**

View file

@ -52,7 +52,7 @@ class Env implements \PHPCI\Plugin
// This allows the standard syntax: "FOO: bar"
$env_var = "$key=$value";
}
if (!putenv($this->phpci->interpolate($env_var))) {
$success = false;
$this->phpci->logFailure(Lang::get('unable_to_set_env'));

View file

@ -52,7 +52,7 @@ class Grunt implements \PHPCI\Plugin
// Handle options:
if (isset($options['directory'])) {
$this->directory = $path . '/' . $options['directory'];
$this->directory = $path . DIRECTORY_SEPARATOR . $options['directory'];
}
if (isset($options['task'])) {

View file

@ -52,7 +52,7 @@ class Gulp implements \PHPCI\Plugin
// Handle options:
if (isset($options['directory'])) {
$this->directory = $path . '/' . $options['directory'];
$this->directory = $path . DIRECTORY_SEPARATOR . $options['directory'];
}
if (isset($options['task'])) {

View file

@ -41,9 +41,9 @@ class Lint implements PHPCI\Plugin
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->phpci = $phpci;
$this->build = $build;
$this->directories = array('');
$this->directories = array('');
$this->ignore = $phpci->ignore;
if (!empty($options['directory'])) {
@ -93,7 +93,7 @@ class Lint implements PHPCI\Plugin
if ($item->isFile() && $item->getExtension() == 'php' && !$this->lintFile($php, $itemPath)) {
$success = false;
} elseif ($item->isDir() && $this->recursive && !$this->lintDirectory($php, $itemPath . '/')) {
} elseif ($item->isDir() && $this->recursive && !$this->lintDirectory($php, $itemPath . DIRECTORY_SEPARATOR)) {
$success = false;
}

View file

@ -33,12 +33,12 @@ class PackageBuild implements \PHPCI\Plugin
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$path = $phpci->buildPath;
$this->build = $build;
$this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $path;
$this->filename = isset($options['filename']) ? $options['filename'] : 'build';
$this->format = isset($options['format']) ? $options['format'] : 'zip';
$path = $phpci->buildPath;
$this->build = $build;
$this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $path;
$this->filename = isset($options['filename']) ? $options['filename'] : 'build';
$this->format = isset($options['format']) ? $options['format'] : 'zip';
}
/**
@ -46,7 +46,7 @@ class PackageBuild implements \PHPCI\Plugin
*/
public function execute()
{
$path = $this->phpci->buildPath;
$path = $this->phpci->buildPath;
$build = $this->build;
if ($this->directory == $path) {

View file

@ -73,9 +73,9 @@ class Pgsql implements \PHPCI\Plugin
}
/**
* Connects to PgSQL and runs a specified set of queries.
* @return boolean
*/
* Connects to PgSQL and runs a specified set of queries.
* @return boolean
*/
public function execute()
{
try {

View file

@ -213,7 +213,7 @@ class Phar implements \PHPCI\Plugin
$content = '';
$filename = $this->getStub();
if ($filename) {
$content = file_get_contents($this->getPHPCI()->buildPath . '/' . $this->getStub());
$content = file_get_contents($this->getPHPCI()->buildPath . DIRECTORY_SEPARATOR . $this->getStub());
}
return $content;
}
@ -227,7 +227,8 @@ class Phar implements \PHPCI\Plugin
$success = false;
try {
$phar = new PHPPhar($this->getDirectory() . '/' . $this->getFilename(), 0, $this->getFilename());
$file = $this->getDirectory() . DIRECTORY_SEPARATOR . $this->getFilename();
$phar = new PHPPhar($file, 0, $this->getFilename());
$phar->buildFromDirectory($this->getPHPCI()->buildPath, $this->getRegExp());
$stub = $this->getStubContent();
@ -236,7 +237,6 @@ class Phar implements \PHPCI\Plugin
}
$success = true;
} catch (Exception $e) {
$this->getPHPCI()->log(Lang::get('phar_internal_error'));
$this->getPHPCI()->log($e->getMessage());

View file

@ -47,7 +47,7 @@ class Phing implements \PHPCI\Plugin
* Set working directory
*/
if (isset($options['directory'])) {
$directory = $phpci->buildPath . '/' . $options['directory'];
$directory = $phpci->buildPath . DIRECTORY_SEPARATOR . $options['directory'];
} else {
$directory = $phpci->buildPath;
}
@ -255,7 +255,7 @@ class Phing implements \PHPCI\Plugin
*/
public function setPropertyFile($propertyFile)
{
if (!file_exists($this->getDirectory() . '/' . $propertyFile)) {
if (!file_exists($this->getDirectory() . DIRECTORY_SEPARATOR . $propertyFile)) {
throw new \Exception(Lang::get('property_file_missing'));
}

View file

@ -12,6 +12,7 @@ namespace PHPCI\Plugin;
use PHPCI;
use PHPCI\Builder;
use PHPCI\Model\Build;
use PHPCI\Model\BuildError;
/**
* PHP Code Sniffer Plugin - Allows PHP Code Sniffer testing.
@ -163,14 +164,13 @@ class PhpCodeSniffer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
);
$output = $this->phpci->getLastOutput();
list($errors, $warnings, $data) = $this->processReport($output);
list($errors, $warnings) = $this->processReport($output);
$this->phpci->logExecOutput(true);
$success = true;
$this->build->storeMeta('phpcs-warnings', $warnings);
$this->build->storeMeta('phpcs-errors', $errors);
$this->build->storeMeta('phpcs-data', $data);
if ($this->allowed_warnings != -1 && $warnings > $this->allowed_warnings) {
$success = false;
@ -226,23 +226,21 @@ class PhpCodeSniffer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$errors = $data['totals']['errors'];
$warnings = $data['totals']['warnings'];
$rtn = array();
foreach ($data['files'] as $fileName => $file) {
$fileName = str_replace($this->phpci->buildPath, '', $fileName);
foreach ($file['messages'] as $message) {
$this->build->reportError($this->phpci, $fileName, $message['line'], 'PHPCS: ' . $message['message']);
$rtn[] = array(
'file' => $fileName,
'line' => $message['line'],
'type' => $message['type'],
'message' => $message['message'],
$this->build->reportError(
$this->phpci,
'php_code_sniffer',
'PHPCS: ' . $message['message'],
$message['type'] == 'ERROR' ? BuildError::SEVERITY_HIGH : BuildError::SEVERITY_LOW,
$fileName,
$message['line']
);
}
}
return array($errors, $warnings, $rtn);
return array($errors, $warnings);
}
}

View file

@ -12,6 +12,7 @@ namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Helper\Lang;
use PHPCI\Model\Build;
use PHPCI\Model\BuildError;
/**
* PHP Copy / Paste Detector - Allows PHP Copy / Paste Detector testing.
@ -74,9 +75,9 @@ class PhpCpd implements \PHPCI\Plugin
if (count($this->ignore)) {
$map = function ($item) {
// remove the trailing slash
$item = (substr($item, -1) == '/' ? substr($item, 0, -1) : $item);
$item = rtrim($item, DIRECTORY_SEPARATOR);
if (is_file($this->path . '/' . $item)) {
if (is_file(rtrim($this->path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $item)) {
return ' --names-exclude ' . $item;
} else {
return ' --exclude ' . $item;
@ -97,9 +98,8 @@ class PhpCpd implements \PHPCI\Plugin
print $this->phpci->getLastOutput();
list($errorCount, $data) = $this->processReport(file_get_contents($tmpfilename));
$errorCount = $this->processReport(file_get_contents($tmpfilename));
$this->build->storeMeta('phpcpd-warnings', $errorCount);
$this->build->storeMeta('phpcpd-data', $data);
unlink($tmpfilename);
@ -122,20 +122,11 @@ class PhpCpd implements \PHPCI\Plugin
}
$warnings = 0;
$data = array();
foreach ($xml->duplication as $duplication) {
foreach ($duplication->file as $file) {
$fileName = (string)$file['path'];
$fileName = str_replace($this->phpci->buildPath, '', $fileName);
$data[] = array(
'file' => $fileName,
'line_start' => (int) $file['line'],
'line_end' => (int) $file['line'] + (int) $duplication['lines'],
'code' => (string) $duplication->codefragment
);
$message = <<<CPD
Copy and paste detected:
@ -144,13 +135,20 @@ Copy and paste detected:
```
CPD;
$this->build->reportError($this->phpci, $fileName, $file['line'], $message);
$this->build->reportError(
$this->phpci,
'php_cpd',
$message,
BuildError::SEVERITY_NORMAL,
$fileName,
$file['line'],
(int) $file['line'] + (int) $duplication['lines']
);
}
$warnings++;
}
return array($warnings, $data);
return $warnings;
}
}

View file

@ -32,10 +32,10 @@ class PhpCsFixer implements \PHPCI\Plugin
protected $build;
protected $workingDir = '';
protected $level = ' --level=psr2';
protected $verbose = '';
protected $diff = '';
protected $levels = array('psr0', 'psr1', 'psr2', 'symfony');
protected $level = ' --level=psr2';
protected $verbose = '';
protected $diff = '';
protected $levels = array('psr0', 'psr1', 'psr2', 'symfony');
/**
* Standard Constructor

View file

@ -143,7 +143,6 @@ class PhpDocblockChecker implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$success = true;
$this->build->storeMeta('phpdoccheck-warnings', $errors);
$this->build->storeMeta('phpdoccheck-data', $output);
$this->reportErrors($output);
if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) {
@ -160,13 +159,22 @@ class PhpDocblockChecker implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
protected function reportErrors($output)
{
foreach ($output as $error) {
$message = 'Class ' . $error['class'] . ' does not have a Docblock comment.';
$message = 'Class ' . $error['class'] . ' is missing a docblock.';
$severity = PHPCI\Model\BuildError::SEVERITY_LOW;
if ($error['type'] == 'method') {
$message = 'Method ' . $error['class'] . '::' . $error['method'] . ' does not have a Docblock comment.';
$message = $error['class'] . '::' . $error['method'] . ' is missing a docblock.';
$severity = PHPCI\Model\BuildError::SEVERITY_NORMAL;
}
$this->build->reportError($this->phpci, $error['file'], $error['line'], $message);
$this->build->reportError(
$this->phpci,
'php_docblock_checker',
$message,
$severity,
$error['file'],
$error['line']
);
}
}
}

View file

@ -69,19 +69,20 @@ class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
public function execute()
{
$ignore = '';
if (count($this->phpci->ignore)) {
$map = function ($item) {
return ' --exclude ' . (substr($item, -1) == '/' ? substr($item, 0, -1) : $item);
};
$ignore = array_map($map, $this->phpci->ignore);
if (count($this->phpci->ignore)) {
$map = function ($item) {
return ' --exclude ' . rtrim($item, DIRECTORY_SEPARATOR);
};
$ignore = array_map($map, $this->phpci->ignore);
$ignore = implode('', $ignore);
}
$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)) {
$data = array();

View file

@ -123,9 +123,8 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$this->executePhpMd($phpmdBinaryPath);
list($errorCount, $data) = $this->processReport(trim($this->phpci->getLastOutput()));
$errorCount = $this->processReport(trim($this->phpci->getLastOutput()));
$this->build->storeMeta('phpmd-warnings', $errorCount);
$this->build->storeMeta('phpmd-data', $data);
return $this->wasLastExecSuccessful($errorCount);
}
@ -158,7 +157,6 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
}
$warnings = 0;
$data = array();
foreach ($xml->file as $file) {
$fileName = (string)$file['name'];
@ -166,22 +164,20 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
foreach ($file->violation as $violation) {
$warnings++;
$warning = array(
'file' => $fileName,
'line_start' => (int)$violation['beginline'],
'line_end' => (int)$violation['endline'],
'rule' => (string)$violation['rule'],
'ruleset' => (string)$violation['ruleset'],
'priority' => (int)$violation['priority'],
'message' => (string)$violation,
);
$this->build->reportError($this->phpci, $fileName, (int)$violation['beginline'], (string)$violation);
$data[] = $warning;
$this->build->reportError(
$this->phpci,
'php_mess_detector',
(string)$violation,
PHPCI\Model\BuildError::SEVERITY_HIGH,
$fileName,
(int)$violation['beginline'],
(int)$violation['endline']
);
}
}
return array($warnings, $data);
return $warnings;
}
/**

View file

@ -55,10 +55,10 @@ class PhpParallelLint implements \PHPCI\Plugin
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->directory = $phpci->buildPath;
$this->ignore = $this->phpci->ignore;
$this->phpci = $phpci;
$this->build = $build;
$this->directory = $phpci->buildPath;
$this->ignore = $this->phpci->ignore;
if (isset($options['directory'])) {
$this->directory = $phpci->buildPath.$options['directory'];

View file

@ -155,7 +155,7 @@ class PhpTalLint implements PHPCI\Plugin
if (!$this->lintFile($itemPath)) {
$success = false;
}
} elseif ($item->isDir() && $this->recursive && !$this->lintDirectory($itemPath . '/')) {
} elseif ($item->isDir() && $this->recursive && !$this->lintDirectory($itemPath . DIRECTORY_SEPARATOR)) {
$success = false;
}
@ -202,7 +202,9 @@ class PhpTalLint implements PHPCI\Plugin
list($suffixes, $tales) = $this->getFlags();
$lint = dirname(__FILE__) . '/../../vendor/phptal/phptal/tools/phptal_lint.php';
$lint = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;
$lint .= 'vendor' . DIRECTORY_SEPARATOR . 'phptal' . DIRECTORY_SEPARATOR . 'phptal' . DIRECTORY_SEPARATOR;
$lint .= 'tools' . DIRECTORY_SEPARATOR . 'phptal_lint.php';
$cmd = '/usr/bin/env php ' . $lint . ' %s %s "%s"';
$this->phpci->executeCommand($cmd, $suffixes, $tales, $this->phpci->buildPath . $path);
@ -222,7 +224,7 @@ class PhpTalLint implements PHPCI\Plugin
$row = str_replace('(use -i to include your custom modifier functions)', '', $row);
$message = str_replace($name . ': ', '', $row);
$parts = explode(' (line ', $message);
$message = trim($parts[0]);

View file

@ -76,8 +76,8 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
return 'phpunit.xml';
}
if (file_exists($buildPath . 'tests/phpunit.xml')) {
return 'tests/phpunit.xml';
if (file_exists($buildPath . 'tests' . DIRECTORY_SEPARATOR . 'phpunit.xml')) {
return 'tests' . DIRECTORY_SEPARATOR . 'phpunit.xml';
}
if (file_exists($buildPath . 'phpunit.xml.dist')) {
@ -85,7 +85,7 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
}
if (file_exists($buildPath . 'tests/phpunit.xml.dist')) {
return 'tests/phpunit.xml.dist';
return 'tests' . DIRECTORY_SEPARATOR . 'phpunit.xml.dist';
}
return null;
@ -194,7 +194,7 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
} else {
if ($this->runFrom) {
$curdir = getcwd();
chdir($this->phpci->buildPath.'/'.$this->runFrom);
chdir($this->phpci->buildPath . DIRECTORY_SEPARATOR . $this->runFrom);
}
$phpunit = $this->phpci->findBinary('phpunit');

View file

@ -124,12 +124,11 @@ class TechnicalDebt implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$success = true;
$this->phpci->logExecOutput(false);
list($errorCount, $data) = $this->getErrorList();
$errorCount = $this->getErrorList();
$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;
@ -164,7 +163,7 @@ class TechnicalDebt implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
}
// Ignore hidden files, else .git, .sass_cache, etc. all get looped over
if (stripos($filePath, '/.') !== false) {
if (stripos($filePath, DIRECTORY_SEPARATOR . '.') !== false) {
$skipFile = true;
}
@ -175,7 +174,6 @@ class TechnicalDebt implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$files = array_filter(array_unique($files));
$errorCount = 0;
$data = array();
foreach ($files as $file) {
foreach ($this->searches as $search) {
@ -191,18 +189,19 @@ class TechnicalDebt implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$errorCount++;
$fileName = str_replace($this->directory, '', $file);
$data[] = array(
'file' => $fileName,
'line' => $lineNumber,
'message' => $content
$this->build->reportError(
$this->phpci,
'technical_debt',
$content,
PHPCI\Model\BuildError::SEVERITY_LOW,
$fileName,
$lineNumber
);
$this->build->reportError($this->phpci, $fileName, $lineNumber, $content);
}
}
}
return array( $errorCount, $data );
return $errorCount;
}
}

View file

@ -8,8 +8,8 @@ namespace 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;

View file

@ -56,6 +56,7 @@ class FilesPluginInformation implements InstalledPluginInformation
if ($this->pluginInfo === null) {
$this->loadPluginInfo();
}
return $this->pluginInfo;
}
@ -83,7 +84,7 @@ class FilesPluginInformation implements InstalledPluginInformation
$this->pluginInfo = array();
foreach ($this->files as $fileInfo) {
if ($fileInfo instanceof \SplFileInfo) {
if ($fileInfo->isFile() && $fileInfo->getExtension()=='php') {
if ($fileInfo->isFile() && $fileInfo->getExtension() == 'php') {
$this->addPluginFromFile($fileInfo);
}
}
@ -99,11 +100,11 @@ class FilesPluginInformation implements InstalledPluginInformation
$class = $this->getFullClassFromFile($fileInfo);
if (!is_null($class)) {
$newPlugin = new \stdClass();
$newPlugin->class = $class;
$newPlugin = new \stdClass();
$newPlugin->class = $class;
$newPlugin->source = "core";
$parts = explode('\\', $newPlugin->class);
$newPlugin->name = end($parts);
$parts = explode('\\', $newPlugin->class);
$newPlugin->name = end($parts);
$this->pluginInfo[] = $newPlugin;
}
@ -123,11 +124,11 @@ class FilesPluginInformation implements InstalledPluginInformation
if (isset($matches[1])) {
$className = $matches[1];
$matches = array();
preg_match('#namespace +([A-Za-z\\\\]+);#i', $contents, $matches);
$namespace = $matches[1];
return $namespace . '\\' . $className;
} else {
return null;

View file

@ -32,9 +32,11 @@ class PluginInformationCollection implements InstalledPluginInformation
public function getInstalledPlugins()
{
$arr = array();
foreach ($this->pluginInformations as $single) {
$arr = array_merge($arr, $single->getInstalledPlugins());
}
return $arr;
}
@ -47,9 +49,11 @@ class PluginInformationCollection implements InstalledPluginInformation
public function getPluginClasses()
{
$arr = array();
foreach ($this->pluginInformations as $single) {
$arr = array_merge($arr, $single->getPluginClasses());
}
return $arr;
}
}

View file

@ -235,18 +235,20 @@ class TapParser
*/
protected function processYamlBlock($indent)
{
$startLine = $this->lineNumber+1;
$endLine = $indent.'...';
$startLine = $this->lineNumber + 1;
$endLine = $indent . '...';
$yamlLines = array();
do {
$line = $this->nextLine();
if ($line === false) {
throw new Exception(Lang::get('tap_error_endless_yaml', $startLine));
} elseif ($line === $endLine) {
break;
}
$yamlLines[] = substr($line, strlen($indent));
$yamlLines[] = substr($line, strlen($indent));
} while (true);
return Yaml::parse(join("\n", $yamlLines));

View file

@ -132,8 +132,9 @@ class XMPP implements \PHPCI\Plugin
*/
public function findConfigFile()
{
if (file_exists($this->phpci->buildPath . '/.sendxmpprc')) {
if (md5(file_get_contents($this->phpci->buildPath . '/.sendxmpprc')) !== md5($this->getConfigFormat())) {
if (file_exists($this->phpci->buildPath . DIRECTORY_SEPARATOR . '.sendxmpprc')) {
if (md5(file_get_contents($this->phpci->buildPath . DIRECTORY_SEPARATOR . '.sendxmpprc'))
!== md5($this->getConfigFormat())) {
return null;
}
@ -160,7 +161,7 @@ class XMPP implements \PHPCI\Plugin
/*
* Try to build conf file
*/
$config_file = $this->phpci->buildPath . '/.sendxmpprc';
$config_file = $this->phpci->buildPath . DIRECTORY_SEPARATOR . '.sendxmpprc';
if (is_null($this->findConfigFile())) {
file_put_contents($config_file, $this->getConfigFormat());
chmod($config_file, 0600);
@ -174,7 +175,7 @@ class XMPP implements \PHPCI\Plugin
$tls = ' -t';
}
$message_file = $this->phpci->buildPath . '/' . uniqid('xmppmessage');
$message_file = $this->phpci->buildPath . DIRECTORY_SEPARATOR . uniqid('xmppmessage');
if ($this->buildMessage($message_file) === false) {
return false;
}

View file

@ -0,0 +1,85 @@
<?php
/**
* BuildError base store for table: build_error
*/
namespace PHPCI\Store\Base;
use b8\Database;
use b8\Exception\HttpException;
use PHPCI\Store;
use PHPCI\Model\BuildError;
/**
* BuildError Base Store
*/
class BuildErrorStoreBase extends Store
{
protected $tableName = 'build_error';
protected $modelName = '\PHPCI\Model\BuildError';
protected $primaryKey = 'id';
/**
* Get a BuildError by primary key (Id)
*/
public function getByPrimaryKey($value, $useConnection = 'read')
{
return $this->getById($value, $useConnection);
}
/**
* Get a single BuildError by Id.
* @return null|BuildError
*/
public function getById($value, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM `build_error` WHERE `id` = :id LIMIT 1';
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':id', $value);
if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new BuildError($data);
}
}
return null;
}
/**
* Get multiple BuildError by BuildId.
* @return array
*/
public function getByBuildId($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM `build_error` WHERE `build_id` = :build_id LIMIT :limit';
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':build_id', $value);
$stmt->bindValue(':limit', (int)$limit, \PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new BuildError($item);
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
}
}
}

View file

@ -75,25 +75,34 @@ class UserStoreBase extends Store
}
/**
* Get a single User by Name.
* @return null|User
* Get multiple User by Name.
* @return array
*/
public function getByName($value, $useConnection = 'read')
public function getByName($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM `user` WHERE `name` = :name LIMIT 1';
$query = 'SELECT * FROM `user` WHERE `name` = :name LIMIT :limit';
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':name', $value);
$stmt->bindValue(':limit', (int)$limit, \PDO::PARAM_INT);
if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new User($data);
}
}
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
return null;
$map = function ($item) {
return new User($item);
};
$rtn = array_map($map, $res);
$count = count($rtn);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
}
}
}

View file

@ -0,0 +1,57 @@
<?php
/**
* BuildError store for table: build_error
*/
namespace PHPCI\Store;
use b8\Database;
use PHPCI\Model\BuildError;
use PHPCI\Store\Base\BuildErrorStoreBase;
/**
* BuildError Store
* @uses PHPCI\Store\Base\BuildErrorStoreBase
*/
class BuildErrorStore extends BuildErrorStoreBase
{
/**
* Get a list of errors for a given build, since a given time.
* @param $buildId
* @param string $since date string
* @return array
*/
public function getErrorsForBuild($buildId, $since = null)
{
$query = 'SELECT * FROM build_error
WHERE build_id = :build';
if (!is_null($since)) {
$query .= ' AND created_date > :since';
}
$query .= ' LIMIT 15000';
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':build', $buildId, \PDO::PARAM_INT);
if (!is_null($since)) {
$stmt->bindValue(':since', $since);
}
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new BuildError($item);
};
$rtn = array_map($map, $res);
return $rtn;
} else {
return array();
}
}
}

View file

@ -10,6 +10,8 @@
namespace PHPCI\Store;
use PHPCI\Store\Base\BuildMetaStoreBase;
use b8\Database;
use PHPCI\Model\BuildMeta;
/**
* BuildMeta Store
@ -17,5 +19,33 @@ use PHPCI\Store\Base\BuildMetaStoreBase;
*/
class BuildMetaStore extends BuildMetaStoreBase
{
// This class has been left blank so that you can modify it - changes in this file will not be overwritten.
/**
* Only used by an upgrade migration to move errors from build_meta to build_error
* @param $start
* @param $limit
* @return array
*/
public function getErrorsForUpgrade($limit)
{
$query = 'SELECT * FROM build_meta
WHERE meta_key IN (\'phpmd-data\', \'phpcs-data\', \'phpdoccheck-data\')
ORDER BY id ASC LIMIT :limit';
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':limit', $limit, \PDO::PARAM_INT);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new BuildMeta($item);
};
$rtn = array_map($map, $res);
return $rtn;
} else {
return array();
}
}
}

View file

@ -0,0 +1,37 @@
<?php
use PHPCI\Helper\Lang;
$linkTemplate = $build->getFileLinkTemplate();
/** @var \PHPCI\Model\BuildError $error */
foreach ($errors as $error):
$link = str_replace('{FILE}', $error->getFile(), $linkTemplate);
$link = str_replace('{LINE}', $error->getLineStart(), $link);
$link = str_replace('{LINE_END}', $error->getLineEnd(), $link);
?>
<tr class="bg-<?php print $error->getSeverityClass(); ?>">
<td>
<span class="label label-<?php print $error->getSeverityClass(); ?>">
<?php print Lang::get($error->getSeverityString()); ?>
</span>
</td>
<td><?php print Lang::get($error->getPlugin()); ?></td>
<td><a href="<?php print $link; ?>" target="_blank"><?php print $error->getFile(); ?></a></td>
<td>
<a href="<?php print $link; ?>" target="_blank">
<?php
if ($error->getLineStart() == $error->getLineEnd() || !$error->getLineEnd()) {
print $error->getLineStart();
} else {
print $error->getLineStart() . ' - ' . $error->getLineEnd();
}
?>
</a>
</td>
<td><?php print $error->getMessage(); ?></td>
</tr>
<?php endforeach; ?>

View file

@ -1,36 +1,162 @@
<?php use PHPCI\Helper\Lang; ?>
<div class="build-info-panel box box-solid">
<div class="box-header">
<h1 class="box-title">
<?php Lang::out('committed_by_x', $build->getCommitterEmail()); ?>
<label class="pull-right label"></label>
</h1>
</div>
<div class="box-body">
<img class="pull-left" src="//www.gravatar.com/avatar/<?php print md5($build->getCommitterEmail()); ?>?d=mm">
<div id="build-info">
<?php if ($build->getCommitMessage()): ?>
<div class="commit-message">
<?php print $build->getCommitMessage(); ?>
</div>
<?php endif; ?>
<?php Lang::out('branch_x', $build->getBranch()); ?>
<?php if ($build->getCommitId() != 'Manual'): ?>
<br><?php Lang::out('commit_id_x', $build->getCommitId()); ?>
<?php endif; ?>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div id="status"></div>
<div id="plugins" class="row"></div>
<div class="col-sm-4">
<div class="box">
<div class="box-header">
<h3 class="box-title">
Build Details
</h3>
</div>
<div class="box-body no-padding">
<table class="table">
<tr>
<th>Project</th>
<td style="text-align: right">
<a href="<?php print PHPCI_URL . 'project/view/' . $build->getProjectId(); ?>">
<i class="fa fa-<?php print $build->getProject()->getIcon(); ?>"></i>
<?php print $build->getProject()->getTitle(); ?>
</a>
</td>
</tr>
<tr>
<th>Branch</th>
<td style="text-align: right">
<a target="_blank" href="<?php print $build->getBranchLink(); ?>">
<span class="label label-default"><?php print $build->getBranch(); ?></span>
</a>
</td>
</tr>
<tr>
<th>Duration</th>
<td style="text-align: right" class="build-duration duration" data-duration="<?php print $build->getDuration(); ?>">
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="box">
<div class="box-header">
<h3 class="box-title">
Commit Details
</h3>
</div>
<div class="box-body no-padding">
<table class="table">
<tr>
<th>Commit</th>
<td style="text-align: right">
<a target="_blank" href="<?php print $build->getCommitLink(); ?>">
<?php print substr($build->getCommitId(), 0, 7); ?>
</a>
</td>
</tr>
<tr>
<th>Committer</th>
<td style="text-align: right">
<?php print $build->getCommitterEmail(); ?>
</td>
</tr>
<tr>
<td colspan="2">
<?php print $build->getCommitMessage(); ?>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="col-sm-4">
<div class="box">
<div class="box-header">
<h3 class="box-title">
Timing
</h3>
</div>
<div class="box-body no-padding">
<table class="table">
<tr>
<th>Created</th>
<td style="text-align: right" class="build-created datetime" data-date="<?php print $build->getCreated() ? $build->getCreated()->format('Y-m-d H:i:s') : ''; ?>">
</td>
</tr>
<tr>
<th>Started</th>
<td style="text-align: right" class="build-started datetime" data-date="<?php print $build->getStarted() ? $build->getStarted()->format('Y-m-d H:i:s') : ''; ?>">
</td>
</tr>
<tr>
<th>Finished</th>
<td style="text-align: right" class="build-finished datetime" data-date="<?php print $build->getFinished() ? $build->getFinished()->format('Y-m-d H:i:s') : ''; ?>">
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active">
<a href="#log" data-toggle="tab"><i class="fa fa-cogs"></i> <?php print Lang::get('build_log'); ?></a>
</li>
<li class="">
<a href="#errors" data-toggle="tab">
<i class="fa fa-exclamation-triangle"></i> <?php print Lang::get('errors'); ?>
<?php if ($data['errors'] == 0): ?>
<span class="errors-label label label-danger" style="display: none">0</span>
<?php else: ?>
<span class="errors-label label label-danger"><?php print $data['errors']; ?></span>
<?php endif; ?>
</a>
</li>
<li class="">
<a href="#information" data-toggle="tab"><i class="fa fa-info-circle"></i> <?php print Lang::get('information'); ?></a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="log">
<pre style="height: 400px; overflow-y: auto;"><?php print $data['log']; ?></pre>
</div>
<div class="tab-pane" id="errors">
<table class="errors-table table table-hover dataTable">
<thead>
<tr>
<th>Severity</th>
<th>Plugin</th>
<th>File</th>
<th data-orderable="false">Lines</th>
<th data-orderable="false">Message</th>
</tr>
</thead>
<tbody>
<?php print $data['error_html']; ?>
</tbody>
</table>
</div>
<div class="tab-pane" id="information">
<div id="plugins" class="row"></div>
</div>
</div>
</div>
@ -38,14 +164,13 @@
<script>
var ActiveBuild = new Build(<?php print $build->getId() ?>);
ActiveBuild.buildData = <?php print $data; ?>;
ActiveBuild.fileLinkTemplate = <?php print json_encode($build->getFileLinkTemplate()); ?>;
ActiveBuild.setupBuild(<?php print json_encode($data); ?>, <?php print json_encode($build->getFileLinkTemplate()); ?>);
</script>
<?php
foreach ($plugins as $plugin) {
print '<script src="'.PHPCI_URL.'assets/js/build-plugins/' . $plugin . '"></script>';
print '<script src="'.PHPCI_URL.'assets/js/build-plugins/' . $plugin . '"></script>' . PHP_EOL;
}
?>
@ -59,47 +184,7 @@ foreach ($plugins as $plugin) {
"<?php echo PHPCI_URL ?>build/delete/<?php print $build->getId(); ?>", "Build"
).onCloseConfirmed = function () {window.location = '/'};
});
$(window).on('build-updated', function(data) {
updateBuildStatus(data.queryData.status);
});
updateBuildStatus(<?php print $build->getStatus(); ?>);
});
function updateBuildStatus(status) {
switch (status) {
case 0:
$('.build-info-panel')
.removeClass('bg-yellow')
.removeClass('bg-green')
.removeClass('bg-red')
.addClass('bg-blue');
break;
case 1:
$('.build-info-panel')
.removeClass('bg-green')
.removeClass('bg-red')
.removeClass('bg-blue')
.addClass('bg-yellow');
break;
case 2:
$('.build-info-panel')
.removeClass('bg-yellow')
.removeClass('bg-red')
.removeClass('bg-blue')
.addClass('bg-green');
break;
case 3:
$('.build-info-panel')
.removeClass('bg-yellow')
.removeClass('bg-green')
.removeClass('bg-blue')
.addClass('bg-red');
break;
}
}
</script>

View file

@ -41,7 +41,9 @@ switch($build->getStatus())
<td><a href="<?php echo PHPCI_URL ?>build/view/<?php print $build->getId(); ?>">#<?php print str_pad($build->getId(), 6, '0', STR_PAD_LEFT); ?></a></td>
<td><?php print $build->getCreated()->format('Y-m-d H:i:s'); ?></td>
<td><a href="<?php echo PHPCI_URL ?>project/view/<?php print $build->getProjectId(); ?>">
<?php
<i class="fa fa-<?php print $build->getProject()->getIcon(); ?>"></i>
<?php
if (is_object($build->getProject())) {
print htmlspecialchars($build->getProject()->getTitle());
} else {

View file

@ -7,9 +7,9 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="<?php echo PHPCI_URL ?>assets/css/bootstrap.min.css">
<script src="//code.jquery.com/jquery-1.8.1.min.js"></script>
<script src="<?php echo PHPCI_URL ?>assets/js/bootstrap.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript"></script>
<style type="text/css">
@ -56,7 +56,7 @@
}
#logo {
background: transparent url('https://www.block8.co.uk/assets/images/b8-phpci-logo-muted.png') no-repeat top left;
background: transparent url('https://block8.digital/assets/images/b8-phpci-logo-muted.png') no-repeat top left;
background-size: 130px 46px;
display: inline-block;
height: 46px;
@ -77,7 +77,7 @@
}
#logo:hover {
background-image: url('https://www.block8.co.uk/assets/images/b8-phpci-logo.png');
background-image: url('https://block8.digital/assets/images/b8-phpci-logo.png');
}
#phpci-logo img {
@ -89,14 +89,14 @@
<body>
<div class="container">
<div class="row" style="margin-top: 10%; text-align: center">
<a id="phpci-logo" href="http://www.phptesting.org">
<a id="phpci-logo" href="https://www.phptesting.org">
<img src="<?php print PHPCI_URL; ?>/assets/img/logo-large.png">
</a>
<div class="" id="login-box">
<?php print $content; ?>
</div>
<a id="logo" href="https://www.block8.co.uk">Block 8 - Manchester Web Development Specialists</a>
<a target="_blank" id="logo" href="https://block8.digital">Block 8 - Digital Development Experts</a>
</div>
</div>
</body>

View file

@ -5,18 +5,16 @@
</p>
<?php else: ?>
<?php if (empty($error)): ?>
<div class="panel panel-success" style="margin-bottom: 0">
<div class="box-header">
<div class="" style="margin-bottom: 15px;">
<?php Lang::out('reset_header'); ?>
</div>
<?php else: ?>
<div class="panel panel-danger" style="margin-bottom: 0">
<div class="box-header">
<div class="alert alert-danger">
<?php print $error; ?>
</div>
<?php endif; ?>
<div class="box-body">
<div class="">
<form class="form" action="<?php print PHPCI_URL; ?>session/forgot-password" method="POST">
<div class="form-group">
<label for="email"><?php Lang::out('reset_email_address'); ?></label>
@ -28,7 +26,6 @@
</div>
</form>
</div>
</div>
<?php endif; ?>

View file

@ -1,6 +1,6 @@
<?php use PHPCI\Helper\Lang; ?>
<?php if (empty($error)): ?>
<div class="panel panel-success" style="margin-bottom: 0">
<div class="box-header">
<?php Lang::out('reset_enter_password'); ?>
</div>
@ -17,7 +17,6 @@
</div>
</form>
</div>
</div>
<?php else: ?>
<div class="alert alert-danger" style="margin-bottom: 0">
<?php print $error; ?>

View file

@ -9,14 +9,14 @@
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/ionicons/1.5.2/css/ionicons.min.css" rel="stylesheet" type="text/css" />
<link href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/css/datepicker/datepicker3.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/css/daterangepicker/daterangepicker-bs3.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/plugins/datepicker/datepicker3.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/plugins/daterangepicker/daterangepicker-bs3.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/css/ansi-colors.css" rel="stylesheet" type="text/css" />
<!-- Theme style -->
<link href="<?php print PHPCI_URL; ?>assets/css/AdminLTE.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/css/AdminLTE.min.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/css/AdminLTE-skins.min.css" rel="stylesheet" type="text/css" />
<link href="<?php print PHPCI_URL; ?>assets/css/AdminLTE-custom.css" rel="stylesheet" type="text/css" />
<script>
@ -35,27 +35,28 @@
<script src="<?php print PHPCI_URL; ?>assets/js/sprintf.js"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/moment.min.js"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/phpci.js" type="text/javascript"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body class="skin-blue">
<body class="phpci <?php print !empty($skin) ? 'skin-' . $skin : 'skin-blue'; ?>">
<div class="wrapper row-offcanvas row-offcanvas-left">
<!-- header logo: style can be found in header.less -->
<header class="header">
<header class="main-header">
<a href="<?php print PHPCI_URL; ?>" class="logo">PHPCI</a>
<!-- Header Navbar: style can be found in header.less -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="navbar-btn sidebar-toggle" data-toggle="offcanvas" role="button">
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
<span class="sr-only"><?php Lang::out('toggle_navigation'); ?></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="navbar-right">
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li class="dropdown messages-menu phpci-pending">
@ -118,9 +119,8 @@
</div>
</nav>
</header>
<div class="wrapper row-offcanvas row-offcanvas-left">
<!-- Left side column. contains the logo and sidebar -->
<aside class="left-side sidebar-offcanvas">
<aside class="main-sidebar sidebar-offcanvas">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
@ -130,7 +130,7 @@
<div class="pull-left image">
<img src="https://www.gravatar.com/avatar/<?php print md5($this->User()->getEmail()); ?>?d=mm" class="img-circle" alt="<?php print $this->User()->getName(); ?>" />
</div>
<div class="info">
<div class="pull-left info">
<p><?php Lang::out('hello_name', $this->User()->getName()); ?></p>
</div>
</div>
@ -262,7 +262,7 @@
<li class="archive<?php print (array_key_exists('archived', $_GET) ? ' active' : ''); ?>">
<a href="<?php print PHPCI_URL . (array_key_exists('archived', $_GET) ? '' : '?archived'); ?>">
<i class="fa fa-archive"></i> <span><?php Lang::get('archived_menu'); ?></span>
<i class="fa fa-archive"></i> <span><?php Lang::out('archived_menu'); ?></span>
</a>
</li>
@ -272,9 +272,13 @@
</aside>
<!-- Right side column. Contains the navbar and content of the page -->
<aside class="right-side">
<aside class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<div class="pull-right">
<?php print (!empty($actions) ? $actions : ''); ?>
</div>
<h1>
<?php print !empty($title) ? $title : 'PHPCI'; ?>
@ -282,27 +286,29 @@
<small><?php print $subtitle; ?></small>
<?php endif; ?>
</h1>
</section>
<!-- Main content -->
<section class="content">
<?php print $content; ?>
</section><!-- /.content -->
</aside><!-- /.right-side -->
</aside><!-- /.content-wrapper -->
</div><!-- ./wrapper -->
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/plugins/daterangepicker/daterangepicker.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/plugins/datepicker/bootstrap-datepicker.js" type="text/javascript"></script>
<?php if (file_exists(PHPCI_DIR . 'assets/js/plugins/datepicker/locales/bootstrap-datepicker.' . Lang::getLanguage() . '.js')) :?>
<script src="<?php print PHPCI_URL; ?>assets/js/plugins/datepicker/locales/bootstrap-datepicker.<?php print Lang::getLanguage(); ?>.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/plugins/chartjs/Chart.min.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/plugins/daterangepicker/daterangepicker.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/plugins/datepicker/bootstrap-datepicker.js" type="text/javascript"></script>
<?php if (file_exists(PHPCI_DIR . 'assets/plugins/datepicker/locales/bootstrap-datepicker.' . Lang::getLanguage() . '.js')) :?>
<script src="<?php print PHPCI_URL; ?>assets/plugins/datepicker/locales/bootstrap-datepicker.<?php print Lang::getLanguage(); ?>.js" type="text/javascript"></script>
<?php endif; ?>
<script src="<?php print PHPCI_URL; ?>assets/js/AdminLTE/app.js" type="text/javascript"></script>
<script src="<?php print PHPCI_URL; ?>assets/js/AdminLTE/app.min.js" type="text/javascript"></script>
</body>
</html>

View file

@ -33,3 +33,6 @@ Contributions from others would be very much appreciated! Please read our [guide
##Questions?
Your best place to go is the [mailing list](https://groups.google.com/forum/#!forum/php-ci), if you're already a member of the mailing list, you can simply email php-ci@googlegroups.com.
Test

View file

@ -107,6 +107,7 @@ class InstallCommandTest extends \PHPUnit_Framework_TestCase
'--admin-name' => 'phpci4',
'--admin-pass' => 'phpci5',
'--url' => 'http://test.phpci.org',
'--queue-disabled' => null,
);
if (!is_null($exclude)) {

View file

@ -49,7 +49,9 @@
"robmorgan/phinx": "~0.4",
"sensiolabs/ansi-to-html": "~1.1",
"pda/pheanstalk": "~3.1",
"maknz/slack": "~1.7"
"maknz/slack": "~1.7",
"hipchat/hipchat-php": "~1.4",
"mremi/flowdock": "~1.0"
},
"require-dev": {
@ -75,7 +77,5 @@
"hipchat/hipchat-php": "Hipchat integration",
"gorkalaucirica/hipchat-v2-api-client": "Hipchat (APIv2) Integration",
"phptal/phptal": "PHPTAL templating engine",
"maknz/slack": "Slack integration",
"mremi/flowdock": "Flowdock integration"
}
}

273
composer.lock generated
View file

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "2acdd123806a7eda47a4a16614e560bb",
"content-hash": "9288b6bc9e7061c6338b039b70d29ea1",
"hash": "f6333ad0763856ed7556296617a7c190",
"content-hash": "6ad9542b5f5959b67d94baf77e2fc45a",
"packages": [
{
"name": "block8/b8framework",
@ -54,6 +54,101 @@
],
"time": "2015-10-05 10:50:20"
},
{
"name": "guzzle/guzzle",
"version": "v3.9.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle3.git",
"reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9",
"reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.3.3",
"symfony/event-dispatcher": "~2.1"
},
"replace": {
"guzzle/batch": "self.version",
"guzzle/cache": "self.version",
"guzzle/common": "self.version",
"guzzle/http": "self.version",
"guzzle/inflection": "self.version",
"guzzle/iterator": "self.version",
"guzzle/log": "self.version",
"guzzle/parser": "self.version",
"guzzle/plugin": "self.version",
"guzzle/plugin-async": "self.version",
"guzzle/plugin-backoff": "self.version",
"guzzle/plugin-cache": "self.version",
"guzzle/plugin-cookie": "self.version",
"guzzle/plugin-curlauth": "self.version",
"guzzle/plugin-error-response": "self.version",
"guzzle/plugin-history": "self.version",
"guzzle/plugin-log": "self.version",
"guzzle/plugin-md5": "self.version",
"guzzle/plugin-mock": "self.version",
"guzzle/plugin-oauth": "self.version",
"guzzle/service": "self.version",
"guzzle/stream": "self.version"
},
"require-dev": {
"doctrine/cache": "~1.3",
"monolog/monolog": "~1.0",
"phpunit/phpunit": "3.7.*",
"psr/log": "~1.0",
"symfony/class-loader": "~2.1",
"zendframework/zend-cache": "2.*,<2.3",
"zendframework/zend-log": "2.*,<2.3"
},
"suggest": {
"guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.9-dev"
}
},
"autoload": {
"psr-0": {
"Guzzle": "src/",
"Guzzle\\Tests": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Guzzle Community",
"homepage": "https://github.com/guzzle/guzzle/contributors"
}
],
"description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2015-03-18 18:23:50"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.1.0",
@ -225,6 +320,48 @@
],
"time": "2015-08-15 19:32:36"
},
{
"name": "hipchat/hipchat-php",
"version": "v1.4",
"source": {
"type": "git",
"url": "https://github.com/hipchat/hipchat-php.git",
"reference": "5936c0a48d2d514d94bfc1d774b04c42cd3bc39e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hipchat/hipchat-php/zipball/5936c0a48d2d514d94bfc1d774b04c42cd3bc39e",
"reference": "5936c0a48d2d514d94bfc1d774b04c42cd3bc39e",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"HipChat": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "HipChat",
"email": "support@hipchat.com",
"homepage": "https://www.hipchat.com",
"role": "Company"
}
],
"description": "PHP library for HipChat",
"homepage": "http://github.com/hipchat/hipchat-php",
"keywords": [
"hipchat"
],
"time": "2015-04-28 22:48:40"
},
{
"name": "ircmaxell/password-compat",
"version": "v1.0.4",
@ -318,16 +455,16 @@
},
{
"name": "monolog/monolog",
"version": "1.17.1",
"version": "1.17.2",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422"
"reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/0524c87587ab85bc4c2d6f5b41253ccb930a5422",
"reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/bee7f0dc9c3e0b69a6039697533dca1e845c8c24",
"reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24",
"shasum": ""
},
"require": {
@ -341,10 +478,11 @@
"aws/aws-sdk-php": "^2.4.9",
"doctrine/couchdb": "~1.0@dev",
"graylog2/gelf-php": "~1.0",
"jakub-onderka/php-parallel-lint": "0.9",
"php-console/php-console": "^3.1.3",
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "2.3.0",
"raven/raven": "~0.11",
"raven/raven": "^0.13",
"ruflin/elastica": ">=0.90 <3.0",
"swiftmailer/swiftmailer": "~5.3",
"videlalvaro/php-amqplib": "~2.4"
@ -390,7 +528,54 @@
"logging",
"psr-3"
],
"time": "2015-08-31 09:17:37"
"time": "2015-10-14 12:51:02"
},
{
"name": "mremi/flowdock",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/mremi/Flowdock.git",
"reference": "e34ca78bbd4f974366e979186e876d78ae488e51"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mremi/Flowdock/zipball/e34ca78bbd4f974366e979186e876d78ae488e51",
"reference": "e34ca78bbd4f974366e979186e876d78ae488e51",
"shasum": ""
},
"require": {
"guzzle/guzzle": "~3.7",
"php": ">=5.3.3",
"symfony/console": "~2.5"
},
"require-dev": {
"phpunit/phpunit": "~4.1"
},
"type": "library",
"autoload": {
"psr-0": {
"Mremi\\Flowdock": "src",
"Mremi\\Flowdock\\Tests": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rémi Marseille",
"email": "marseille.remi@gmail.com"
}
],
"description": "A PHP5 library to interact with the Flowdock API",
"homepage": "https://github.com/mremi/Flowdock",
"keywords": [
"api",
"flowdock"
],
"time": "2015-01-08 21:03:29"
},
{
"name": "pda/pheanstalk",
@ -477,9 +662,7 @@
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
"email": "fabien@symfony.com"
}
],
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
@ -843,6 +1026,64 @@
"homepage": "https://symfony.com",
"time": "2015-09-25 08:32:23"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.7.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae4dcc2a8d3de98bd794167a3ccda1311597c5d9",
"reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~2.0,>=2.0.5",
"symfony/dependency-injection": "~2.6",
"symfony/expression-language": "~2.6",
"symfony/phpunit-bridge": "~2.7",
"symfony/stopwatch": "~2.3"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2015-09-22 13:49:29"
},
{
"name": "symfony/filesystem",
"version": "v2.7.5",
@ -1606,16 +1847,16 @@
},
{
"name": "phpunit/phpunit",
"version": "4.8.12",
"version": "4.8.13",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "00194eb95989190a73198390ceca081ad3441a7f"
"reference": "be067d6105286b74272facefc2697038f8807b77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/00194eb95989190a73198390ceca081ad3441a7f",
"reference": "00194eb95989190a73198390ceca081ad3441a7f",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/be067d6105286b74272facefc2697038f8807b77",
"reference": "be067d6105286b74272facefc2697038f8807b77",
"shasum": ""
},
"require": {
@ -1674,7 +1915,7 @@
"testing",
"xunit"
],
"time": "2015-10-12 03:36:47"
"time": "2015-10-14 13:49:40"
},
{
"name": "phpunit/phpunit-mock-objects",

View file

@ -22,6 +22,7 @@ use PHPCI\Command\PollCommand;
use PHPCI\Command\CreateAdminCommand;
use PHPCI\Command\CreateBuildCommand;
use PHPCI\Command\WorkerCommand;
use PHPCI\Command\RebuildQueueCommand;
use PHPCI\Service\BuildService;
use Symfony\Component\Console\Application;
use b8\Store\Factory;
@ -38,5 +39,6 @@ $application->add(new PollCommand($loggerConfig->getFor('PollCommand')));
$application->add(new CreateAdminCommand(Factory::getStore('User')));
$application->add(new CreateBuildCommand(Factory::getStore('Project'), new BuildService(Factory::getStore('Build'))));
$application->add(new WorkerCommand($loggerConfig->getFor('WorkerCommand')));
$application->add(new RebuildQueueCommand($loggerConfig->getFor('RebuildQueueCommand')));
$application->run();

View file

@ -1,4 +1,4 @@
.skin-blue .logo, .skin-blue .logo:hover {
.phpci .main-header .logo, .phpci .main-header .logo:hover {
background-image: url('/assets/img/logo-large.png');
background-repeat: no-repeat;
background-size: 40%;
@ -76,16 +76,6 @@
font-size: 11px;
}
.user-panel > .image {
padding-right: 15px;
}
.user-panel > .info {
padding: 0;
font-size: inherit;
line-height: inherit;
}
#phpunit-data th div { margin: 0 0.5em; }
#phpunit-data .success td { background: none; color: #00a65a; }
#phpunit-data .fail td { background: none; color: #f56954; }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

7
public/assets/css/AdminLTE.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,3 +0,0 @@
/*! bootstrap3-wysihtml5-bower 2013-11-22 */
ul.wysihtml5-toolbar{margin:0;padding:0;display:block}ul.wysihtml5-toolbar::after{clear:both;display:table;content:""}ul.wysihtml5-toolbar>li{float:left;display:list-item;list-style:none;margin:0 5px 10px 0}ul.wysihtml5-toolbar a[data-wysihtml5-command=bold]{font-weight:700}ul.wysihtml5-toolbar a[data-wysihtml5-command=italic]{font-style:italic}ul.wysihtml5-toolbar a[data-wysihtml5-command=underline]{text-decoration:underline}ul.wysihtml5-toolbar a.btn.wysihtml5-command-active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);background-color:#E6E6E6;background-color:#D9D9D9;outline:0}ul.wysihtml5-commands-disabled .dropdown-menu{display:none!important}ul.wysihtml5-toolbar div.wysihtml5-colors{display:block;width:50px;height:20px;margin-top:2px;margin-left:5px;position:absolute;pointer-events:none}ul.wysihtml5-toolbar a.wysihtml5-colors-title{padding-left:70px}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=black]{background:#000!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=silver]{background:silver!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=gray]{background:gray!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=maroon]{background:maroon!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=red]{background:red!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=purple]{background:purple!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=green]{background:green!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=olive]{background:olive!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=navy]{background:navy!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=blue]{background:#00f!important}ul.wysihtml5-toolbar div[data-wysihtml5-command-value=orange]{background:orange!important}

File diff suppressed because one or more lines are too long

View file

@ -1,9 +0,0 @@
/*!
* Bootstrap Colorpicker
* http://mjolnic.github.io/bootstrap-colorpicker/
*
* Originally written by (c) 2012 Stefan Petre
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
*/.colorpicker-saturation{float:left;width:100px;height:100px;cursor:crosshair;background-image:url("../../img/bootstrap-colorpicker/saturation.png")}.colorpicker-saturation i{position:absolute;top:0;left:0;display:block;width:5px;height:5px;margin:-4px 0 0 -4px;border:1px solid #000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-saturation i b{display:block;width:5px;height:5px;border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-hue,.colorpicker-alpha{float:left;width:15px;height:100px;margin-bottom:4px;margin-left:4px;cursor:row-resize}.colorpicker-hue i,.colorpicker-alpha i{position:absolute;top:0;left:0;display:block;width:100%;height:1px;margin-top:-1px;background:#000;border-top:1px solid #fff}.colorpicker-hue{background-image:url("../../img/bootstrap-colorpicker/hue.png")}.colorpicker-alpha{display:none;background-image:url("../../img/bootstrap-colorpicker/alpha.png")}.colorpicker{top:0;left:0;z-index:2500;min-width:130px;padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1}.colorpicker:before,.colorpicker:after{display:table;line-height:0;content:""}.colorpicker:after{clear:both}.colorpicker:before{position:absolute;top:-7px;left:6px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.colorpicker:after{position:absolute;top:-6px;left:7px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.colorpicker div{position:relative}.colorpicker.colorpicker-with-alpha{min-width:140px}.colorpicker.colorpicker-with-alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-image:url("../../img/bootstrap-colorpicker/alpha.png");background-position:0 100%}.colorpicker-color div{height:10px}.colorpicker-element .input-group-addon i{display:block;width:16px;height:16px;cursor:pointer}.colorpicker.colorpicker-inline{position:relative;display:inline-block;float:none}.colorpicker.colorpicker-horizontal{width:110px;height:auto;min-width:110px}.colorpicker.colorpicker-horizontal .colorpicker-saturation{margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-color{width:100px}.colorpicker.colorpicker-horizontal .colorpicker-hue,.colorpicker.colorpicker-horizontal .colorpicker-alpha{float:left;width:100px;height:15px;margin-bottom:4px;margin-left:0;cursor:col-resize}.colorpicker.colorpicker-horizontal .colorpicker-hue i,.colorpicker.colorpicker-horizontal .colorpicker-alpha i{position:absolute;top:0;left:0;display:block;width:1px;height:15px;margin-top:0;background:#fff;border:0}.colorpicker.colorpicker-horizontal .colorpicker-hue{background-image:url("../../img/bootstrap-colorpicker/hue-horizontal.png")}.colorpicker.colorpicker-horizontal .colorpicker-alpha{background-image:url("../../img/bootstrap-colorpicker/alpha-horizontal.png")}.colorpicker.colorpicker-hidden{display:none}.colorpicker.colorpicker-visible{display:block}.colorpicker-inline.colorpicker-visible{display:inline-block}

View file

@ -1,223 +0,0 @@
div.dataTables_length label {
font-weight: normal;
float: left;
text-align: left;
}
div.dataTables_length select {
width: 75px;
}
div.dataTables_filter label {
font-weight: normal;
float: right;
}
div.dataTables_filter input {
width: 16em;
}
div.dataTables_info {
padding-top: 8px;
}
div.dataTables_paginate {
float: right;
margin: 0;
}
div.dataTables_paginate ul.pagination {
margin: 2px 0;
white-space: nowrap;
}
table.dataTable,
table.dataTable td,
table.dataTable th {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
table.dataTable {
clear: both;
margin-top: 6px !important;
margin-bottom: 6px !important;
max-width: none !important;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc,
table.dataTable thead .sorting_asc_disabled,
table.dataTable thead .sorting_desc_disabled {
cursor: pointer;
}
table.dataTable thead .sorting { background: url('images/sort_both.png') no-repeat center right; }
table.dataTable thead .sorting_asc { background: url('images/sort_asc.png') no-repeat center right; }
table.dataTable thead .sorting_desc { background: url('images/sort_desc.png') no-repeat center right; }
table.dataTable thead .sorting_asc_disabled { background: url('images/sort_asc_disabled.png') no-repeat center right; }
table.dataTable thead .sorting_desc_disabled { background: url('images/sort_desc_disabled.png') no-repeat center right; }
table.dataTable th:active {
outline: none;
}
/* Scrolling */
div.dataTables_scrollHead table {
margin-bottom: 0 !important;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
div.dataTables_scrollHead table thead tr:last-child th:first-child,
div.dataTables_scrollHead table thead tr:last-child td:first-child {
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.dataTables_scrollBody table {
border-top: none;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
div.dataTables_scrollBody tbody tr:first-child th,
div.dataTables_scrollBody tbody tr:first-child td {
border-top: none;
}
div.dataTables_scrollFoot table {
margin-top: 0 !important;
border-top: none;
}
/*
* TableTools styles
*/
.table tbody tr.active td,
.table tbody tr.active th {
background-color: #08C;
color: white;
}
.table tbody tr.active:hover td,
.table tbody tr.active:hover th {
background-color: #0075b0 !important;
}
.table tbody tr.active a {
color: white;
}
.table-striped tbody tr.active:nth-child(odd) td,
.table-striped tbody tr.active:nth-child(odd) th {
background-color: #017ebc;
}
table.DTTT_selectable tbody tr {
cursor: pointer;
}
div.DTTT .btn {
color: #333 !important;
font-size: 12px;
}
div.DTTT .btn:hover {
text-decoration: none !important;
}
ul.DTTT_dropdown.dropdown-menu {
z-index: 2003;
}
ul.DTTT_dropdown.dropdown-menu a {
color: #333 !important; /* needed only when demo_page.css is included */
}
ul.DTTT_dropdown.dropdown-menu li {
position: relative;
}
ul.DTTT_dropdown.dropdown-menu li:hover a {
background-color: #0088cc;
color: white !important;
}
div.DTTT_collection_background {
z-index: 2002;
}
/* TableTools information display */
div.DTTT_print_info.modal {
height: 150px;
margin-top: -75px;
text-align: center;
}
div.DTTT_print_info h6 {
font-weight: normal;
font-size: 28px;
line-height: 28px;
margin: 1em;
}
div.DTTT_print_info p {
font-size: 14px;
line-height: 20px;
}
/*
* FixedColumns styles
*/
div.DTFC_LeftHeadWrapper table,
div.DTFC_LeftFootWrapper table,
div.DTFC_RightHeadWrapper table,
div.DTFC_RightFootWrapper table,
table.DTFC_Cloned tr.even {
background-color: white;
}
div.DTFC_RightHeadWrapper table ,
div.DTFC_LeftHeadWrapper table {
margin-bottom: 0 !important;
border-top-right-radius: 0 !important;
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,
div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,
div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,
div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.DTFC_RightBodyWrapper table,
div.DTFC_LeftBodyWrapper table {
border-top: none;
margin-bottom: 0 !important;
}
div.DTFC_RightBodyWrapper tbody tr:first-child th,
div.DTFC_RightBodyWrapper tbody tr:first-child td,
div.DTFC_LeftBodyWrapper tbody tr:first-child th,
div.DTFC_LeftBodyWrapper tbody tr:first-child td {
border-top: none;
}
div.DTFC_RightFootWrapper table,
div.DTFC_LeftFootWrapper table {
border-top: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -1,77 +0,0 @@
body {
background: #f9f9f9;
font-family: Arial, Sans-Serif;
font-style: normal;
font-weight: 300;
padding-top: 70px;
}
.navbar {
background-color: #eee;
}
.navbar-brand {
padding: 10px 15px;
}
#latest-builds td,
#project-overview td,
#users td {
vertical-align: middle;
}
.table th {
background-color: #efefef;
background-image: -webkit-gradient(linear, 0 0%, 0 100%, from(#fdfdfd), to(#eaeaea));
background-image: -webkit-linear-gradient(top, #fdfdfd 0%, #eaeaea 100%);
background-image: -moz-linear-gradient(top, #fdfdfd 0%, #eaeaea 100%);
background-image: -ms-linear-gradient(top, #fdfdfd 0%, #eaeaea 100%);
background-image: -o-linear-gradient(top, #fdfdfd 0%, #eaeaea 100%);
background-image: -linear-gradient(top, #fdfdfd 0%, #eaeaea 100%);
border-bottom: 1px solid #CDCDCD;
}
h1 {
border-bottom: 1px solid #ddd;
font-size: 2em;
padding: 10px 0;
}
h1 i {
font-size: 23px;
margin-right: 10px;
}
#loading {
background: #246;
bottom: 25px;
color: #fff;
display: none;
font-size: 1.5em;
padding: 20px 40px;
position: absolute;
right: 25px;
width: 200px;
}
.word-wrap {
word-wrap: break-word;
}
ul.pagination {
}
ul.pagination > li > span {
color: #333;
}
ul.pagination > li > span:hover,
ul.pagination > li > span:focus {
color: #333;
background-color: #fff;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Some files were not shown because too many files have changed in this diff Show more