Holy cleanup, batman.

This commit is contained in:
Dan Cryer 2013-10-10 01:01:06 +01:00
parent 4cbfc06022
commit 77fae9a56d
58 changed files with 976 additions and 856 deletions

View file

@ -32,11 +32,14 @@ class Application extends b8\Application
$externalAction = in_array($this->controllerName, array('Bitbucket', 'Github', 'Gitlab', 'BuildStatus')); $externalAction = in_array($this->controllerName, array('Bitbucket', 'Github', 'Gitlab', 'BuildStatus'));
$skipValidation = ($externalAction || $sessionAction); $skipValidation = ($externalAction || $sessionAction);
if($skipValidation || $this->validateSession()) { if ($skipValidation || $this->validateSession()) {
parent::handleRequest(); parent::handleRequest();
} }
} catch (\Exception $ex) { } catch (\Exception $ex) {
$content = '<h1>There was a problem with this request</h1><p>Please paste the details below into a <a href="https://github.com/Block8/PHPCI/issues/new">new bug report</a> so that we can investigate and fix it.</p>'; $content = '<h1>There was a problem with this request</h1>
<p>Please paste the details below into a
<a href="https://github.com/Block8/PHPCI/issues/new">new bug report</a>
so that we can investigate and fix it.</p>';
ob_start(); ob_start();
var_dump(array( var_dump(array(

View file

@ -52,12 +52,7 @@ class Builder
/** /**
* @var bool * @var bool
*/ */
protected $verbose = false; protected $verbose = true;
/**
* @var bool[]
*/
protected $plugins = array();
/** /**
* @var \PHPCI\Model\Build * @var \PHPCI\Model\Build
@ -84,7 +79,6 @@ class Builder
* interpolation and environment variables * interpolation and environment variables
* @var array * @var array
* @see setInterpolationVars() * @see setInterpolationVars()
* @see getInterpolationVars()
*/ */
protected $interpolation_vars = array(); protected $interpolation_vars = array();
@ -93,19 +87,21 @@ class Builder
*/ */
protected $store; protected $store;
/**
* @var bool
*/
public $quiet = false;
/** /**
* Set up the builder. * Set up the builder.
* @param \PHPCI\Model\Build * @param \PHPCI\Model\Build
* @param callable * @param callable
*/ */
public function __construct(Build $build, $logCallback = null) public function __construct(Build $build, callable $logCallback)
{ {
$this->build = $build; $this->build = $build;
$this->store = Store\Factory::getStore('Build'); $this->store = Store\Factory::getStore('Build');
$this->logCallback = $logCallback;
if (!is_null($logCallback) && is_callable($logCallback)) {
$this->logCallback = $logCallback;
}
} }
/** /**
@ -123,7 +119,13 @@ class Builder
*/ */
public function getConfig($key) public function getConfig($key)
{ {
return isset($this->config[$key]) ? $this->config[$key] : null; $rtn = null;
if (isset($this->config[$key])) {
$rtn = $this->config[$key];
}
return $rtn;
} }
/** /**
@ -136,29 +138,11 @@ class Builder
return Config::getInstance()->get($key); return Config::getInstance()->get($key);
} }
/**
* Access the build.
* @param Build
*/
public function getBuild()
{
return $this->build;
}
/** /**
* @return string The title of the project being built. * @return string The title of the project being built.
*/ */
public function getBuildProjectTitle() { public function getBuildProjectTitle() {
return $this->getBuild()->getProject()->getTitle(); return $this->build->getProject()->getTitle();
}
/**
* Indicates if the build has passed or failed.
* @return bool
*/
public function getSuccessStatus()
{
return $this->success;
} }
/** /**
@ -173,47 +157,41 @@ class Builder
$this->build->sendStatusPostback(); $this->build->sendStatusPostback();
try { try {
if ($this->setupBuild()) { // Set up the build:
// Run setup steps: $this->setupBuild();
$this->executePlugins('setup');
// Run the any tests: // Run the core plugin stages:
$this->executePlugins('test'); foreach (array('setup', 'test', 'complete') as $stage) {
$this->executePlugins($stage);
$this->log(''); $this->log('');
// Run build complete steps:
$this->executePlugins('complete');
// Run success or failure plugins:
if ($this->success) {
$this->build->setStatus(2);
$this->executePlugins('success');
$this->logSuccess('BUILD SUCCESSFUL!');
} else {
$this->build->setStatus(3);
$this->executePlugins('failure');
$this->logFailure('BUILD FAILED!');
}
$this->log('');
} else {
$this->build->setStatus(3);
} }
// Failed build? Execute failure plugins and then mark the build as failed.
if (!$this->success) {
$this->executePlugins('failure');
throw new \Exception('BUILD FAILED!');
}
// If we got this far, the build was successful!
if ($this->success) {
$this->build->setStatus(2);
$this->executePlugins('success');
$this->logSuccess('BUILD SUCCESSFUL!');
}
} catch (\Exception $ex) { } catch (\Exception $ex) {
$this->logFailure($ex->getMessage()); $this->logFailure($ex->getMessage());
$this->build->setStatus(3); $this->build->setStatus(3);
} }
// Clean up: // Clean up:
$this->removeBuild(); $this->log('Removing build.');
shell_exec(sprintf('rm -Rf "%s"', $this->buildPath));
// Update the build in the database, ping any external services, etc. // Update the build in the database, ping any external services, etc.
$this->build->sendStatusPostback(); $this->build->sendStatusPostback();
$this->build->setFinished(new \DateTime()); $this->build->setFinished(new \DateTime());
$this->build->setLog($this->log); $this->build->setLog($this->log);
$this->build->setPlugins(json_encode($this->plugins));
$this->store->save($this->build); $this->store->save($this->build);
} }
@ -223,8 +201,10 @@ class Builder
public function executeCommand() public function executeCommand()
{ {
$command = call_user_func_array('sprintf', func_get_args()); $command = call_user_func_array('sprintf', func_get_args());
$this->log('Executing: ' . $command, ' '); if (!$this->quiet) {
$this->log('Executing: ' . $command, ' ');
}
$status = 0; $status = 0;
exec($command, $this->lastOutput, $status); exec($command, $this->lastOutput, $status);
@ -233,7 +213,14 @@ class Builder
$this->log($this->lastOutput, ' '); $this->log($this->lastOutput, ' ');
} }
return ($status == 0) ? true : false;
$rtn = false;
if ($status == 0) {
$rtn = true;
}
return $rtn;
} }
/** /**
@ -251,25 +238,16 @@ class Builder
*/ */
public function log($message, $prefix = '') public function log($message, $prefix = '')
{ {
if (is_array($message)) { if (!is_array($message)) {
foreach ($message as $item) { $message = array($message);
if (is_callable($this->logCallback)) { }
call_user_func_array($this->logCallback, array($prefix . $item));
}
$this->log .= $prefix . $item . PHP_EOL;
}
} else {
$message = $prefix . $message;
$this->log .= $message . PHP_EOL;
if (isset($this->logCallback) && is_callable($this->logCallback)) { foreach ($message as $item) {
call_user_func_array($this->logCallback, array($message)); call_user_func_array($this->logCallback, array($prefix . $item));
} $this->log .= $prefix . $item . PHP_EOL;
} }
$this->build->setLog($this->log); $this->build->setLog($this->log);
$this->build->setPlugins(json_encode($this->plugins));
$this->store->save($this->build); $this->store->save($this->build);
} }
@ -291,15 +269,6 @@ class Builder
$this->log("\033[0;31m" . $message . "\033[0m"); $this->log("\033[0;31m" . $message . "\033[0m");
} }
/**
* Get an array key => value pairs that are used for interpolation
* @return array
*/
public function getInterpolationVars()
{
return $this->interpolation_vars;
}
/** /**
* Replace every occurance of the interpolation vars in the given string * Replace every occurance of the interpolation vars in the given string
* Example: "This is build %PHPCI_BUILD%" => "This is build 182" * Example: "This is build %PHPCI_BUILD%" => "This is build 182"
@ -308,12 +277,9 @@ class Builder
*/ */
public function interpolate($input) public function interpolate($input)
{ {
$trans_table = array(); $keys = array_keys($this->interpolation_vars);
foreach ($this->getInterpolationVars() as $key => $value) { $values = array_values($this->interpolation_vars);
$trans_table['%'.$key.'%'] = $value; return str_replace($keys, $values, $input);
$trans_table['%PHPCI_'.$key.'%'] = $value;
}
return strtr($input, $trans_table);
} }
/** /**
@ -322,15 +288,28 @@ class Builder
*/ */
protected function setInterpolationVars() protected function setInterpolationVars()
{ {
$this->interpolation_vars = array( $this->interpolation_vars = array();
'PHPCI' => 1, $this->interpolation_vars['%PHPCI%'] = 1;
'COMMIT' => $this->build->getCommitId(), $this->interpolation_vars['%COMMIT%'] = $this->build->getCommitId();
'PROJECT' => $this->build->getProject()->getId(), $this->interpolation_vars['%PROJECT%'] = $this->build->getProjectId();
'BUILD' => $this->build->getId(), $this->interpolation_vars['%BUILD%'] = $this->build->getId();
'PROJECT_TITLE' => $this->build->getProject()->getTitle(), $this->interpolation_vars['%PROJECT_TITLE%'] = $this->getBuildProjectTitle();
'BUILD_PATH' => $this->buildPath, $this->interpolation_vars['%BUILD_PATH%'] = $this->buildPath;
'BUILD_URI' => PHPCI_URL . "build/view/" . $this->build->getId(), $this->interpolation_vars['%BUILD_URI%'] = PHPCI_URL . "build/view/" . $this->build->getId();
); $this->interpolation_vars['%PHPCI_COMMIT%'] = $this->interpolation_vars['%COMMIT%'];
$this->interpolation_vars['%PHPCI_PROJECT%'] = $this->interpolation_vars['%PROJECT%'];
$this->interpolation_vars['%PHPCI_BUILD%'] = $this->interpolation_vars['%BUILD%'];
$this->interpolation_vars['%PHPCI_PROJECT_TITLE%'] = $this->interpolation_vars['%PROJECT_TITLE%'];
$this->interpolation_vars['%PHPCI_BUILD_PATH%'] = $this->interpolation_vars['%BUILD_PATH%'];
$this->interpolation_vars['%PHPCI_BUILD_URI%'] = $this->interpolation_vars['%BUILD_URI%'];
putenv('PHPCI=1');
putenv('PHPCI_COMMIT='.$this->interpolation_vars['%COMMIT%']);
putenv('PHPCI_PROJECT='.$this->interpolation_vars['%PROJECT%']);
putenv('PHPCI_BUILD='.$this->interpolation_vars['%BUILD%']);
putenv('PHPCI_PROJECT_TITLE='.$this->interpolation_vars['%PROJECT_TITLE%']);
putenv('PHPCI_BUILD_PATH='.$this->interpolation_vars['%BUILD_PATH%']);
putenv('PHPCI_BUILD_URI='.$this->interpolation_vars['%BUILD_URI%']);
} }
/** /**
@ -338,28 +317,20 @@ class Builder
*/ */
protected function setupBuild() protected function setupBuild()
{ {
$commitId = $this->build->getCommitId();
$buildId = 'project' . $this->build->getProject()->getId() . '-build' . $this->build->getId(); $buildId = 'project' . $this->build->getProject()->getId() . '-build' . $this->build->getId();
$this->ciDir = dirname(__FILE__) . '/../'; $this->ciDir = dirname(__FILE__) . '/../';
$this->buildPath = $this->ciDir . 'build/' . $buildId . '/'; $this->buildPath = $this->ciDir . 'build/' . $buildId . '/';
$this->setInterpolationVars(); $this->setInterpolationVars();
// Setup environment vars that will be accessible during exec()
foreach ($this->getInterpolationVars() as $key => $value) {
putenv($key.'='.$value);
}
// Create a working copy of the project: // Create a working copy of the project:
if (!$this->build->createWorkingCopy($this, $this->buildPath)) { if (!$this->build->createWorkingCopy($this, $this->buildPath)) {
return false; throw new \Exception('Could not create a working copy.');
} }
// Does the project's phpci.yml request verbose mode? // Does the project's phpci.yml request verbose mode?
if (!isset($this->config['build_settings']['verbose']) || !$this->config['build_settings']['verbose']) { if (!isset($this->config['build_settings']['verbose']) || !$this->config['build_settings']['verbose']) {
$this->verbose = false; $this->verbose = false;
} else {
$this->verbose = true;
} }
// Does the project have any paths it wants plugins to ignore? // Does the project have any paths it wants plugins to ignore?
@ -390,78 +361,55 @@ class Builder
$options['allow_failures'] = false; $options['allow_failures'] = false;
} }
$class = str_replace('_', ' ', $plugin); // Try and execute it:
$class = ucwords($class); if ($this->executePlugin($plugin, $options)) {
$class = 'PHPCI\\Plugin\\' . str_replace(' ', '', $class);
if (!class_exists($class)) { // Execution was successful:
$this->logFailure('Plugin does not exist: ' . $plugin); $this->logSuccess('PLUGIN STATUS: SUCCESS!');
if ($stage == 'test') { } else {
$this->plugins[$plugin] = false;
if (!$options['allow_failures']) { // If we're in the "test" stage and the plugin is not allowed to fail,
$this->success = false; // then mark the build as failed:
} if ($stage == 'test' && !$options['allow_failures']) {
} $this->success = false;
continue;
}
try {
$obj = new $class($this, $options);
if (!$obj->execute()) {
if ($stage == 'test') {
$this->plugins[$plugin] = false;
if (!$options['allow_failures']) {
$this->success = false;
}
}
$this->logFailure('PLUGIN STATUS: FAILED');
continue;
}
} catch (\Exception $ex) {
$this->logFailure('EXCEPTION: ' . $ex->getMessage());
if ($stage == 'test') {
$this->plugins[$plugin] = false;
if (!$options['allow_failures']) {
$this->success = false;
}
} }
$this->logFailure('PLUGIN STATUS: FAILED'); $this->logFailure('PLUGIN STATUS: FAILED');
continue;
} }
if ($stage == 'test') {
$this->plugins[$plugin] = true;
}
$this->logSuccess('PLUGIN STATUS: SUCCESS!');
} }
} }
/** /**
* Clean up our working copy. * Executes a given plugin, with options and returns the result.
*/
protected function removeBuild()
{
$this->log('Removing build.');
shell_exec(sprintf('rm -Rf "%s"', $this->buildPath));
}
/**
* Store build meta data
*/ */
public function storeBuildMeta($key, $value) protected function executePlugin($plugin, $options)
{ {
$value = json_encode($value); // Figure out the class name and check the plugin exists:
$this->store->setMeta($this->build->getProjectId(), $this->build->getId(), $key, $value); $class = str_replace('_', ' ', $plugin);
$class = ucwords($class);
$class = 'PHPCI\\Plugin\\' . str_replace(' ', '', $class);
if (!class_exists($class)) {
$this->logFailure('Plugin does not exist: ' . $plugin);
return false;
}
$rtn = true;
// Try running it:
try {
$obj = new $class($this, $this->build, $options);
if (!$obj->execute()) {
$rtn = false;
}
} catch (\Exception $ex) {
$this->logFailure('EXCEPTION: ' . $ex->getMessage());
$rtn = false;
}
return $rtn;
} }
/** /**

View file

@ -66,7 +66,7 @@ class DaemonCommand extends Command
protected function startDaemon() protected function startDaemon()
{ {
if ( file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) { if (file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
echo "Already started\n"; echo "Already started\n";
return "alreadystarted"; return "alreadystarted";
} }
@ -80,7 +80,7 @@ class DaemonCommand extends Command
protected function stopDaemon() protected function stopDaemon()
{ {
if ( !file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) { if (!file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
echo "Not started\n"; echo "Not started\n";
return "notstarted"; return "notstarted";
} }
@ -94,14 +94,14 @@ class DaemonCommand extends Command
protected function statusDaemon() protected function statusDaemon()
{ {
if ( !file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) { if (!file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
echo "Not running\n"; echo "Not running\n";
return "notrunning"; return "notrunning";
} }
$pid = trim(file_get_contents(PHPCI_DIR.'/daemon/daemon.pid')); $pid = trim(file_get_contents(PHPCI_DIR.'/daemon/daemon.pid'));
$pidcheck = sprintf("/proc/%s", $pid); $pidcheck = sprintf("/proc/%s", $pid);
if ( is_dir($pidcheck) ) { if (is_dir($pidcheck)) {
echo "Running\n"; echo "Running\n";
return "running"; return "running";
} }

View file

@ -57,7 +57,7 @@ class DaemoniseCommand extends Command
if (0 == $buildCount && $this->sleep < 15) { if (0 == $buildCount && $this->sleep < 15) {
$this->sleep++; $this->sleep++;
} else if (1 < $this->sleep) { } elseif (1 < $this->sleep) {
$this->sleep--; $this->sleep--;
} }
echo '.'.(0 === $buildCount?'':'build'); echo '.'.(0 === $buildCount?'':'build');

View file

@ -14,6 +14,8 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use b8\Database;
use b8\Database\CodeGenerator;
/** /**
* Generate console command - Reads the database and generates models and stores. * Generate console command - Reads the database and generates models and stores.
@ -35,7 +37,7 @@ class GenerateCommand extends Command
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output)
{ {
$gen = new \b8\Database\CodeGenerator(\b8\Database::getConnection(), 'PHPCI', PHPCI_DIR . '/PHPCI/'); $gen = new CodeGenerator(Database::getConnection(), 'PHPCI', PHPCI_DIR . '/PHPCI/', false);
$gen->generateModels(); $gen->generateModels();
$gen->generateStores(); $gen->generateStores();
} }

View file

@ -44,7 +44,8 @@ class InstallCommand extends Command
$conf['b8']['database']['name'] = $this->ask('Enter the database name PHPCI should use: '); $conf['b8']['database']['name'] = $this->ask('Enter the database name PHPCI should use: ');
$conf['b8']['database']['username'] = $this->ask('Enter your MySQL username: '); $conf['b8']['database']['username'] = $this->ask('Enter your MySQL username: ');
$conf['b8']['database']['password'] = $this->ask('Enter your MySQL password: ', true); $conf['b8']['database']['password'] = $this->ask('Enter your MySQL password: ', true);
$conf['phpci']['url'] = $this->ask('Your PHPCI URL (without trailing slash): ', false, array(FILTER_VALIDATE_URL,"/[^\/]$/i")); $ask = 'Your PHPCI URL (without trailing slash): ';
$conf['phpci']['url'] = $this->ask($ask, false, array(FILTER_VALIDATE_URL,"/[^\/]$/i"));
$conf['phpci']['github']['id'] = $this->ask('(Optional) Github Application ID: ', true); $conf['phpci']['github']['id'] = $this->ask('(Optional) Github Application ID: ', true);
$conf['phpci']['github']['secret'] = $this->ask('(Optional) Github Application Secret: ', true); $conf['phpci']['github']['secret'] = $this->ask('(Optional) Github Application Secret: ', true);
@ -54,7 +55,9 @@ class InstallCommand extends Command
$conf['phpci']['email_settings']['smtp_username'] = $this->ask('(Optional) Smtp Username: ', true); $conf['phpci']['email_settings']['smtp_username'] = $this->ask('(Optional) Smtp Username: ', true);
$conf['phpci']['email_settings']['smtp_password'] = $this->ask('(Optional) Smtp Password: ', true); $conf['phpci']['email_settings']['smtp_password'] = $this->ask('(Optional) Smtp Password: ', true);
$conf['phpci']['email_settings']['from_address'] = $this->ask('(Optional) Email address to send from: ', true); $conf['phpci']['email_settings']['from_address'] = $this->ask('(Optional) Email address to send from: ', true);
$conf['phpci']['email_settings']['default_mailto_address'] = $this->ask('(Optional) Default address to email notifications to: ', true);
$ask = '(Optional) Default address to email notifications to: ';
$conf['phpci']['email_settings']['default_mailto_address'] = $this->ask($ask, true);
$dbUser = $conf['b8']['database']['username']; $dbUser = $conf['b8']['database']['username'];
$dbPass = $conf['b8']['database']['password']; $dbPass = $conf['b8']['database']['password'];
@ -126,7 +129,7 @@ class InstallCommand extends Command
return $rtn; return $rtn;
} }
protected function controlFormat($valueToInspect,$filter,&$statusMessage) protected function controlFormat($valueToInspect, $filter, &$statusMessage)
{ {
$filters = !(is_array($filter))? array($filter) : $filter; $filters = !(is_array($filter))? array($filter) : $filter;
$statusMessage = ''; $statusMessage = '';
@ -148,13 +151,13 @@ class InstallCommand extends Command
switch ($filter) switch ($filter)
{ {
case FILTER_VALIDATE_URL : case FILTER_VALIDATE_URL:
$statusMessage = 'Incorrect url format.' . PHP_EOL; $statusMessage = 'Incorrect url format.' . PHP_EOL;
break; break;
case FILTER_VALIDATE_EMAIL : case FILTER_VALIDATE_EMAIL:
$statusMessage = 'Incorrect e-mail format.' . PHP_EOL; $statusMessage = 'Incorrect e-mail format.' . PHP_EOL;
break; break;
case FILTER_VALIDATE_REGEXP : case FILTER_VALIDATE_REGEXP:
$statusMessage = 'Incorrect format.' . PHP_EOL; $statusMessage = 'Incorrect format.' . PHP_EOL;
break; break;
} }

View file

@ -52,7 +52,9 @@ class RunCommand extends Command
if ($input->getOption('verbose')) { if ($input->getOption('verbose')) {
$builder = new Builder($build, array($this, 'logCallback')); $builder = new Builder($build, array($this, 'logCallback'));
} else { } else {
$builder = new Builder($build); $builder = new Builder($build, function () {
// Empty stub function.
});
} }
$builder->execute(); $builder->execute();

View file

@ -19,46 +19,49 @@ class Controller extends \b8\Controller
*/ */
protected $view; protected $view;
public function init() {} public function init()
{
// Extended by actual controllers.
}
public function __construct(Config $config, Request $request, Response $response) public function __construct(Config $config, Request $request, Response $response)
{ {
parent::__construct($config, $request, $response); parent::__construct($config, $request, $response);
$class = explode('\\', get_class($this)); $class = explode('\\', get_class($this));
$this->className = substr(array_pop($class), 0, -10); $this->className = substr(array_pop($class), 0, -10);
$this->setControllerView(); $this->setControllerView();
} }
protected function setControllerView() protected function setControllerView()
{ {
if (View::exists($this->className)) { if (View::exists($this->className)) {
$this->controllerView = new View($this->className); $this->controllerView = new View($this->className);
} else { } else {
$this->controllerView = new View\UserView('{@content}'); $this->controllerView = new View\UserView('{@content}');
} }
} }
protected function setView($action) protected function setView($action)
{ {
if (View::exists($this->className . '/' . $action)) { if (View::exists($this->className . '/' . $action)) {
$this->view = new View($this->className . '/' . $action); $this->view = new View($this->className . '/' . $action);
} }
} }
public function handleAction($action, $actionParams) public function handleAction($action, $actionParams)
{ {
$this->setView($action); $this->setView($action);
$response = parent::handleAction($action, $actionParams); $response = parent::handleAction($action, $actionParams);
if (is_string($response)) { if (is_string($response)) {
$this->controllerView->content = $response; $this->controllerView->content = $response;
} elseif (isset($this->view)) { } elseif (isset($this->view)) {
$this->controllerView->content = $this->view->render(); $this->controllerView->content = $this->view->render();
} }
$this->response->setContent($this->controllerView->render()); $this->response->setContent($this->controllerView->render());
return $this->response; return $this->response;
} }
} }

