Merge pull request #241 from meadsteve/buillder-component-extraction

Buillder component extraction
This commit is contained in:
Steve B 2014-01-16 00:52:42 -08:00
commit 53e295f145
18 changed files with 401 additions and 169 deletions

View file

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

View file

@ -9,8 +9,10 @@
namespace PHPCI;
use PHPCI\Helper\BuildInterpolator;
use PHPCI\Helper\CommandExecutor;
use PHPCI\Helper\MailerFactory;
use PHPCI\Logging\BuildLogger;
use PHPCI\Model\Build;
use b8\Store;
use b8\Config;
@ -22,7 +24,7 @@ use Psr\Log\LogLevel;
* PHPCI Build Runner
* @author Dan Cryer <dan@block8.co.uk>
*/
class Builder implements LoggerAwareInterface, BuildLogger
class Builder implements LoggerAwareInterface
{
/**
* @var string
@ -75,12 +77,9 @@ class Builder implements LoggerAwareInterface, BuildLogger
protected $lastOutput;
/**
* An array of key => value pairs that will be used for
* interpolation and environment variables
* @var array
* @see setInterpolationVars()
* @var BuildInterpolator
*/
protected $interpolation_vars = array();
protected $interpolator;
/**
* @var \PHPCI\Store\BuildStore
@ -102,21 +101,34 @@ class Builder implements LoggerAwareInterface, BuildLogger
*/
protected $commandExecutor;
/**
* @var Logging\BuildLogger
*/
protected $buildLogger;
/**
* Set up the builder.
* @param \PHPCI\Model\Build $build
* @param LoggerInterface $logger
*/
public function __construct(Build $build, $logger = null)
public function __construct(Build $build, LoggerInterface $logger = null)
{
if ($logger) {
$this->setLogger($logger);
}
$this->build = $build;
$this->store = Store\Factory::getStore('Build');
$this->pluginExecutor = new Plugin\Util\Executor($this->buildPluginFactory($build), $this);
$this->commandExecutor = new CommandExecutor($this, PHPCI_DIR, $this->quiet, $this->verbose);
$this->buildLogger = new BuildLogger($logger, $build);
$this->pluginExecutor = new Plugin\Util\Executor($this->buildPluginFactory($build), $this->buildLogger);
$this->commandExecutor = new CommandExecutor(
$this->buildLogger,
PHPCI_DIR,
$this->quiet,
$this->verbose
);
$this->interpolator = new BuildInterpolator();
}
/**
@ -195,15 +207,15 @@ class Builder implements LoggerAwareInterface, BuildLogger
if ($this->success) {
$this->pluginExecutor->executePlugins($this->config, 'success');
$this->logSuccess('BUILD SUCCESSFUL!');
$this->buildLogger->logSuccess('BUILD SUCCESSFUL!');
}
else {
$this->pluginExecutor->executePlugins($this->config, 'failure');
$this->logFailure("BUILD FAILURE");
$this->buildLogger->logFailure("BUILD FAILURE");
}
// Clean up:
$this->log('Removing build.');
$this->buildLogger->log('Removing build.');
shell_exec(sprintf('rm -Rf "%s"', $this->buildPath));
// Update the build in the database, ping any external services, etc.
@ -239,107 +251,14 @@ class Builder implements LoggerAwareInterface, BuildLogger
}
/**
* Add an entry to the build log.
* @param string|string[] $message
* @param string $level
* @param mixed[] $context
*/
public function log($message, $level = LogLevel::INFO, $context = array())
{
// Skip if no logger has been loaded.
if (!$this->logger) {
return;
}
if (!is_array($message)) {
$message = array($message);
}
// The build is added to the context so the logger can use
// details from it if required.
$context['build'] = $this->build;
foreach ($message as $item) {
$this->logger->log($level, $item, $context);
}
}
/**
* Add a success-coloured message to the log.
* @param string
*/
public function logSuccess($message)
{
$this->log("\033[0;32m" . $message . "\033[0m");
}
/**
* Add a failure-coloured message to the log.
* @param string $message
* @param \Exception $exception The exception that caused the error.
*/
public function logFailure($message, \Exception $exception = null)
{
$context = array();
// The psr3 log interface stipulates that exceptions should be passed
// as the exception key in the context array.
if ($exception) {
$context['exception'] = $exception;
}
$this->log(
"\033[0;31m" . $message . "\033[0m",
LogLevel::ERROR,
$context
);
}
/**
* Replace every occurance of the interpolation vars in the given string
* Replace every occurrence of the interpolation vars in the given string
* Example: "This is build %PHPCI_BUILD%" => "This is build 182"
* @param string $input
* @return string
*/
public function interpolate($input)
{
$keys = array_keys($this->interpolation_vars);
$values = array_values($this->interpolation_vars);
return str_replace($keys, $values, $input);
}
/**
* Sets the variables that will be used for interpolation. This must be run
* from setupBuild() because prior to that, we don't know the buildPath
*/
protected function setInterpolationVars()
{
$this->interpolation_vars = array();
$this->interpolation_vars['%PHPCI%'] = 1;
$this->interpolation_vars['%COMMIT%'] = $this->build->getCommitId();
$this->interpolation_vars['%PROJECT%'] = $this->build->getProjectId();
$this->interpolation_vars['%BUILD%'] = $this->build->getId();
$this->interpolation_vars['%PROJECT_TITLE%'] = $this->getBuildProjectTitle(
);
$this->interpolation_vars['%BUILD_PATH%'] = $this->buildPath;
$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%']);
return $this->interpolator->interpolate($input);
}
/**
@ -352,7 +271,11 @@ class Builder implements LoggerAwareInterface, BuildLogger
$this->ciDir = dirname(__FILE__) . '/../';
$this->buildPath = $this->ciDir . 'build/' . $buildId . '/';
$this->setInterpolationVars();
$this->interpolator->setupInterpolationVars(
$this->build,
$this->buildPath,
PHPCI_URL
);
// Create a working copy of the project:
if (!$this->build->createWorkingCopy($this, $this->buildPath)) {
@ -369,7 +292,7 @@ class Builder implements LoggerAwareInterface, BuildLogger
$this->ignore = $this->config['build_settings']['ignore'];
}
$this->logSuccess('Working copy created: ' . $this->buildPath);
$this->buildLogger->logSuccess('Working copy created: ' . $this->buildPath);
return true;
}
@ -381,17 +304,31 @@ class Builder implements LoggerAwareInterface, BuildLogger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
$this->buildLogger->setLogger($logger);
}
public function log($message, $level = LogLevel::INFO, $context = array())
{
$this->buildLogger->log($message, $level, $context);
}
/**
* Add a success-coloured message to the log.
* @param string
*/
public function logSuccess($message)
{
$this->buildLogger->logSuccess($message);
}
/**
* returns the logger attached to this builder.
*
* @return LoggerInterface
* Add a failure-coloured message to the log.
* @param string $message
* @param \Exception $exception The exception that caused the error.
*/
public function getLogger()
public function logFailure($message, \Exception $exception = null)
{
return $this->logger;
$this->buildLogger->logFailure($message, $exception);
}
private function buildPluginFactory(Build $build)

View file

@ -10,9 +10,9 @@
namespace PHPCI\Command;
use Monolog\Logger;
use PHPCI\Helper\BuildDBLogHandler;
use PHPCI\Helper\LoggedBuildContextTidier;
use PHPCI\Helper\OutputLogHandler;
use PHPCI\Logging\BuildDBLogHandler;
use PHPCI\Logging\LoggedBuildContextTidier;
use PHPCI\Logging\OutputLogHandler;
use Psr\Log\LoggerAwareInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;

View file

@ -0,0 +1,61 @@
<?php
namespace PHPCI\Helper;
use PHPCI\Model\Build;
class BuildInterpolator
{
/**
* An array of key => value pairs that will be used for
* interpolation and environment variables
* @var mixed[]
* @see setupInterpolationVars()
*/
protected $interpolation_vars = array();
/**
* Sets the variables that will be used for interpolation.
* @param Build $build
* @param string $buildPath
* @param string $phpCiUrl
*/
public function setupInterpolationVars(Build $build, $buildPath, $phpCiUrl)
{
$this->interpolation_vars = array();
$this->interpolation_vars['%PHPCI%'] = 1;
$this->interpolation_vars['%COMMIT%'] = $build->getCommitId();
$this->interpolation_vars['%PROJECT%'] = $build->getProjectId();
$this->interpolation_vars['%BUILD%'] = $build->getId();
$this->interpolation_vars['%PROJECT_TITLE%'] = $build->getProjectTitle();
$this->interpolation_vars['%BUILD_PATH%'] = $buildPath;
$this->interpolation_vars['%BUILD_URI%'] = $phpCiUrl . "build/view/" . $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%']);
}
/**
* Replace every occurrence of the interpolation vars in the given string
* Example: "This is build %PHPCI_BUILD%" => "This is build 182"
* @param string $input
* @return string
*/
public function interpolate($input)
{
$keys = array_keys($this->interpolation_vars);
$values = array_values($this->interpolation_vars);
return str_replace($keys, $values, $input);
}
}

View file

@ -3,12 +3,12 @@
namespace PHPCI\Helper;
use PHPCI\BuildLogger;
use \PHPCI\Logging\BuildLogger;
class CommandExecutor
{
/**
* @var \PHPCI\BuildLogger
* @var \PHPCI\Logging\BuildLogger
*/
protected $logger;

View file

@ -1,6 +1,6 @@
<?php
namespace PHPCI\Helper;
namespace PHPCI\Logging;
use b8\Store;

View file

@ -0,0 +1,96 @@
<?php
namespace PHPCI\Logging;
use PHPCI\Model\Build;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
class BuildLogger implements LoggerAwareInterface
{
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @var Build
*/
protected $build;
function __construct(LoggerInterface $logger = null, Build $build)
{
$this->logger = $logger;
$this->build = $build;
}
/**
* Add an entry to the build log.
* @param string|string[] $message
* @param string $level
* @param mixed[] $context
*/
public function log($message, $level = LogLevel::INFO, $context = array())
{
// Skip if no logger has been loaded.
if (!$this->logger) {
return;
}
if (!is_array($message)) {
$message = array($message);
}
// The build is added to the context so the logger can use
// details from it if required.
$context['build'] = $this->build;
foreach ($message as $item) {
$this->logger->log($level, $item, $context);
}
}
/**
* Add a success-coloured message to the log.
* @param string
*/
public function logSuccess($message)
{
$this->log("\033[0;32m" . $message . "\033[0m");
}
/**
* Add a failure-coloured message to the log.
* @param string $message
* @param \Exception $exception The exception that caused the error.
*/
public function logFailure($message, \Exception $exception = null)
{
$context = array();
// The psr3 log interface stipulates that exceptions should be passed
// as the exception key in the context array.
if ($exception) {
$context['exception'] = $exception;
}
$this->log(
"\033[0;31m" . $message . "\033[0m",
LogLevel::ERROR,
$context
);
}
/**
* Sets a logger instance on the object
*
* @param LoggerInterface $logger
* @return null
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}

View file

@ -1,6 +1,6 @@
<?php
namespace PHPCI\Helper;
namespace PHPCI\Logging;
use PHPCI\Model\Build;

View file

@ -1,7 +1,7 @@
<?php
namespace PHPCI\Helper;
namespace PHPCI\Logging;
use Monolog\Logger;

View file

@ -1,6 +1,6 @@
<?php
namespace PHPCI\Helper;
namespace PHPCI\Logging;
use Monolog\Handler\AbstractProcessingHandler;
use Psr\Log\LogLevel;

View file

@ -550,6 +550,17 @@ class BuildBase extends Model
return $rtn;
}
/**
* Get the value of the project's Title / title.
*
* @return string
*/
public function getProjectTitle()
{
return $this->getProject()->getTitle();
}
/**
* Set Project - Accepts an ID, an array representing a Project or a Project model.
*

View file

@ -2,7 +2,7 @@
namespace PHPCI\Plugin\Util;
use PHPCI\BuildLogger;
use \PHPCI\Logging\BuildLogger;
class Executor
{
@ -17,7 +17,7 @@ class Executor
*/
protected $pluginFactory;
function __construct(Factory $pluginFactory, BuildLogger $logger)
function __construct(Factory $pluginFactory,BuildLogger $logger)
{
$this->pluginFactory = $pluginFactory;
$this->logger = $logger;

View file

@ -0,0 +1,49 @@
<?php
namespace PHPCI\Plugin\Tests\Helper;
use PHPCI\Helper\BuildInterpolator;
use Prophecy\PhpUnit\ProphecyTestCase;
class BuildInterpolatorTest extends ProphecyTestCase
{
/**
* @var BuildInterpolator
*/
protected $testedInterpolator;
protected function setUp()
{
parent::setup();
$this->testedInterpolator = new BuildInterpolator();
}
public function testInterpolate_LeavesStringsUnchangedByDefault()
{
$string = "Hello World";
$expectedOutput = "Hello World";
$actualOutput = $this->testedInterpolator->interpolate($string);
$this->assertEquals($expectedOutput, $actualOutput);
}
public function testInterpolate_LeavesStringsUnchangedWhenBuildIsSet()
{
$build = $this->prophesize('PHPCI\\Model\\Build')->reveal();
$string = "Hello World";
$expectedOutput = "Hello World";
$this->testedInterpolator->setupInterpolationVars(
$build,
"/buildpath/",
"phpci.com"
);
$actualOutput = $this->testedInterpolator->interpolate($string);
$this->assertEquals($expectedOutput, $actualOutput);
}
}

View file

@ -15,7 +15,7 @@ class CommandExecutorTest extends ProphecyTestCase
protected function setUp()
{
parent::setUp();
$mockBuildLogger = $this->prophesize('\PHPCI\BuildLogger');
$mockBuildLogger = $this->prophesize('PHPCI\Logging\BuildLogger');
$this->testedExecutor = new CommandExecutor($mockBuildLogger->reveal(), __DIR__ . "/");
}

View file

@ -0,0 +1,107 @@
<?php
namespace PHPCI\Plugin\Tests\Helper;
use PHPCI\Logging\BuildLogger;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTestCase;
use Psr\Log\LogLevel;
class BuildLoggerTest extends ProphecyTestCase
{
/**
* @var BuildLogger
*/
protected $testedBuildLogger;
protected $mockLogger;
protected $mockBuild;
protected function setUp()
{
parent::setUp();
$this->mockLogger = $this->prophesize('\Psr\Log\LoggerInterface');
$this->mockBuild = $this->prophesize('\PHPCI\Model\Build');
$this->testedBuildLogger = new BuildLogger(
$this->mockLogger->reveal(),
$this->mockBuild->reveal()
);
}
public function testLog_CallsWrappedLogger()
{
$level = LogLevel::NOTICE;
$message = "Testing";
$contextIn = array();
$this->mockLogger->log($level, $message, Argument::type('array'))
->shouldBeCalledTimes(1);
$this->testedBuildLogger->log($message, $level, $contextIn);
}
public function testLog_CallsWrappedLoggerForEachMessage()
{
$level = LogLevel::NOTICE;
$message = array("One", "Two", "Three");
$contextIn = array();
$this->mockLogger->log($level, "One", Argument::type('array'))
->shouldBeCalledTimes(1);
$this->mockLogger->log($level, "Two", Argument::type('array'))
->shouldBeCalledTimes(1);
$this->mockLogger->log($level, "Three", Argument::type('array'))
->shouldBeCalledTimes(1);
$this->testedBuildLogger->log($message, $level, $contextIn);
}
public function testLog_AddsBuildToContext()
{
$level = LogLevel::NOTICE;
$message = "Testing";
$contextIn = array();
$expectedContext = array(
'build' => $this->mockBuild->reveal()
);
$this->mockLogger->log($level, $message, $expectedContext)
->shouldBeCalledTimes(1);
$this->testedBuildLogger->log($message, $level, $contextIn);
}
public function testLogFailure_LogsAsErrorLevel()
{
$message = "Testing";
$expectedLevel = LogLevel::ERROR;
$this->mockLogger->log($expectedLevel,
Argument::type('string'),
Argument::type('array'))
->shouldBeCalledTimes(1);
$this->testedBuildLogger->logFailure($message);
}
public function testLogFailure_AddsExceptionContext()
{
$message = "Testing";
$exception = new \Exception("Expected Exception");
$this->mockLogger->log(Argument::type('string'),
Argument::type('string'),
Argument::withEntry('exception', $exception))
->shouldBeCalledTimes(1);
$this->testedBuildLogger->logFailure($message, $exception);
}
}

View file

@ -1,8 +1,10 @@
<?php
use \PHPCI\Helper\LoggerConfig;
namespace PHPCI\Plugin\Tests\Helper;
class LoggerConfigTest extends PHPUnit_Framework_TestCase
use \PHPCI\Logging\LoggerConfig;
class LoggerConfigTest extends \PHPUnit_Framework_TestCase
{
public function testGetFor_ReturnsPSRLogger()
{
@ -20,7 +22,7 @@ class LoggerConfigTest extends PHPUnit_Framework_TestCase
public function testGetFor_AttachesAlwaysPresentHandlers()
{
$expectedHandler = new Monolog\Handler\NullHandler();
$expectedHandler = new \Monolog\Handler\NullHandler();
$config = new LoggerConfig(array(
LoggerConfig::KEY_AlwaysLoaded => function() use ($expectedHandler) {
return array($expectedHandler);
@ -36,7 +38,7 @@ class LoggerConfigTest extends PHPUnit_Framework_TestCase
public function testGetFor_AttachesSpecificHandlers()
{
$expectedHandler = new Monolog\Handler\NullHandler();
$expectedHandler = new \Monolog\Handler\NullHandler();
$config = new LoggerConfig(array(
"Specific" => function() use ($expectedHandler) {
return array($expectedHandler);
@ -52,8 +54,8 @@ class LoggerConfigTest extends PHPUnit_Framework_TestCase
public function testGetFor_IgnoresAlternativeHandlers()
{
$expectedHandler = new Monolog\Handler\NullHandler();
$alternativeHandler = new Monolog\Handler\NullHandler();
$expectedHandler = new \Monolog\Handler\NullHandler();
$alternativeHandler = new \Monolog\Handler\NullHandler();
$config = new LoggerConfig(array(
"Specific" => function() use ($expectedHandler) {

View file

@ -22,7 +22,7 @@ class ExecutorTest extends ProphecyTestCase
protected function setUp()
{
parent::setUp();
$this->mockBuildLogger = $this->prophesize('\PHPCI\BuildLogger');
$this->mockBuildLogger = $this->prophesize('\PHPCI\Logging\BuildLogger');
$this->mockFactory = $this->prophesize('\PHPCI\Plugin\Util\Factory');
$this->testedExecutor = new Executor($this->mockFactory->reveal(), $this->mockBuildLogger->reveal());
}

View file

@ -20,7 +20,7 @@ use PHPCI\Command\DaemonCommand;
use PHPCI\Command\PollCommand;
use Symfony\Component\Console\Application;
$loggerConfig = \PHPCI\Helper\LoggerConfig::newFromFile(__DIR__ . "/loggerconfig.php");
$loggerConfig = \PHPCI\Logging\LoggerConfig::newFromFile(__DIR__ . "/loggerconfig.php");
$application = new Application();