php-censor/PHPCI/Builder.php

284 lines
5.8 KiB
PHP
Raw Normal View History

2013-05-03 17:02:53 +02:00
<?php
2013-05-16 03:16:56 +02:00
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
2013-05-03 17:02:53 +02:00
namespace PHPCI;
use PHPCI\Model\Build;
use b8\Store;
use Symfony\Component\Yaml\Parser as YamlParser;
2013-05-03 17:02:53 +02:00
2013-05-16 03:16:56 +02:00
/**
* PHPCI Build Runner
* @author Dan Cryer <dan@block8.co.uk>
*/
2013-05-03 17:02:53 +02:00
class Builder
{
public $buildPath;
public $ignore = array();
protected $ciDir;
protected $directory;
protected $success = true;
protected $log = '';
protected $verbose = false;
protected $plugins = array();
2013-05-03 17:02:53 +02:00
protected $build;
protected $logCallback;
protected $config;
2013-05-03 17:02:53 +02:00
public function __construct(Build $build, $logCallback = null)
2013-05-03 17:02:53 +02:00
{
$this->build = $build;
2013-05-10 13:28:43 +02:00
$this->store = Store\Factory::getStore('Build');
if(!is_null($logCallback) && is_callable($logCallback))
{
$this->logCallback = $logCallback;
}
2013-05-03 17:02:53 +02:00
}
public function setConfigArray(array $config)
{
$this->config = $config;
}
public function getConfig($key)
{
return isset($this->config[$key]) ? $this->config[$key] : null;
}
2013-05-03 17:02:53 +02:00
public function execute()
{
$this->build->setStatus(1);
2013-05-10 13:28:43 +02:00
$this->build->setStarted(new \DateTime());
$this->store->save($this->build);
2013-05-14 17:58:14 +02:00
$this->build->sendStatusPostback();
2013-05-03 17:02:53 +02:00
if($this->setupBuild())
{
2013-05-10 13:28:43 +02:00
$this->executePlugins('setup');
$this->executePlugins('test');
2013-05-03 17:02:53 +02:00
$this->log('');
2013-05-10 13:28:43 +02:00
$this->executePlugins('complete');
2013-05-03 17:02:53 +02:00
if($this->success)
{
2013-05-10 13:28:43 +02:00
$this->executePlugins('success');
2013-05-03 17:02:53 +02:00
$this->logSuccess('BUILD SUCCESSFUL!');
$this->build->setStatus(2);
}
else
{
2013-05-10 13:28:43 +02:00
$this->executePlugins('failure');
2013-05-03 17:02:53 +02:00
$this->logFailure('BUILD FAILED!');
$this->build->setStatus(3);
}
$this->log('');
}
2013-05-10 13:28:43 +02:00
else
{
$this->build->setStatus(3);
}
2013-05-03 17:02:53 +02:00
$this->removeBuild();
2013-05-14 17:58:14 +02:00
$this->build->sendStatusPostback();
2013-05-10 13:28:43 +02:00
$this->build->setFinished(new \DateTime());
2013-05-03 17:02:53 +02:00
$this->build->setLog($this->log);
$this->build->setPlugins(json_encode($this->plugins));
2013-05-10 13:28:43 +02:00
$this->store->save($this->build);
2013-05-03 17:02:53 +02:00
}
public function executeCommand()
2013-05-03 17:02:53 +02:00
{
$command = call_user_func_array('sprintf', func_get_args());
2013-05-03 17:02:53 +02:00
$this->log('Executing: ' . $command, ' ');
$output = '';
$status = 0;
exec($command, $output, $status);
if(!empty($output) && ($this->verbose || $status != 0))
{
$this->log($output, ' ');
}
return ($status == 0) ? true : false;
}
public function log($message, $prefix = '')
2013-05-03 17:02:53 +02:00
{
2013-05-03 17:02:53 +02:00
if(is_array($message))
{
foreach ($message as $item)
{
if(is_callable($this->logCallback))
{
$this->logCallback($prefix . $item);
}
$this->log .= $prefix . $item . PHP_EOL;
}
2013-05-03 17:02:53 +02:00
}
else
{
$message = $prefix . $message;
$this->log .= $message . PHP_EOL;
2013-05-03 17:02:53 +02:00
if(isset($this->logCallback) && is_callable($this->logCallback))
{
$cb = $this->logCallback;
$cb($message);
}
2013-05-03 17:02:53 +02:00
}
2013-05-10 13:28:43 +02:00
$this->build->setLog($this->log);
$this->build->setPlugins(json_encode($this->plugins));
$this->store->save($this->build);
2013-05-03 17:02:53 +02:00
}
public function logSuccess($message)
2013-05-03 17:02:53 +02:00
{
$this->log("\033[0;32m" . $message . "\033[0m");
}
public function logFailure($message)
2013-05-03 17:02:53 +02:00
{
$this->log("\033[0;31m" . $message . "\033[0m");
}
protected function setupBuild()
{
$commitId = $this->build->getCommitId();
2013-05-10 13:28:43 +02:00
$buildId = 'project' . $this->build->getProject()->getId() . '-build' . $this->build->getId();
2013-05-03 17:02:53 +02:00
$this->ciDir = realpath(dirname(__FILE__) . '/../') . '/';
2013-05-10 13:28:43 +02:00
$this->buildPath = $this->ciDir . 'build/' . $buildId . '/';
2013-05-03 17:02:53 +02:00
// Create a working copy of the project:
if(!$this->build->createWorkingCopy($this, $this->buildPath)) {
return false;
2013-05-10 13:28:43 +02:00
}
2013-05-03 17:02:53 +02:00
// Does the project's phpci.yml request verbose mode?
if(!isset($this->config['build_settings']['verbose']) || !$this->config['build_settings']['verbose']) {
2013-05-03 17:02:53 +02:00
$this->verbose = false;
}
else {
2013-05-03 17:02:53 +02:00
$this->verbose = true;
}
// Does the project have any paths it wants plugins to ignore?
if(isset($this->config['build_settings']['ignore'])) {
$this->ignore = $this->config['build_settings']['ignore'];
2013-05-03 17:02:53 +02:00
}
$this->logSuccess('Working copy created: ' . $this->buildPath);
2013-05-03 17:02:53 +02:00
return true;
}
protected function removeBuild()
{
$this->log('Removing build.');
shell_exec(sprintf('rm -Rf "%s"', $this->buildPath));
2013-05-03 17:02:53 +02:00
}
2013-05-10 13:28:43 +02:00
protected function executePlugins($stage)
2013-05-03 17:02:53 +02:00
{
// Ignore any stages for which we don't have plugins set:
if(!array_key_exists($stage, $this->config) || !is_array($this->config[$stage]))
{
return;
}
2013-05-10 13:28:43 +02:00
foreach($this->config[$stage] as $plugin => $options)
2013-05-03 17:02:53 +02:00
{
$this->log('');
$this->log('RUNNING PLUGIN: ' . $plugin);
// Is this plugin allowed to fail?
2013-05-10 13:28:43 +02:00
if($stage == 'test' && !isset($options['allow_failures']))
2013-05-03 17:02:53 +02:00
{
$options['allow_failures'] = false;
}
$class = str_replace('_', ' ', $plugin);
$class = ucwords($class);
$class = 'PHPCI\\Plugin\\' . str_replace(' ', '', $class);
if(!class_exists($class))
{
$this->logFailure('Plugin does not exist: ' . $plugin);
if($stage == 'test')
2013-05-03 17:02:53 +02:00
{
$this->plugins[$plugin] = false;
if(!$options['allow_failures'])
{
$this->success = false;
}
2013-05-03 17:02:53 +02:00
}
2013-05-15 22:53:36 +02:00
2013-05-03 17:02:53 +02:00
continue;
}
try
{
$obj = new $class($this, $options);
2013-05-03 17:02:53 +02:00
if(!$obj->execute())
2013-05-03 17:02:53 +02:00
{
if($stage == 'test')
2013-05-03 17:02:53 +02:00
{
$this->plugins[$plugin] = false;
if(!$options['allow_failures'])
{
$this->success = false;
}
2013-05-03 17:02:53 +02:00
}
2013-05-15 22:53:36 +02:00
2013-05-03 17:02:53 +02:00
$this->logFailure('PLUGIN STATUS: FAILED');
continue;
}
}
catch(\Exception $ex)
{
$this->logFailure('EXCEPTION: ' . $ex->getMessage());
if($stage == 'test')
2013-05-03 17:02:53 +02:00
{
$this->plugins[$plugin] = false;
if(!$options['allow_failures'])
{
$this->success = false;
}
2013-05-03 17:02:53 +02:00
}
$this->logFailure('PLUGIN STATUS: FAILED');
continue;
2013-05-03 17:02:53 +02:00
}
if($stage == 'test')
{
$this->plugins[$plugin] = true;
}
2013-05-15 22:53:36 +02:00
2013-05-03 17:02:53 +02:00
$this->logSuccess('PLUGIN STATUS: SUCCESS!');
}
}
}