View file

@ -38,7 +38,7 @@ class BuildController extends \PHPCI\Controller
$build = $this->buildStore->getById($buildId); $build = $this->buildStore->getById($buildId);
$this->view->plugins = $this->getUiPlugins(); $this->view->plugins = $this->getUiPlugins();
$this->view->build = $build; $this->view->build = $build;
$this->view->data = $this->getBuildData($buildId); $this->view->data = $this->getBuildData($build);
} }
protected function getUiPlugins() protected function getUiPlugins()
@ -63,7 +63,7 @@ class BuildController extends \PHPCI\Controller
*/ */
public function data($buildId) public function data($buildId)
{ {
die($this->getBuildData($buildId)); die($this->getBuildData($this->buildStore->getById($buildId)));
} }
/** /**
@ -86,10 +86,8 @@ class BuildController extends \PHPCI\Controller
/** /**
* Get build data from database and json encode it: * Get build data from database and json encode it:
*/ */
protected function getBuildData($buildId) protected function getBuildData($build)
{ {
$build = $this->buildStore->getById($buildId);
$data = array(); $data = array();
$data['status'] = (int)$build->getStatus(); $data['status'] = (int)$build->getStatus();
$data['log'] = $this->cleanLog($build->getLog()); $data['log'] = $this->cleanLog($build->getLog());

View file

@ -68,7 +68,7 @@ class PluginController extends \PHPCI\Controller
$this->setComposerJson($json); $this->setComposerJson($json);
if ($this->canInstall) { if ($this->canInstall) {
$res = shell_exec($this->composerPath . ' update --working-dir=' . APPLICATION_PATH . ' > /dev/null 2>&1 &'); shell_exec($this->composerPath . ' update --working-dir=' . APPLICATION_PATH . ' > /dev/null 2>&1 &');
} }
header('Location: ' . PHPCI_URL . 'plugin?r=' . $package); header('Location: ' . PHPCI_URL . 'plugin?r=' . $package);
@ -89,7 +89,7 @@ class PluginController extends \PHPCI\Controller
$this->setComposerJson($json); $this->setComposerJson($json);
if ($this->canInstall) { if ($this->canInstall) {
$res = shell_exec($this->composerPath . ' update --working-dir=' . APPLICATION_PATH . ' > /dev/null 2>&1 &'); shell_exec($this->composerPath . ' update --working-dir=' . APPLICATION_PATH . ' > /dev/null 2>&1 &');
header('Location: ' . PHPCI_URL . 'plugin?i=' . $package); header('Location: ' . PHPCI_URL . 'plugin?i=' . $package);
die; die;
@ -141,10 +141,10 @@ class PluginController extends \PHPCI\Controller
public function packagistSearch() public function packagistSearch()
{ {
$q = $this->getParam('q', ''); $searchQuery = $this->getParam('q', '');
$http = new \b8\HttpClient(); $http = new \b8\HttpClient();
$http->setHeaders(array('User-Agent: PHPCI/1.0 (+http://www.phptesting.org)')); $http->setHeaders(array('User-Agent: PHPCI/1.0 (+http://www.phptesting.org)'));
$res = $http->get('https://packagist.org/search.json', array('q' => $q)); $res = $http->get('https://packagist.org/search.json', array('q' => $searchQuery));
die(json_encode($res['body'])); die(json_encode($res['body']));
} }

View file

@ -173,7 +173,7 @@ class ProjectController extends \PHPCI\Controller
$values = $form->getValues(); $values = $form->getValues();
if ($values['type'] == "gitlab") { if ($values['type'] == "gitlab") {
preg_match('`^(.*)@(.*):(.*)/(.*)\.git`',$values['reference'],$matches); preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches);
$info = array(); $info = array();
$info["user"] = $matches[1]; $info["user"] = $matches[1];
$info["domain"] = $matches[2]; $info["domain"] = $matches[2];
@ -238,7 +238,8 @@ class ProjectController extends \PHPCI\Controller
$values['key'] = $values['git_key']; $values['key'] = $values['git_key'];
if ($values['type'] == "gitlab") { if ($values['type'] == "gitlab") {
$accessInfo = $project->getAccessInformation(); $accessInfo = $project->getAccessInformation();
$values['reference'] = $accessInfo["user"].'@'.$accessInfo["domain"].':' . $project->getReference().".git"; $reference = $accessInfo["user"].'@'.$accessInfo["domain"].':' . $project->getReference().".git";
$values['reference'] = $reference;
} }
} }
@ -259,12 +260,12 @@ class ProjectController extends \PHPCI\Controller
$values['git_key'] = $values['key']; $values['git_key'] = $values['key'];
if ($values['type'] == "gitlab") { if ($values['type'] == "gitlab") {
preg_match('`^(.*)@(.*):(.*)/(.*)\.git`',$values['reference'],$matches); preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches);
$info = array(); $info = array();
$info["user"] = $matches[1]; $info["user"] = $matches[1];
$info["domain"] = $matches[2]; $info["domain"] = $matches[2];
$values['access_information'] = serialize($info); $values['access_information'] = serialize($info);
$values['reference'] = $matches[3]."/".$matches[4]; $values['reference'] = $matches[3] . "/" . $matches[4];
} }
$project->setValues($values); $project->setValues($values);
@ -314,44 +315,9 @@ class ProjectController extends \PHPCI\Controller
$form->addField($field); $form->addField($field);
} }
$referenceValidator = function ($val) use ($values) {
$type = $values['type'];
switch($type) {
case 'hg':
if (!preg_match('/^(https?):\/\//', $val)) {
throw new \Exception('Mercurial repository URL must be start with http:// or https://.');
}
break;
case 'remote':
if (!preg_match('/^(git|https?):\/\//', $val)) {
throw new \Exception('Repository URL must be start with git://, http:// or https://.');
}
break;
case 'local':
if (!is_dir($val)) {
throw new \Exception('The path you specified does not exist.');
}
break;
case 'gitlab':
if (!preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $val)) {
throw new \Exception('GitLab Repository name must be in the format "user@domain.tld:owner/repo.git".');
}
break;
case 'github':
case 'bitbucket':
if (!preg_match('/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-\.]+$/', $val)) {
throw new \Exception('Repository name must be in the format "owner/repo".');
}
break;
}
return true;
};
$field = new Form\Element\Text('reference'); $field = new Form\Element\Text('reference');
$field->setRequired(true); $field->setRequired(true);
$field->setValidator($referenceValidator); $field->setValidator($this->getReferenceValidator($values));
$field->setLabel('Repository Name / URL (Remote) or Path (Local)'); $field->setLabel('Repository Name / URL (Remote) or Path (Local)');
$field->setClass('form-control'); $field->setClass('form-control');
$field->setContainerClass('form-group'); $field->setContainerClass('form-group');
@ -401,4 +367,42 @@ class ProjectController extends \PHPCI\Controller
return $rtn; return $rtn;
} }
protected function getReferenceValidator($values)
{
return function ($val) use ($values) {
$type = $values['type'];
$validators = array(
'hg' => array(
'regex' => '/^(https?):\/\//',
'message' => 'Mercurial repository URL must be start with http:// or https://'
),
'remote' => array(
'regex' => '/^(git|https?):\/\//',
'message' => 'Repository URL must be start with git://, http:// or https://'
),
'gitlab' => array(
'regex' => '`^(.*)@(.*):(.*)/(.*)\.git`',
'message' => 'GitLab Repository name must be in the format "user@domain.tld:owner/repo.git"'
),
'github' => array(
'regex' => '/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-\.]+$/',
'message' => 'Repository name must be in the format "owner/repo"'
),
'bitbucket' => array(
'regex' => '/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-\.]+$/',
'message' => 'Repository name must be in the format "owner/repo"'
),
);
if (in_array($type, $validators) && !preg_match($validators[$type]['regex'], $val)) {
throw new \Exception($validators[$type]['message']);
} elseif ($type == 'local' && !is_dir($val)) {
throw new \Exception('The path you specified does not exist.');
}
return true;
};
}
} }

View file

