Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
e77a5a75fb
|
@ -10,6 +10,7 @@
|
|||
namespace PHPCI;
|
||||
|
||||
use b8;
|
||||
use b8\Registry;
|
||||
use b8\Http\Response\RedirectResponse;
|
||||
use b8\View;
|
||||
|
||||
|
@ -33,8 +34,11 @@ class Application extends b8\Application
|
|||
$sessionAction = ($this->controllerName == 'Session' && in_array($this->action, array('login', 'logout')));
|
||||
$externalAction = in_array($this->controllerName, array('Bitbucket', 'Github', 'BuildStatus'));
|
||||
$skipValidation = ($externalAction || $sessionAction);
|
||||
|
||||
|
||||
if($skipValidation || $this->validateSession()) {
|
||||
if ( !empty($_SESSION['user']) ) {
|
||||
Registry::getInstance()->set('user', $_SESSION['user']);
|
||||
}
|
||||
parent::handleRequest();
|
||||
}
|
||||
|
||||
|
@ -43,7 +47,7 @@ class Application extends b8\Application
|
|||
$view->content = $this->response->getContent();
|
||||
$this->response->setContent($view->render());
|
||||
}
|
||||
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ class BuildFactory
|
|||
{
|
||||
switch($base->getProject()->getType())
|
||||
{
|
||||
case 'remote':
|
||||
$type = 'RemoteGitBuild';
|
||||
break;
|
||||
case 'local':
|
||||
$type = 'LocalBuild';
|
||||
break;
|
||||
|
|
|
@ -116,6 +116,16 @@ class Builder
|
|||
return isset($this->config[$key]) ? $this->config[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access a variable from the config.yml
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSystemConfig($key)
|
||||
{
|
||||
return \b8\Registry::getInstance()->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the build.
|
||||
* @param Build
|
||||
|
@ -125,6 +135,22 @@ class Builder
|
|||
return $this->build;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The title of the project being built.
|
||||
*/
|
||||
public function getBuildProjectTitle() {
|
||||
return $this->getBuild()->getProject()->getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the build has passed or failed.
|
||||
* @return bool
|
||||
*/
|
||||
public function getSuccessStatus()
|
||||
{
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the active build.
|
||||
*/
|
||||
|
|
122
PHPCI/Command/DaemonCommand.php
Normal file
122
PHPCI/Command/DaemonCommand.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPCI - Continuous Integration for PHP
|
||||
* nohup PHPCI_DIR/console phpci:start-daemon > /dev/null 2>&1 &
|
||||
*
|
||||
* @copyright Copyright 2013, Block 8 Limited.
|
||||
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||
* @link http://www.phptesting.org/
|
||||
*/
|
||||
|
||||
namespace PHPCI\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use b8\Store\Factory;
|
||||
use PHPCI\Builder;
|
||||
use PHPCI\BuildFactory;
|
||||
|
||||
/**
|
||||
* Daemon that loops and call the run-command.
|
||||
* @author Gabriel Baker <gabriel.baker@autonomicpilot.co.uk>
|
||||
* @package PHPCI
|
||||
* @subpackage Console
|
||||
*/
|
||||
class DaemonCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('phpci:daemon')
|
||||
->setDescription('Initiates the daemon to run commands.')
|
||||
->addArgument(
|
||||
'state',
|
||||
InputArgument::REQUIRED,
|
||||
'start|stop|status'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through running.
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$state = $input->getArgument('state');
|
||||
|
||||
switch ($state) {
|
||||
case 'start':
|
||||
$this->startDaemon();
|
||||
break;
|
||||
case 'stop':
|
||||
$this->stopDaemon();
|
||||
break;
|
||||
case 'status':
|
||||
$this->statusDaemon();
|
||||
break;
|
||||
default:
|
||||
echo "Not a valid choice, please use start stop or status";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function startDaemon()
|
||||
{
|
||||
|
||||
if ( file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) {
|
||||
echo "Already started\n";
|
||||
return "alreadystarted";
|
||||
}
|
||||
|
||||
$logfile = PHPCI_DIR."/daemon/daemon.log";
|
||||
$cmd = "nohup %s/daemonise phpci:daemonise > %s 2>&1 &";
|
||||
$command = sprintf($cmd, PHPCI_DIR, $logfile);
|
||||
exec($command);
|
||||
}
|
||||
|
||||
protected function stopDaemon()
|
||||
{
|
||||
|
||||
if ( !file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) {
|
||||
echo "Not started\n";
|
||||
return "notstarted";
|
||||
}
|
||||
|
||||
$cmd = "kill $(cat %s/daemon/daemon.pid)";
|
||||
$command = sprintf($cmd, PHPCI_DIR);
|
||||
exec($command);
|
||||
unlink(PHPCI_DIR.'/daemon/daemon.pid');
|
||||
}
|
||||
|
||||
protected function statusDaemon()
|
||||
{
|
||||
|
||||
if ( !file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) {
|
||||
echo "Not running\n";
|
||||
return "notrunning";
|
||||
}
|
||||
|
||||
$pid = trim(file_get_contents(PHPCI_DIR.'/daemon/daemon.pid'));
|
||||
$pidcheck = sprintf("/proc/%s", $pid);
|
||||
if ( is_dir($pidcheck) ) {
|
||||
echo "Running\n";
|
||||
return "running";
|
||||
}
|
||||
|
||||
unlink(PHPCI_DIR.'/daemon/daemon.pid');
|
||||
echo "Not running\n";
|
||||
return "notrunning";
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when log entries are made in Builder / the plugins.
|
||||
* @see \PHPCI\Builder::log()
|
||||
*/
|
||||
public function logCallback($log)
|
||||
{
|
||||
$this->output->writeln($log);
|
||||
}
|
||||
}
|
76
PHPCI/Command/DaemoniseCommand.php
Normal file
76
PHPCI/Command/DaemoniseCommand.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPCI - Continuous Integration for PHP
|
||||
* nohup PHPCI_DIR/console phpci:start-daemon > /dev/null 2>&1 &
|
||||
*
|
||||
* @copyright Copyright 2013, Block 8 Limited.
|
||||
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||
* @link http://www.phptesting.org/
|
||||
*/
|
||||
|
||||
namespace PHPCI\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use b8\Store\Factory;
|
||||
use PHPCI\Builder;
|
||||
use PHPCI\BuildFactory;
|
||||
|
||||
/**
|
||||
* Daemon that loops and call the run-command.
|
||||
* @author Gabriel Baker <gabriel.baker@autonomicpilot.co.uk>
|
||||
* @package PHPCI
|
||||
* @subpackage Console
|
||||
*/
|
||||
class DaemoniseCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('phpci:daemonise')
|
||||
->setDescription('Starts the daemon to run commands.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through running.
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$cmd = "echo %s > '%s/daemon/daemon.pid'";
|
||||
$command = sprintf($cmd, getmypid(), PHPCI_DIR);
|
||||
exec($command);
|
||||
|
||||
$this->run = true;
|
||||
$this->sleep = 0;
|
||||
$runner = new RunCommand;
|
||||
|
||||
while ($this->run) {
|
||||
|
||||
try {
|
||||
$buildCount = $runner->execute($input, $output);
|
||||
} catch (\Exception $e) {
|
||||
var_dump($e);
|
||||
}
|
||||
|
||||
if (0 == $buildCount && $this->sleep < 15) {
|
||||
$this->sleep++;
|
||||
} else if (1 < $this->sleep) {
|
||||
$this->sleep--;
|
||||
}
|
||||
echo '.'.(0 === $buildCount?'':'build');
|
||||
sleep($this->sleep);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when log entries are made in Builder / the plugins.
|
||||
* @see \PHPCI\Builder::log()
|
||||
*/
|
||||
public function logCallback($log)
|
||||
{
|
||||
$this->output->writeln($log);
|
||||
}
|
||||
}
|
|
@ -48,6 +48,14 @@ class InstallCommand extends Command
|
|||
$conf['phpci']['github']['id'] = $this->ask('(Optional) Github Application ID: ', true);
|
||||
$conf['phpci']['github']['secret'] = $this->ask('(Optional) Github Application Secret: ', true);
|
||||
|
||||
$conf['phpci']['email_settings']['smtp_address'] = $this->ask('(Optional) Smtp server address: ', true);
|
||||
$conf['phpci']['email_settings']['smtp_port'] = $this->ask('(Optional) Smtp port: ', true);
|
||||
$conf['phpci']['email_settings']['smtp_encryption'] = $this->ask('(Optional) Smtp encryption: ', 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']['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);
|
||||
|
||||
$dbUser = $conf['b8']['database']['username'];
|
||||
$dbPass = $conf['b8']['database']['password'];
|
||||
$dbHost = $conf['b8']['database']['servers']['write'];
|
||||
|
|
|
@ -42,18 +42,23 @@ class RunCommand extends Command
|
|||
|
||||
$store = Factory::getStore('Build');
|
||||
$result = $store->getByStatus(0);
|
||||
$builds = 0;
|
||||
|
||||
foreach ($result['items'] as $build) {
|
||||
$builds++;
|
||||
|
||||
$build = BuildFactory::getBuild($build);
|
||||
|
||||
|
||||
if ($input->getOption('verbose')) {
|
||||
$builder = new Builder($build, array($this, 'logCallback'));
|
||||
} else {
|
||||
$builder = new Builder($build);
|
||||
}
|
||||
|
||||
|
||||
$builder->execute();
|
||||
}
|
||||
|
||||
return $builds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,6 +79,7 @@ class BuildController extends \PHPCI\Controller
|
|||
$build = $this->_buildStore->save($build);
|
||||
|
||||
header('Location: '.PHPCI_URL.'build/view/' . $build->getId());
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,14 +87,15 @@ class BuildController extends \PHPCI\Controller
|
|||
*/
|
||||
public function delete($buildId)
|
||||
{
|
||||
if (!Registry::getInstance()->get('user')->getIsAdmin()) {
|
||||
if (empty($_SESSION['user']) || !$_SESSION['user']->getIsAdmin()) {
|
||||
throw new \Exception('You do not have permission to do that.');
|
||||
}
|
||||
|
||||
|
||||
$build = $this->_buildStore->getById($buildId);
|
||||
$this->_buildStore->delete($build);
|
||||
|
||||
header('Location: '.PHPCI_URL.'project/view/' . $build->getProjectId());
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,7 @@ class IndexController extends \PHPCI\Controller
|
|||
$projects = $this->_projectStore->getWhere(array(), 50, 0, array(), array('title' => 'ASC'));
|
||||
$summary = $this->_buildStore->getBuildSummary();
|
||||
|
||||
$summaryView = new b8\View('BuildsTable');
|
||||
$summaryView = new b8\View('SummaryTable');
|
||||
$summaryView->builds = $summary['items'];
|
||||
|
||||
$this->view->builds = $this->getLatestBuildsHtml();
|
||||
|
|
|
@ -63,6 +63,7 @@ class ProjectController extends \PHPCI\Controller
|
|||
$build = $this->_buildStore->save($build);
|
||||
|
||||
header('Location: '.PHPCI_URL.'build/view/' . $build->getId());
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,6 +79,7 @@ class ProjectController extends \PHPCI\Controller
|
|||
$this->_projectStore->delete($project);
|
||||
|
||||
header('Location: '.PHPCI_URL);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -252,12 +254,13 @@ class ProjectController extends \PHPCI\Controller
|
|||
'choose' => 'Select repository type...',
|
||||
'github' => 'Github',
|
||||
'bitbucket' => 'Bitbucket',
|
||||
'remote' => 'Remote URL',
|
||||
'local' => 'Local Path'
|
||||
);
|
||||
|
||||
$field = new Form\Element\Select('type');
|
||||
$field->setRequired(true);
|
||||
$field->setPattern('^(github|bitbucket|local)');
|
||||
$field->setPattern('^(github|bitbucket|remote|local)');
|
||||
$field->setOptions($options);
|
||||
$field->setLabel('Where is your project hosted?');
|
||||
$field->setClass('span4');
|
||||
|
@ -275,6 +278,11 @@ class ProjectController extends \PHPCI\Controller
|
|||
$type = $values['type'];
|
||||
|
||||
switch($type) {
|
||||
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.');
|
||||
|
@ -282,7 +290,7 @@ class ProjectController extends \PHPCI\Controller
|
|||
break;
|
||||
case 'github':
|
||||
case 'bitbucket':
|
||||
if (!preg_match('/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-]+$/', $val)) {
|
||||
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;
|
||||
|
|
|
@ -25,11 +25,22 @@ class LocalBuild extends Build
|
|||
* Create a working copy by cloning, copying, or similar.
|
||||
*/
|
||||
public function createWorkingCopy(Builder $builder, $buildPath)
|
||||
{
|
||||
{
|
||||
$reference = $this->getProject()->getReference();
|
||||
$reference = substr($reference, -1) == '/' ? substr($reference, 0, -1) : $reference;
|
||||
$buildPath = substr($buildPath, 0, -1);
|
||||
$yamlParser = new YamlParser();
|
||||
|
||||
if(is_file($reference.'/config')) {
|
||||
//We're probably looing at a bare repository. We'll open the config and check
|
||||
$gitConfig = parse_ini_file($reference.'/config',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')) {
|
||||
$builder->logFailure('Project does not contain a phpci.yml file.');
|
||||
|
|
|
@ -19,12 +19,15 @@ use Symfony\Component\Yaml\Parser as YamlParser;
|
|||
* @package PHPCI
|
||||
* @subpackage Core
|
||||
*/
|
||||
abstract class RemoteGitBuild extends Build
|
||||
class RemoteGitBuild extends Build
|
||||
{
|
||||
/**
|
||||
* Get the URL to be used to clone this remote repository.
|
||||
*/
|
||||
abstract protected function getCloneUrl();
|
||||
protected function getCloneUrl()
|
||||
{
|
||||
return $this->getProject()->getReference();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a working copy by cloning, copying, or similar.
|
||||
|
|
51
PHPCI/Plugin/Atoum.php
Normal file
51
PHPCI/Plugin/Atoum.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace PHPCI\Plugin;
|
||||
|
||||
class Atoum implements \PHPCI\Plugin
|
||||
{
|
||||
private $args;
|
||||
private $config;
|
||||
private $directory;
|
||||
private $executable;
|
||||
|
||||
public function __construct(\PHPCI\Builder $phpci, array $options = array())
|
||||
{
|
||||
$this->phpci = $phpci;
|
||||
|
||||
if (isset($options['executable'])) {
|
||||
$this->executable = $options['executable'];
|
||||
}
|
||||
else {
|
||||
$this->executable = './vendor/bin/atoum';
|
||||
}
|
||||
|
||||
if (isset($options['args'])) {
|
||||
$this->args = $options['args'];
|
||||
}
|
||||
|
||||
if (isset($options['config'])) {
|
||||
$this->config = $options['config'];
|
||||
}
|
||||
|
||||
if (isset($options['directory'])) {
|
||||
$this->directory = $options['directory'];
|
||||
}
|
||||
}
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$cmd = $this->phpci->buildPath . DIRECTORY_SEPARATOR . $this->executable;
|
||||
|
||||
if ($this->args !== null) {
|
||||
$cmd .= " {$this->args}";
|
||||
}
|
||||
if ($this->config !== null) {
|
||||
$cmd .= " -c '{$this->config}'";
|
||||
}
|
||||
if ($this->directory !== null) {
|
||||
$cmd .= " -d '{$this->directory}'";
|
||||
}
|
||||
return $this->phpci->executeCommand($cmd);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ class Composer implements \PHPCI\Plugin
|
|||
{
|
||||
protected $directory;
|
||||
protected $action;
|
||||
protected $preferDist;
|
||||
protected $phpci;
|
||||
|
||||
public function __construct(\PHPCI\Builder $phpci, array $options = array())
|
||||
|
@ -27,6 +28,7 @@ class Composer implements \PHPCI\Plugin
|
|||
$this->phpci = $phpci;
|
||||
$this->directory = isset($options['directory']) ? $path . '/' . $options['directory'] : $path;
|
||||
$this->action = isset($options['action']) ? $options['action'] : 'update';
|
||||
$this->preferDist = isset($options['prefer_dist']) ? $options['prefer_dist'] : true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,7 +36,7 @@ class Composer implements \PHPCI\Plugin
|
|||
*/
|
||||
public function execute()
|
||||
{
|
||||
$cmd = PHPCI_DIR . 'composer.phar --prefer-dist --working-dir="%s" %s';
|
||||
$cmd = PHPCI_DIR . 'composer.phar '. ($this->preferDist ? '--prefer-dist' : null) .' --working-dir="%s" %s';
|
||||
return $this->phpci->executeCommand($cmd, $this->directory, $this->action);
|
||||
}
|
||||
}
|
||||
|
|
194
PHPCI/Plugin/Email.php
Normal file
194
PHPCI/Plugin/Email.php
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPCI - Continuous Integration for PHP
|
||||
*
|
||||
* @copyright Copyright 2013, Block 8 Limited.
|
||||
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||
* @link http://www.phptesting.org/
|
||||
*/
|
||||
|
||||
namespace PHPCI\Plugin;
|
||||
|
||||
|
||||
/**
|
||||
* Email Plugin - Provides simple email capability to PHPCI.
|
||||
* @author Steve Brazier <meadsteve@gmail.com>
|
||||
* @package PHPCI
|
||||
* @subpackage Plugins
|
||||
*/
|
||||
class Email implements \PHPCI\Plugin
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \PHPCI\Builder
|
||||
*/
|
||||
protected $phpci;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $emailConfig;
|
||||
|
||||
/**
|
||||
* @var \Swift_Mailer
|
||||
*/
|
||||
protected $mailer;
|
||||
|
||||
public function __construct(\PHPCI\Builder $phpci,
|
||||
array $options = array(),
|
||||
\Swift_Mailer $mailer = null)
|
||||
{
|
||||
$phpCiSettings = $phpci->getSystemConfig('phpci');
|
||||
$this->phpci = $phpci;
|
||||
$this->options = $options;
|
||||
$this->emailConfig = isset($phpCiSettings['email_settings']) ? $phpCiSettings['email_settings'] : array();
|
||||
|
||||
// Either a mailer will have been passed in or we load from the
|
||||
// config.
|
||||
if ($mailer === null) {
|
||||
$this->loadSwiftMailerFromConfig();
|
||||
}
|
||||
else {
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to MySQL and runs a specified set of queries.
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$addresses = $this->getEmailAddresses();
|
||||
|
||||
// Without some email addresses in the yml file then we
|
||||
// can't do anything.
|
||||
if (count($addresses) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sendFailures = array();
|
||||
|
||||
$subjectTemplate = "PHPCI - %s - %s";
|
||||
$projectName = $this->phpci->getBuildProjectTitle();
|
||||
$logText = $this->phpci->getBuild()->getLog();
|
||||
|
||||
if($this->phpci->getSuccessStatus()) {
|
||||
$sendFailures = $this->sendSeparateEmails(
|
||||
$addresses,
|
||||
sprintf($subjectTemplate, $projectName, "Passing Build"),
|
||||
sprintf("Log Output: <br><pre>%s</pre>", $logText)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$sendFailures = $this->sendSeparateEmails(
|
||||
$addresses,
|
||||
sprintf($subjectTemplate, $projectName, "Failing Build"),
|
||||
sprintf("Log Output: <br><pre>%s</pre>", $logText)
|
||||
);
|
||||
}
|
||||
|
||||
// This is a success if we've not failed to send anything.
|
||||
$this->phpci->log(sprintf(
|
||||
"%d emails sent",
|
||||
(count($addresses) - count($sendFailures)))
|
||||
);
|
||||
$this->phpci->log(sprintf(
|
||||
"%d emails failed to send",
|
||||
count($sendFailures))
|
||||
);
|
||||
return (count($sendFailures) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $toAddresses Array or single address to send to
|
||||
* @param string $subject Email subject
|
||||
* @param string $body Email body
|
||||
* @return array Array of failed addresses
|
||||
*/
|
||||
public function sendEmail($toAddresses, $subject, $body)
|
||||
{
|
||||
$message = \Swift_Message::newInstance($subject)
|
||||
->setFrom($this->getMailConfig('from_address'))
|
||||
->setTo($toAddresses)
|
||||
->setBody($body)
|
||||
->setContentType("text/html");
|
||||
$failedAddresses = array();
|
||||
$this->mailer->send($message, $failedAddresses);
|
||||
|
||||
return $failedAddresses;
|
||||
}
|
||||
|
||||
public function sendSeparateEmails(array $toAddresses, $subject, $body)
|
||||
{
|
||||
$failures = array();
|
||||
foreach($toAddresses as $address) {
|
||||
$newFailures = $this->sendEmail($address, $subject, $body);
|
||||
foreach($newFailures as $failure) {
|
||||
$failures[] = $failure;
|
||||
}
|
||||
}
|
||||
return $failures;
|
||||
}
|
||||
|
||||
protected function loadSwiftMailerFromConfig()
|
||||
{
|
||||
/** @var \Swift_SmtpTransport $transport */
|
||||
$transport = \Swift_SmtpTransport::newInstance(
|
||||
$this->getMailConfig('smtp_address'),
|
||||
$this->getMailConfig('smtp_port'),
|
||||
$this->getMailConfig('smtp_encryption')
|
||||
);
|
||||
$transport->setUsername($this->getMailConfig('smtp_username'));
|
||||
$transport->setPassword($this->getMailConfig('smtp_password'));
|
||||
|
||||
$this->mailer = \Swift_Mailer::newInstance($transport);
|
||||
}
|
||||
|
||||
protected function getMailConfig($configName)
|
||||
{
|
||||
if (isset($this->emailConfig[$configName])
|
||||
&& $this->emailConfig[$configName] != "")
|
||||
{
|
||||
return $this->emailConfig[$configName];
|
||||
}
|
||||
// Check defaults
|
||||
else {
|
||||
switch($configName) {
|
||||
case 'smtp_address':
|
||||
return "localhost";
|
||||
case 'default_mailto_address':
|
||||
return null;
|
||||
case 'smtp_port':
|
||||
return '25';
|
||||
case 'smtp_encryption':
|
||||
return null;
|
||||
case 'from_address':
|
||||
return "notifications-ci@phptesting.org";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getEmailAddresses()
|
||||
{
|
||||
$addresses = array();
|
||||
|
||||
if (isset($this->options['addresses'])) {
|
||||
foreach ($this->options['addresses'] as $address) {
|
||||
$addresses[] = $address;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->options['default_mailto_address'])) {
|
||||
$addresses[] = $this->options['default_mailto_address'];
|
||||
return $addresses;
|
||||
}
|
||||
return $addresses;
|
||||
}
|
||||
}
|
|
@ -18,10 +18,16 @@ namespace PHPCI\Plugin;
|
|||
class PhpMessDetector implements \PHPCI\Plugin
|
||||
{
|
||||
protected $directory;
|
||||
/**
|
||||
* Array of PHPMD rules. Possible values: codesize, unusedcode, naming, design, controversial
|
||||
* @var array
|
||||
*/
|
||||
protected $rules;
|
||||
|
||||
public function __construct(\PHPCI\Builder $phpci, array $options = array())
|
||||
{
|
||||
$this->phpci = $phpci;
|
||||
$this->rules = isset($options['rules']) ? (array)$options['rules'] : array('codesize', 'unusedcode', 'naming');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +41,7 @@ class PhpMessDetector implements \PHPCI\Plugin
|
|||
$ignore = ' --exclude ' . implode(',', $this->phpci->ignore);
|
||||
}
|
||||
|
||||
$cmd = PHPCI_BIN_DIR . 'phpmd "%s" text codesize,unusedcode,naming %s';
|
||||
return $this->phpci->executeCommand($cmd, $this->phpci->buildPath, $ignore);
|
||||
$cmd = PHPCI_BIN_DIR . 'phpmd "%s" text %s %s';
|
||||
return $this->phpci->executeCommand($cmd, $this->phpci->buildPath, implode(',', $this->rules), $ignore);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class BuildStore extends BuildStoreBase
|
|||
$count = 0;
|
||||
}
|
||||
|
||||
$query = 'SELECT b.* FROM build b LEFT JOIN project p on p.id = b.project_id GROUP BY b.project_id ORDER BY p.title ASC, b.id DESC';
|
||||
$query = 'SELECT b.* FROM build b LEFT JOIN project p on p.id = b.project_id ORDER BY p.title ASC, b.id DESC';
|
||||
$stmt = \b8\Database::getConnection('read')->prepare($query);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<li class="nav-header">Options</li>
|
||||
<li><a href="<?= PHPCI_URL ?>build/rebuild/<?php print $build->getId(); ?>"><i class="icon-cog"></i> Rebuild</a></li>
|
||||
<?php if($this->User()->getIsAdmin()): ?>
|
||||
<li><a href="javascript:confirmDelete('<?= PHPCI_URL ?>build/delete/<?php print $build->getId(); ?>')"><i class="icon-trash"></i> Delete Build</a></li>
|
||||
<li><a href="#" id="delete-build"><i class="icon-trash"></i> Delete Build</a></li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -73,8 +73,12 @@
|
|||
}, 10000);
|
||||
<?php endif; ?>
|
||||
|
||||
$(document).ready(function()
|
||||
{
|
||||
$(function() {
|
||||
updateBuildView(window.initial);
|
||||
|
||||
$('#delete-build').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
confirmDelete("<?= PHPCI_URL ?>build/delete/<?php print $build->getId(); ?>");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -11,21 +11,26 @@ switch($build->getStatus())
|
|||
{
|
||||
case 0:
|
||||
$cls = 'info';
|
||||
$subcls = 'info';
|
||||
$status = 'Pending';
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$cls = 'warning';
|
||||
$subcls = 'warning';
|
||||
$status = 'Running';
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$cls = 'success';
|
||||
$subcls = 'success';
|
||||
$status = 'Success';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$cls = 'error';
|
||||
$subcls = 'important';
|
||||
$status = 'Failed';
|
||||
break;
|
||||
}
|
||||
|
@ -35,7 +40,31 @@ switch($build->getStatus())
|
|||
<td><a href="<?= PHPCI_URL ?>project/view/<?php print $build->getProjectId(); ?>"><?php print $build->getProject()->getTitle(); ?></a></td>
|
||||
<td><a href="<?php print $build->getCommitLink(); ?>"><?php print $build->getCommitId(); ?></a></td>
|
||||
<td><a href="<?php print $build->getBranchLink(); ?>"><?php print $build->getBranch(); ?></a></td>
|
||||
<td><?php print $status; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$plugins = json_decode($build->getPlugins(), true);
|
||||
|
||||
if ( !is_array($plugins) ) {
|
||||
$plugins = array();
|
||||
}
|
||||
if ( 0 === count($plugins) ) {
|
||||
?>
|
||||
<span class='label label-<?= $subcls ?>'>
|
||||
<?= $status ?>
|
||||
</span>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
foreach($plugins as $plugin => $pluginstatus):
|
||||
$subcls = $pluginstatus?'label label-success':'label label-important';
|
||||
?>
|
||||
<span class='<?= $subcls ?>'>
|
||||
<?= ucwords(str_replace('_', ' ', $plugin)) ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
<br style='clear:both;' />
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a class="btn" href="<?= PHPCI_URL ?>build/view/<?php print $build->getId(); ?>">View</a>
|
||||
|
|
|
@ -44,11 +44,11 @@
|
|||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Health</th>
|
||||
<th>Project</th>
|
||||
<th>Commit</th>
|
||||
<th>Branch</th>
|
||||
<th>Status</th>
|
||||
<th>Last Success</th>
|
||||
<th>Last Failure</th>
|
||||
<th>Success/Failures</th>
|
||||
<th style="width: 1%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -14,13 +14,15 @@
|
|||
|
||||
<?php if($this->User()->getIsAdmin()): ?>
|
||||
<li><a href="<?= PHPCI_URL ?>project/edit/<?php print $project->getId(); ?>"><i class="icon-edit"></i> Edit Project</a></li>
|
||||
<li><a href="javascript:confirmDelete('<?= PHPCI_URL ?>project/delete/<?php print $project->getId(); ?>')"><i class="icon-trash"></i> Delete Project</a></li>
|
||||
<li><a href="#" id="delete-project"><i class="icon-trash"></i> Delete Project</a></li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<p class="alert alert-info">To automatically build this project when new commits are pushed, add the URL below
|
||||
<?php if (in_array($project->getType(), array('github', 'bitbucket'))): ?>
|
||||
<br>
|
||||
<p class="alert alert-info">To automatically build this project when new commits are pushed, add the URL below
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
switch($project->getType())
|
||||
|
@ -61,14 +63,14 @@
|
|||
$pages = ceil($total / 10);
|
||||
$pages = $pages == 0 ? 1 : $pages;
|
||||
|
||||
print '<li class="'.($page == 1 ? 'disabled' : '').'"><a href="<?= PHPCI_URL ?>project/view/'.$project->getId().'?p='.($page == 1 ? '1' : $page - 1).'">«</a></li>';
|
||||
print '<li class="'.($page == 1 ? 'disabled' : '').'"><a href="' . PHPCI_URL . 'project/view/'.$project->getId().'?p='.($page == 1 ? '1' : $page - 1).'">«</a></li>';
|
||||
|
||||
for($i = 1; $i <= $pages; $i++)
|
||||
{
|
||||
print '<li><a href="<?= PHPCI_URL ?>project/view/' . $project->getId() . '?p=' . $i . '">' . $i . '</a></li>';
|
||||
print '<li><a href="' . PHPCI_URL . 'project/view/' . $project->getId() . '?p=' . $i . '">' . $i . '</a></li>';
|
||||
}
|
||||
|
||||
print '<li class="'.($page == $pages ? 'disabled' : '').'"><a href="<?= PHPCI_URL ?>project/view/'.$project->getId().'?p='.($page == $pages ? $pages : $page + 1).'">»</a></li>';
|
||||
print '<li class="'.($page == $pages ? 'disabled' : '').'"><a href="' . PHPCI_URL . 'project/view/'.$project->getId().'?p='.($page == $pages ? $pages : $page + 1).'">»</a></li>';
|
||||
|
||||
print '</ul></div>';
|
||||
|
||||
|
@ -78,9 +80,16 @@
|
|||
|
||||
<?php if($page == 1): ?>
|
||||
<script>
|
||||
setInterval(function()
|
||||
{
|
||||
$('#latest-builds').load('<?= PHPCI_URL ?>project/builds/<?php print $project->getId(); ?>');
|
||||
}, 10000);
|
||||
setInterval(function()
|
||||
{
|
||||
$('#latest-builds').load('<?= PHPCI_URL ?>project/builds/<?php print $project->getId(); ?>');
|
||||
}, 10000);
|
||||
|
||||
$(function() {
|
||||
$('#delete-project').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
confirmDelete("<?= PHPCI_URL ?>project/delete/<?php print $project->getId(); ?>");
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
|
114
PHPCI/View/SummaryTable.phtml
Normal file
114
PHPCI/View/SummaryTable.phtml
Normal file
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
// echo "<pre>";
|
||||
// var_dump($builds);
|
||||
// echo "</pre>";
|
||||
|
||||
$maxbuildcount = 5;
|
||||
$projects = array();
|
||||
$prevBuild = null;
|
||||
$health = false;
|
||||
|
||||
foreach($builds as $build):
|
||||
|
||||
if ($build->getStatus() < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( is_null($prevBuild) || $build->getProjectId() !== $prevBuild->getProjectId() ) {
|
||||
$health = false;
|
||||
$projects[$build->getProjectId()]['count'] = 0;
|
||||
$projects[$build->getProjectId()]['health'] = 0;
|
||||
$projects[$build->getProjectId()]['successes'] = 0;
|
||||
$projects[$build->getProjectId()]['failures'] = 0;
|
||||
$projects[$build->getProjectId()]['lastbuildstatus'] = (int)$build->getStatus();
|
||||
}
|
||||
|
||||
if (
|
||||
!is_null($prevBuild) &&
|
||||
$projects[$build->getProjectId()]['count'] >= $maxbuildcount &&
|
||||
$build->getProjectId() === $prevBuild->getProjectId()
|
||||
) {
|
||||
$projects[$build->getProjectId()]['count']++;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ((int)$build->getStatus()) {
|
||||
case 2:
|
||||
$projects[$build->getProjectId()]['health']++;
|
||||
$projects[$build->getProjectId()]['successes']++;
|
||||
|
||||
if ( empty($projects[$build->getProjectId()]['lastsuccess']) ) {
|
||||
$projects[$build->getProjectId()]['lastsuccess'] = $build;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
$projects[$build->getProjectId()]['health']--;
|
||||
$projects[$build->getProjectId()]['failures']++;
|
||||
|
||||
if ( empty($projects[$build->getProjectId()]['lastfailure']) ) {
|
||||
$projects[$build->getProjectId()]['lastfailure'] = $build;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$projects[$build->getProjectId()]['count']++;
|
||||
$projects[$build->getProjectId()]['projectname'] = $build->getProject()->getTitle();
|
||||
$prevBuild = $build;
|
||||
endforeach;
|
||||
|
||||
foreach($projects as $projectId => $project):
|
||||
switch($project['lastbuildstatus'])
|
||||
{
|
||||
case 0:
|
||||
$cls = 'info';
|
||||
$status = 'Pending';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$cls = 'warning';
|
||||
$status = 'Running';
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$cls = 'success';
|
||||
$status = 'Success';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$cls = 'error';
|
||||
$status = 'Failed';
|
||||
break;
|
||||
}
|
||||
|
||||
$health = ($project['health'] < 0 ? 'Stormy': ($project['health'] < 5? 'Overcast': 'Sunny'));
|
||||
$subcls = ($project['health'] < 0 ? 'important': ($project['health'] < 5? 'warning': 'success'));
|
||||
?>
|
||||
<tr class="<?php print $cls; ?>">
|
||||
<td>
|
||||
<span class='label label-<?= $subcls ?>'>
|
||||
<?= $health ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><a href='<?= PHPCI_URL ?>project/view/<?= $projectId ?>'><?= $project['projectname'] ?></a></td>
|
||||
<td>
|
||||
<?php if (empty($project['lastsuccess'])) {
|
||||
echo "Never";
|
||||
} else { ?>
|
||||
<a href='<?= PHPCI_URL ?>build/view/<?= $project['lastsuccess']->getId() ?>'>
|
||||
<?= $project['lastsuccess']->getStarted()->format("Y-m-d H:i:s") ?>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (empty($project['lastfailure'])) {
|
||||
echo "Never";
|
||||
} else { ?>
|
||||
<a href='<?= PHPCI_URL ?>build/view/<?= $project['lastfailure']->getId() ?>'>
|
||||
<?= $project['lastfailure']->getStarted()->format("Y-m-d H:i:s") ?>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td><?= $project['successes'] ?>/<?= $project['failures'] ?></td>
|
||||
<td><a class="btn" href='<?= PHPCI_URL ?>project/build/<?= $projectId ?>'>build</a></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
|
@ -17,7 +17,7 @@
|
|||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="<?= PHPCI_URL ?>">PHPCI <span class="badge badge-important" style="position: relative; top: -3px; margin-left: 10px">1.0 Alpha</span></a>
|
||||
<a class="brand" href="<?= PHPCI_URL ?>">PHPCI <span class="badge badge-important" style="position: relative; top: -3px; margin-left: 10px">1.0.0 Beta</span></a>
|
||||
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="<?= PHPCI_URL ?>session/logout">Log out</a></li>
|
||||
|
@ -35,4 +35,4 @@
|
|||
<?php print $content; ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -3,14 +3,14 @@ PHPCI
|
|||
|
||||
PHPCI is a free and open source continuous integration tool specifically designed for PHP. We've built it with simplicity in mind, so whilst it doesn't do *everything* Jenkins can do, it is a breeze to set up and use.
|
||||
|
||||
_**Please be aware that this is a brand new project, in an alpha state, so there will be bugs and missing features.**_
|
||||
_**Please be aware that PHPCI is a beta-release project, so whilst it is very stable, there may be bugs and/or missing features.**_
|
||||
|
||||
**Current Build Status**
|
||||
|
||||
![Build Status](http://phpci.block8.net/build-status/image/2)
|
||||
|
||||
##What it does:
|
||||
* Clones your project from Github, Bitbucket or a local path (support for standard remote Git repositories coming soon.)
|
||||
* Clones your project from Github, Bitbucket or a local path
|
||||
* Allows you to set up and tear down test databases.
|
||||
* Installs your project's Composer dependencies.
|
||||
* Runs through any combination of the following plugins:
|
||||
|
@ -28,7 +28,6 @@ _**Please be aware that this is a brand new project, in an alpha state, so there
|
|||
* Multiple testing workers.
|
||||
* Install PEAR or PECL extensions.
|
||||
* Deployments.
|
||||
* Success / Failure emails.
|
||||
|
||||
##Installing PHPCI:
|
||||
####Pre-requisites:
|
||||
|
|
256
Tests/PHPCI/Plugin/Email.php
Normal file
256
Tests/PHPCI/Plugin/Email.php
Normal file
|
@ -0,0 +1,256 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPCI - Continuous Integration for PHP
|
||||
*
|
||||
* @copyright Copyright 2013, Block 8 Limited.
|
||||
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||
* @link http://www.phptesting.org/
|
||||
*/
|
||||
|
||||
namespace PHPCI\Plugin\Tests;
|
||||
use PHPCI\Plugin\Email as EmailPlugin;
|
||||
|
||||
define('PHPCI_BIN_DIR', "FAKEPHPCIBIN");
|
||||
|
||||
/**
|
||||
* Unit test for the PHPUnit plugin.
|
||||
* @author meadsteve
|
||||
*/
|
||||
class EmailTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* @var EmailPlugin $testedPhpUnit
|
||||
*/
|
||||
protected $testedEmailPlugin;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject $mockCiBuilder
|
||||
*/
|
||||
protected $mockCiBuilder;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject $mockMailer
|
||||
*/
|
||||
protected $mockMailer;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject $mockMailer
|
||||
*/
|
||||
protected $mockBuild;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->mockBuild = $this->getMock(
|
||||
'\PHPCI\Model\Build',
|
||||
array('getLog'),
|
||||
array(),
|
||||
"mockBuild",
|
||||
false
|
||||
);
|
||||
|
||||
$this->mockBuild->expects($this->any())
|
||||
->method('getLog')
|
||||
->will($this->returnValue("Build Log"));
|
||||
|
||||
$this->mockCiBuilder = $this->getMock(
|
||||
'\PHPCI\Builder',
|
||||
array('getSystemConfig',
|
||||
'getBuildProjectTitle',
|
||||
'getBuild',
|
||||
'log'),
|
||||
array(),
|
||||
"mockBuilder",
|
||||
false
|
||||
);
|
||||
|
||||
$this->mockCiBuilder->buildPath = "/";
|
||||
|
||||
$this->mockCiBuilder->expects($this->any())
|
||||
->method('getSystemConfig')
|
||||
->with('phpci')
|
||||
->will($this->returnValue(array(
|
||||
'email_settings' => array(
|
||||
'from_address' => "test-from-address@example.com"
|
||||
)
|
||||
)));
|
||||
$this->mockCiBuilder->expects($this->any())
|
||||
->method('getBuildProjectTitle')
|
||||
->will($this->returnValue('Test-Project'));
|
||||
$this->mockCiBuilder->expects($this->any())
|
||||
->method('getBuild')
|
||||
->will($this->returnValue($this->mockBuild));
|
||||
|
||||
$this->mockMailer = $this->getMock(
|
||||
'\Swift_Mailer',
|
||||
array('send'),
|
||||
array(),
|
||||
"mockMailer",
|
||||
false
|
||||
);
|
||||
|
||||
$this->loadEmailPluginWithOptions();
|
||||
}
|
||||
|
||||
protected function loadEmailPluginWithOptions($arrOptions = array())
|
||||
{
|
||||
$this->testedEmailPlugin = new EmailPlugin(
|
||||
$this->mockCiBuilder,
|
||||
$arrOptions,
|
||||
$this->mockMailer
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers PHPUnit::execute
|
||||
*/
|
||||
public function testExecute_ReturnsFalseWithoutArgs()
|
||||
{
|
||||
$returnValue = $this->testedEmailPlugin->execute();
|
||||
// As no addresses will have been mailed as non are configured.
|
||||
$expectedReturn = false;
|
||||
|
||||
$this->assertEquals($expectedReturn, $returnValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers PHPUnit::execute
|
||||
*/
|
||||
public function testExecute_BuildsBasicEmails()
|
||||
{
|
||||
$this->loadEmailPluginWithOptions(array(
|
||||
'addresses' => array('test-receiver@example.com')
|
||||
));
|
||||
|
||||
/** @var \Swift_Message $actualMail */
|
||||
$actualMail = null;
|
||||
$this->catchMailPassedToSend($actualMail);
|
||||
|
||||
$returnValue = $this->testedEmailPlugin->execute();
|
||||
$expectedReturn = true;
|
||||
|
||||
$this->assertSystemMail(
|
||||
'test-receiver@example.com',
|
||||
'test-from-address@example.com',
|
||||
"Log Output: <br><pre>Build Log</pre>",
|
||||
"PHPCI - Test-Project - Passing Build",
|
||||
$actualMail
|
||||
);
|
||||
|
||||
$this->assertEquals($expectedReturn, $returnValue);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers PHPUnit::sendEmail
|
||||
*/
|
||||
public function testSendEmail_CallsMailerSend()
|
||||
{
|
||||
$this->mockMailer->expects($this->once())
|
||||
->method('send');
|
||||
$this->testedEmailPlugin->sendEmail("test@email.com", "hello", "body");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers PHPUnit::sendEmail
|
||||
*/
|
||||
public function testSendEmail_BuildsAMessageObject()
|
||||
{
|
||||
$subject = "Test mail";
|
||||
$body = "Message Body";
|
||||
$toAddress = "test@example.com";
|
||||
|
||||
$this->mockMailer->expects($this->once())
|
||||
->method('send')
|
||||
->with($this->isInstanceOf('\Swift_Message'), $this->anything());
|
||||
$this->testedEmailPlugin->sendEmail($toAddress, $subject, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers PHPUnit::sendEmail
|
||||
*/
|
||||
public function testSendEmail_BuildsExpectedMessage()
|
||||
{
|
||||
$subject = "Test mail";
|
||||
$body = "Message Body";
|
||||
$toAddress = "test@example.com";
|
||||
$expectedMessage = \Swift_Message::newInstance($subject)
|
||||
->setFrom('test-from-address@example.com')
|
||||
->setTo($toAddress)
|
||||
->setBody($body);
|
||||
|
||||
/** @var \Swift_Message $actualMail */
|
||||
$actualMail = null;
|
||||
$this->catchMailPassedToSend($actualMail);
|
||||
|
||||
$this->testedEmailPlugin->sendEmail($toAddress, $subject, $body);
|
||||
|
||||
$this->assertSystemMail(
|
||||
$toAddress,
|
||||
'test-from-address@example.com',
|
||||
$body,
|
||||
$subject,
|
||||
$actualMail
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Swift_Message $actualMail passed by ref and populated with
|
||||
* the message object the mock mailer
|
||||
* receives.
|
||||
*/
|
||||
protected function catchMailPassedToSend(&$actualMail)
|
||||
{
|
||||
$this->mockMailer->expects($this->once())
|
||||
->method('send')
|
||||
->will(
|
||||
$this->returnCallback(
|
||||
function ($passedMail) use (&$actualMail) {
|
||||
$actualMail = $passedMail;
|
||||
return array();
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the actual mail object is populated as expected.
|
||||
*
|
||||
* @param string $expectedToAddress
|
||||
* @param $expectedFromAddress
|
||||
* @param string $expectedBody
|
||||
* @param string $expectedSubject
|
||||
* @param \Swift_Message $actualMail
|
||||
*/
|
||||
protected function assertSystemMail($expectedToAddress,
|
||||
$expectedFromAddress,
|
||||
$expectedBody,
|
||||
$expectedSubject,
|
||||
$actualMail)
|
||||
{
|
||||
if (! ($actualMail instanceof \Swift_Message)) {
|
||||
$type = is_object($actualMail) ? get_class($actualMail) : gettype($actualMail);
|
||||
throw new \Exception("Expected Swift_Message got " . $type);
|
||||
}
|
||||
$this->assertEquals(
|
||||
array($expectedFromAddress => null),
|
||||
$actualMail->getFrom()
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array($expectedToAddress => null),
|
||||
$actualMail->getTo()
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$expectedBody,
|
||||
$actualMail->getBody()
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$expectedSubject,
|
||||
$actualMail->getSubject()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,20 @@ body
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
td .label { margin-right: 5px; }
|
||||
|
||||
.success-message {
|
||||
background-color: #4F8A10;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #FF4747;
|
||||
}
|
||||
|
||||
#latest-builds td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.widget-title, .modal-header, .table th, div.dataTables_wrapper .ui-widget-header, .ui-dialog .ui-dialog-titlebar {
|
||||
background-color: #efefef;
|
||||
background-image: -webkit-gradient(linear, 0 0%, 0 100%, from(#fdfdfd), to(#eaeaea));
|
||||
|
@ -61,7 +75,7 @@ body
|
|||
background: url('/assets/img/icon-build-running.png') no-repeat top left;
|
||||
}
|
||||
|
||||
h3
|
||||
h3
|
||||
{
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
margin-top: 0;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"phpspec/phpspec" : "2.*",
|
||||
"symfony/yaml" : "2.2.x-dev",
|
||||
"symfony/console" : "2.2.*",
|
||||
"fabpot/php-cs-fixer" : "0.3.*@dev"
|
||||
"fabpot/php-cs-fixer" : "0.3.*@dev",
|
||||
"swiftmailer/swiftmailer" : "v5.0.0"
|
||||
}
|
||||
}
|
||||
|
|
3
console
3
console
|
@ -10,6 +10,7 @@
|
|||
|
||||
define('PHPCI_BIN_DIR', dirname(__FILE__) . '/vendor/bin/');
|
||||
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.
|
||||
|
@ -28,10 +29,12 @@ require('bootstrap.php');
|
|||
use PHPCI\Command\RunCommand;
|
||||
use PHPCI\Command\GenerateCommand;
|
||||
use PHPCI\Command\InstallCommand;
|
||||
use PHPCI\Command\DaemonCommand;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
$application = new Application();
|
||||
$application->add(new RunCommand);
|
||||
$application->add(new InstallCommand);
|
||||
$application->add(new GenerateCommand);
|
||||
$application->add(new DaemonCommand);
|
||||
$application->run();
|
||||
|
|
2
daemon/.gitignore
vendored
Normal file
2
daemon/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
22
daemonise
Executable file
22
daemonise
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* PHPCI - Continuous Integration for PHP
|
||||
*
|
||||
* @copyright Copyright 2013, Block 8 Limited.
|
||||
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||
* @link http://www.phptesting.org/
|
||||
*/
|
||||
|
||||
define('PHPCI_BIN_DIR', dirname(__FILE__) . '/vendor/bin/');
|
||||
define('PHPCI_DIR', dirname(__FILE__) . '/');
|
||||
define('ENABLE_SHELL_PLUGIN', false);
|
||||
|
||||
require('bootstrap.php');
|
||||
|
||||
use PHPCI\Command\DaemoniseCommand;
|
||||
use Symfony\Component\Console\Application;
|
||||
|
||||
$application = new Application();
|
||||
$application->add(new DaemoniseCommand);
|
||||
$application->run();
|
Loading…
Reference in a new issue