Track and display the build progression, for each stages and plugins.
Translations for the build summary. Closed #944
This commit is contained in:
parent
8549ba30cf
commit
ad29ba4cfd
|
@ -295,6 +295,17 @@ PHPCI',
|
|||
'search_packagist_for_more' => 'Search Packagist for more packages',
|
||||
'search' => 'Search »',
|
||||
|
||||
// Summary plugin
|
||||
'build-summary' => 'Summary',
|
||||
'stage' => 'Stage',
|
||||
'duration' => 'Duration',
|
||||
'plugin' => 'Plugin',
|
||||
'stage_setup' => 'Setup',
|
||||
'stage_test' => 'Test',
|
||||
'stage_complete' => 'Complete',
|
||||
'stage_success' => 'Success',
|
||||
'stage_failure' => 'Failure',
|
||||
|
||||
// Installer
|
||||
'installation_url' => 'PHPCI Installation URL',
|
||||
'db_host' => 'Database Host',
|
||||
|
|
|
@ -286,6 +286,17 @@ PHPCI',
|
|||
'search_packagist_for_more' => 'Rechercher sur Packagist pour trouver plus de paquets',
|
||||
'search' => 'Rechercher »',
|
||||
|
||||
// Summary plugin
|
||||
'build-summary' => 'Résumé',
|
||||
'stage' => 'Étape',
|
||||
'duration' => 'Durée',
|
||||
'plugin' => 'Plugin',
|
||||
'stage_setup' => 'Préparation',
|
||||
'stage_test' => 'Test',
|
||||
'stage_complete' => 'Terminé',
|
||||
'stage_success' => 'Succes',
|
||||
'stage_failure' => 'Échec',
|
||||
|
||||
// Installer
|
||||
'installation_url' => 'URL d\'installation de PHPCI',
|
||||
'db_host' => 'Hôte de la BDD',
|
||||
|
|
|
@ -2,8 +2,12 @@
|
|||
|
||||
namespace PHPCI\Plugin\Util;
|
||||
|
||||
use b8\Store\Factory as StoreFactory;
|
||||
use Exception;
|
||||
use PHPCI\Helper\Lang;
|
||||
use \PHPCI\Logging\BuildLogger;
|
||||
use PHPCI\Logging\BuildLogger;
|
||||
use PHPCI\Model\Build;
|
||||
use PHPCI\Store\BuildStore;
|
||||
|
||||
/**
|
||||
* Plugin Executor - Runs the configured plugins for a given build stage.
|
||||
|
@ -21,14 +25,20 @@ class Executor
|
|||
*/
|
||||
protected $pluginFactory;
|
||||
|
||||
/**
|
||||
* @var BuildStore
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* @param Factory $pluginFactory
|
||||
* @param BuildLogger $logger
|
||||
*/
|
||||
public function __construct(Factory $pluginFactory, BuildLogger $logger)
|
||||
public function __construct(Factory $pluginFactory, BuildLogger $logger, BuildStore $store = null)
|
||||
{
|
||||
$this->pluginFactory = $pluginFactory;
|
||||
$this->logger = $logger;
|
||||
$this->store = $store ?: StoreFactory::getStore('Build');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,22 +58,29 @@ class Executor
|
|||
foreach ($config[$stage] as $plugin => $options) {
|
||||
$this->logger->log(Lang::get('running_plugin', $plugin));
|
||||
|
||||
// Try and execute it:
|
||||
if ($this->executePlugin($plugin, $options)) {
|
||||
// Execution was successful:
|
||||
$this->logger->logSuccess(Lang::get('plugin_success'));
|
||||
} elseif ($stage == 'setup') {
|
||||
// If we're in the "setup" stage, execution should not continue after
|
||||
// a plugin has failed:
|
||||
throw new \Exception('Plugin failed: ' . $plugin);
|
||||
} else {
|
||||
// If we're in the "test" stage and the plugin is not allowed to fail,
|
||||
// then mark the build as failed:
|
||||
if ($stage == 'test' && (!isset($options['allow_failures']) || !$options['allow_failures'])) {
|
||||
$success = false;
|
||||
}
|
||||
$this->setPluginStatus($stage, $plugin, Build::STATUS_RUNNING);
|
||||
|
||||
// Try and execute it
|
||||
if ($this->executePlugin($plugin, $options)) {
|
||||
// Execution was successful
|
||||
$this->logger->logSuccess(Lang::get('plugin_success'));
|
||||
$this->setPluginStatus($stage, $plugin, Build::STATUS_SUCCESS);
|
||||
} else {
|
||||
// Execution failed
|
||||
$this->logger->logFailure(Lang::get('plugin_failed'));
|
||||
$this->setPluginStatus($stage, $plugin, Build::STATUS_FAILED);
|
||||
|
||||
if ($stage === 'setup') {
|
||||
// If we're in the "setup" stage, execution should not continue after
|
||||
// a plugin has failed:
|
||||
throw new Exception('Plugin failed: ' . $plugin);
|
||||
} elseif ($stage === 'test') {
|
||||
// If we're in the "test" stage and the plugin is not allowed to fail,
|
||||
// then mark the build as failed:
|
||||
if (empty($options['allow_failures'])) {
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,20 +108,62 @@ class Executor
|
|||
return false;
|
||||
}
|
||||
|
||||
$rtn = true;
|
||||
|
||||
// Try running it:
|
||||
try {
|
||||
// Build and run it
|
||||
$obj = $this->pluginFactory->buildPlugin($class, $options);
|
||||
|
||||
if (!$obj->execute()) {
|
||||
$rtn = false;
|
||||
}
|
||||
return $obj->execute();
|
||||
} catch (\Exception $ex) {
|
||||
$this->logger->logFailure(Lang::get('exception') . $ex->getMessage(), $ex);
|
||||
$rtn = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the status of a plugin for a given stage.
|
||||
*
|
||||
* @param string $stage The builder stage.
|
||||
* @param string $plugin The plugin name.
|
||||
* @param int $status The new status.
|
||||
*/
|
||||
protected function setPluginStatus($stage, $plugin, $status)
|
||||
{
|
||||
$summary = $this->getBuildSummary();
|
||||
|
||||
if (!isset($summary[$stage][$plugin])) {
|
||||
$summary[$stage][$plugin] = array();
|
||||
}
|
||||
|
||||
return $rtn;
|
||||
$summary[$stage][$plugin]['status'] = $status;
|
||||
|
||||
if ($status === Build::STATUS_RUNNING) {
|
||||
$summary[$stage][$plugin]['started'] = time();
|
||||
} elseif ($status >= Build::STATUS_SUCCESS) {
|
||||
$summary[$stage][$plugin]['ended'] = time();
|
||||
}
|
||||
|
||||
$this->setBuildSummary($summary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the summary data of the current build.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getBuildSummary()
|
||||
{
|
||||
$build = $this->pluginFactory->getResourceFor('PHPCI\Model\Build');
|
||||
$metas = $this->store->getMeta('plugin-summary', $build->getProjectId(), $build->getId());
|
||||
return isset($metas[0]['meta_value']) ? $metas[0]['meta_value'] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the summary data of the current build.
|
||||
*
|
||||
* @param array summary
|
||||
*/
|
||||
private function setBuildSummary($summary)
|
||||
{
|
||||
$build = $this->pluginFactory->getResourceFor('PHPCI\Model\Build');
|
||||
$this->store->setMeta($build->getProjectId(), $build->getId(), 'plugin-summary', json_encode($summary));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,11 +150,11 @@ class Factory
|
|||
}
|
||||
|
||||
/**
|
||||
* @param null $type
|
||||
* @param null $name
|
||||
* @return null
|
||||
* @param string $type
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
private function getResourceFor($type = null, $name = null)
|
||||
public function getResourceFor($type = null, $name = null)
|
||||
{
|
||||
$fullId = $this->getInternalID($type, $name);
|
||||
if (isset($this->container[$fullId])) {
|
||||
|
|
|
@ -165,7 +165,9 @@ class BuildStore extends BuildStoreBase
|
|||
$stmt->bindValue(':projectId', (int)$projectId, \PDO::PARAM_INT);
|
||||
$stmt->bindValue(':buildId', (int)$buildId, \PDO::PARAM_INT);
|
||||
$stmt->bindValue(':numResults', (int)$numResults, \PDO::PARAM_INT);
|
||||
$stmt->bindValue(':branch', $branch, \PDO::PARAM_STR);
|
||||
if (!is_null($branch)) {
|
||||
$stmt->bindValue(':branch', $branch, \PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$rtn = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
|
|
@ -24,12 +24,19 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
protected $mockFactory;
|
||||
|
||||
protected $mockStore;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->mockBuildLogger = $this->prophesize('\PHPCI\Logging\BuildLogger');
|
||||
$this->mockFactory = $this->prophesize('\PHPCI\Plugin\Util\Factory');
|
||||
$this->testedExecutor = new Executor($this->mockFactory->reveal(), $this->mockBuildLogger->reveal());
|
||||
$this->mockStore = $this->prophesize('\PHPCI\Store\BuildStore');
|
||||
$this->testedExecutor = new Executor(
|
||||
$this->mockFactory->reveal(),
|
||||
$this->mockBuildLogger->reveal(),
|
||||
$this->mockStore->reveal()
|
||||
);
|
||||
}
|
||||
|
||||
public function testExecutePlugin_AssumesPHPCINamespaceIfNoneGiven()
|
||||
|
@ -61,11 +68,13 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
$options = array();
|
||||
$pluginName = 'PhpUnit';
|
||||
$build = new \PHPCI\Model\Build();
|
||||
|
||||
$mockPlugin = $this->prophesize('PHPCI\Plugin');
|
||||
$mockPlugin->execute()->shouldBeCalledTimes(1);
|
||||
|
||||
$this->mockFactory->buildPlugin(Argument::any(), Argument::any())->willReturn($mockPlugin->reveal());
|
||||
$this->mockFactory->getResourceFor('PHPCI\Model\Build')->willReturn($build);
|
||||
|
||||
$this->testedExecutor->executePlugin($pluginName, $options);
|
||||
}
|
||||
|
@ -119,6 +128,7 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
$phpUnitPluginOptions = array();
|
||||
$behatPluginOptions = array();
|
||||
$build = new \PHPCI\Model\Build();
|
||||
|
||||
$config = array(
|
||||
'stageOne' => array(
|
||||
|
@ -134,7 +144,7 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$this->mockFactory->buildPlugin($pluginNamespace . 'PhpUnit', $phpUnitPluginOptions)
|
||||
->willReturn($mockPhpUnitPlugin->reveal());
|
||||
|
||||
$this->mockFactory->getResourceFor('PHPCI\Model\Build')->willReturn($build);
|
||||
|
||||
$mockBehatPlugin = $this->prophesize('PHPCI\Plugin');
|
||||
$mockBehatPlugin->execute()->shouldBeCalledTimes(1)->willReturn(true);
|
||||
|
@ -142,7 +152,6 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||
$this->mockFactory->buildPlugin($pluginNamespace . 'Behat', $behatPluginOptions)
|
||||
->willReturn($mockBehatPlugin->reveal());
|
||||
|
||||
|
||||
$this->testedExecutor->executePlugins($config, 'stageOne');
|
||||
}
|
||||
|
||||
|
|
67
public/assets/js/build-plugins/summary.js
Normal file
67
public/assets/js/build-plugins/summary.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
var SummaryPlugin = ActiveBuild.UiPlugin.extend({
|
||||
id: 'build-summary',
|
||||
css: 'col-lg-6 col-md-12 col-sm-12 col-xs-12',
|
||||
title: Lang.get('build-summary'),
|
||||
box: true,
|
||||
statusIcons: [ 'fa-clock-o', 'fa-cogs', 'fa-check', 'fa-remove' ],
|
||||
statusLabels: [ Lang.get('pending'), Lang.get('running'), Lang.get('successful'), Lang.get('failed') ],
|
||||
statusClasses: ['text-blue', 'text-yellow', 'text-green', 'text-red'],
|
||||
|
||||
register: function() {
|
||||
var self = this;
|
||||
var query = ActiveBuild.registerQuery('plugin-summary', 5, {key: 'plugin-summary'})
|
||||
|
||||
$(window).on('plugin-summary', function(data) {
|
||||
self.onUpdate(data);
|
||||
});
|
||||
|
||||
$(window).on('build-updated', function() {
|
||||
query();
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return $(
|
||||
'<div class="table-responsive"><table class="table" id="plugin-summary">' +
|
||||
'<thead><tr>' +
|
||||
'<th>'+Lang.get('stage')+'</th>' +
|
||||
'<th>'+Lang.get('plugin')+'</th>' +
|
||||
'<th>'+Lang.get('status')+'</th>' +
|
||||
'<th class="text-right">'+Lang.get('duration')+' (s)</th>' +
|
||||
'</tr></thead><tbody></tbody></table></div>'
|
||||
);
|
||||
},
|
||||
|
||||
onUpdate: function(e) {
|
||||
if (!e.queryData) {
|
||||
$('#build-summary').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var tbody = $('#plugin-summary tbody'),
|
||||
summary = e.queryData[0].meta_value;
|
||||
tbody.empty();
|
||||
|
||||
for(var stage in summary) {
|
||||
for(var plugin in summary[stage]) {
|
||||
var data = summary[stage][plugin],
|
||||
duration = data.started ? ((data.ended || Math.floor(Date.now()/1000)) - data.started) : '-';
|
||||
tbody.append(
|
||||
'<tr>' +
|
||||
'<td>' + Lang.get('stage_'+stage) + '</td>' +
|
||||
'<td>' + plugin + '</td>' +
|
||||
'<td><span class="' + this.statusClasses[data.status] + '">' +
|
||||
'<i class="fa ' + this.statusIcons[data.status] + '"></i> ' +
|
||||
this.statusLabels[data.status] +
|
||||
'</span></td>' +
|
||||
'<td class="text-right">' + duration + '</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$('#build-summary').show();
|
||||
}
|
||||
});
|
||||
|
||||
ActiveBuild.registerPlugin(new SummaryPlugin());
|
Loading…
Reference in a new issue