@ -10,8 +10,9 @@
namespace PHPCI\Controller; namespace PHPCI\Controller;
use b8; use b8;
use PHPCI\Model\User;
use b8\Form; use b8\Form;
use PHPCI\Controller;
use PHPCI\Model\User;
/** /**
* User Controller - Allows an administrator to view, add, edit and delete users. * User Controller - Allows an administrator to view, add, edit and delete users.
@ -19,7 +20,7 @@ use b8\Form;
* @package PHPCI * @package PHPCI
* @subpackage Web * @subpackage Web
*/ */
class UserController extends \PHPCI\Controller class UserController extends Controller
{ {
/** /**
* @var \PHPCI\Store\UserStore * @var \PHPCI\Store\UserStore

View file

@ -7,6 +7,7 @@
namespace PHPCI\Model\Base; namespace PHPCI\Model\Base;
use b8\Model; use b8\Model;
use b8\Store\Factory;
/** /**
* Build Base Model * Build Base Model
@ -43,12 +44,13 @@ class BuildBase extends Model
'finished' => null, 'finished' => null,
'plugins' => null, 'plugins' => null,
'committer_email' => null, 'committer_email' => null,
); );
/** /**
* @var array * @var array
*/ */
protected $getters = array( protected $getters = array(
// Direct property getters:
'id' => 'getId', 'id' => 'getId',
'project_id' => 'getProjectId', 'project_id' => 'getProjectId',
'commit_id' => 'getCommitId', 'commit_id' => 'getCommitId',
@ -60,13 +62,16 @@ class BuildBase extends Model
'finished' => 'getFinished', 'finished' => 'getFinished',
'plugins' => 'getPlugins', 'plugins' => 'getPlugins',
'committer_email' => 'getCommitterEmail', 'committer_email' => 'getCommitterEmail',
// Foreign key getters:
'Project' => 'getProject', 'Project' => 'getProject',
); );
/** /**
* @var array * @var array
*/ */
protected $setters = array( protected $setters = array(
// Direct property setters:
'id' => 'setId', 'id' => 'setId',
'project_id' => 'setProjectId', 'project_id' => 'setProjectId',
'commit_id' => 'setCommitId', 'commit_id' => 'setCommitId',
@ -78,8 +83,10 @@ class BuildBase extends Model
'finished' => 'setFinished', 'finished' => 'setFinished',
'plugins' => 'setPlugins', 'plugins' => 'setPlugins',
'committer_email' => 'setCommitterEmail', 'committer_email' => 'setCommitterEmail',
// Foreign key setters:
'Project' => 'setProject', 'Project' => 'setProject',
); );
/** /**
* @var array * @var array
@ -87,69 +94,63 @@ class BuildBase extends Model
public $columns = array( public $columns = array(
'id' => array( 'id' => array(
'type' => 'int', 'type' => 'int',
'length' => '11', 'length' => 11,
'primary_key' => true, 'primary_key' => true,
'auto_increment' => true, 'auto_increment' => true,
'default' => null, 'default' => null,
), ),
'project_id' => array( 'project_id' => array(
'type' => 'int', 'type' => 'int',
'length' => '11', 'length' => 11,
'default' => null, 'default' => null,
), ),
'commit_id' => array( 'commit_id' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '50', 'length' => 50,
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'status' => array( 'status' => array(
'type' => 'tinyint', 'type' => 'tinyint',
'length' => '4', 'length' => 4,
'default' => '0', ),
),
'log' => array( 'log' => array(
'type' => 'longtext', 'type' => 'longtext',
'length' => '',
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'branch' => array( 'branch' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '50', 'length' => 50,
'default' => 'master', 'default' => 'master',
), ),
'created' => array( 'created' => array(
'type' => 'datetime', 'type' => 'datetime',
'length' => '',
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'started' => array( 'started' => array(
'type' => 'datetime', 'type' => 'datetime',
'length' => '',
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'finished' => array( 'finished' => array(
'type' => 'datetime', 'type' => 'datetime',
'length' => '',
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'plugins' => array( 'plugins' => array(
'type' => 'text', 'type' => 'text',
'length' => '',
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'committer_email' => array( 'committer_email' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '512', 'length' => 512,
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
); );
/** /**
* @var array * @var array
@ -158,7 +159,7 @@ class BuildBase extends Model
'PRIMARY' => array('unique' => true, 'columns' => 'id'), 'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'project_id' => array('columns' => 'project_id'), 'project_id' => array('columns' => 'project_id'),
'idx_status' => array('columns' => 'status'), 'idx_status' => array('columns' => 'status'),
); );
/** /**
* @var array * @var array
@ -171,8 +172,7 @@ class BuildBase extends Model
'table' => 'project', 'table' => 'project',
'col' => 'id' 'col' => 'id'
), ),
); );
/** /**
* Get the value of Id / id. * Get the value of Id / id.
@ -183,7 +183,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['id']; $rtn = $this->data['id'];
return $rtn; return $rtn;
} }
@ -196,7 +195,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['project_id']; $rtn = $this->data['project_id'];
return $rtn; return $rtn;
} }
@ -209,7 +207,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['commit_id']; $rtn = $this->data['commit_id'];
return $rtn; return $rtn;
} }
@ -222,7 +219,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['status']; $rtn = $this->data['status'];
return $rtn; return $rtn;
} }
@ -235,7 +231,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['log']; $rtn = $this->data['log'];
return $rtn; return $rtn;
} }
@ -248,7 +243,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['branch']; $rtn = $this->data['branch'];
return $rtn; return $rtn;
} }
@ -261,11 +255,9 @@ class BuildBase extends Model
{ {
$rtn = $this->data['created']; $rtn = $this->data['created'];
if (!empty($rtn)) { if (!empty($rtn)) {
$rtn = new \DateTime($rtn); $rtn = new \DateTime($rtn);
} }
return $rtn; return $rtn;
} }
@ -279,11 +271,9 @@ class BuildBase extends Model
{ {
$rtn = $this->data['started']; $rtn = $this->data['started'];
if (!empty($rtn)) { if (!empty($rtn)) {
$rtn = new \DateTime($rtn); $rtn = new \DateTime($rtn);
} }
return $rtn; return $rtn;
} }
@ -297,11 +287,9 @@ class BuildBase extends Model
{ {
$rtn = $this->data['finished']; $rtn = $this->data['finished'];
if (!empty($rtn)) { if (!empty($rtn)) {
$rtn = new \DateTime($rtn); $rtn = new \DateTime($rtn);
} }
return $rtn; return $rtn;
} }
@ -315,7 +303,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['plugins']; $rtn = $this->data['plugins'];
return $rtn; return $rtn;
} }
@ -328,7 +315,6 @@ class BuildBase extends Model
{ {
$rtn = $this->data['committer_email']; $rtn = $this->data['committer_email'];
return $rtn; return $rtn;
} }
@ -342,6 +328,7 @@ class BuildBase extends Model
{ {
$this->_validateNotNull('Id', $value); $this->_validateNotNull('Id', $value);
$this->_validateInt('Id', $value); $this->_validateInt('Id', $value);
if ($this->data['id'] === $value) { if ($this->data['id'] === $value) {
return; return;
} }
@ -361,6 +348,7 @@ class BuildBase extends Model
{ {
$this->_validateNotNull('ProjectId', $value); $this->_validateNotNull('ProjectId', $value);
$this->_validateInt('ProjectId', $value); $this->_validateInt('ProjectId', $value);
if ($this->data['project_id'] === $value) { if ($this->data['project_id'] === $value) {
return; return;
} }
@ -377,8 +365,8 @@ class BuildBase extends Model
*/ */
public function setCommitId($value) public function setCommitId($value)
{ {
$this->_validateString('CommitId', $value); $this->_validateString('CommitId', $value);
if ($this->data['commit_id'] === $value) { if ($this->data['commit_id'] === $value) {
return; return;
} }
@ -398,6 +386,7 @@ class BuildBase extends Model
{ {
$this->_validateNotNull('Status', $value); $this->_validateNotNull('Status', $value);
$this->_validateInt('Status', $value); $this->_validateInt('Status', $value);
if ($this->data['status'] === $value) { if ($this->data['status'] === $value) {
return; return;
} }
@ -414,8 +403,8 @@ class BuildBase extends Model
*/ */
public function setLog($value) public function setLog($value)
{ {
$this->_validateString('Log', $value); $this->_validateString('Log', $value);
if ($this->data['log'] === $value) { if ($this->data['log'] === $value) {
return; return;
} }
@ -435,6 +424,7 @@ class BuildBase extends Model
{ {
$this->_validateNotNull('Branch', $value); $this->_validateNotNull('Branch', $value);
$this->_validateString('Branch', $value); $this->_validateString('Branch', $value);
if ($this->data['branch'] === $value) { if ($this->data['branch'] === $value) {
return; return;
} }
@ -451,8 +441,8 @@ class BuildBase extends Model
*/ */
public function setCreated($value) public function setCreated($value)
{ {
$this->_validateDate('Created', $value); $this->_validateDate('Created', $value);
if ($this->data['created'] === $value) { if ($this->data['created'] === $value) {
return; return;
} }
@ -469,8 +459,8 @@ class BuildBase extends Model
*/ */
public function setStarted($value) public function setStarted($value)
{ {
$this->_validateDate('Started', $value); $this->_validateDate('Started', $value);
if ($this->data['started'] === $value) { if ($this->data['started'] === $value) {
return; return;
} }
@ -487,8 +477,8 @@ class BuildBase extends Model
*/ */
public function setFinished($value) public function setFinished($value)
{ {
$this->_validateDate('Finished', $value); $this->_validateDate('Finished', $value);
if ($this->data['finished'] === $value) { if ($this->data['finished'] === $value) {
return; return;
} }
@ -505,8 +495,8 @@ class BuildBase extends Model
*/ */
public function setPlugins($value) public function setPlugins($value)
{ {
$this->_validateString('Plugins', $value); $this->_validateString('Plugins', $value);
if ($this->data['plugins'] === $value) { if ($this->data['plugins'] === $value) {
return; return;
} }
@ -523,8 +513,8 @@ class BuildBase extends Model
*/ */
public function setCommitterEmail($value) public function setCommitterEmail($value)
{ {
$this->_validateString('CommitterEmail', $value); $this->_validateString('CommitterEmail', $value);
if ($this->data['committer_email'] === $value) { if ($this->data['committer_email'] === $value) {
return; return;
} }
@ -553,7 +543,7 @@ class BuildBase extends Model
$rtn = $this->cache->get($cacheKey, null); $rtn = $this->cache->get($cacheKey, null);
if (empty($rtn)) { if (empty($rtn)) {
$rtn = \b8\Store\Factory::getStore('Project')->getById($key); $rtn = Factory::getStore('Project')->getById($key);
$this->cache->set($cacheKey, $rtn); $this->cache->set($cacheKey, $rtn);
} }
@ -600,6 +590,6 @@ class BuildBase extends Model
*/ */
public function getBuildBuildMetas() public function getBuildBuildMetas()
{ {
return \b8\Store\Factory::getStore('BuildMeta')->getByBuildId($this->getId()); return Factory::getStore('BuildMeta')->getByBuildId($this->getId());
} }
} }

View file

@ -7,6 +7,7 @@
namespace PHPCI\Model\Base; namespace PHPCI\Model\Base;
use b8\Model; use b8\Model;
use b8\Store\Factory;
/** /**
* BuildMeta Base Model * BuildMeta Base Model
@ -37,31 +38,37 @@ class BuildMetaBase extends Model
'build_id' => null, 'build_id' => null,
'meta_key' => null, 'meta_key' => null,
'meta_value' => null, 'meta_value' => null,
); );
/** /**
* @var array * @var array
*/ */
protected $getters = array( protected $getters = array(
// Direct property getters:
'id' => 'getId', 'id' => 'getId',
'project_id' => 'getProjectId', 'project_id' => 'getProjectId',
'build_id' => 'getBuildId', 'build_id' => 'getBuildId',
'meta_key' => 'getMetaKey', 'meta_key' => 'getMetaKey',
'meta_value' => 'getMetaValue', 'meta_value' => 'getMetaValue',
// Foreign key getters:
'Build' => 'getBuild', 'Build' => 'getBuild',
); );
/** /**
* @var array * @var array
*/ */
protected $setters = array( protected $setters = array(
// Direct property setters:
'id' => 'setId', 'id' => 'setId',
'project_id' => 'setProjectId', 'project_id' => 'setProjectId',
'build_id' => 'setBuildId', 'build_id' => 'setBuildId',
'meta_key' => 'setMetaKey', 'meta_key' => 'setMetaKey',
'meta_value' => 'setMetaValue', 'meta_value' => 'setMetaValue',
// Foreign key setters:
'Build' => 'setBuild', 'Build' => 'setBuild',
); );
/** /**
* @var array * @var array
@ -69,34 +76,32 @@ class BuildMetaBase extends Model
public $columns = array( public $columns = array(
'id' => array( 'id' => array(
'type' => 'int', 'type' => 'int',
'length' => '10', 'length' => 10,
'primary_key' => true, 'primary_key' => true,
'auto_increment' => true, 'auto_increment' => true,
'default' => null, 'default' => null,
), ),
'project_id' => array( 'project_id' => array(
'type' => 'int', 'type' => 'int',
'length' => '11', 'length' => 11,
'default' => null, 'default' => null,
), ),
'build_id' => array( 'build_id' => array(
'type' => 'int', 'type' => 'int',
'length' => '11', 'length' => 11,
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'meta_key' => array( 'meta_key' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '255', 'length' => 255,
'default' => '', ),
),
'meta_value' => array( 'meta_value' => array(
'type' => 'text', 'type' => 'text',
'length' => '',
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
); );
/** /**
* @var array * @var array
@ -104,7 +109,7 @@ class BuildMetaBase extends Model
public $indexes = array( public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'), 'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'idx_meta_id' => array('unique' => true, 'columns' => 'build_id, meta_key'), 'idx_meta_id' => array('unique' => true, 'columns' => 'build_id, meta_key'),
); );
/** /**
* @var array * @var array
@ -117,8 +122,7 @@ class BuildMetaBase extends Model
'table' => 'build', 'table' => 'build',
'col' => 'id' 'col' => 'id'
), ),
); );
/** /**
* Get the value of Id / id. * Get the value of Id / id.
@ -129,7 +133,6 @@ class BuildMetaBase extends Model
{ {
$rtn = $this->data['id']; $rtn = $this->data['id'];
return $rtn; return $rtn;
} }
@ -142,7 +145,6 @@ class BuildMetaBase extends Model
{ {
$rtn = $this->data['project_id']; $rtn = $this->data['project_id'];
return $rtn; return $rtn;
} }
@ -155,7 +157,6 @@ class BuildMetaBase extends Model
{ {
$rtn = $this->data['build_id']; $rtn = $this->data['build_id'];
return $rtn; return $rtn;
} }
@ -168,7 +169,6 @@ class BuildMetaBase extends Model
{ {
$rtn = $this->data['meta_key']; $rtn = $this->data['meta_key'];
return $rtn; return $rtn;
} }
@ -181,7 +181,6 @@ class BuildMetaBase extends Model
{ {
$rtn = $this->data['meta_value']; $rtn = $this->data['meta_value'];
return $rtn; return $rtn;
} }
@ -195,6 +194,7 @@ class BuildMetaBase extends Model
{ {
$this->_validateNotNull('Id', $value); $this->_validateNotNull('Id', $value);
$this->_validateInt('Id', $value); $this->_validateInt('Id', $value);
if ($this->data['id'] === $value) { if ($this->data['id'] === $value) {
return; return;
} }
@ -214,6 +214,7 @@ class BuildMetaBase extends Model
{ {
$this->_validateNotNull('ProjectId', $value); $this->_validateNotNull('ProjectId', $value);
$this->_validateInt('ProjectId', $value); $this->_validateInt('ProjectId', $value);
if ($this->data['project_id'] === $value) { if ($this->data['project_id'] === $value) {
return; return;
} }
@ -230,8 +231,8 @@ class BuildMetaBase extends Model
*/ */
public function setBuildId($value) public function setBuildId($value)
{ {
$this->_validateInt('BuildId', $value); $this->_validateInt('BuildId', $value);
if ($this->data['build_id'] === $value) { if ($this->data['build_id'] === $value) {
return; return;
} }
@ -251,6 +252,7 @@ class BuildMetaBase extends Model
{ {
$this->_validateNotNull('MetaKey', $value); $this->_validateNotNull('MetaKey', $value);
$this->_validateString('MetaKey', $value); $this->_validateString('MetaKey', $value);
if ($this->data['meta_key'] === $value) { if ($this->data['meta_key'] === $value) {
return; return;
} }
@ -267,8 +269,8 @@ class BuildMetaBase extends Model
*/ */
public function setMetaValue($value) public function setMetaValue($value)
{ {
$this->_validateString('MetaValue', $value); $this->_validateString('MetaValue', $value);
if ($this->data['meta_value'] === $value) { if ($this->data['meta_value'] === $value) {
return; return;
} }
@ -297,7 +299,7 @@ class BuildMetaBase extends Model
$rtn = $this->cache->get($cacheKey, null); $rtn = $this->cache->get($cacheKey, null);
if (empty($rtn)) { if (empty($rtn)) {
$rtn = \b8\Store\Factory::getStore('Build')->getById($key); $rtn = Factory::getStore('Build')->getById($key);
$this->cache->set($cacheKey, $rtn); $this->cache->set($cacheKey, $rtn);
} }

View file

@ -7,6 +7,7 @@
namespace PHPCI\Model\Base; namespace PHPCI\Model\Base;
use b8\Model; use b8\Model;
use b8\Store\Factory;
/** /**
* Project Base Model * Project Base Model
@ -39,12 +40,13 @@ class ProjectBase extends Model
'type' => null, 'type' => null,
'token' => null, 'token' => null,
'access_information' => null, 'access_information' => null,
); );
/** /**
* @var array * @var array
*/ */
protected $getters = array( protected $getters = array(
// Direct property getters:
'id' => 'getId', 'id' => 'getId',
'title' => 'getTitle', 'title' => 'getTitle',
'reference' => 'getReference', 'reference' => 'getReference',
@ -52,12 +54,15 @@ class ProjectBase extends Model
'type' => 'getType', 'type' => 'getType',
'token' => 'getToken', 'token' => 'getToken',
'access_information' => 'getAccessInformation', 'access_information' => 'getAccessInformation',
);
// Foreign key getters:
);
/** /**
* @var array * @var array
*/ */
protected $setters = array( protected $setters = array(
// Direct property setters:
'id' => 'setId', 'id' => 'setId',
'title' => 'setTitle', 'title' => 'setTitle',
'reference' => 'setReference', 'reference' => 'setReference',
@ -65,7 +70,9 @@ class ProjectBase extends Model
'type' => 'setType', 'type' => 'setType',
'token' => 'setToken', 'token' => 'setToken',
'access_information' => 'setAccessInformation', 'access_information' => 'setAccessInformation',
);
// Foreign key setters:
);
/** /**
* @var array * @var array
@ -73,59 +80,56 @@ class ProjectBase extends Model
public $columns = array( public $columns = array(
'id' => array( 'id' => array(
'type' => 'int', 'type' => 'int',
'length' => '11', 'length' => 11,
'primary_key' => true, 'primary_key' => true,
'auto_increment' => true, 'auto_increment' => true,
'default' => null, 'default' => null,
), ),
'title' => array( 'title' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '250', 'length' => 250,
'default' => '', ),
),
'reference' => array( 'reference' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '250', 'length' => 250,
'default' => '', ),
),
'git_key' => array( 'git_key' => array(
'type' => 'text', 'type' => 'text',
'length' => '',
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'type' => array( 'type' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '50', 'length' => 50,
'default' => '1', 'default' => 1,
), ),
'token' => array( 'token' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '50', 'length' => 50,
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
'access_information' => array( 'access_information' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '250', 'length' => 250,
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
); );
/** /**
* @var array * @var array
*/ */
public $indexes = array( public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'), 'PRIMARY' => array('unique' => true, 'columns' => 'id'),
); 'idx_project_title' => array('columns' => 'title'),
);
/** /**
* @var array * @var array
*/ */
public $foreignKeys = array( public $foreignKeys = array(
); );
/** /**
* Get the value of Id / id. * Get the value of Id / id.
@ -136,7 +140,6 @@ class ProjectBase extends Model
{ {
$rtn = $this->data['id']; $rtn = $this->data['id'];
return $rtn; return $rtn;
} }
@ -149,7 +152,6 @@ class ProjectBase extends Model
{ {
$rtn = $this->data['title']; $rtn = $this->data['title'];
return $rtn; return $rtn;
} }
@ -162,7 +164,6 @@ class ProjectBase extends Model
{ {
$rtn = $this->data['reference']; $rtn = $this->data['reference'];
return $rtn; return $rtn;
} }
@ -175,7 +176,6 @@ class ProjectBase extends Model
{ {
$rtn = $this->data['git_key']; $rtn = $this->data['git_key'];
return $rtn; return $rtn;
} }
@ -188,7 +188,6 @@ class ProjectBase extends Model
{ {
$rtn = $this->data['type']; $rtn = $this->data['type'];
return $rtn; return $rtn;
} }
@ -201,7 +200,6 @@ class ProjectBase extends Model
{ {
$rtn = $this->data['token']; $rtn = $this->data['token'];
return $rtn; return $rtn;
} }
@ -214,7 +212,6 @@ class ProjectBase extends Model
{ {
$rtn = $this->data['access_information']; $rtn = $this->data['access_information'];
return $rtn; return $rtn;
} }
@ -228,6 +225,7 @@ class ProjectBase extends Model
{ {
$this->_validateNotNull('Id', $value); $this->_validateNotNull('Id', $value);
$this->_validateInt('Id', $value); $this->_validateInt('Id', $value);
if ($this->data['id'] === $value) { if ($this->data['id'] === $value) {
return; return;
} }
@ -247,6 +245,7 @@ class ProjectBase extends Model
{ {
$this->_validateNotNull('Title', $value); $this->_validateNotNull('Title', $value);
$this->_validateString('Title', $value); $this->_validateString('Title', $value);
if ($this->data['title'] === $value) { if ($this->data['title'] === $value) {
return; return;
} }
@ -266,6 +265,7 @@ class ProjectBase extends Model
{ {
$this->_validateNotNull('Reference', $value); $this->_validateNotNull('Reference', $value);
$this->_validateString('Reference', $value); $this->_validateString('Reference', $value);
if ($this->data['reference'] === $value) { if ($this->data['reference'] === $value) {
return; return;
} }
@ -282,8 +282,8 @@ class ProjectBase extends Model
*/ */
public function setGitKey($value) public function setGitKey($value)
{ {
$this->_validateString('GitKey', $value); $this->_validateString('GitKey', $value);
if ($this->data['git_key'] === $value) { if ($this->data['git_key'] === $value) {
return; return;
} }
@ -303,6 +303,7 @@ class ProjectBase extends Model
{ {
$this->_validateNotNull('Type', $value); $this->_validateNotNull('Type', $value);
$this->_validateString('Type', $value); $this->_validateString('Type', $value);
if ($this->data['type'] === $value) { if ($this->data['type'] === $value) {
return; return;
} }
@ -319,8 +320,8 @@ class ProjectBase extends Model
*/ */
public function setToken($value) public function setToken($value)
{ {
$this->_validateString('Token', $value); $this->_validateString('Token', $value);
if ($this->data['token'] === $value) { if ($this->data['token'] === $value) {
return; return;
} }
@ -337,8 +338,8 @@ class ProjectBase extends Model
*/ */
public function setAccessInformation($value) public function setAccessInformation($value)
{ {
$this->_validateString('AccessInformation', $value); $this->_validateString('AccessInformation', $value);
if ($this->data['access_information'] === $value) { if ($this->data['access_information'] === $value) {
return; return;
} }
@ -357,6 +358,6 @@ class ProjectBase extends Model
*/ */
public function getProjectBuilds() public function getProjectBuilds()
{ {
return \b8\Store\Factory::getStore('Build')->getByProjectId($this->getId()); return Factory::getStore('Build')->getByProjectId($this->getId());
} }
} }

View file

@ -7,6 +7,7 @@
namespace PHPCI\Model\Base; namespace PHPCI\Model\Base;
use b8\Model; use b8\Model;
use b8\Store\Factory;
/** /**
* User Base Model * User Base Model
@ -37,29 +38,35 @@ class UserBase extends Model
'hash' => null, 'hash' => null,
'is_admin' => null, 'is_admin' => null,
'name' => null, 'name' => null,
); );
/** /**
* @var array * @var array
*/ */
protected $getters = array( protected $getters = array(
// Direct property getters:
'id' => 'getId', 'id' => 'getId',
'email' => 'getEmail', 'email' => 'getEmail',
'hash' => 'getHash', 'hash' => 'getHash',
'is_admin' => 'getIsAdmin', 'is_admin' => 'getIsAdmin',
'name' => 'getName', 'name' => 'getName',
);
// Foreign key getters:
);
/** /**
* @var array * @var array
*/ */
protected $setters = array( protected $setters = array(
// Direct property setters:
'id' => 'setId', 'id' => 'setId',
'email' => 'setEmail', 'email' => 'setEmail',
'hash' => 'setHash', 'hash' => 'setHash',
'is_admin' => 'setIsAdmin', 'is_admin' => 'setIsAdmin',
'name' => 'setName', 'name' => 'setName',
);
// Foreign key setters:
);
/** /**
* @var array * @var array
@ -67,33 +74,30 @@ class UserBase extends Model
public $columns = array( public $columns = array(
'id' => array( 'id' => array(
'type' => 'int', 'type' => 'int',
'length' => '11', 'length' => 11,
'primary_key' => true, 'primary_key' => true,
'auto_increment' => true, 'auto_increment' => true,
'default' => null, 'default' => null,
), ),
'email' => array( 'email' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '250', 'length' => 250,
'default' => '', ),
),
'hash' => array( 'hash' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '250', 'length' => 250,
'default' => '', ),
),
'is_admin' => array( 'is_admin' => array(
'type' => 'tinyint', 'type' => 'tinyint',
'length' => '1', 'length' => 1,
'default' => '0', ),
),
'name' => array( 'name' => array(
'type' => 'varchar', 'type' => 'varchar',
'length' => '250', 'length' => 250,
'nullable' => true, 'nullable' => true,
'default' => null, 'default' => null,
), ),
); );
/** /**
* @var array * @var array
@ -101,14 +105,13 @@ class UserBase extends Model
public $indexes = array( public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'), 'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'idx_email' => array('unique' => true, 'columns' => 'email'), 'idx_email' => array('unique' => true, 'columns' => 'email'),
); );
/** /**
* @var array * @var array
*/ */
public $foreignKeys = array( public $foreignKeys = array(
); );
/** /**
* Get the value of Id / id. * Get the value of Id / id.
@ -119,7 +122,6 @@ class UserBase extends Model
{ {
$rtn = $this->data['id']; $rtn = $this->data['id'];
return $rtn; return $rtn;
} }
@ -132,7 +134,6 @@ class UserBase extends Model
{ {
$rtn = $this->data['email']; $rtn = $this->data['email'];
return $rtn; return $rtn;
} }
@ -145,7 +146,6 @@ class UserBase extends Model
{ {
$rtn = $this->data['hash']; $rtn = $this->data['hash'];
return $rtn; return $rtn;
} }
@ -158,7 +158,6 @@ class UserBase extends Model
{ {
$rtn = $this->data['is_admin']; $rtn = $this->data['is_admin'];
return $rtn; return $rtn;
} }
@ -171,7 +170,6 @@ class UserBase extends Model
{ {
$rtn = $this->data['name']; $rtn = $this->data['name'];
return $rtn; return $rtn;
} }
@ -185,6 +183,7 @@ class UserBase extends Model
{ {
$this->_validateNotNull('Id', $value); $this->_validateNotNull('Id', $value);
$this->_validateInt('Id', $value); $this->_validateInt('Id', $value);
if ($this->data['id'] === $value) { if ($this->data['id'] === $value) {
return; return;
} }
@ -204,6 +203,7 @@ class UserBase extends Model
{ {
$this->_validateNotNull('Email', $value); $this->_validateNotNull('Email', $value);
$this->_validateString('Email', $value); $this->_validateString('Email', $value);
if ($this->data['email'] === $value) { if ($this->data['email'] === $value) {
return; return;
} }
@ -223,6 +223,7 @@ class UserBase extends Model
{ {
$this->_validateNotNull('Hash', $value); $this->_validateNotNull('Hash', $value);
$this->_validateString('Hash', $value); $this->_validateString('Hash', $value);
if ($this->data['hash'] === $value) { if ($this->data['hash'] === $value) {
return; return;
} }
@ -242,6 +243,7 @@ class UserBase extends Model
{ {
$this->_validateNotNull('IsAdmin', $value); $this->_validateNotNull('IsAdmin', $value);
$this->_validateInt('IsAdmin', $value); $this->_validateInt('IsAdmin', $value);
if ($this->data['is_admin'] === $value) { if ($this->data['is_admin'] === $value) {
return; return;
} }
@ -258,8 +260,8 @@ class UserBase extends Model
*/ */
public function setName($value) public function setName($value)
{ {
$this->_validateString('Name', $value); $this->_validateString('Name', $value);
if ($this->data['name'] === $value) { if ($this->data['name'] === $value) {
return; return;
} }

View file

@ -9,8 +9,8 @@
namespace PHPCI\Model; namespace PHPCI\Model;
use b8\Store\Factory;
use PHPCI\Model\Base\BuildBase; use PHPCI\Model\Base\BuildBase;
use PHPCI\Builder;
/** /**
* Build Model * Build Model
@ -21,6 +21,11 @@ use PHPCI\Builder;
*/ */
class Build extends BuildBase class Build extends BuildBase
{ {
const STATUS_NEW = 0;
const STATUS_RUNNING = 1;
const STATUS_SUCCESS = 2;
const STATUS_FAILED = 3;
/** /**
* Get link to commit from another source (i.e. Github) * Get link to commit from another source (i.e. Github)
*/ */
@ -46,9 +51,19 @@ class Build extends BuildBase
} }
/** /**
* Create a working copy by cloning, copying, or similar. * Store build metadata
*/ */
public function createWorkingCopy(Builder $builder, $buildPath) public function storeMeta($key, $value)
{ {
$value = json_encode($value);
Factory::getStore('Build')->setMeta($this->getProjectId(), $this->getId(), $key, $value);
}
/**
* Is this build successful?
*/
public function isSuccessful()
{
return ($this->getStatus() === self::STATUS_SUCCESS);
} }
} }

View file

@ -29,44 +29,68 @@ class LocalBuild extends Build
$reference = $this->getProject()->getReference(); $reference = $this->getProject()->getReference();
$reference = substr($reference, -1) == '/' ? substr($reference, 0, -1) : $reference; $reference = substr($reference, -1) == '/' ? substr($reference, 0, -1) : $reference;
$buildPath = substr($buildPath, 0, -1); $buildPath = substr($buildPath, 0, -1);
$yamlParser = new YamlParser();
// If there's a /config file in the reference directory, it is probably a bare repository
if(is_file($reference.'/config')) { // which we'll extract into our build path directly.
//We're probably looing at a bare repository. We'll open the config and check if(is_file($reference.'/config') && $this->handleBareRepository($builder, $reference, $buildPath) === true) {
$gitConfig = parse_ini_file($reference.'/config',TRUE); return true;
if($gitConfig["core"]["bare"]) {
// Looks like we're right. We need to extract the archive!
$guid = uniqid();
$builder->executeCommand('mkdir "/tmp/%s" && git --git-dir="%s" archive master | tar -x -C "/tmp/%s"', $guid, $reference, $guid);
$reference = '/tmp/'.$guid;
}
} }
if (!is_file($reference . '/phpci.yml')) { $buildSettings = $this->handleConfig($builder, $reference);
$builder->logFailure('Project does not contain a phpci.yml file.');
if ($buildSettings === false) {
return false; return false;
} }
$yamlFile = file_get_contents($reference . '/phpci.yml');
$builder->setConfigArray($yamlParser->parse($yamlFile));
$buildSettings = $builder->getConfig('build_settings');
if (isset($buildSettings['prefer_symlink']) && $buildSettings['prefer_symlink'] === true) { if (isset($buildSettings['prefer_symlink']) && $buildSettings['prefer_symlink'] === true) {
if (is_link($buildPath) && is_file($buildPath)) { return $this->handleSymlink($builder, $reference, $buildPath);
unlink($buildPath);
}
$builder->log(sprintf('Symlinking: %s to %s', $reference, $buildPath));
if (!symlink($reference, $buildPath)) {
$builder->logFailure('Failed to symlink.');
return false;
}
} else { } else {
$builder->executeCommand('cp -Rf "%s" "%s/"', $reference, $buildPath); $builder->executeCommand('cp -Rf "%s" "%s/"', $reference, $buildPath);
} }
return true; return true;
} }
protected function handleBareRepository(Builder $builder, $reference, $buildPath)
{
$gitConfig = parse_ini_file($reference.'/config', true);
// If it is indeed a bare repository, then extract it into our build path:
if($gitConfig['core']['bare']) {
$builder->executeCommand('git --git-dir="%s" archive master | tar -x -C "%s"', $reference, $buildPath);
return true;
}
return false;
}
protected function handleSymlink(Builder $builder, $reference, $buildPath)
{
if (is_link($buildPath) && is_file($buildPath)) {
unlink($buildPath);
}
$builder->log(sprintf('Symlinking: %s to %s', $reference, $buildPath));
if (!symlink($reference, $buildPath)) {
$builder->logFailure('Failed to symlink.');
return false;
}
return true;
}
protected function handleConfig(Builder $builder, $reference)
{
/** @todo Add support for database-based yml definition */
if (!is_file($reference . '/phpci.yml')) {
$builder->logFailure('Project does not contain a phpci.yml file.');
return false;
}
$yamlParser = new YamlParser();
$yamlFile = file_get_contents($reference . '/phpci.yml');
$builder->setConfigArray($yamlParser->parse($yamlFile));
return $builder->getConfig('build_settings');
}
} }

View file

@ -52,8 +52,8 @@ class MercurialBuild extends Build
/** /**
* Use an mercurial clone. * Use an mercurial clone.
*/ */
protected function cloneByHttp(Builder $builder, $to) protected function cloneByHttp(Builder $builder, $cloneTo)
{ {
return $builder->executeCommand('hg clone %s "%s" -r %s', $this->getCloneUrl(), $to, $this->getBranch()); return $builder->executeCommand('hg clone %s "%s" -r %s', $this->getCloneUrl(), $cloneTo, $this->getBranch());
} }
} }

View file

@ -63,21 +63,21 @@ class RemoteGitBuild extends Build
/** /**
* Use an HTTP-based git clone. * Use an HTTP-based git clone.
*/ */
protected function cloneByHttp(Builder $builder, $to) protected function cloneByHttp(Builder $builder, $cloneTo)
{ {
return $builder->executeCommand('git clone -b %s %s "%s"', $this->getBranch(), $this->getCloneUrl(), $to); return $builder->executeCommand('git clone -b %s %s "%s"', $this->getBranch(), $this->getCloneUrl(), $cloneTo);
} }
/** /**
* Use an SSH-based git clone. * Use an SSH-based git clone.
*/ */
protected function cloneBySsh(Builder $builder, $to) protected function cloneBySsh(Builder $builder, $cloneTo)
{ {
// Copy the project's keyfile to disk: // Copy the project's keyfile to disk:
$keyPath = realpath($to); $keyPath = realpath($cloneTo);
if ($keyPath === false) { if ($keyPath === false) {
$keyPath = dirname($to); $keyPath = dirname($cloneTo);
} }
$keyFile = $keyPath . '.key'; $keyFile = $keyPath . '.key';
@ -87,7 +87,7 @@ class RemoteGitBuild extends Build
// Use the key file to do an SSH clone: // Use the key file to do an SSH clone:
$cmd = 'eval `ssh-agent -s` && ssh-add "%s" && git clone -b %s %s "%s" && ssh-agent -k'; $cmd = 'eval `ssh-agent -s` && ssh-add "%s" && git clone -b %s %s "%s" && ssh-agent -k';
$success = $builder->executeCommand($cmd, $keyFile, $this->getBranch(), $this->getCloneUrl(), $to); $success = $builder->executeCommand($cmd, $keyFile, $this->getBranch(), $this->getCloneUrl(), $cloneTo);
// Remove the key file: // Remove the key file:
unlink($keyFile); unlink($keyFile);

View file

@ -9,12 +9,15 @@
namespace PHPCI; namespace PHPCI;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHPCI Plugin Interface - Used by all build plugins. * PHPCI Plugin Interface - Used by all build plugins.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
*/ */
interface Plugin interface Plugin
{ {
public function __construct(\PHPCI\Builder $phpci, array $options = array()); public function __construct(Builder $phpci, Build $build, array $options = array());
public function execute(); public function execute();
} }

View file

@ -2,15 +2,19 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
class Atoum implements \PHPCI\Plugin class Atoum implements \PHPCI\Plugin
{ {
private $args; private $args;
private $config; private $config;
private $directory; private $directory;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->build = $build;
if (isset($options['executable'])) { if (isset($options['executable'])) {
$this->executable = $this->phpci->buildPath . DIRECTORY_SEPARATOR.$options['executable']; $this->executable = $this->phpci->buildPath . DIRECTORY_SEPARATOR.$options['executable'];
@ -50,7 +54,7 @@ class Atoum implements \PHPCI\Plugin
$status = true; $status = true;
exec($cmd, $output); exec($cmd, $output);
if (count(preg_grep("/Success \(/", $output)) == 0 ) { if (count(preg_grep("/Success \(/", $output)) == 0) {
$status = false; $status = false;
$this->phpci->log($output, ' '); $this->phpci->log($output, ' ');
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Behat BDD Plugin * Behat BDD Plugin
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -18,10 +21,16 @@ namespace PHPCI\Plugin;
class Behat implements \PHPCI\Plugin class Behat implements \PHPCI\Plugin
{ {
protected $phpci; protected $phpci;
protected $features;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->features = '';
if (!empty($options['features'])) {
$this->features = $options['features'];
}
} }
/** /**
@ -32,14 +41,14 @@ class Behat implements \PHPCI\Plugin
$curdir = getcwd(); $curdir = getcwd();
chdir($this->phpci->buildPath); chdir($this->phpci->buildPath);
$phpspec = $this->phpci->findBinary('phpspec'); $behat = $this->phpci->findBinary('behat');
if (!$phpspec) { if (!$behat) {
$this->phpci->logFailure('Could not find phpspec.'); $this->phpci->logFailure('Could not find behat.');
return false; return false;
} }
$success = $this->phpci->executeCommand($phpspec); $success = $this->phpci->executeCommand($behat . ' --no-time --format="failed" %s', $this->features);
chdir($curdir); chdir($curdir);
return $success; return $success;

View file

@ -1,6 +1,10 @@
<?php <?php
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Campfire Plugin - Allows Campfire API actions. * Campfire Plugin - Allows Campfire API actions.
* strongly based on icecube (http://labs.mimmin.com/icecube) * strongly based on icecube (http://labs.mimmin.com/icecube)
@ -10,10 +14,6 @@ namespace PHPCI\Plugin;
*/ */
class Campfire implements \PHPCI\Plugin class Campfire implements \PHPCI\Plugin
{ {
private $args;
private $config;
private $directory;
private $url; private $url;
private $authToken; private $authToken;
private $userAgent; private $userAgent;
@ -21,12 +21,13 @@ class Campfire implements \PHPCI\Plugin
private $verbose; private $verbose;
private $roomId; private $roomId;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->build = $build;
$this->message = $options['message']; $this->message = $options['message'];
$this->userAgent = "Phpci/1.0 (http://www.phptesting.org/)"; $this->userAgent = "PHPCI/1.0 (+http://www.phptesting.org/)";
$this->cookie = "phpcicookie"; $this->cookie = "phpcicookie";
$buildSettings = $phpci->getConfig('build_settings'); $buildSettings = $phpci->getConfig('build_settings');
@ -36,14 +37,14 @@ class Campfire implements \PHPCI\Plugin
$this->authToken = $campfire['authToken']; $this->authToken = $campfire['authToken'];
$this->roomId = $campfire['roomId']; $this->roomId = $campfire['roomId'];
} else { } else {
throw new \Exception("No connexion parameters given for Campfire plugin"); throw new \Exception("No connection parameters given for Campfire plugin");
} }
} }
public function execute() public function execute()
{ {
$url = PHPCI_URL."build/view/".$this->phpci->getBuild()->getId(); $url = PHPCI_URL."build/view/".$this->build->getId();
$message = str_replace("%buildurl%", $url, $this->message); $message = str_replace("%buildurl%", $url, $this->message);
$this->joinRoom($this->roomId); $this->joinRoom($this->roomId);
$status = $this->speak($message, $this->roomId); $status = $this->speak($message, $this->roomId);
@ -52,19 +53,15 @@ class Campfire implements \PHPCI\Plugin
return $status; return $status;
} }
public function joinRoom($roomId) public function joinRoom($roomId)
{ {
$this->_getPageByPost('/room/'.$roomId.'/join.json'); $this->getPageByPost('/room/'.$roomId.'/join.json');
} }
public function leaveRoom($roomId) public function leaveRoom($roomId)
{ {
$this->_getPageByPost('/room/'.$roomId.'/leave.json'); $this->getPageByPost('/room/'.$roomId.'/leave.json');
}
public function logout()
{
// New API is stateless, no concept of logout
} }
public function speak($message, $roomId, $isPaste = false) public function speak($message, $roomId, $isPaste = false)
@ -76,12 +73,11 @@ class Campfire implements \PHPCI\Plugin
$type = 'TextMessage'; $type = 'TextMessage';
} }
return $this->_getPageByPost($page, return $this->getPageByPost($page, array('message' => array('type' => $type, 'body' => $message)));
array('message' => array('type' => $type, 'body' => $message)));
} }
private function _getPageByPost($page, $data = null) private function getPageByPost($page, $data = null)
{ {
$url = $this->url . $page; $url = $this->url . $page;
// The new API allows JSON, so we can pass // The new API allows JSON, so we can pass
@ -89,21 +85,21 @@ class Campfire implements \PHPCI\Plugin
$json = json_encode($data); $json = json_encode($data);
// cURL init & config // cURL init & config
$ch = curl_init(); $handle = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($handle, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($handle, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent); curl_setopt($handle, CURLOPT_USERAGENT, $this->userAgent);
curl_setopt($ch, CURLOPT_VERBOSE, $this->verbose); curl_setopt($handle, CURLOPT_VERBOSE, $this->verbose);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($handle, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_USERPWD, $this->authToken . ':x'); curl_setopt($handle, CURLOPT_USERPWD, $this->authToken . ':x');
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: application/json")); curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookie); curl_setopt($handle, CURLOPT_COOKIEFILE, $this->cookie);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json); curl_setopt($handle, CURLOPT_POSTFIELDS, $json);
$output = curl_exec($ch); $output = curl_exec($handle);
curl_close($ch); curl_close($handle);
// We tend to get one space with an otherwise blank response // We tend to get one space with an otherwise blank response
$output = trim($output); $output = trim($output);

View file

@ -9,6 +9,8 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Clean build removes Composer related files and allows PHPCI users to clean up their build directory. * Clean build removes Composer related files and allows PHPCI users to clean up their build directory.
* Useful as a precursor to copy_build. * Useful as a precursor to copy_build.
@ -21,9 +23,8 @@ class CleanBuild implements \PHPCI\Plugin
protected $remove; protected $remove;
protected $phpci; protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$path = $phpci->buildPath;
$this->phpci = $phpci; $this->phpci = $phpci;
$this->remove = isset($options['remove']) && is_array($options['remove']) ? $options['remove'] : array(); $this->remove = isset($options['remove']) && is_array($options['remove']) ? $options['remove'] : array();
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Codeception Plugin - Enables full acceptance, unit, and functional testing. * Codeception Plugin - Enables full acceptance, unit, and functional testing.
* @author Don Gilbert <don@dongilbert.net> * @author Don Gilbert <don@dongilbert.net>
@ -25,7 +28,7 @@ class Codeception implements \PHPCI\Plugin
*/ */
protected $xmlConfigFile; protected $xmlConfigFile;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
@ -81,4 +84,4 @@ class Codeception implements \PHPCI\Plugin
} }
return $success; return $success;
} }
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Composer Plugin - Provides access to Composer functionality. * Composer Plugin - Provides access to Composer functionality.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -22,7 +25,7 @@ class Composer implements \PHPCI\Plugin
protected $preferDist; protected $preferDist;
protected $phpci; protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$path = $phpci->buildPath; $path = $phpci->buildPath;
$this->phpci = $phpci; $this->phpci = $phpci;
@ -43,7 +46,8 @@ class Composer implements \PHPCI\Plugin
return false; return false;
} }
$cmd = $composerLocation . ' --no-ansi --no-interaction '. ($this->preferDist ? '--prefer-dist' : null) .' --working-dir="%s" %s'; $cmd = $composerLocation . ' --no-ansi --no-interaction ';
$cmd .= ($this->preferDist ? '--prefer-dist' : null) . ' --working-dir="%s" %s';
return $this->phpci->executeCommand($cmd, $this->directory, $this->action); return $this->phpci->executeCommand($cmd, $this->directory, $this->action);
} }

View file

@ -9,6 +9,8 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Copy Build Plugin - Copies the entire build to another directory. * Copy Build Plugin - Copies the entire build to another directory.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -20,7 +22,7 @@ class CopyBuild implements \PHPCI\Plugin
protected $directory; protected $directory;
protected $phpci; protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$path = $phpci->buildPath; $path = $phpci->buildPath;
$this->phpci = $phpci; $this->phpci = $phpci;

View file

@ -9,6 +9,8 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Email Plugin - Provides simple email capability to PHPCI. * Email Plugin - Provides simple email capability to PHPCI.
@ -18,7 +20,6 @@ namespace PHPCI\Plugin;
*/ */
class Email implements \PHPCI\Plugin class Email implements \PHPCI\Plugin
{ {
/** /**
* @var \PHPCI\Builder * @var \PHPCI\Builder
*/ */
@ -39,23 +40,15 @@ class Email implements \PHPCI\Plugin
*/ */
protected $mailer; protected $mailer;
public function __construct(\PHPCI\Builder $phpci, public function __construct(Builder $phpci, Build $build, array $options = array())
array $options = array(),
\Swift_Mailer $mailer = null)
{ {
$phpCiSettings = $phpci->getSystemConfig('phpci'); $phpCiSettings = $phpci->getSystemConfig('phpci');
$this->phpci = $phpci; $this->phpci = $phpci;
$this->build = $build;
$this->options = $options; $this->options = $options;
$this->emailConfig = isset($phpCiSettings['email_settings']) ? $phpCiSettings['email_settings'] : array(); $this->emailConfig = isset($phpCiSettings['email_settings']) ? $phpCiSettings['email_settings'] : array();
// Either a mailer will have been passed in or we load from the $this->loadSwiftMailerFromConfig();
// config.
if ($mailer === null) {
$this->loadSwiftMailerFromConfig();
}
else {
$this->mailer = $mailer;
}
} }
/** /**
@ -71,20 +64,17 @@ class Email implements \PHPCI\Plugin
return false; return false;
} }
$sendFailures = array();
$subjectTemplate = "PHPCI - %s - %s"; $subjectTemplate = "PHPCI - %s - %s";
$projectName = $this->phpci->getBuildProjectTitle(); $projectName = $this->phpci->getBuildProjectTitle();
$logText = $this->phpci->getBuild()->getLog(); $logText = $this->build->getLog();
if($this->phpci->getSuccessStatus()) { if ($this->build->isSuccessful()) {
$sendFailures = $this->sendSeparateEmails( $sendFailures = $this->sendSeparateEmails(
$addresses, $addresses,
sprintf($subjectTemplate, $projectName, "Passing Build"), sprintf($subjectTemplate, $projectName, "Passing Build"),
sprintf("Log Output: <br><pre>%s</pre>", $logText) sprintf("Log Output: <br><pre>%s</pre>", $logText)
); );
} } else {
else {
$sendFailures = $this->sendSeparateEmails( $sendFailures = $this->sendSeparateEmails(
$addresses, $addresses,
sprintf($subjectTemplate, $projectName, "Failing Build"), sprintf($subjectTemplate, $projectName, "Failing Build"),
@ -93,14 +83,9 @@ class Email implements \PHPCI\Plugin
} }
// This is a success if we've not failed to send anything. // This is a success if we've not failed to send anything.
$this->phpci->log(sprintf( $this->phpci->log(sprintf("%d emails sent", (count($addresses) - count($sendFailures))));
"%d emails sent", $this->phpci->log(sprintf("%d emails failed to send", count($sendFailures)));
(count($addresses) - count($sendFailures)))
);
$this->phpci->log(sprintf(
"%d emails failed to send",
count($sendFailures))
);
return (count($sendFailures) == 0); return (count($sendFailures) == 0);
} }
@ -126,9 +111,9 @@ class Email implements \PHPCI\Plugin
public function sendSeparateEmails(array $toAddresses, $subject, $body) public function sendSeparateEmails(array $toAddresses, $subject, $body)
{ {
$failures = array(); $failures = array();
foreach($toAddresses as $address) { foreach ($toAddresses as $address) {
$newFailures = $this->sendEmail($address, $subject, $body); $newFailures = $this->sendEmail($address, $subject, $body);
foreach($newFailures as $failure) { foreach ($newFailures as $failure) {
$failures[] = $failure; $failures[] = $failure;
} }
} }
@ -151,13 +136,11 @@ class Email implements \PHPCI\Plugin
protected function getMailConfig($configName) protected function getMailConfig($configName)
{ {
if (isset($this->emailConfig[$configName]) if (isset($this->emailConfig[$configName]) && $this->emailConfig[$configName] != "") {
&& $this->emailConfig[$configName] != "")
{
return $this->emailConfig[$configName]; return $this->emailConfig[$configName];
} } else {
// Check defaults // Check defaults
else {
switch($configName) { switch($configName) {
case 'smtp_address': case 'smtp_address':
return "localhost"; return "localhost";
@ -178,7 +161,7 @@ class Email implements \PHPCI\Plugin
protected function getEmailAddresses() protected function getEmailAddresses()
{ {
$addresses = array(); $addresses = array();
$committer = $this->phpci->getBuild()->getCommitterEmail(); $committer = $this->build->getCommitterEmail();
if (isset($this->options['committer']) && !empty($committer)) { if (isset($this->options['committer']) && !empty($committer)) {
$addresses[] = $committer; $addresses[] = $committer;
@ -196,4 +179,4 @@ class Email implements \PHPCI\Plugin
} }
return $addresses; return $addresses;
} }
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Environment variable plugin * Environment variable plugin
* @author Steve Kamerman <stevekamerman@gmail.com> * @author Steve Kamerman <stevekamerman@gmail.com>
@ -20,7 +23,7 @@ class Env implements \PHPCI\Plugin
protected $phpci; protected $phpci;
protected $env_vars; protected $env_vars;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->env_vars = $options; $this->env_vars = $options;

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Grunt Plugin - Provides access to grunt functionality. * Grunt Plugin - Provides access to grunt functionality.
* @author Tobias Tom <t.tom@succont.de> * @author Tobias Tom <t.tom@succont.de>
@ -24,14 +27,31 @@ class Grunt implements \PHPCI\Plugin
protected $grunt; protected $grunt;
protected $gruntfile; protected $gruntfile;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$path = $phpci->buildPath; $path = $phpci->buildPath;
$this->phpci = $phpci; $this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $path . '/' . $options['directory'] : $path; $this->directory = $path;
$this->task = isset($options['task']) ? $options['task'] : null; $this->task = null;
$this->grunt = isset($options['grunt']) ? $options['grunt'] : $this->phpci->findBinary('grunt'); $this->grunt = $this->phpci->findBinary('grunt');
$this->gruntfile = isset($options['gruntfile']) ? $options['gruntfile'] : 'Gruntfile.js'; $this->gruntfile = 'Gruntfile.js';
// Handle options:
if (isset($options['directory'])) {
$this->directory = $path . '/' . $options['directory'];
}
if (isset($options['task'])) {
$this->task = $options['task'];
}
if (isset($options['grunt'])) {
$this->grunt = $options['grunt'];
}
if (isset($options['gruntfile'])) {
$this->gruntfile = $options['gruntfile'];
}
} }
/** /**
@ -40,7 +60,7 @@ class Grunt implements \PHPCI\Plugin
public function execute() public function execute()
{ {
// if npm does not work, we cannot use grunt, so we return false // if npm does not work, we cannot use grunt, so we return false
if ( !$this->phpci->executeCommand( 'cd %s && npm install', $this->directory ) ) { if (!$this->phpci->executeCommand('cd %s && npm install', $this->directory)) {
return false; return false;
} }

View file

@ -1,6 +1,10 @@
<?php <?php
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* IRC Plugin - Sends a notification to an IRC channel * IRC Plugin - Sends a notification to an IRC channel
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -16,8 +20,7 @@ class Irc implements \PHPCI\Plugin
private $room; private $room;
private $nick; private $nick;
public function __construct(Builder $phpci, Build $build, array $options = array())
public function __construct(\PHPCI\Builder $phpci, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->message = $options['message']; $this->message = $options['message'];
@ -53,7 +56,9 @@ class Irc implements \PHPCI\Plugin
fputs($sock, 'PRIVMSG ' . $this->room . ' :' . $msg . "\r\n"); fputs($sock, 'PRIVMSG ' . $this->room . ' :' . $msg . "\r\n");
while ($res = fgets($sock)) { while ($res = fgets($sock)) {
$this->phpci->log($res); // We don't need to do anything,
// but the IRC server doesn't appear to post the message
// unless we wait for responses.
} }
fclose($sock); fclose($sock);

View file

@ -11,6 +11,7 @@ namespace PHPCI\Plugin;
use PHPCI\Builder; use PHPCI\Builder;
use PHPCI\Model\Build; use PHPCI\Model\Build;
/** /**
* PHP Lint Plugin - Provides access to PHP lint functionality. * PHP Lint Plugin - Provides access to PHP lint functionality.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -24,7 +25,7 @@ class Lint implements \PHPCI\Plugin
protected $ignore; protected $ignore;
protected $phpci; protected $phpci;
public function __construct(Builder $phpci, Build $build, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->directories = array(''); $this->directories = array('');
@ -64,6 +65,19 @@ class Lint implements \PHPCI\Plugin
return $success; return $success;
} }
protected function lintItem($php, $item, $itemPath)
{
$success = true;
if ($item->isFile() && $item->getExtension() == 'php' && !$this->lintFile($php, $itemPath)) {
$success = false;
} elseif ($item->isDir() && $this->recursive && !$this->lintDirectory($php, $itemPath . '/')) {
$success = false;
}
return $success;
}
protected function lintDirectory($php, $path) protected function lintDirectory($php, $path)
{ {
$success = true; $success = true;
@ -80,9 +94,7 @@ class Lint implements \PHPCI\Plugin
continue; continue;
} }
if ($item->isFile() && $item->getExtension() == 'php' && !$this->lintFile($php, $itemPath)) { if (!$this->lintItem($php, $item, $itemPath)) {
$success = false;
} else if ($item->isDir() && $this->recursive && !$this->lintDirectory($php, $itemPath . '/')) {
$success = false; $success = false;
} }
} }

View file

@ -10,6 +10,8 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PDO; use PDO;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* MySQL Plugin - Provides access to a MySQL database. * MySQL Plugin - Provides access to a MySQL database.
@ -37,24 +39,33 @@ class Mysql implements \PHPCI\Plugin
*/ */
protected $pdo; protected $pdo;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->queries = $options; $this->queries = $options;
$config = \b8\Database::getConnection('write')->getDetails(); $config = \b8\Database::getConnection('write')->getDetails();
$this->host =(defined('PHPCI_DB_HOST')) ? PHPCI_DB_HOST : null; $this->host =(defined('PHPCI_DB_HOST')) ? PHPCI_DB_HOST : null;
$this->user = $config['user']; $this->user = $config['user'];
$this->pass = $config['pass']; $this->pass = $config['pass'];
$buildSettings = $phpci->getConfig('build_settings'); $buildSettings = $phpci->getConfig('build_settings');
if (isset($buildSettings['mysql'])) {
$sql = $buildSettings['mysql'];
$this->host = !empty($sql['host']) ? $sql['host'] : $this->phpci->interpolate($this->host); if (!isset($buildSettings['mysql'])) {
$this->user = !empty($sql['user']) ? $sql['user'] : $this->phpci->interpolate($this->user); return;
$this->pass = array_key_exists('pass', $sql) ? $sql['pass'] : $this->pass; }
if (!empty($buildSettings['mysql']['host'])) {
$this->host = $this->phpci->interpolate($buildSettings['mysql']['host']);
}
if (!empty($buildSettings['mysql']['user'])) {
$this->user = $this->phpci->interpolate($buildSettings['mysql']['user']);
}
if (array_key_exists('pass', $buildSettings['mysql'])) {
$this->pass = $buildSettings['mysql']['pass'];
} }
} }
@ -73,7 +84,7 @@ class Mysql implements \PHPCI\Plugin
if (!is_array($query)) { if (!is_array($query)) {
// Simple query // Simple query
$this->pdo->query($this->phpci->interpolate($query)); $this->pdo->query($this->phpci->interpolate($query));
} else if (isset($query['import'])) { } elseif (isset($query['import'])) {
// SQL file execution // SQL file execution
$this->executeFile($query['import']); $this->executeFile($query['import']);
} else { } else {
@ -96,15 +107,15 @@ class Mysql implements \PHPCI\Plugin
$import_file = $this->phpci->buildPath . $this->phpci->interpolate($query['file']); $import_file = $this->phpci->buildPath . $this->phpci->interpolate($query['file']);
if (!is_readable($import_file)) { if (!is_readable($import_file)) {
throw new \Exception("Cannot open SQL import file: $import_file"); throw new \Exception("Cannot open SQL import file: $import_file");
} }
$database = isset($query['database'])? $this->phpci->interpolate($query['database']): null; $database = isset($query['database']) ? $this->phpci->interpolate($query['database']) : null;
$import_command = $this->getImportCommand($import_file, $database); $import_command = $this->getImportCommand($import_file, $database);
if (!$this->phpci->executeCommand($import_command)) { if (!$this->phpci->executeCommand($import_command)) {
throw new \Exception("Unable to execute SQL file"); throw new \Exception("Unable to execute SQL file");
} }
return true; return true;
} }
@ -115,7 +126,8 @@ class Mysql implements \PHPCI\Plugin
* @param string $database If specified, this database is selected before execution * @param string $database If specified, this database is selected before execution
* @return string * @return string
*/ */
protected function getImportCommand($import_file, $database=null) { protected function getImportCommand($import_file, $database = null)
{
$decompression = array( $decompression = array(
'bz2' => '| bzip2 --decompress', 'bz2' => '| bzip2 --decompress',
'gz' => '| gzip --decompress', 'gz' => '| gzip --decompress',
@ -136,4 +148,4 @@ class Mysql implements \PHPCI\Plugin
); );
return strtr('cat :import_file :decomp_cmd | mysql -u:user -p:pass :database', $args); return strtr('cat :import_file :decomp_cmd | mysql -u:user -p:pass :database', $args);
} }
} }

View file

@ -9,6 +9,8 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Create a ZIP or TAR.GZ archive of the entire build. * Create a ZIP or TAR.GZ archive of the entire build.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -22,9 +24,10 @@ class PackageBuild implements \PHPCI\Plugin
protected $format; protected $format;
protected $phpci; protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$path = $phpci->buildPath; $path = $phpci->buildPath;
$this->build = $build;
$this->phpci = $phpci; $this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $path; $this->directory = isset($options['directory']) ? $options['directory'] : $path;
$this->filename = isset($options['filename']) ? $options['filename'] : 'build'; $this->filename = isset($options['filename']) ? $options['filename'] : 'build';
@ -37,7 +40,7 @@ class PackageBuild implements \PHPCI\Plugin
public function execute() public function execute()
{ {
$path = $this->phpci->buildPath; $path = $this->phpci->buildPath;
$build = $this->phpci->getBuild(); $build = $this->build;
if ($this->directory == $path) { if ($this->directory == $path) {
return false; return false;

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Pdepend Plugin - Allows Pdepend report * Pdepend Plugin - Allows Pdepend report
* @author Johan van der Heide <info@japaveh.nl> * @author Johan van der Heide <info@japaveh.nl>
@ -44,16 +47,17 @@ class Pdepend implements \PHPCI\Plugin
*/ */
protected $location; protected $location;
public function __construct(Builder $phpci, Build $build, array $options = array())
public function __construct(\PHPCI\Builder $phpci, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->build = $build;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath; $this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath;
$this->summary = $phpci->getBuildProjectTitle() . '-summary.xml'; $title = $phpci->getBuildProjectTitle();
$this->pyramid = $phpci->getBuildProjectTitle() . '-pyramid.svg'; $this->summary = $title . '-summary.xml';
$this->chart = $phpci->getBuildProjectTitle() . '-chart.svg'; $this->pyramid = $title . '-pyramid.svg';
$this->chart = $title . '-chart.svg';
$this->location = $this->phpci->buildPath . '..' . DIRECTORY_SEPARATOR . 'pdepend'; $this->location = $this->phpci->buildPath . '..' . DIRECTORY_SEPARATOR . 'pdepend';
} }

View file

@ -10,6 +10,8 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PDO; use PDO;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PgSQL Plugin - Provides access to a PgSQL database. * PgSQL Plugin - Provides access to a PgSQL database.
@ -26,7 +28,7 @@ class Pgsql implements \PHPCI\Plugin
protected $user; protected $user;
protected $pass; protected $pass;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->queries = $options; $this->queries = $options;

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHP Code Sniffer Plugin - Allows PHP Code Sniffer testing. * PHP Code Sniffer Plugin - Allows PHP Code Sniffer testing.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -62,22 +65,88 @@ class PhpCodeSniffer implements \PHPCI\Plugin
* @param \PHPCI\Builder $phpci * @param \PHPCI\Builder $phpci
* @param array $options * @param array $options
*/ */
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->suffixes = isset($options['suffixes']) ? (array)$options['suffixes'] : array('php'); $this->build = $build;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath; $this->suffixes = array('php');
$this->standard = isset($options['standard']) ? $options['standard'] : 'PSR2'; $this->directory = $phpci->buildPath;
$this->tab_width = isset($options['tab_width']) ? $options['tab_width'] : ''; $this->standard = 'PSR2';
$this->encoding = isset($options['encoding']) ? $options['encoding'] : ''; $this->tab_width = '';
$this->path = (isset($options['path'])) ? $options['path'] : ''; $this->encoding = '';
$this->ignore = (isset($options['ignore'])) ? (array)$options['ignore'] : $this->phpci->ignore; $this->path = '';
$this->ignore = $this->phpci->ignore;
if (isset($options['suffixes'])) {
$this->suffixes = (array)$options['suffixes'];
}
if (isset($options['directory'])) {
$this->directory = $options['directory'];
}
if (isset($options['standard'])) {
$this->standard = $options['standard'];
}
if (!empty($options['tab_width'])) {
$this->tab_width = ' --tab-width='.$options['tab_width'];
}
if (!empty($options['encoding'])) {
$this->encoding = ' --encoding=' . $options['encoding'];
}
if (isset($options['path'])) {
$this->path = $options['path'];
}
if (isset($options['ignore'])) {
$this->ignore = $options['ignore'];
}
} }
/** /**
* Runs PHP Code Sniffer in a specified directory, to a specified standard. * Runs PHP Code Sniffer in a specified directory, to a specified standard.
*/ */
public function execute() public function execute()
{
list($ignore, $standard, $suffixes) = $this->getFlags();
$phpcs = $this->phpci->findBinary('phpcs');
if (!$phpcs) {
$this->phpci->logFailure('Could not find phpcs.');
return false;
}
$cmd = $phpcs . ' %s %s %s %s %s "%s"';
$success = $this->phpci->executeCommand(
$cmd,
$standard,
$suffixes,
$ignore,
$this->tab_width,
$this->encoding,
$this->phpci->buildPath . $this->path
);
$output = $this->phpci->getLastOutput();
$matches = array();
if (preg_match_all('/WARNING/', $output, $matches)) {
$this->build->storeMeta('phpcs-warnings', count($matches[0]));
}
$matches = array();
if (preg_match_all('/ERROR/', $output, $matches)) {
$this->build->storeMeta('phpcs-errors', count($matches[0]));
}
return $success;
}
protected function getFlags()
{ {
$ignore = ''; $ignore = '';
if (count($this->ignore)) { if (count($this->ignore)) {
@ -95,38 +164,6 @@ class PhpCodeSniffer implements \PHPCI\Plugin
$suffixes = ' --extensions=' . implode(',', $this->suffixes); $suffixes = ' --extensions=' . implode(',', $this->suffixes);
} }
$tab_width = ''; return array($ignore, $standard, $suffixes);
if (strlen($this->tab_width)) {
$tab_width = ' --tab-width='.$this->tab_width;
}
$encoding = '';
if (strlen($this->encoding)) {
$encoding = ' --encoding='.$this->encoding;
}
$phpcs = $this->phpci->findBinary('phpcs');
if (!$phpcs) {
$this->phpci->logFailure('Could not find phpcs.');
return false;
}
$cmd = $phpcs . ' %s %s %s %s %s "%s"';
$success = $this->phpci->executeCommand($cmd, $standard, $suffixes, $ignore, $tab_width, $encoding, $this->phpci->buildPath . $this->path);
$output = $this->phpci->getLastOutput();
$matches = array();
if (preg_match_all('/WARNING/', $output, $matches)) {
$this->phpci->storeBuildMeta('phpcs-warnings', count($matches[0]));
}
$matches = array();
if (preg_match_all('/ERROR/', $output, $matches)) {
$this->phpci->storeBuildMeta('phpcs-errors', count($matches[0]));
}
return $success;
} }
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHP Copy / Paste Detector - Allows PHP Copy / Paste Detector testing. * PHP Copy / Paste Detector - Allows PHP Copy / Paste Detector testing.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -32,14 +35,24 @@ class PhpCpd implements \PHPCI\Plugin
*/ */
protected $ignore; protected $ignore;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath; $this->path = $phpci->buildPath;
$this->standard = isset($options['standard']) ? $options['standard'] : 'PSR2'; $this->standard = 'PSR1';
$this->path = (isset($options['path'])) ? $options['path'] : ''; $this->ignore = $phpci->ignore;
$this->ignore = (isset($options['ignore'])) ? (array)$options['ignore'] : $this->phpci->ignore;
if (!empty($options['path'])) {
$this->path = $phpci->buildPath . $options['path'];
}
if (!empty($options['standard'])) {
$this->standard = $options['standard'];
}
if (!empty($options['ignore'])) {
$this->ignore = $this->phpci->ignore;
}
} }
/** /**

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHP CS Fixer - Works with the PHP CS Fixer for testing coding standards. * PHP CS Fixer - Works with the PHP CS Fixer for testing coding standards.
* @author Gabriel Baker <gabriel@autonomicpilot.co.uk> * @author Gabriel Baker <gabriel@autonomicpilot.co.uk>
@ -19,16 +22,13 @@ class PhpCsFixer implements \PHPCI\Plugin
{ {
protected $phpci; protected $phpci;
protected $args = '';
protected $workingDir = ''; protected $workingDir = '';
protected $level = 'all'; protected $level = ' --level=all';
protected $dryRun = true; protected $verbose = '';
protected $verbose = false; protected $diff = '';
protected $diff = false;
protected $levels = array('psr0', 'psr1', 'psr2', 'all'); protected $levels = array('psr0', 'psr1', 'psr2', 'all');
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->workingdir = $this->phpci->buildPath; $this->workingdir = $this->phpci->buildPath;
@ -37,8 +37,6 @@ class PhpCsFixer implements \PHPCI\Plugin
public function execute() public function execute()
{ {
$success = false;
$curdir = getcwd(); $curdir = getcwd();
chdir($this->workingdir); chdir($this->workingdir);
@ -49,8 +47,8 @@ class PhpCsFixer implements \PHPCI\Plugin
return false; return false;
} }
$cmd = $phpcsfixer . ' fix . %s'; $cmd = $phpcsfixer . ' fix . %s %s %s';
$success = $this->phpci->executeCommand($cmd, $this->args); $success = $this->phpci->executeCommand($cmd, $this->verbose, $this->diff, $this->level);
chdir($curdir); chdir($curdir);
@ -59,38 +57,21 @@ class PhpCsFixer implements \PHPCI\Plugin
public function buildArgs($options) public function buildArgs($options)
{ {
$argstring = ""; if (isset($options['verbose']) && $options['verbose']) {
$this->verbose = ' --verbose';
if ( array_key_exists('verbose', $options) && $options['verbose'] )
{
$this->verbose = true;
$this->args .= ' --verbose';
} }
if ( array_key_exists('diff', $options) && $options['diff'] ) if (isset($options['diff']) && $options['diff']) {
{ $this->diff = ' --diff';
$this->diff = true;
$this->args .= ' --diff';
} }
if ( array_key_exists('level', $options) && in_array($options['level'], $this->levels) ) if (isset($options['level']) && in_array($options['level'], $this->levels)) {
{ $this->level = ' --level='.$options['level'];
$this->level = $options['level'];
$this->args .= ' --level='.$options['level'];
} }
if ( array_key_exists('dryrun', $options) && $options['dryrun'] ) if (isset($options['workingdir']) && $options['workingdir']) {
{ $this->workingdir = $this->phpci->buildPath . $options['workingdir'];
$this->dryRun = true;
$this->args .= ' --dry-run';
}
if ( array_key_exists('workingdir', $options)
&& $options['workingdir']
&& is_dir($this->phpci->buildPath.$options['workingdir']) )
{
$this->workingdir = $this->phpci->buildPath.$options['workingdir'];
} }
} }
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHP Loc - Allows PHP Copy / Lines of Code testing. * PHP Loc - Allows PHP Copy / Lines of Code testing.
* @author Johan van der Heide <info@japaveh.nl> * @author Johan van der Heide <info@japaveh.nl>
@ -26,9 +29,10 @@ class PhpLoc implements \PHPCI\Plugin
*/ */
protected $phpci; protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->build = $build;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath; $this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath;
} }
@ -63,9 +67,9 @@ class PhpLoc implements \PHPCI\Plugin
$data[$v] = (int)$matches[2][$k]; $data[$v] = (int)$matches[2][$k];
} }
$this->phpci->storeBuildMeta('phploc', $data); $this->build->storeMeta('phploc', $data);
} }
return $success; return $success;
} }
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHP Mess Detector Plugin - Allows PHP Mess Detector testing. * PHP Mess Detector Plugin - Allows PHP Mess Detector testing.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -49,21 +52,21 @@ class PhpMessDetector implements \PHPCI\Plugin
* @param \PHPCI\Builder $phpci * @param \PHPCI\Builder $phpci
* @param array $options * @param array $options
*/ */
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
$this->build = $build;
$this->suffixes = array('php');
$this->ignore = $phpci->ignore;
$this->path = '';
$this->rules = array('codesize', 'unusedcode', 'naming');
$this->suffixes = isset($options['suffixes']) ? (array)$options['suffixes'] : array('php'); if (!empty($options['path'])) {
$this->path = $options['path'];
}
$this->ignore = (isset($options['ignore'])) ? (array)$options['ignore'] : $this->phpci->ignore; foreach (array('rules', 'ignore', 'suffixes') as $key) {
$this->overrideSetting($options, $key);
$this->path = (isset($options['path'])) ? $options['path'] : '';
$this->rules = isset($options['rules']) ? (array)$options['rules'] : array('codesize', 'unusedcode', 'naming');
foreach ($this->rules as &$rule) {
if ($rule[0] !== '/' && strpos($rule, '/') !== FALSE) {
$rule = $this->phpci->buildPath . $rule;
}
} }
} }
@ -82,6 +85,12 @@ class PhpMessDetector implements \PHPCI\Plugin
$suffixes = ' --suffixes ' . implode(',', $this->suffixes); $suffixes = ' --suffixes ' . implode(',', $this->suffixes);
} }
foreach ($this->rules as &$rule) {
if ($rule[0] !== '/' && strpos($rule, '/') !== false) {
$rule = $this->phpci->buildPath . $rule;
}
}
$phpmd = $this->phpci->findBinary('phpmd'); $phpmd = $this->phpci->findBinary('phpmd');
if (!$phpmd) { if (!$phpmd) {
@ -90,10 +99,24 @@ class PhpMessDetector implements \PHPCI\Plugin
} }
$cmd = $phpmd . ' "%s" text %s %s %s'; $cmd = $phpmd . ' "%s" text %s %s %s';
$success = $this->phpci->executeCommand($cmd, $this->phpci->buildPath . $this->path, implode(',', $this->rules), $ignore, $suffixes); $success = $this->phpci->executeCommand(
$cmd,
$this->phpci->buildPath . $this->path,
implode(',', $this->rules),
$ignore,
$suffixes
);
$errors = count(array_filter(explode(PHP_EOL, $this->phpci->getLastOutput()))); $errors = count(array_filter(explode(PHP_EOL, $this->phpci->getLastOutput())));
$this->phpci->storeBuildMeta('phpmd-warnings', $errors); $this->build->storeMeta('phpmd-warnings', $errors);
return $success; return $success;
} }
protected function overrideSetting($options, $key)
{
if (isset($options[$key]) && is_array($options['key'])) {
$this->{$key} = $options[$key];
}
}
} }

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Php Parallel Lint Plugin - Provides access to PHP lint functionality. * Php Parallel Lint Plugin - Provides access to PHP lint functionality.
* @author Vaclav Makes <vaclav@makes.cz> * @author Vaclav Makes <vaclav@makes.cz>
@ -21,7 +24,7 @@ class PhpParallelLint implements \PHPCI\Plugin
protected $preferDist; protected $preferDist;
protected $phpci; protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$path = $phpci->buildPath; $path = $phpci->buildPath;
$this->phpci = $phpci; $this->phpci = $phpci;

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHP Spec Plugin - Allows PHP Spec testing. * PHP Spec Plugin - Allows PHP Spec testing.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -18,10 +21,15 @@ namespace PHPCI\Plugin;
class PhpSpec implements \PHPCI\Plugin class PhpSpec implements \PHPCI\Plugin
{ {
protected $phpci; protected $phpci;
protected $bootstrap;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;
if (!empty($options['bootstrap'])) {
$this->bootstrap = $this->buildPath . $options['bootstrap'];
}
} }
/** /**
@ -32,14 +40,19 @@ class PhpSpec implements \PHPCI\Plugin
$curdir = getcwd(); $curdir = getcwd();
chdir($this->phpci->buildPath); chdir($this->phpci->buildPath);
$phpspec = $this->phpci->findBinary('phpspec'); $phpspec = $this->phpci->findBinary(array('phpspec', 'phpspec.php'));
if (!$phpspec) { if (!$phpspec) {
$this->phpci->logFailure('Could not find phpspec.'); $this->phpci->logFailure('Could not find phpspec.');
return false; return false;
} }
$success = $this->phpci->executeCommand($phpspec); if ($this->bootstrap) {
$success = $this->phpci->executeCommand($phpspec . ' -f d');
} else {
$success = $this->phpci->executeCommand($phpspec . ' -f d --bootstrap "%s"', $this->bootstrap);
}
chdir($curdir); chdir($curdir);
return $success; return $success;

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* PHP Unit Plugin - Allows PHP Unit testing. * PHP Unit Plugin - Allows PHP Unit testing.
* @author Dan Cryer <dan@block8.co.uk> * @author Dan Cryer <dan@block8.co.uk>
@ -43,7 +46,7 @@ class PhpUnit implements \PHPCI\Plugin
*/ */
protected $xmlConfigFile; protected $xmlConfigFile;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;

