This commit is contained in:
steve.brazier 2013-12-12 12:44:21 +00:00
commit 6eb38d1039
36 changed files with 1142 additions and 405 deletions

31
PHPCI/BuildLogger.php Normal file
View file

@ -0,0 +1,31 @@
<?php
namespace PHPCI;
use Psr\Log\LogLevel;
/**
* PHPCI Build Logger
*/
interface BuildLogger
{
/**
* Add an entry to the build log.
* @param string|string[] $message
* @param string $level
* @param mixed[] $context
*/
public function log($message, $level = LogLevel::INFO, $context = array());
/**
* Add a success-coloured message to the log.
* @param string
*/
public function logSuccess($message);
/**
* Add a failure-coloured message to the log.
* @param string $message
* @param \Exception $exception The exception that caused the error.
*/
public function logFailure($message, \Exception $exception = null);
}

View file

@ -21,7 +21,7 @@ use Psr\Log\LogLevel;
* PHPCI Build Runner
* @author Dan Cryer <dan@block8.co.uk>
*/
class Builder implements LoggerAwareInterface
class Builder implements LoggerAwareInterface, BuildLogger
{
/**
* @var string
@ -92,9 +92,9 @@ class Builder implements LoggerAwareInterface
public $quiet = false;
/**
* @var \PHPCI\Plugin\Util\Factory
* @var \PHPCI\Plugin\Util\Executor
*/
protected $pluginFactory;
protected $pluginExecutor;
/**
* Set up the builder.
@ -108,7 +108,7 @@ class Builder implements LoggerAwareInterface
}
$this->build = $build;
$this->store = Store\Factory::getStore('Build');
$this->setupPluginFactory($build);
$this->pluginExecutor = new Plugin\Util\Executor($this->buildPluginFactory($build), $this);
}
/**
@ -159,36 +159,39 @@ class Builder implements LoggerAwareInterface
public function execute()
{
// Update the build in the database, ping any external services.
$this->build->setStatus(1);
$this->build->setStatus(Build::STATUS_RUNNING);
$this->build->setStarted(new \DateTime());
$this->store->save($this->build);
$this->build->sendStatusPostback();
$this->success = true;
try {
// Set up the build:
$this->setupBuild();
// Set up the build:
$this->setupBuild();
// Run the core plugin stages:
foreach (array('setup', 'test', 'complete') as $stage) {
$this->executePlugins($stage);
}
// Run the core plugin stages:
foreach (array('setup', 'test') as $stage) {
$this->success &= $this->pluginExecutor->executePlugins($this->config, $stage);
}
// Failed build? Execute failure plugins and then mark the build as failed.
if (!$this->success) {
$this->executePlugins('failure');
throw new \Exception('BUILD FAILED!');
}
// Set the status so this can be used by complete, success and failure
// stages.
if ($this->success) {
$this->build->setStatus(Build::STATUS_SUCCESS);
}
else {
$this->build->setStatus(Build::STATUS_FAILED);
}
// If we got this far, the build was successful!
if ($this->success) {
$this->build->setStatus(2);
$this->executePlugins('success');
$this->logSuccess('BUILD SUCCESSFUL!');
}
// Complete stage plugins are always run
$this->pluginExecutor->executePlugins($this->config, 'complete');
} catch (\Exception $ex) {
$this->logFailure($ex->getMessage(), $ex);
$this->build->setStatus(3);
if ($this->success) {
$this->pluginExecutor->executePlugins($this->config, 'success');
$this->logSuccess('BUILD SUCCESSFUL!');
}
else {
$this->pluginExecutor->executePlugins($this->config, 'failure');
$this->logFailure("BUILD FAILURE");
}
// Clean up:
@ -372,79 +375,6 @@ class Builder implements LoggerAwareInterface
return true;
}
/**
* Execute a the appropriate set of plugins for a given build stage.
*/
protected function executePlugins($stage)
{
// Ignore any stages for which we don't have plugins set:
if (!array_key_exists(
$stage,
$this->config
) || !is_array($this->config[$stage])
) {
return;
}
foreach ($this->config[$stage] as $plugin => $options) {
$this->log('RUNNING PLUGIN: ' . $plugin);
// Is this plugin allowed to fail?
if ($stage == 'test' && !isset($options['allow_failures'])) {
$options['allow_failures'] = false;
}
// Try and execute it:
if ($this->executePlugin($plugin, $options)) {
// Execution was successful:
$this->logSuccess('PLUGIN STATUS: SUCCESS!');
} 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' && !$options['allow_failures']) {
$this->success = false;
}
$this->logFailure('PLUGIN STATUS: FAILED');
}
}
}
/**
* Executes a given plugin, with options and returns the result.
*/
protected function executePlugin($plugin, $options)
{
// Figure out the class name and check the plugin exists:
$class = str_replace('_', ' ', $plugin);
$class = ucwords($class);
$class = 'PHPCI\\Plugin\\' . str_replace(' ', '', $class);
if (!class_exists($class)) {
$this->logFailure('Plugin does not exist: ' . $plugin, $ex);
return false;
}
$rtn = true;
// Try running it:
try {
$obj = $this->pluginFactory->buildPlugin($class, $options);
if (!$obj->execute()) {
$rtn = false;
}
} catch (\Exception $ex) {
$this->logFailure('EXCEPTION: ' . $ex->getMessage(), $ex);
$rtn = false;
}
return $rtn;
}
/**
* Find a binary required by a plugin.
* @param $binary
@ -499,12 +429,12 @@ class Builder implements LoggerAwareInterface
return $this->logger;
}
private function setupPluginFactory(Build $build)
private function buildPluginFactory(Build $build)
{
$this->pluginFactory = new Plugin\Util\Factory();
$pluginFactory = new Plugin\Util\Factory();
$self = $this;
$this->pluginFactory->registerResource(
$pluginFactory->registerResource(
function () use($self) {
return $self;
},
@ -512,7 +442,7 @@ class Builder implements LoggerAwareInterface
'PHPCI\Builder'
);
$this->pluginFactory->registerResource(
$pluginFactory->registerResource(
function () use($build) {
return $build;
},
@ -520,7 +450,7 @@ class Builder implements LoggerAwareInterface
'PHPCI\Model\Build'
);
$this->pluginFactory->registerResource(
$pluginFactory->registerResource(
function () use ($self) {
$factory = new MailerFactory($self->getSystemConfig('phpci'));
return $factory->getSwiftMailerFromConfig();
@ -528,5 +458,7 @@ class Builder implements LoggerAwareInterface
null,
'Swift_Mailer'
);
return $pluginFactory;
}
}

View file

@ -84,7 +84,7 @@ class PollCommand extends Command
$build = new Build();
$build->setProjectId($project->getId());
$build->setCommitId($last_commit);
$build->setStatus(0);
$build->setStatus(Build::STATUS_NEW);
$build->setBranch($project->getType() === 'hg' ? 'default' : 'master');
$build->setCreated(new \DateTime());

View file

@ -53,7 +53,7 @@ class BitbucketController extends \PHPCI\Controller
$build = new Build();
$build->setProjectId($project);
$build->setCommitId($commits[$branch]);
$build->setStatus(0);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$build->setBranch($branch);

View file

@ -109,7 +109,7 @@ class BuildController extends \PHPCI\Controller
$build = new Build();
$build->setProjectId($copy->getProjectId());
$build->setCommitId($copy->getCommitId());
$build->setStatus(0);
$build->setStatus(Build::STATUS_NEW);
$build->setBranch($copy->getBranch());
$build->setCreated(new \DateTime());
@ -129,6 +129,12 @@ class BuildController extends \PHPCI\Controller
}
$build = $this->buildStore->getById($buildId);
if (!$build) {
$this->response->setResponseCode(404);
return '404 - Not Found';
}
$this->buildStore->delete($build);
header('Location: '.PHPCI_URL.'project/view/' . $build->getProjectId());

View file

@ -47,7 +47,7 @@ class GitController extends \PHPCI\Controller
$build->setCommitId($commit);
}
$build->setStatus(0);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
} catch (\Exception $ex) {

View file

@ -48,7 +48,7 @@ class GithubController extends \PHPCI\Controller
$build = new Build();
$build->setProjectId($project);
$build->setCommitId($payload['after']);
$build->setStatus(0);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$build->setBranch(str_replace('refs/heads/', '', $payload['ref']));

View file

@ -42,7 +42,7 @@ class GitlabController extends \PHPCI\Controller
$build = new Build();
$build->setProjectId($project);
$build->setCommitId($payload['after']);
$build->setStatus(0);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$build->setBranch(str_replace('refs/heads/', '', $payload['ref']));

View file

@ -69,7 +69,7 @@ class ProjectController extends \PHPCI\Controller
$build = new Build();
$build->setProjectId($projectId);
$build->setCommitId('Manual');
$build->setStatus(0);
$build->setStatus(Build::STATUS_NEW);
$build->setBranch($project->getType() === 'hg' ? 'default' : 'master');
$build->setCreated(new \DateTime());

View file

@ -101,7 +101,10 @@ class SettingsController extends Controller
$dumper = new Dumper();
$yaml = $dumper->dump($this->settings);
file_put_contents(APPLICATION_PATH . 'PHPCI/config.yml', $yaml);
if(error_get_last()) return error_get_last()['message'];
if (error_get_last()) {
$error_get_last = error_get_last();
return $error_get_last['message'];
}
}
protected function getGithubForm()

View file

@ -13,18 +13,31 @@ class LoggerConfig {
private $config;
/**
* The file specified is expected to return an array. Where each key
* is the name of a logger. The value of each key should be an array or
* a function that returns an array of LogHandlers.
* @param $logConfigFilePath
* The filepath is expected to return an array which will be
* passed to the normal constructor.
*
* @param string $filePath
* @return LoggerConfig
*/
function __construct($logConfigFilePath) {
if (file_exists($logConfigFilePath)) {
$this->config = require_once($logConfigFilePath);
public static function newFromFile($filePath)
{
if (file_exists($filePath)) {
$configArray = require($filePath);
}
else {
$this->config = array();
$configArray = array();
}
return new self($configArray);
}
/**
* Each key of the array is the name of a logger. The value of
* each key should be an array or a function that returns an
* array of LogHandlers.
* @param array $configArray
*/
function __construct(array $configArray = array()) {
$this->config = $configArray;
}
/**
@ -33,7 +46,7 @@ class LoggerConfig {
* @param $name
* @return Logger
*/
public function GetFor($name) {
public function getFor($name) {
$handlers = $this->getHandlers(self::KEY_AlwaysLoaded);
$handlers = array_merge($handlers, $this->getHandlers($name));
return new Logger($name, $handlers);

View file

@ -215,11 +215,19 @@ class ProjectBase extends Model
/**
* Get the value of AccessInformation / access_information.
*
* @param string|null $key Key of desired information
*
* @return string
*/
public function getAccessInformation()
public function getAccessInformation($key = null)
{
$rtn = $this->data['access_information'];
if (is_null($key)) {
$rtn = $this->data['access_information'];
} else if (isset($this->data['access_information'][$key])) {
$rtn = $this->data['access_information'][$key];
} else {
$rtn = null;
}
return $rtn;
}

View file

@ -25,7 +25,7 @@ class GitlabBuild extends RemoteGitBuild
*/
public function getCommitLink()
{
$domain = $this->getProject()->getAccessInformation()["domain"];
$domain = $this->getProject()->getAccessInformation("domain");
return 'http://' . $domain . '/' . $this->getProject()->getReference() . '/commit/' . $this->getCommitId();
}
@ -34,7 +34,7 @@ class GitlabBuild extends RemoteGitBuild
*/
public function getBranchLink()
{
$domain = $this->getProject()->getAccessInformation()["domain"];
$domain = $this->getProject()->getAccessInformation("domain");
return 'http://' . $domain . '/' . $this->getProject()->getReference() . '/tree/' . $this->getBranch();
}
@ -46,8 +46,8 @@ class GitlabBuild extends RemoteGitBuild
$key = trim($this->getProject()->getGitKey());
if (!empty($key)) {
$user = $this->getProject()->getAccessInformation()["user"];
$domain = $this->getProject()->getAccessInformation()["domain"];
$user = $this->getProject()->getAccessInformation("user");
$domain = $this->getProject()->getAccessInformation("domain");
return $user . '@' . $domain . ':' . $this->getProject()->getReference() . '.git';
}
}

View file

@ -57,7 +57,7 @@ class LocalBuild extends Build
// If it is indeed a bare repository, then extract it into our build path:
if ($gitConfig['core']['bare']) {
$builder->executeCommand('mkdir %2$s; git --git-dir="%1$s" archive master | tar -x -C "%2$s"', $reference, $buildPath);
$builder->executeCommand('mkdir %2$s; git --git-dir="%1$s" archive %3$s | tar -x -C "%2$s"', $reference, $buildPath, $this->getBranch());
return true;
}

View file

@ -128,7 +128,7 @@ class PhpUnit implements \PHPCI\Plugin
protected function runDir($dirPath)
{
if (is_array($dirPath)) {
return $this->recurseArg($dirPath, array($this, "runConfigFile"));
return $this->recurseArg($dirPath, array($this, "runDir"));
} else {
$curdir = getcwd();
chdir($this->phpci->buildPath);

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -13,43 +13,63 @@ use PHPCI\Builder;
use PHPCI\Model\Build;
/**
* Shell Plugin - Allows execute shell commands.
* @author Kinn Coelho Julião <kinncj@gmail.com>
* @package PHPCI
* @subpackage Plugins
*/
* Shell Plugin - Allows execute shell commands.
* @author Kinn Coelho Julião <kinncj@gmail.com>
* @package PHPCI
* @subpackage Plugins
*/
class Shell implements \PHPCI\Plugin
{
protected $args;
protected $phpci;
/**
* @var string $command The command to be executed
* @var string[] $commands The commands to be executed
*/
protected $command;
protected $commands = array();
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
if (isset($options['command'])) {
$command = $options['command'];
$command = str_replace("%buildpath%", $this->phpci->buildPath, $command);
$this->command = $command;
// Keeping this for backwards compatibility, new projects should use interpolation vars.
$options['command'] = str_replace("%buildpath%", $this->phpci->buildPath, $options['command']);
$this->commands = array($options['command']);
return;
}
/*
* Support the new syntax:
*
* shell:
* - "cd /www"
* - "rm -f file.txt"
*/
if (is_array($options)) {
$this->commands = $options;
}
}
/**
* Runs the shell command.
*/
* Runs the shell command.
*/
public function execute()
{
if (!defined('ENABLE_SHELL_PLUGIN') || !ENABLE_SHELL_PLUGIN) {
throw new \Exception('The shell plugin is not enabled.');
}
$success = $this->phpci->executeCommand($this->command);
$success = true;
foreach ($this->commands as $command) {
$command = $this->phpci->interpolate($command);
if (!$this->phpci->executeCommand($command)) {
$success = false;
}
}
return $success;
}
}

View file

@ -0,0 +1,108 @@
<?php
namespace PHPCI\Plugin\Util;
use PHPCI\BuildLogger;
class Executor
{
/**
* @var BuildLogger
*/
protected $logger;
/**
* @var Factory
*/
protected $pluginFactory;
function __construct(Factory $pluginFactory, BuildLogger $logger)
{
$this->pluginFactory = $pluginFactory;
$this->logger = $logger;
}
/**
* Execute a the appropriate set of plugins for a given build stage.
* @param array $config PHPCI configuration
* @param string $stage
* @return bool
*/
public function executePlugins(&$config, $stage)
{
$success = true;
// Ignore any stages for which we don't have plugins set:
if (!array_key_exists($stage, $config) || !is_array($config[$stage])) {
return $success;
}
foreach ($config[$stage] as $plugin => $options) {
$this->logger->log('RUNNING PLUGIN: ' . $plugin);
// Is this plugin allowed to fail?
if ($stage == 'test' && !isset($options['allow_failures'])) {
$options['allow_failures'] = false;
}
// Try and execute it:
if ($this->executePlugin($plugin, $options)) {
// Execution was successful:
$this->logger->logSuccess('PLUGIN STATUS: SUCCESS!');
} 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' && !$options['allow_failures']) {
$success = false;
}
$this->logger->logFailure('PLUGIN STATUS: FAILED');
}
}
return $success;
}
/**
* Executes a given plugin, with options and returns the result.
*/
public function executePlugin($plugin, $options)
{
// Any plugin name without a namespace separator is a PHPCI built in plugin
// if not we assume it's a fully name-spaced class name that implements the plugin interface.
// If not the factory will throw an exception.
if (strpos($plugin, '\\') === false) {
$class = str_replace('_', ' ', $plugin);
$class = ucwords($class);
$class = 'PHPCI\\Plugin\\' . str_replace(' ', '', $class);
}
else {
$class = $plugin;
}
if (!class_exists($class)) {
$this->logger->logFailure('Plugin does not exist: ' . $plugin);
return false;
}
$rtn = true;
// Try running it:
try {
$obj = $this->pluginFactory->buildPlugin($class, $options);
if (!$obj->execute()) {
$rtn = false;
}
} catch (\Exception $ex) {
$this->logger->logFailure('EXCEPTION: ' . $ex->getMessage(), $ex);
$rtn = false;
}
return $rtn;
}
}

View file

@ -9,6 +9,8 @@ class Factory {
const TYPE_ARRAY = "array";
const TYPE_CALLABLE = "callable";
const INTERFACE_PHPCI_PLUGIN = '\PHPCI\Plugin';
private $currentPluginOptions;
/**
@ -45,6 +47,7 @@ class Factory {
*
* @param $className
* @param array $options
* @throws \InvalidArgumentException if $className doesn't represent a valid plugin
* @return \PHPCI\Plugin
*/
public function buildPlugin($className, array $options = array())
@ -53,6 +56,12 @@ class Factory {
$reflectedPlugin = new \ReflectionClass($className);
if (!$reflectedPlugin->implementsInterface(self::INTERFACE_PHPCI_PLUGIN)) {
throw new \InvalidArgumentException(
"Requested class must implement " . self:: INTERFACE_PHPCI_PLUGIN
);
}
$constructor = $reflectedPlugin->getConstructor();
if ($constructor) {

View file

@ -73,7 +73,7 @@ switch($build->getStatus())
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="javascript:confirmDelete('<?= PHPCI_URL ?>build/delete/<?php print $build->getId(); ?>');">Delete Build</a></li>
<li><a href="javascript:confirmDelete('<?= PHPCI_URL ?>build/delete/<?php print $build->getId(); ?>', 'Build').onClose = function(){refreshBuildsTable();};">Delete Build</a></li>
</ul>
<?php endif; ?>
</div>

View file

@ -58,8 +58,10 @@
</div>
<script>
setInterval(function()
{
$('#latest-builds').load('<?= PHPCI_URL ?>home/latest');
}, 10000);
refreshBuildsTable = function()
{
$('#latest-builds').load('<?= PHPCI_URL ?>home/latest');
};
setInterval(refreshBuildsTable, 10000);
</script>

View file

@ -1,7 +1,7 @@
<h1 id="title">Plugins</h1>
<?php if (!$canInstall): ?>
<p class="alert alert-danger">PHPCI cannot automatically install/remove plugins for you, as the <strong>shell_exec()</strong>
function is disabled. PHPCI will update composer.json for you, but you will need to run Composer manually to make the changes.</p>
<p class="alert alert-danger">PHPCI cannot automatically install/remove plugins for you, as either the <strong>shell_exec()</strong>
function is disabled or PHPCI could not find Composer. PHPCI will update composer.json for you, but you will need to run Composer manually to make the changes.</p>
<?php endif; ?>
<?php if (!$canWrite): ?>

View file

@ -92,7 +92,9 @@
$(function() {
$('#delete-project').on('click', function (e) {
e.preventDefault();
confirmDelete("<?= PHPCI_URL ?>project/delete/<?php print $project->getId(); ?>");
confirmDelete(
"<?= PHPCI_URL ?>project/delete/<?php print $project->getId(); ?>", "Project"
).onCloseConfirmed = function () {window.location = '/'};
});
})
</script>

View file

@ -50,7 +50,7 @@
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="javascript:confirmDelete('<?= PHPCI_URL ?>user/delete/<?php print $user->getId(); ?>');">Delete User</a></li>
<li><a href="javascript:confirmDelete('<?= PHPCI_URL ?>user/delete/<?php print $user->getId(); ?>', 'User', true);">Delete User</a></li>
</ul>
</div>
<?php endif; ?>

View file

@ -0,0 +1,75 @@
<?php
use \PHPCI\Helper\LoggerConfig;
class LoggerConfigTest extends PHPUnit_Framework_TestCase
{
public function testGetFor_ReturnsPSRLogger()
{
$config = new LoggerConfig(array());
$logger = $config->getFor("something");
$this->assertInstanceOf('\Psr\Log\LoggerInterface', $logger);
}
public function testGetFor_ReturnsMonologInstance()
{
$config = new LoggerConfig(array());
$logger = $config->getFor("something");
$this->assertInstanceOf('\Monolog\Logger', $logger);
}
public function testGetFor_AttachesAlwaysPresentHandlers()
{
$expectedHandler = new Monolog\Handler\NullHandler();
$config = new LoggerConfig(array(
LoggerConfig::KEY_AlwaysLoaded => function() use ($expectedHandler) {
return array($expectedHandler);
}
));
/** @var \Monolog\Logger $logger */
$logger = $config->getFor("something");
$actualHandler = $logger->popHandler();
$this->assertEquals($expectedHandler, $actualHandler);
}
public function testGetFor_AttachesSpecificHandlers()
{
$expectedHandler = new Monolog\Handler\NullHandler();
$config = new LoggerConfig(array(
"Specific" => function() use ($expectedHandler) {
return array($expectedHandler);
}
));
/** @var \Monolog\Logger $logger */
$logger = $config->getFor("Specific");
$actualHandler = $logger->popHandler();
$this->assertSame($expectedHandler, $actualHandler);
}
public function testGetFor_IgnoresAlternativeHandlers()
{
$expectedHandler = new Monolog\Handler\NullHandler();
$alternativeHandler = new Monolog\Handler\NullHandler();
$config = new LoggerConfig(array(
"Specific" => function() use ($expectedHandler) {
return array($expectedHandler);
},
"Other" => function() use ($alternativeHandler) {
return array($alternativeHandler);
}
));
/** @var \Monolog\Logger $logger */
$logger = $config->getFor("Specific");
$actualHandler = $logger->popHandler();
$this->assertSame($expectedHandler, $actualHandler);
$this->assertNotSame($alternativeHandler, $actualHandler);
}
}

View file

@ -1,32 +1,33 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
namespace PHPCI\Plugin\Tests;
use PHPCI\Plugin\Email as EmailPlugin;
/**
* Unit test for the PHPUnit plugin.
* @author meadsteve
*/
* Unit test for the PHPUnit plugin.
* @author meadsteve
*/
class EmailTest extends \PHPUnit_Framework_TestCase
{
/**
* @var EmailPlugin $testedPhpUnit
*/
protected $testedEmailPlugin;
/**
* @var EmailPlugin $testedPhpUnit
*/
protected $testedEmailPlugin;
/**
* @var \PHPUnit_Framework_MockObject_MockObject $mockCiBuilder
*/
protected $mockCiBuilder;
/**
* @var \PHPUnit_Framework_MockObject_MockObject $mockCiBuilder
*/
protected $mockCiBuilder;
/**
* @var \PHPUnit_Framework_MockObject_MockObject $mockMailer
@ -38,15 +39,15 @@ class EmailTest extends \PHPUnit_Framework_TestCase
*/
protected $mockBuild;
public function setUp()
{
public function setUp()
{
$this->mockBuild = $this->getMock(
'\PHPCI\Model\Build',
array('getLog', 'getStatus'),
array(),
"mockBuild",
false
);
'\PHPCI\Model\Build',
array('getLog', 'getStatus'),
array(),
"mockBuild",
false
);
$this->mockBuild->expects($this->any())
->method('getLog')
@ -56,27 +57,33 @@ class EmailTest extends \PHPUnit_Framework_TestCase
->method('getStatus')
->will($this->returnValue(\PHPCI\Model\Build::STATUS_SUCCESS));
$this->mockCiBuilder = $this->getMock(
'\PHPCI\Builder',
array('getSystemConfig',
'getBuildProjectTitle',
'getBuild',
'log'),
array(),
"mockBuilder",
false
);
$this->mockCiBuilder = $this->getMock(
'\PHPCI\Builder',
array(
'getSystemConfig',
'getBuildProjectTitle',
'getBuild',
'log'
),
array(),
"mockBuilder_email",
false
);
$this->mockCiBuilder->buildPath = "/";
$this->mockCiBuilder->expects($this->any())
->method('getSystemConfig')
->with('phpci')
->will($this->returnValue(array(
'email_settings' => array(
'from_address' => "test-from-address@example.com"
->will(
$this->returnValue(
array(
'email_settings' => array(
'from_address' => "test-from-address@example.com"
)
)
)
)));
);
$this->mockCiBuilder->expects($this->any())
->method('getBuildProjectTitle')
->will($this->returnValue('Test-Project'));
@ -85,53 +92,55 @@ class EmailTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue($this->mockBuild));
$this->mockMailer = $this->getMock(
'\Swift_Mailer',
array('send'),
array(),
"mockMailer",
false
);
'\Swift_Mailer',
array('send'),
array(),
"mockMailer",
false
);
$this->loadEmailPluginWithOptions();
}
$this->loadEmailPluginWithOptions();
}
protected function loadEmailPluginWithOptions($arrOptions = array())
{
$this->testedEmailPlugin = new EmailPlugin(
protected function loadEmailPluginWithOptions($arrOptions = array())
{
$this->testedEmailPlugin = new EmailPlugin(
$this->mockCiBuilder,
$this->mockBuild,
$this->mockMailer,
$arrOptions
);
}
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_ReturnsFalseWithoutArgs()
{
$returnValue = $this->testedEmailPlugin->execute();
/**
* @covers PHPUnit::execute
*/
public function testExecute_ReturnsFalseWithoutArgs()
{
$returnValue = $this->testedEmailPlugin->execute();
// As no addresses will have been mailed as non are configured.
$expectedReturn = false;
$expectedReturn = false;
$this->assertEquals($expectedReturn, $returnValue);
}
$this->assertEquals($expectedReturn, $returnValue);
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_BuildsBasicEmails()
{
$this->loadEmailPluginWithOptions(array(
'addresses' => array('test-receiver@example.com')
));
/**
* @covers PHPUnit::execute
*/
public function testExecute_BuildsBasicEmails()
{
$this->loadEmailPluginWithOptions(
array(
'addresses' => array('test-receiver@example.com')
)
);
/** @var \Swift_Message $actualMail */
$actualMail = null;
$this->catchMailPassedToSend($actualMail);
$returnValue = $this->testedEmailPlugin->execute();
$expectedReturn = true;
$returnValue = $this->testedEmailPlugin->execute();
$expectedReturn = true;
$this->assertSystemMail(
'test-receiver@example.com',
@ -141,14 +150,14 @@ class EmailTest extends \PHPUnit_Framework_TestCase
$actualMail
);
$this->assertEquals($expectedReturn, $returnValue);
$this->assertEquals($expectedReturn, $returnValue);
}
}
/**
* @covers PHPUnit::sendEmail
*/
* @covers PHPUnit::sendEmail
*/
public function testSendEmail_CallsMailerSend()
{
$this->mockMailer->expects($this->once())
@ -157,8 +166,8 @@ class EmailTest extends \PHPUnit_Framework_TestCase
}
/**
* @covers PHPUnit::sendEmail
*/
* @covers PHPUnit::sendEmail
*/
public function testSendEmail_BuildsAMessageObject()
{
$subject = "Test mail";
@ -172,8 +181,8 @@ class EmailTest extends \PHPUnit_Framework_TestCase
}
/**
* @covers PHPUnit::sendEmail
*/
* @covers PHPUnit::sendEmail
*/
public function testSendEmail_BuildsExpectedMessage()
{
$subject = "Test mail";
@ -200,7 +209,7 @@ class EmailTest extends \PHPUnit_Framework_TestCase
}
/**
* @param \Swift_Message $actualMail passed by ref and populated with
* @param \Swift_Message $actualMail passed by ref and populated with
* the message object the mock mailer
* receives.
*/
@ -227,14 +236,17 @@ class EmailTest extends \PHPUnit_Framework_TestCase
* @param string $expectedSubject
* @param \Swift_Message $actualMail
*/
protected function assertSystemMail($expectedToAddress,
$expectedFromAddress,
$expectedBody,
$expectedSubject,
$actualMail)
{
if (! ($actualMail instanceof \Swift_Message)) {
$type = is_object($actualMail) ? get_class($actualMail) : gettype($actualMail);
protected function assertSystemMail(
$expectedToAddress,
$expectedFromAddress,
$expectedBody,
$expectedSubject,
$actualMail
) {
if (!($actualMail instanceof \Swift_Message)) {
$type = is_object($actualMail) ? get_class($actualMail) : gettype(
$actualMail
);
throw new \Exception("Expected Swift_Message got " . $type);
}
$this->assertEquals(

View file

@ -1,71 +1,73 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
namespace PHPCI\Plugin\Tests;
use PHPCI\Plugin\PHPUnit;
use PHPCI\Plugin\PhpUnit;
/**
* Unit test for the PHPUnit plugin.
* @author meadsteve
*/
class PHPUnitTest extends \PHPUnit_Framework_TestCase
* Unit test for the PHPUnit plugin.
* @author meadsteve
*/
class PHPUnitTest extends \PHPUnit_Framework_TestCase
{
/**
* @var PHPUnit $testedPhpUnit
*/
protected $testedPhpUnit;
/**
* @var \PHPUnit_Framework_MockObject_MockObject $mockCiBuilder
*/
protected $mockCiBuilder;
/**
* @var PhpUnit $testedPhpUnit
*/
protected $testedPhpUnit;
/**
* @var \PHPUnit_Framework_MockObject_MockObject $mockCiBuilder
*/
protected $mockBuild;
* @var \PHPUnit_Framework_MockObject_MockObject $mockCiBuilder
*/
protected $mockCiBuilder;
public function setUp()
{
$this->mockCiBuilder = $this->getMock(
'\PHPCI\Builder',
array(),
array(),
"mockBuilder",
false
);
$this->mockCiBuilder->buildPath = "/";
/**
* @var \PHPUnit_Framework_MockObject_MockObject $mockCiBuilder
*/
protected $mockBuild;
public function setUp()
{
$this->mockCiBuilder = $this->getMock(
'\PHPCI\Builder',
array('findBinary', 'executeCommand'),
array(),
"mockBuilder_phpUnit",
false
);
$this->mockCiBuilder->buildPath = "/";
$this->mockBuild = $this->getMock(
'\PHPCI\Model\Build',
array(),
array(),
"MockBuild",
false
);
'\PHPCI\Model\Build',
array(),
array(),
"MockBuild",
false
);
$this->loadPhpUnitWithOptions();
}
$this->loadPhpUnitWithOptions();
}
protected function loadPhpUnitWithOptions($arrOptions = array())
{
$this->testedPhpUnit = new PHPUnit($this->mockCiBuilder,$this->mockBuild, $arrOptions);
}
protected function loadPhpUnitWithOptions($arrOptions = array())
{
$this->testedPhpUnit = new PhpUnit($this->mockCiBuilder, $this->mockBuild, $arrOptions);
}
/**
* @param \PHPUnit_Framework_MockObject_Matcher_Invocation $expectation
*/
protected function expectFindBinaryToBeCalled($expectation) {
protected function expectFindBinaryToBeCalled($expectation)
{
$this->mockCiBuilder->expects($expectation)
->method("findBinary")
->will($this->returnValue("phpunit"));
->method("findBinary")
->will($this->returnValue("phpunit"));
}
/**
@ -74,89 +76,97 @@ class PHPUnitTest extends \PHPUnit_Framework_TestCase
public function expectExectuteCommandToBeCalled($expectation)
{
$this->mockCiBuilder->expects($expectation)
->method("executeCommand");
->method("executeCommand");
}
/**
* @covers PHPUnit::execute
*/
public function testExecute_ReturnsTrueWithoutArgs()
{
$returnValue = $this->testedPhpUnit->execute();
$expectedReturn = true;
/**
* @covers PHPUnit::execute
*/
public function testExecute_ReturnsTrueWithoutArgs()
{
$returnValue = $this->testedPhpUnit->execute();
$expectedReturn = true;
$this->assertEquals($expectedReturn, $returnValue);
}
$this->assertEquals($expectedReturn, $returnValue);
}
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runDir
*/
public function testExecute_CallsExecuteCommandOnceWhenGivenStringDirectory()
{
chdir('/');
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runDir
*/
public function testExecute_CallsExecuteCommandOnceWhenGivenStringDirectory()
{
chdir('/');
$this->loadPhpUnitWithOptions(array(
'directory' => "Fake/Test/Path"
));
$this->expectFindBinaryToBeCalled($this->once());
$this->expectExectuteCommandToBeCalled($this->once());
$returnValue = $this->testedPhpUnit->execute();
}
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runConfigFile
*/
public function testExecute_CallsExecuteCommandOnceWhenGivenStringConfig()
{
chdir('/');
$this->loadPhpUnitWithOptions(array(
'config' => "Fake/Test/config.xml"
));
$this->loadPhpUnitWithOptions(
array(
'directory' => "Fake/Test/Path"
)
);
$this->expectFindBinaryToBeCalled($this->once());
$this->expectExectuteCommandToBeCalled($this->once());
$returnValue = $this->testedPhpUnit->execute();
}
}
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runDir
*/
public function testExecute_CallsExecuteCommandManyTimesWhenGivenArrayDirectory()
{
chdir('/');
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runConfigFile
*/
public function testExecute_CallsExecuteCommandOnceWhenGivenStringConfig()
{
chdir('/');
$this->loadPhpUnitWithOptions(array(
'directory' => array(0, 1)
));
$this->loadPhpUnitWithOptions(
array(
'config' => "Fake/Test/config.xml"
)
);
$this->mockCiBuilder->expects($this->at(0))->method("executeCommand");
$this->mockCiBuilder->expects($this->at(1))->method("executeCommand");
$this->expectFindBinaryToBeCalled($this->once());
$this->expectExectuteCommandToBeCalled($this->once());
$returnValue = $this->testedPhpUnit->execute();
}
$returnValue = $this->testedPhpUnit->execute();
}
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runConfigFile
*/
public function testExecute_CallsExecuteCommandManyTimesWhenGivenArrayConfig()
{
chdir('/');
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runDir
*/
public function testExecute_CallsExecuteCommandManyTimesWhenGivenArrayDirectory()
{
chdir('/');
$this->loadPhpUnitWithOptions(array(
'config' => array(0, 1)
));
$this->loadPhpUnitWithOptions(
array(
'directory' => array("dir1", "dir2")
)
);
$this->mockCiBuilder->expects($this->at(0))->method("executeCommand");
$this->mockCiBuilder->expects($this->at(1))->method("executeCommand");
$this->expectFindBinaryToBeCalled($this->exactly(2));
$this->expectExectuteCommandToBeCalled($this->exactly(2));
$returnValue = $this->testedPhpUnit->execute();
}
$returnValue = $this->testedPhpUnit->execute();
}
/**
* @covers PHPUnit::execute
* @covers PHPUnit::runConfigFile
*/
public function testExecute_CallsExecuteCommandManyTimesWhenGivenArrayConfig()
{
chdir('/');
$this->loadPhpUnitWithOptions(
array(
'config' => array("configfile1.xml", "configfile2.xml")
)
);
$this->expectFindBinaryToBeCalled($this->exactly(2));
$this->expectExectuteCommandToBeCalled($this->exactly(2));
$returnValue = $this->testedPhpUnit->execute();
}
}

View file

@ -5,18 +5,28 @@ use PHPCI\Builder;
use PHPCI\Model\Build;
use PHPCI\Plugin;
class ExamplePluginWithNoConstructorArgs {
class ExamplePluginWithNoConstructorArgs implements Plugin
{
public function execute()
{
}
}
class ExamplePluginWithSingleOptionalArg {
class ExamplePluginWithSingleOptionalArg implements Plugin
{
function __construct($optional = null)
{
}
public function execute()
{
}
}
class ExamplePluginWithSingleRequiredArg {
class ExamplePluginWithSingleRequiredArg implements Plugin
{
public $RequiredArgument;
@ -24,9 +34,15 @@ class ExamplePluginWithSingleRequiredArg {
{
$this->RequiredArgument = $requiredArgument;
}
public function execute()
{
}
}
class ExamplePluginWithSingleTypedRequiredArg {
class ExamplePluginWithSingleTypedRequiredArg implements Plugin
{
public $RequiredArgument;
@ -34,6 +50,11 @@ class ExamplePluginWithSingleTypedRequiredArg {
{
$this->RequiredArgument = $requiredArgument;
}
public function execute()
{
}
}
class ExamplePluginFull implements Plugin {

View file

@ -0,0 +1,146 @@
<?php
namespace PHPCI\Plugin\Tests\Util;
require_once __DIR__ . "/ExamplePlugins.php";
use PHPCI\Plugin\Util\Executor;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTestCase;
class ExecutorTest extends ProphecyTestCase
{
/**
* @var Executor
*/
protected $testedExecutor;
protected $mockBuildLogger;
protected $mockFactory;
protected function setUp()
{
parent::setUp();
$this->mockBuildLogger = $this->prophesize('\PHPCI\BuildLogger');
$this->mockFactory = $this->prophesize('\PHPCI\Plugin\Util\Factory');
$this->testedExecutor = new Executor($this->mockFactory->reveal(), $this->mockBuildLogger->reveal());
}
public function testExecutePlugin_AssumesPHPCINamespaceIfNoneGiven()
{
$options = array();
$pluginName = 'PhpUnit';
$pluginNamespace = 'PHPCI\\Plugin\\';
$this->mockFactory->buildPlugin($pluginNamespace . $pluginName, $options)
->shouldBeCalledTimes(1)
->willReturn($this->prophesize('PHPCI\Plugin')->reveal());
$this->testedExecutor->executePlugin($pluginName, $options);
}
public function testExecutePlugin_KeepsCalledNameSpace()
{
$options = array();
$pluginName = 'ExamplePluginFull';
$pluginNamespace = '\\PHPCI\\Plugin\\Tests\\Util\\';
$this->mockFactory->buildPlugin($pluginNamespace . $pluginName, $options)
->shouldBeCalledTimes(1)
->willReturn($this->prophesize('PHPCI\Plugin')->reveal());
$this->testedExecutor->executePlugin($pluginNamespace . $pluginName, $options);
}
public function testExecutePlugin_CallsExecuteOnFactoryBuildPlugin()
{
$options = array();
$pluginName = 'PhpUnit';
$mockPlugin = $this->prophesize('PHPCI\Plugin');
$mockPlugin->execute()->shouldBeCalledTimes(1);
$this->mockFactory->buildPlugin(Argument::any(), Argument::any())->willReturn($mockPlugin->reveal());
$this->testedExecutor->executePlugin($pluginName, $options);
}
public function testExecutePlugin_ReturnsPluginSuccess()
{
$options = array();
$pluginName = 'PhpUnit';
$expectedReturnValue = true;
$mockPlugin = $this->prophesize('PHPCI\Plugin');
$mockPlugin->execute()->willReturn($expectedReturnValue);
$this->mockFactory->buildPlugin(Argument::any(), Argument::any())->willReturn($mockPlugin->reveal());
$returnValue = $this->testedExecutor->executePlugin($pluginName, $options);
$this->assertEquals($expectedReturnValue, $returnValue);
}
public function testExecutePlugin_LogsFailureForNonExistentClasses()
{
$options = array();
$pluginName = 'DOESNTEXIST';
$this->mockBuildLogger->logFailure('Plugin does not exist: ' . $pluginName)->shouldBeCalledTimes(1);
$this->testedExecutor->executePlugin($pluginName, $options);
}
public function testExecutePlugin_LogsFailureWhenExceptionsAreThrownByPlugin()
{
$options = array();
$pluginName = 'PhpUnit';
$expectedException = new \RuntimeException("Generic Error");
$mockPlugin = $this->prophesize('PHPCI\Plugin');
$mockPlugin->execute()->willThrow($expectedException);
$this->mockFactory->buildPlugin(Argument::any(), Argument::any())->willReturn($mockPlugin->reveal());
$this->mockBuildLogger->logFailure('EXCEPTION: ' . $expectedException->getMessage(), $expectedException)
->shouldBeCalledTimes(1);
$this->testedExecutor->executePlugin($pluginName, $options);
}
public function testExecutePlugins_CallsEachPluginForStage()
{
$phpUnitPluginOptions = array();
$behatPluginOptions = array();
$config = array(
'stageOne' => array(
'PhpUnit' => $phpUnitPluginOptions,
'Behat' => $behatPluginOptions,
)
);
$pluginNamespace = 'PHPCI\\Plugin\\';
$mockPhpUnitPlugin = $this->prophesize('PHPCI\Plugin');
$mockPhpUnitPlugin->execute()->shouldBeCalledTimes(1)->willReturn(true);
$this->mockFactory->buildPlugin($pluginNamespace . 'PhpUnit', $phpUnitPluginOptions)
->willReturn($mockPhpUnitPlugin->reveal());
$mockBehatPlugin = $this->prophesize('PHPCI\Plugin');
$mockBehatPlugin->execute()->shouldBeCalledTimes(1)->willReturn(true);
$this->mockFactory->buildPlugin($pluginNamespace . 'Behat', $behatPluginOptions)
->willReturn($mockBehatPlugin->reveal());
$this->testedExecutor->executePlugins($config, 'stageOne');
}
}

View file

@ -37,10 +37,16 @@ class FactoryTest extends \PHPUnit_Framework_TestCase {
public function testRegisterResourceThrowsExceptionWithoutTypeAndName()
{
$this->setExpectedException("InvalidArgumentException");
$this->setExpectedException('InvalidArgumentException', 'Type or Name must be specified');
$this->testedFactory->registerResource($this->resourceLoader, null, null);
}
public function testRegisterResourceThrowsExceptionIfLoaderIsntFunction()
{
$this->setExpectedException('InvalidArgumentException', '$loader is expected to be a function');
$this->testedFactory->registerResource(array("dummy"), "TestName", "TestClass");
}
public function testBuildPluginWorksWithConstructorlessPlugins()
{
$namespace = '\\PHPCI\\Plugin\\Tests\\Util\\';
@ -49,6 +55,12 @@ class FactoryTest extends \PHPUnit_Framework_TestCase {
$this->assertInstanceOf($expectedPluginClass, $plugin);
}
public function testBuildPluginFailsForNonPluginClasses()
{
$this->setExpectedException('InvalidArgumentException', 'Requested class must implement \PHPCI\Plugin');
$plugin = $this->testedFactory->buildPlugin("stdClass");
}
public function testBuildPluginWorksWithSingleOptionalArgConstructor()
{
$namespace = '\\PHPCI\\Plugin\\Tests\\Util\\';

View file

@ -47,7 +47,9 @@ $conf['b8']['app']['namespace'] = 'PHPCI';
$conf['b8']['app']['default_controller'] = 'Home';
$conf['b8']['view']['path'] = dirname(__FILE__) . '/PHPCI/View/';
$config = new b8\Config($conf);
$config->loadYaml(dirname(__FILE__) . '/PHPCI/config.yml');
if (file_exists(dirname(__FILE__) . '/PHPCI/config.yml')) {
$config = new b8\Config($conf);
$config->loadYaml(dirname(__FILE__) . '/PHPCI/config.yml');
}
require_once(dirname(__FILE__) . '/vars.php');

View file

@ -33,6 +33,10 @@
"pimple/pimple": "1.1.*"
},
"require-dev": {
"phpspec/prophecy-phpunit": "1.*"
},
"suggest": {
"phpunit/phpunit": "PHP unit testing framework",
"phpmd/phpmd": "PHP Mess Detector",

142
composer.lock generated
View file

@ -3,7 +3,7 @@
"This file locks the dependencies of your project to a known state",
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
],
"hash": "2f0615871ce4ee1eb8e4642bf0c731da",
"hash": "07f37de4c8bacd8a1a7b6e14269178d1",
"packages": [
{
"name": "block8/b8framework",
@ -239,16 +239,16 @@
},
{
"name": "swiftmailer/swiftmailer",
"version": "v5.0.2",
"version": "v5.0.3",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "f3917ecef35a4e4d98b303eb9fee463bc983f379"
"reference": "32edc3b0de0fdc1b10f5c4912e8677b3f411a230"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/f3917ecef35a4e4d98b303eb9fee463bc983f379",
"reference": "f3917ecef35a4e4d98b303eb9fee463bc983f379",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/32edc3b0de0fdc1b10f5c4912e8677b3f411a230",
"reference": "32edc3b0de0fdc1b10f5c4912e8677b3f411a230",
"shasum": ""
},
"require": {
@ -284,21 +284,21 @@
"mail",
"mailer"
],
"time": "2013-08-30 12:35:21"
"time": "2013-12-03 13:33:24"
},
{
"name": "symfony/console",
"version": "v2.3.7",
"version": "v2.4.0",
"target-dir": "Symfony/Component/Console",
"source": {
"type": "git",
"url": "https://github.com/symfony/Console.git",
"reference": "00848d3e13cf512e77c7498c2b3b0192f61f4b18"
"reference": "3c1496ae96d24ccc6c340fcc25f71d7a1ab4c12c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Console/zipball/00848d3e13cf512e77c7498c2b3b0192f61f4b18",
"reference": "00848d3e13cf512e77c7498c2b3b0192f61f4b18",
"url": "https://api.github.com/repos/symfony/Console/zipball/3c1496ae96d24ccc6c340fcc25f71d7a1ab4c12c",
"reference": "3c1496ae96d24ccc6c340fcc25f71d7a1ab4c12c",
"shasum": ""
},
"require": {
@ -313,7 +313,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
"dev-master": "2.4-dev"
}
},
"autoload": {
@ -337,21 +337,21 @@
],
"description": "Symfony Console Component",
"homepage": "http://symfony.com",
"time": "2013-11-13 21:27:40"
"time": "2013-11-27 09:10:40"
},
{
"name": "symfony/yaml",
"version": "v2.3.7",
"version": "v2.4.0",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "c1bda5b459d792cb253de12c65beba3040163b2b"
"reference": "1ae235a1b9d3ad3d9f3860ff20acc072df95b7f5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/c1bda5b459d792cb253de12c65beba3040163b2b",
"reference": "c1bda5b459d792cb253de12c65beba3040163b2b",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/1ae235a1b9d3ad3d9f3860ff20acc072df95b7f5",
"reference": "1ae235a1b9d3ad3d9f3860ff20acc072df95b7f5",
"shasum": ""
},
"require": {
@ -360,7 +360,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
"dev-master": "2.4-dev"
}
},
"autoload": {
@ -384,11 +384,115 @@
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2013-10-17 11:48:01"
"time": "2013-11-26 16:40:27"
}
],
"packages-dev": [
{
"name": "phpspec/prophecy",
"version": "v1.0.4",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "79d9c8bd94801bffbf9b56964f6438762da6d8cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/79d9c8bd94801bffbf9b56964f6438762da6d8cd",
"reference": "79d9c8bd94801bffbf9b56964f6438762da6d8cd",
"shasum": ""
},
"require-dev": {
"phpspec/phpspec": "2.0.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Prophecy\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"description": "Highly opinionated mocking framework for PHP 5.3+",
"homepage": "http://phpspec.org",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"spy",
"stub"
],
"time": "2013-08-10 11:11:45"
},
{
"name": "phpspec/prophecy-phpunit",
"version": "v1.0.0",
"target-dir": "Prophecy/PhpUnit",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy-phpunit.git",
"reference": "ebc983be95b026fcea18afb7870e7b9041dc9d11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/ebc983be95b026fcea18afb7870e7b9041dc9d11",
"reference": "ebc983be95b026fcea18afb7870e7b9041dc9d11",
"shasum": ""
},
"require": {
"phpspec/prophecy": "~1.0"
},
"suggest": {
"phpunit/phpunit": "if it is not installed globally"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Prophecy\\PhpUnit\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christophe Coevoet",
"email": "stof@notk.org"
}
],
"description": "PhpUnit test case integrating the Prophecy mocking library",
"homepage": "http://phpspec.org",
"keywords": [
"phpunit",
"prophecy"
],
"time": "2013-07-04 21:27:53"
}
],
"aliases": [

10
console
View file

@ -20,15 +20,15 @@ use PHPCI\Command\DaemonCommand;
use PHPCI\Command\PollCommand;
use Symfony\Component\Console\Application;
$loggerConfig = new \PHPCI\Helper\LoggerConfig(__DIR__ . "/loggerconfig.php");
$loggerConfig = \PHPCI\Helper\LoggerConfig::newFromFile(__DIR__ . "/loggerconfig.php");
$application = new Application();
$application->add(new RunCommand($loggerConfig->GetFor('RunCommand')));
$application->add(new RunCommand($loggerConfig->getFor('RunCommand')));
$application->add(new InstallCommand);
$application->add(new UpdateCommand($loggerConfig->GetFor('UpdateCommand')));
$application->add(new UpdateCommand($loggerConfig->getFor('UpdateCommand')));
$application->add(new GenerateCommand);
$application->add(new DaemonCommand($loggerConfig->GetFor('DaemonCommand')));
$application->add(new PollCommand($loggerConfig->GetFor('PollCommand')));
$application->add(new DaemonCommand($loggerConfig->getFor('DaemonCommand')));
$application->add(new PollCommand($loggerConfig->getFor('PollCommand')));
$application->run();

View file

@ -1,18 +1,235 @@
/**
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
* for the details of code below
*/
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {
},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
/**
* Used for delete buttons in the system, just to prevent accidental clicks.
*/
function confirmDelete(url)
{
if(confirm('Are you sure you want to delete this?'))
{
window.location.href = url;
}
else
{
return false;
}
function confirmDelete(url, subject, reloadAfter) {
var dialog = new PHPCIConfirmDialog({
message: subject + ' will be permanently deleted. Are you sure?',
confirmBtnCaption: 'Delete',
/*
confirm-btn click handler
*/
confirmed: function (e) {
var dialog = this;
e.preventDefault();
/*
Call delete URL
*/
$.ajax({
url: url,
'success': function (data) {
if (reloadAfter) {
dialog.onClose = function () {
window.location.reload();
};
}
dialog.showStatusMessage('Successfully deleted!', 1000);
},
'error': function (data) {
dialog.showStatusMessage('Deletion failed! Server says "' + data.statusText + '"');
}
});
}
});
dialog.show();
return dialog;
}
/**
* PHPCIConfirmDialog constructor options object
* @type {{message: string, title: string, confirmBtnCaption: string, cancelBtnCaption: string, confirmed: Function}}
*/
var PHPCIConfirmDialogOptions = {
message: 'The action will be performed and cannot be undone. Are you sure?',
title: 'Confirmation Dialog',
confirmBtnCaption: 'Ok',
cancelBtnCaption: 'Cancel',
confirmed: function (e) {
this.close();
}
};
var PHPCIConfirmDialog = Class.extend({
/**
* @private
* @var {bool} Determines whether the dialog has been confirmed
*/
confirmed: false,
/**
* @param {PHPCIConfirmDialogOptions} options
*/
init: function (options) {
options = options ? $.extend(PHPCIConfirmDialogOptions, options) : PHPCIConfirmDialogOptions;
if (!$('#confirm-dialog').length) {
/*
Add the dialog html to a page on first use. No need to have it there before first use.
*/
$('body').append(
'<div class="modal fade" id="confirm-dialog">'
+ '<div class="modal-dialog">'
+ '<div class="modal-content">'
+ '<div class="modal-header">'
+ '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>'
+ '<h4 class="modal-title"></h4>'
+ '</div>'
+ '<div class="modal-body">'
+ '<p></p>'
+ '</div>'
+ '<div class="modal-footer">'
+ '<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>'
+ '<button type="button" class="btn btn-primary"></button>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
);
}
/*
Define dialog controls
*/
this.$dialog = $('#confirm-dialog');
this.$cancelBtn = this.$dialog.find('div.modal-footer button.btn-default');
this.$confirmBtn = this.$dialog.find('div.modal-footer button.btn-primary');
this.$title = this.$dialog.find('h4.modal-title');
this.$body = this.$dialog.find('div.modal-body');
/*
Initialize its values
*/
this.$title.html(options.title ? options.title : PHPCIConfirmDialogOptions.title);
this.$body.html(options.message ? options.message : PHPCIConfirmDialogOptions.message);
this.$confirmBtn.html(
options.confirmBtnCaption ? options.confirmBtnCaption : PHPCIConfirmDialogOptions.confirmBtnCaption
);
this.$cancelBtn.html(
options.cancelBtnCaption ? options.cancelBtnCaption : PHPCIConfirmDialogOptions.cancelBtnCaption
);
/*
Events
*/
this.confirmBtnClick = options.confirmed;
/*
Re-bind handlers
*/
this.$confirmBtn.unbind('click');
this.$confirmBtn.click(this.onConfirm.bind(this));
this.$confirmBtn.unbind('hidden.bs.modal');
/*
Bind the close event of the dialog to the set of onClose* methods
*/
this.$dialog.on('hidden.bs.modal', function () {this.onClose()}.bind(this));
this.$dialog.on('hidden.bs.modal', function () {
if (this.confirmed) {
this.onCloseConfirmed();
} else {
this.onCloseCanceled();
}
}.bind(this));
/*
Restore state if was changed previously
*/
this.$cancelBtn.show();
this.$confirmBtn.show();
this.confirmed = false;
},
/**
* Show dialog
*/
show: function () {
this.$dialog.modal('show');
},
/**
* Hide dialog
*/
close: function () {
this.$dialog.modal('hide');
},
onConfirm: function (e) {
this.confirmed = true;
$(this).attr('disabled', 'disabled');
this.confirmBtnClick(e);
},
/**
* Called only when confirmed dialog was closed
*/
onCloseConfirmed: function () {},
/**
* Called only when canceled dialog was closed
*/
onCloseCanceled: function () {},
/**
* Called always when the dialog was closed
*/
onClose: function () {},
showStatusMessage: function (message, closeTimeout) {
this.$confirmBtn.hide();
this.$cancelBtn.html('Close');
/*
Status message
*/
this.$body.html(message);
if (closeTimeout) {
window.setTimeout(function () {
/*
Hide the dialog
*/
this.close();
}.bind(this), closeTimeout);
}
}
});
/**
* Used to initialise the project form:
*/

View file

@ -5,7 +5,7 @@ require_once(dirname(__FILE__) . '/../bootstrap.php');
$installStage = 'start';
$formAction = '';
$config = array();
$ciUrl = ($_SERVER['HTTPS'] == "on" ? 'https' : 'http') . '://';
$ciUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on" ? 'https' : 'http') . '://';
$ciUrl .= $_SERVER['HTTP_HOST'];
$ciUrl .= str_replace('/install.php', '', $_SERVER['REQUEST_URI']);

View file

@ -7,7 +7,7 @@ if (!defined('APPLICATION_PATH')) {
}
// Define our PHPCI_URL, if not already defined:
if (!defined('PHPCI_URL')) {
if (!defined('PHPCI_URL') && isset($config)) {
define('PHPCI_URL', $config->get('phpci.url', '') . '/');
}