View file

@ -9,6 +9,9 @@
namespace PHPCI\Plugin; namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/** /**
* Shell Plugin - Allows execute shell commands. * Shell Plugin - Allows execute shell commands.
* @author Kinn Coelho Julião <kinncj@gmail.com> * @author Kinn Coelho Julião <kinncj@gmail.com>
@ -25,7 +28,7 @@ class Shell implements \PHPCI\Plugin
*/ */
protected $command; protected $command;
public function __construct(\PHPCI\Builder $phpci, array $options = array()) public function __construct(Builder $phpci, Build $build, array $options = array())
{ {
$this->phpci = $phpci; $this->phpci = $phpci;

View file

@ -6,7 +6,10 @@
namespace PHPCI\Store\Base; namespace PHPCI\Store\Base;
use b8\Database;
use b8\Exception\HttpException;
use b8\Store; use b8\Store;
use PHPCI\Model\BuildMeta;
/** /**
* BuildMeta Base Store * BuildMeta Base Store
@ -22,21 +25,19 @@ class BuildMetaStoreBase extends Store
return $this->getById($value, $useConnection); return $this->getById($value, $useConnection);
} }
public function getById($value, $useConnection = 'read') public function getById($value, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$query = 'SELECT * FROM build_meta WHERE id = :id LIMIT 1'; $query = 'SELECT * FROM build_meta WHERE id = :id LIMIT 1';
$stmt = \b8\Database::getConnection($useConnection)->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':id', $value); $stmt->bindValue(':id', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) { if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new \PHPCI\Model\BuildMeta($data); return new BuildMeta($data);
} }
} }
@ -46,7 +47,7 @@ class BuildMetaStoreBase extends Store
public function getByBuildId($value, $limit = null, $useConnection = 'read') public function getByBuildId($value, $limit = null, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$add = ''; $add = '';
@ -55,26 +56,17 @@ class BuildMetaStoreBase extends Store
$add .= ' LIMIT ' . $limit; $add .= ' LIMIT ' . $limit;
} }
$query = 'SELECT COUNT(*) AS cnt FROM build_meta WHERE build_id = :build_id' . $add; $count = null;
$stmt = \b8\Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':build_id', $value);
if ($stmt->execute()) {
$res = $stmt->fetch(\PDO::FETCH_ASSOC);
$count = (int)$res['cnt'];
} else {
$count = 0;
}
$query = 'SELECT * FROM build_meta WHERE build_id = :build_id' . $add; $query = 'SELECT * FROM build_meta WHERE build_id = :build_id' . $add;
$stmt = \b8\Database::getConnection('read')->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':build_id', $value); $stmt->bindValue(':build_id', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC); $res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) { $map = function ($item) {
return new \PHPCI\Model\BuildMeta($item); return new BuildMeta($item);
}; };
$rtn = array_map($map, $res); $rtn = array_map($map, $res);

View file

@ -6,7 +6,10 @@
namespace PHPCI\Store\Base; namespace PHPCI\Store\Base;
use b8\Database;
use b8\Exception\HttpException;
use b8\Store; use b8\Store;
use PHPCI\Model\Build;
/** /**
* Build Base Store * Build Base Store
@ -22,21 +25,19 @@ class BuildStoreBase extends Store
return $this->getById($value, $useConnection); return $this->getById($value, $useConnection);
} }
public function getById($value, $useConnection = 'read') public function getById($value, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$query = 'SELECT * FROM build WHERE id = :id LIMIT 1'; $query = 'SELECT * FROM build WHERE id = :id LIMIT 1';
$stmt = \b8\Database::getConnection($useConnection)->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':id', $value); $stmt->bindValue(':id', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) { if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new \PHPCI\Model\Build($data); return new Build($data);
} }
} }
@ -46,7 +47,7 @@ class BuildStoreBase extends Store
public function getByProjectId($value, $limit = null, $useConnection = 'read') public function getByProjectId($value, $limit = null, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$add = ''; $add = '';
@ -55,26 +56,17 @@ class BuildStoreBase extends Store
$add .= ' LIMIT ' . $limit; $add .= ' LIMIT ' . $limit;
} }
$query = 'SELECT COUNT(*) AS cnt FROM build WHERE project_id = :project_id' . $add; $count = null;
$stmt = \b8\Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':project_id', $value);
if ($stmt->execute()) {
$res = $stmt->fetch(\PDO::FETCH_ASSOC);
$count = (int)$res['cnt'];
} else {
$count = 0;
}
$query = 'SELECT * FROM build WHERE project_id = :project_id' . $add; $query = 'SELECT * FROM build WHERE project_id = :project_id' . $add;
$stmt = \b8\Database::getConnection('read')->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':project_id', $value); $stmt->bindValue(':project_id', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC); $res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) { $map = function ($item) {
return new \PHPCI\Model\Build($item); return new Build($item);
}; };
$rtn = array_map($map, $res); $rtn = array_map($map, $res);
@ -87,7 +79,7 @@ class BuildStoreBase extends Store
public function getByStatus($value, $limit = null, $useConnection = 'read') public function getByStatus($value, $limit = null, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$add = ''; $add = '';
@ -96,26 +88,17 @@ class BuildStoreBase extends Store
$add .= ' LIMIT ' . $limit; $add .= ' LIMIT ' . $limit;
} }
$query = 'SELECT COUNT(*) AS cnt FROM build WHERE status = :status' . $add; $count = null;
$stmt = \b8\Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':status', $value);
if ($stmt->execute()) {
$res = $stmt->fetch(\PDO::FETCH_ASSOC);
$count = (int)$res['cnt'];
} else {
$count = 0;
}
$query = 'SELECT * FROM build WHERE status = :status' . $add; $query = 'SELECT * FROM build WHERE status = :status' . $add;
$stmt = \b8\Database::getConnection('read')->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':status', $value); $stmt->bindValue(':status', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC); $res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) { $map = function ($item) {
return new \PHPCI\Model\Build($item); return new Build($item);
}; };
$rtn = array_map($map, $res); $rtn = array_map($map, $res);

View file

@ -6,7 +6,10 @@
namespace PHPCI\Store\Base; namespace PHPCI\Store\Base;
use b8\Database;
use b8\Exception\HttpException;
use b8\Store; use b8\Store;
use PHPCI\Model\Project;
/** /**
* Project Base Store * Project Base Store
@ -22,24 +25,54 @@ class ProjectStoreBase extends Store
return $this->getById($value, $useConnection); return $this->getById($value, $useConnection);
} }
public function getById($value, $useConnection = 'read') public function getById($value, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$query = 'SELECT * FROM project WHERE id = :id LIMIT 1'; $query = 'SELECT * FROM project WHERE id = :id LIMIT 1';
$stmt = \b8\Database::getConnection($useConnection)->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':id', $value); $stmt->bindValue(':id', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) { if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new \PHPCI\Model\Project($data); return new Project($data);
} }
} }
return null; return null;
} }
public function getByTitle($value, $limit = null, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$add = '';
if ($limit) {
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM project WHERE title = :title' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':title', $value);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new Project($item);
};
$rtn = array_map($map, $res);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
}
}
} }

View file

@ -6,7 +6,10 @@
namespace PHPCI\Store\Base; namespace PHPCI\Store\Base;
use b8\Database;
use b8\Exception\HttpException;
use b8\Store; use b8\Store;
use PHPCI\Model\User;
/** /**
* User Base Store * User Base Store
@ -22,21 +25,19 @@ class UserStoreBase extends Store
return $this->getById($value, $useConnection); return $this->getById($value, $useConnection);
} }
public function getById($value, $useConnection = 'read') public function getById($value, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$query = 'SELECT * FROM user WHERE id = :id LIMIT 1'; $query = 'SELECT * FROM user WHERE id = :id LIMIT 1';
$stmt = \b8\Database::getConnection($useConnection)->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':id', $value); $stmt->bindValue(':id', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) { if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new \PHPCI\Model\User($data); return new User($data);
} }
} }
@ -46,16 +47,16 @@ class UserStoreBase extends Store
public function getByEmail($value, $useConnection = 'read') public function getByEmail($value, $useConnection = 'read')
{ {
if (is_null($value)) { if (is_null($value)) {
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
} }
$query = 'SELECT * FROM user WHERE email = :email LIMIT 1'; $query = 'SELECT * FROM user WHERE email = :email LIMIT 1';
$stmt = \b8\Database::getConnection($useConnection)->prepare($query); $stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':email', $value); $stmt->bindValue(':email', $value);
if ($stmt->execute()) { if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) { if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new \PHPCI\Model\User($data); return new User($data);
} }
} }

View file

@ -12,31 +12,8 @@
<?php if (count($projects)): ?> <?php if (count($projects)): ?>
<h5>Projects</h5> <h5>Projects</h5>
<ul class="nav nav-pills nav-stacked"> <ul class="nav nav-pills nav-stacked">
<?php <?php foreach($projects as $project): ?>
foreach($projects as $project): <li><a href="<?= PHPCI_URL ?>project/view/<?php print $project->getId(); ?>"><?php print $project->getTitle(); ?></a></li>
$status = 'icon-build-ok';
$build = $project->getLatestBuild('master');
if (isset($build)) {
switch($build->getStatus())
{
case 0:
$status = 'icon-build-pending';
break;
case 1:
$status = 'icon-build-running';
break;
case 3:
$status = 'icon-build-failed';
break;
case 2:
default:
$status = 'icon-build-ok';
break;
}
}
?>
<li><a href="<?= PHPCI_URL ?>project/view/<?php print $project->getId(); ?>"><i class="<?= $status; ?>"></i> <?php print $project->getTitle(); ?></a></li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
<?php endif; ?> <?php endif; ?>

View file

@ -27,20 +27,22 @@ $autoload = function ($class) {
spl_autoload_register($autoload, true, true); spl_autoload_register($autoload, true, true);
// Define our APPLICATION_PATH, if not already defined:
if (!defined('APPLICATION_PATH')) {
define('APPLICATION_PATH', dirname(__FILE__) . '/');
}
if (!file_exists(APPLICATION_PATH . 'PHPCI/config.yml')) {
header('Location: install.php'); if (!file_exists(dirname(__FILE__) . '/PHPCI/config.yml')) {
die; if (defined('PHPCI_IS_CONSOLE') && PHPCI_IS_CONSOLE) {
file_put_contents('php://stderr', 'Please install PHPCI with "composer install" before using console');
exit(1);
} else {
header('Location: install.php');
die;
}
} }
// Load Composer autoloader: // Load Composer autoloader:
require_once(APPLICATION_PATH . 'vendor/autoload.php'); require_once(dirname(__FILE__) . '/vendor/autoload.php');
// Load configuration if present: // Load configuration if present:
$conf = array(); $conf = array();
@ -49,9 +51,6 @@ $conf['b8']['app']['default_controller'] = 'Home';
$conf['b8']['view']['path'] = dirname(__FILE__) . '/PHPCI/View/'; $conf['b8']['view']['path'] = dirname(__FILE__) . '/PHPCI/View/';
$config = new b8\Config($conf); $config = new b8\Config($conf);
$config->loadYaml(APPLICATION_PATH . 'PHPCI/config.yml'); $config->loadYaml(dirname(__FILE__) . '/PHPCI/config.yml');
// Define our PHPCI_URL, if not already defined: require_once(dirname(__FILE__) . '/vars.php');
if (!defined('PHPCI_URL')) {
define('PHPCI_URL', $config->get('phpci.url', '') . '/');
}

11
console
View file

@ -8,16 +8,7 @@
* @link http://www.phptesting.org/ * @link http://www.phptesting.org/
*/ */
define('PHPCI_BIN_DIR', dirname(__FILE__) . '/vendor/bin/'); define('PHPCI_IS_CONSOLE', true);
define('PHPCI_DIR', dirname(__FILE__) . '/');
define('ENABLE_SHELL_PLUGIN', false);
// If this is the first time ./console has been run, we probably don't have Composer or any of our dependencies yet.
// So we need to install and run Composer.
if (!file_exists(PHPCI_DIR . 'vendor/autoload.php')) {
file_put_contents('php://stderr', 'Please install PHPCI with "composer install" before using console');
exit( 1 );
}
require('bootstrap.php'); require('bootstrap.php');

View file

@ -8,9 +8,7 @@
* @link http://www.phptesting.org/ * @link http://www.phptesting.org/
*/ */
define('PHPCI_BIN_DIR', dirname(__FILE__) . '/vendor/bin/'); define('PHPCI_IS_CONSOLE', true);
define('PHPCI_DIR', dirname(__FILE__) . '/');
define('ENABLE_SHELL_PLUGIN', false);
require('bootstrap.php'); require('bootstrap.php');

View file

@ -2,27 +2,20 @@ build_settings:
verbose: false verbose: false
ignore: ignore:
- "vendor" - "vendor"
- "assets"
- "build"
- "Tests" - "Tests"
- "composer.phar" - "PHPCI/Command" # PHPMD complains about un-used parameters, but they are required.
- "public/install.php" # PHPCS really doesn't like PHP mixed with HTML (and so it shouldn't)
irc: irc:
server: "irc.freenode.net" server: "irc.freenode.net"
port: 6667 port: 6667
room: "#phpci" room: "#phpci"
nick: "phpcidev" nick: "phpcidev"
setup:
composer:
action: "install"
test: test:
php_mess_detector: php_mess_detector:
allow_failures: true
php_code_sniffer: php_code_sniffer:
standard: "PSR2" standard: "PSR2"
php_loc: php_loc:
allow_failures: true
success: success:
irc: irc:

View file

@ -16,4 +16,3 @@ require_once('../bootstrap.php');
$fc = new PHPCI\Application($config, new b8\Http\Request()); $fc = new PHPCI\Application($config, new b8\Http\Request());
print $fc->handleRequest(); print $fc->handleRequest();

View file

@ -1,15 +1,10 @@
<?php <?php
error_reporting(E_ALL); require_once(dirname(__FILE__) . '/../vars.php');
ini_set('display_errors', 'On');
$installStage = 'start'; $installStage = 'start';
$formAction = ''; $formAction = '';
$config = array(); $config = array();
define('PHPCI_DIR', realpath('../') . '/');
$ciUrl = ($_SERVER['HTTPS'] == "on" ? 'https' : 'http') . '://'; $ciUrl = ($_SERVER['HTTPS'] == "on" ? 'https' : 'http') . '://';
$ciUrl .= $_SERVER['HTTP_HOST']; $ciUrl .= $_SERVER['HTTP_HOST'];
$ciUrl .= str_replace('/install.php', '', $_SERVER['REQUEST_URI']); $ciUrl .= str_replace('/install.php', '', $_SERVER['REQUEST_URI']);
@ -22,12 +17,37 @@ $composerInstalled = true;
$isWriteable = true; $isWriteable = true;
$phpOK = true; $phpOK = true;
$checkWriteable = function ($path) {
if ($path{strlen($path)-1}=='/') {
return is__writable($path.uniqid(mt_rand()).'.tmp');
} elseif (is_dir($path)) {
return is__writable($path.'/'.uniqid(mt_rand()).'.tmp');
}
// check tmp file for read/write capabilities
$remove = file_exists($path);
$file = @fopen($path, 'a');
if ($file === false) {
return false;
}
fclose($file);
if (!$remove) {
unlink($path);
}
return true;
};
if (!file_exists(PHPCI_DIR . 'vendor/autoload.php')) { if (!file_exists(PHPCI_DIR . 'vendor/autoload.php')) {
$composerInstalled = false; $composerInstalled = false;
$installOK = false; $installOK = false;
} }
if (!is__writable(PHPCI_DIR . 'PHPCI/config.yml')) { if (!$checkWriteable(PHPCI_DIR . 'PHPCI/config.yml')) {
$isWriteable = false; $isWriteable = false;
$installOK = false; $installOK = false;
} }
@ -160,16 +180,8 @@ switch ($installStage) {
body body
{ {
background: #224466; /* Old browsers */ background: #224466; /* Old browsers */
background: -moz-radial-gradient(center, ellipse cover, #224466 0%, #112233 100%); /* FF3.6+ */ background: radial-gradient(ellipse at center, #224466 0%,#112233 100%);
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#224466), color-stop(100%,#112233)); /* Chrome,Safari4+ */
background: -webkit-radial-gradient(center, ellipse cover, #224466 0%,#112233 100%); /* Chrome10+,Safari5.1+ */
background: -o-radial-gradient(center, ellipse cover, #224466 0%,#112233 100%); /* Opera 12+ */
background: -ms-radial-gradient(center, ellipse cover, #224466 0%,#112233 100%); /* IE10+ */
background: radial-gradient(ellipse at center, #224466 0%,#112233 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#224466', endColorstr='#112233',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
min-height: 100%; min-height: 100%;
font-family: Roboto, Arial, Sans-Serif; font-family: Roboto, Arial, Sans-Serif;
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
@ -178,15 +190,7 @@ switch ($installStage) {
#form-box #form-box
{ {
background: #fcfcfc; /* Old browsers */ background: linear-gradient(to bottom, #fcfcfc 50%,#e0e0e0 100%);
background: -moz-linear-gradient(top, #fcfcfc 50%, #e0e0e0 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(50%,#fcfcfc), color-stop(100%,#e0e0e0)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #fcfcfc 50%,#e0e0e0 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #fcfcfc 50%,#e0e0e0 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #fcfcfc 50%,#e0e0e0 100%); /* IE10+ */
background: linear-gradient(to bottom, #fcfcfc 50%,#e0e0e0 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfcfc', endColorstr='#e0e0e0',GradientType=0 ); /* IE6-9 */
border-radius: 5px; border-radius: 5px;
box-shadow: 0 0 30px rgba(0,0,0, 0.3); box-shadow: 0 0 30px rgba(0,0,0, 0.3);
margin: 0 auto; margin: 0 auto;
@ -235,12 +239,18 @@ switch ($installStage) {
<?php endif; ?> <?php endif; ?>
<?php if (!$composerInstalled): ?> <?php if (!$composerInstalled): ?>
<p class="alert alert-danger"><strong>Important!</strong> You need to run composer to install dependencies before running the installer.</p> <p class="alert alert-danger">
<strong>Important!</strong>
You need to run composer to install dependencies before running the installer.
</p>
<?php endif; ?> <?php endif; ?>
<?php if (!$isWriteable): ?> <?php if (!$isWriteable): ?>
<p class="alert alert-danger"><strong>Important!</strong> ./PHPCI/config.yml needs to be writeable to continue.</p> <p class="alert alert-danger">
<strong>Important!</strong>
./PHPCI/config.yml needs to be writeable to continue.
</p>
<?php endif; ?> <?php endif; ?>
<?php if (!$phpOK): ?> <?php if (!$phpOK): ?>
@ -391,30 +401,3 @@ switch ($installStage) {
</div> </div>
</body> </body>
</html> </html>
<?php
/** Supporting functions */
function is__writable($path) {
if ($path{strlen($path)-1}=='/') {
return is__writable($path.uniqid(mt_rand()).'.tmp');
} elseif (is_dir($path)) {
return is__writable($path.'/'.uniqid(mt_rand()).'.tmp');
}
// check tmp file for read/write capabilities
$rm = file_exists($path);
$f = @fopen($path, 'a');
if ($f === false) {
return false;
}
fclose($f);
if (!$rm) {
unlink($path);
}
return true;
}

27
vars.php Normal file
View file

@ -0,0 +1,27 @@
<?php
// Define our APPLICATION_PATH, if not already defined:
if (!defined('APPLICATION_PATH')) {
define('APPLICATION_PATH', dirname(__FILE__) . '/');
define('PHPCI_DIR', APPLICATION_PATH);
}
// Define our PHPCI_URL, if not already defined:
if (!defined('PHPCI_URL')) {
define('PHPCI_URL', $config->get('phpci.url', '') . '/');
}
// Define PHPCI_BIN_DIR
if (!defined('PHPCI_BIN_DIR')) {
define('PHPCI_BIN_DIR', PHPCI_DIR . 'vendor/bin/');
}
// Should PHPCI run the Shell plugin?
if (!defined('ENABLE_SHELL_PLUGIN')) {
define('ENABLE_SHELL_PLUGIN', false);
}
// If this is not already defined, we're not running in the console:
if (!defined('PHPCI_IS_CONSOLE')) {
define('PHPCI_IS_CONSOLE', false);
}