From 0c1c3d60effd570a55e09c795a799e5458e945d8 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Fri, 31 May 2013 12:36:12 +0100 Subject: [PATCH 01/45] Adding v5.0 of SwiftMailer to composer. --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7b8c37b3..d034e3c5 100644 --- a/composer.json +++ b/composer.json @@ -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" } } From f76a2a75ccb06143bfec0559707b8d67cf0a2111 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Fri, 31 May 2013 12:56:35 +0100 Subject: [PATCH 02/45] Empty Email plugin and test committed. --- PHPCI/Plugin/Email.php | 46 ++++++++++++++++++++++++++ Tests/PHPCI/Plugin/Email.php | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 PHPCI/Plugin/Email.php create mode 100644 Tests/PHPCI/Plugin/Email.php diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php new file mode 100644 index 00000000..6cff58f9 --- /dev/null +++ b/PHPCI/Plugin/Email.php @@ -0,0 +1,46 @@ + +* @package PHPCI +* @subpackage Plugins +*/ +class Email implements \PHPCI\Plugin +{ + + /** + * @var \PHPCI\Builder + */ + protected $phpci; + + /** + * @var array + */ + protected $options; + + public function __construct(\PHPCI\Builder $phpci, array $options = array()) + { + $this->phpci = $phpci; + $this->options = $options; + } + + /** + * Connects to MySQL and runs a specified set of queries. + */ + public function execute() + { + + return true; + } +} \ No newline at end of file diff --git a/Tests/PHPCI/Plugin/Email.php b/Tests/PHPCI/Plugin/Email.php new file mode 100644 index 00000000..f1e97ffe --- /dev/null +++ b/Tests/PHPCI/Plugin/Email.php @@ -0,0 +1,64 @@ +mockCiBuilder = $this->getMock( + '\PHPCI\Builder', + array(), + array(), + "mockBuilder", + false + ); + $this->mockCiBuilder->buildPath = "/"; + + $this->loadEmailPluginWithOptions(); + } + + protected function loadEmailPluginWithOptions($arrOptions = array()) + { + $this->testedEmailPlugin = new EmailPlugin( + $this->mockCiBuilder, + $arrOptions + ); + } + + /** + * @covers PHPUnit::execute + */ + public function testExecute_ReturnsTrueWithoutArgs() + { + $returnValue = $this->testedEmailPlugin->execute(); + $expectedReturn = true; + + $this->assertEquals($expectedReturn, $returnValue); + } +} \ No newline at end of file From f0a5ba50ca1672bdbd5e1b225fb348cdccfa1ca6 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sat, 1 Jun 2013 09:40:05 +0100 Subject: [PATCH 03/45] Filled out the Plugin\Email::sendEmail(). Pulls in the following settings from the phpci config under the heading email_settings: smtp_address smtp_port smtp_username smtp_password and from_address --- PHPCI/Plugin/Email.php | 73 ++++++++++++++++++- Tests/PHPCI/Plugin/Email.php | 132 ++++++++++++++++++++++++++++++++++- 2 files changed, 202 insertions(+), 3 deletions(-) diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php index 6cff58f9..a0b88312 100644 --- a/PHPCI/Plugin/Email.php +++ b/PHPCI/Plugin/Email.php @@ -29,10 +29,32 @@ class Email implements \PHPCI\Plugin */ protected $options; - public function __construct(\PHPCI\Builder $phpci, array $options = array()) + /** + * @var array + */ + protected $emailConfig; + + /** + * @var \Swift_Mailer + */ + protected $mailer; + + public function __construct(\PHPCI\Builder $phpci, + array $options = array(), + \Swift_Mailer $mailer = null) { $this->phpci = $phpci; $this->options = $options; + $this->emailConfig = $phpci->getConfig('email_settings'); + + // Either a mailer will have been passed in or we load from the + // config. + if ($mailer === null) { + $this->loadSwiftMailerFromConfig(); + } + else { + $this->mailer = $mailer; + } } /** @@ -43,4 +65,53 @@ class Email implements \PHPCI\Plugin return true; } + + /** + * @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); + $failedAddresses = array(); + $this->mailer->send($message, $failedAddresses); + + return $failedAddresses; + } + + protected function loadSwiftMailerFromConfig() + { + /** @var \Swift_SmtpTransport $transport */ + $transport = \Swift_SmtpTransport::newInstance( + $this->getMailConfig('smtp_address'), + $this->getMailConfig('smtp_port') + ); + $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])) { + return $this->emailConfig[$configName]; + } + // Check defaults + else { + switch($configName) { + case 'smtp_port': + return '25'; + case 'from_address': + return "notifications-ci@phptesting.org"; + default: + return ""; + } + } + } } \ No newline at end of file diff --git a/Tests/PHPCI/Plugin/Email.php b/Tests/PHPCI/Plugin/Email.php index f1e97ffe..9e8052be 100644 --- a/Tests/PHPCI/Plugin/Email.php +++ b/Tests/PHPCI/Plugin/Email.php @@ -29,16 +29,35 @@ class EmailTest extends \PHPUnit_Framework_TestCase */ protected $mockCiBuilder; + /** + * @var \PHPUnit_Framework_MockObject_MockObject $mockMailer + */ + protected $mockMailer; + public function setUp() { $this->mockCiBuilder = $this->getMock( '\PHPCI\Builder', - array(), + array('getConfig'), array(), "mockBuilder", false ); $this->mockCiBuilder->buildPath = "/"; + $this->mockCiBuilder->expects($this->any()) + ->method('getConfig') + ->with('email_settings') + ->will($this->returnValue(array( + 'from_address' => "test-from-address@example.com" + ))); + + $this->mockMailer = $this->getMock( + '\Swift_Mailer', + array('send'), + array(), + "mockMailer", + false + ); $this->loadEmailPluginWithOptions(); } @@ -47,7 +66,8 @@ class EmailTest extends \PHPUnit_Framework_TestCase { $this->testedEmailPlugin = new EmailPlugin( $this->mockCiBuilder, - $arrOptions + $arrOptions, + $this->mockMailer ); } @@ -61,4 +81,112 @@ class EmailTest extends \PHPUnit_Framework_TestCase $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) + { + $this->assertEquals( + array($expectedFromAddress => null), + $actualMail->getFrom() + ); + + $this->assertEquals( + array($expectedToAddress => null), + $actualMail->getTo() + ); + + $this->assertEquals( + $expectedBody, + $actualMail->getBody() + ); + + $this->assertEquals( + $expectedSubject, + $actualMail->getSubject() + ); + } } \ No newline at end of file From 7761d9fc085293863e7c310cc2cc9d214524ea96 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sat, 1 Jun 2013 13:28:42 +0100 Subject: [PATCH 04/45] Adding Builder::getSystemConfig() to provide easy access to config.yml. --- PHPCI/Builder.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index a7b60bc1..1f98cf44 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -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 From 76e5c66b3837c388e757c73daab9cbfa458e67c2 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sat, 1 Jun 2013 13:29:59 +0100 Subject: [PATCH 05/45] Fixing the email plugin so that it retrieves the system config correctly. --- PHPCI/Plugin/Email.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php index a0b88312..09dd4ebd 100644 --- a/PHPCI/Plugin/Email.php +++ b/PHPCI/Plugin/Email.php @@ -43,9 +43,10 @@ class Email implements \PHPCI\Plugin array $options = array(), \Swift_Mailer $mailer = null) { + $phpCiSettings = $phpci->getSystemConfig('phpci'); $this->phpci = $phpci; $this->options = $options; - $this->emailConfig = $phpci->getConfig('email_settings'); + $this->emailConfig = isset($phpCiSettings['email_settings']) ? $phpCiSettings['email_settings'] : array(); // Either a mailer will have been passed in or we load from the // config. @@ -99,12 +100,16 @@ class Email implements \PHPCI\Plugin protected function getMailConfig($configName) { - if (isset($this->emailConfig[$configName])) { + if (isset($this->emailConfig[$configName]) + && $this->emailConfig[$configName] != "") + { return $this->emailConfig[$configName]; } // Check defaults else { switch($configName) { + case 'smtp_address': + return "localhost"; case 'smtp_port': return '25'; case 'from_address': From 196a1b82b5b7fbb3cca49a417361fe18a540e7cb Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sat, 1 Jun 2013 13:30:34 +0100 Subject: [PATCH 06/45] Adding email settings to the install command. --- PHPCI/Command/InstallCommand.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index 35459aec..8e06d7ed 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -48,6 +48,12 @@ 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_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); + $dbUser = $conf['b8']['database']['username']; $dbPass = $conf['b8']['database']['password']; $dbHost = $conf['b8']['database']['servers']['write']; From d2c408f5897fd90b793e234cfbcc1f29731ca7b3 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sat, 1 Jun 2013 13:31:15 +0100 Subject: [PATCH 07/45] Updating the email plugin tests so that getSystemConfig is mocked correctly. --- Tests/PHPCI/Plugin/Email.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Tests/PHPCI/Plugin/Email.php b/Tests/PHPCI/Plugin/Email.php index 9e8052be..16588671 100644 --- a/Tests/PHPCI/Plugin/Email.php +++ b/Tests/PHPCI/Plugin/Email.php @@ -38,17 +38,19 @@ class EmailTest extends \PHPUnit_Framework_TestCase { $this->mockCiBuilder = $this->getMock( '\PHPCI\Builder', - array('getConfig'), + array('getSystemConfig'), array(), "mockBuilder", false ); $this->mockCiBuilder->buildPath = "/"; $this->mockCiBuilder->expects($this->any()) - ->method('getConfig') - ->with('email_settings') + ->method('getSystemConfig') + ->with('phpci') ->will($this->returnValue(array( - 'from_address' => "test-from-address@example.com" + 'email_settings' => array( + 'from_address' => "test-from-address@example.com" + ) ))); $this->mockMailer = $this->getMock( From a4c051e024ed2f2c3838017b9c932b549deffd54 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sat, 1 Jun 2013 13:56:09 +0100 Subject: [PATCH 08/45] Adding Getter for builder's success property so that plugins can find out if the the build has succeeded or not. --- PHPCI/Builder.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index 1f98cf44..b1f7c489 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -135,6 +135,15 @@ class Builder return $this->build; } + /** + * Indicates if the build has passed or failed. + * @return bool + */ + public function getSuccessStatus() + { + return $this->success; + } + /** * Run the active build. */ From f8407e39c856d7b5aa91b38e67392a650584de6c Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sat, 1 Jun 2013 13:57:39 +0100 Subject: [PATCH 09/45] Email plugin now looks in the yaml file for an addresses setting. All these addresses will be mailed with a pass or fail message. --- PHPCI/Plugin/Email.php | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php index 09dd4ebd..eec4cda8 100644 --- a/PHPCI/Plugin/Email.php +++ b/PHPCI/Plugin/Email.php @@ -63,8 +63,34 @@ class Email implements \PHPCI\Plugin */ public function execute() { + // Without some email addresses in the yml file then we + // can't do anything. + if (!isset($this->options['addresses'])) { + return false; + } - return true; + $addresses = $this->options['addresses']; + $sendFailures = array(); + + if($this->phpci->getSuccessStatus()) { + $body = ""; + $sendFailures = $this->sendSeparateEmails( + $addresses, + "PASSED", + $body + ); + } + else { + $body = ""; + $sendFailures = $this->sendSeparateEmails( + $addresses, + "FAILED", + $body + ); + } + + // This is a success if we've not failed to send anything. + return (count($sendFailures) == 0); } /** @@ -85,6 +111,18 @@ class Email implements \PHPCI\Plugin 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 */ From 9574b63470f4cf1f34d8d94353562b3d37cac96b Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Tue, 4 Jun 2013 19:14:47 +0100 Subject: [PATCH 10/45] css and html tweaks for plugin statueses in builds --- PHPCI/View/BuildsTable.phtml | 15 ++++++++++++++- assets/css/phpci.css | 23 ++++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/PHPCI/View/BuildsTable.phtml b/PHPCI/View/BuildsTable.phtml index 8ced123f..6b0c5b16 100644 --- a/PHPCI/View/BuildsTable.phtml +++ b/PHPCI/View/BuildsTable.phtml @@ -35,7 +35,20 @@ switch($build->getStatus()) getProject()->getTitle(); ?> getCommitId(); ?> getBranch(); ?> - + + getPlugins(), true); + if ( !is_array($plugins) ) { + $plugins = array(); + } + ?> + $pluginstatus): ?> +
'> + +
+ +
+
View diff --git a/assets/css/phpci.css b/assets/css/phpci.css index 931c4b0a..8d540519 100644 --- a/assets/css/phpci.css +++ b/assets/css/phpci.css @@ -14,6 +14,27 @@ body padding: 10px; } +.build-plugin-status { + text-align: center; + min-width: 80px; + float: left; + padding: 5px; + margin-right: 5px; + border: 1px solid black; +} + +.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 +82,7 @@ body background: url('/assets/img/icon-build-running.png') no-repeat top left; } -h3 +h3 { border-bottom: 1px solid #f0f0f0; margin-top: 0; From 4eadb1aef3d8a5eba2f65addfddf30d488ca2dd3 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Tue, 4 Jun 2013 19:49:26 +0100 Subject: [PATCH 11/45] Fix user entity not bein in registry --- PHPCI/Application.php | 8 ++++++-- PHPCI/Controller/BuildController.php | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/PHPCI/Application.php b/PHPCI/Application.php index c0048adf..3378a050 100644 --- a/PHPCI/Application.php +++ b/PHPCI/Application.php @@ -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; } diff --git a/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php index 21de59c9..d4cf64b6 100644 --- a/PHPCI/Controller/BuildController.php +++ b/PHPCI/Controller/BuildController.php @@ -89,7 +89,7 @@ class BuildController extends \PHPCI\Controller if (!Registry::getInstance()->get('user')->getIsAdmin()) { throw new \Exception('You do not have permission to do that.'); } - + $build = $this->_buildStore->getById($buildId); $this->_buildStore->delete($build); From 3dd621713379be6ed5963e34c9e0ff4513fecc30 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Tue, 4 Jun 2013 19:54:56 +0100 Subject: [PATCH 12/45] Fixes #75 user entity not being in the registry --- PHPCI/Application.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PHPCI/Application.php b/PHPCI/Application.php index c0048adf..3378a050 100644 --- a/PHPCI/Application.php +++ b/PHPCI/Application.php @@ -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; } From eaac43e0e878f93052b9ed9cf3398662ebc82b95 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Tue, 4 Jun 2013 20:13:15 +0100 Subject: [PATCH 13/45] Updating unit test to reflect that the test will fail without any addresses defined. --- Tests/PHPCI/Plugin/Email.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tests/PHPCI/Plugin/Email.php b/Tests/PHPCI/Plugin/Email.php index 16588671..fdcb0a05 100644 --- a/Tests/PHPCI/Plugin/Email.php +++ b/Tests/PHPCI/Plugin/Email.php @@ -76,10 +76,11 @@ class EmailTest extends \PHPUnit_Framework_TestCase /** * @covers PHPUnit::execute */ - public function testExecute_ReturnsTrueWithoutArgs() + public function testExecute_ReturnsFalseWithoutArgs() { $returnValue = $this->testedEmailPlugin->execute(); - $expectedReturn = true; + // As no addresses will have been mailed as non are configured. + $expectedReturn = false; $this->assertEquals($expectedReturn, $returnValue); } From 757a82c26f4e5bd31144443eda4466eb83d19ee5 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Tue, 4 Jun 2013 20:17:17 +0100 Subject: [PATCH 14/45] removed deprecated registry and use session --- PHPCI/Application.php | 4 ---- PHPCI/Controller/BuildController.php | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/PHPCI/Application.php b/PHPCI/Application.php index 3378a050..9e555d5c 100644 --- a/PHPCI/Application.php +++ b/PHPCI/Application.php @@ -10,7 +10,6 @@ namespace PHPCI; use b8; -use b8\Registry; use b8\Http\Response\RedirectResponse; use b8\View; @@ -36,9 +35,6 @@ class Application extends b8\Application $skipValidation = ($externalAction || $sessionAction); if($skipValidation || $this->validateSession()) { - if ( !empty($_SESSION['user']) ) { - Registry::getInstance()->set('user', $_SESSION['user']); - } parent::handleRequest(); } diff --git a/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php index 21de59c9..b41287aa 100644 --- a/PHPCI/Controller/BuildController.php +++ b/PHPCI/Controller/BuildController.php @@ -86,10 +86,10 @@ 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); From 33b840a82d6bd318de505aec1278cfbe43be7298 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Tue, 4 Jun 2013 21:09:16 +0100 Subject: [PATCH 15/45] Adding a default address that is always mailed to by notifications. --- PHPCI/Command/InstallCommand.php | 1 + PHPCI/Plugin/Email.php | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index 8e06d7ed..ad9cbeb7 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -53,6 +53,7 @@ class InstallCommand extends Command $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']; diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php index eec4cda8..d4758ddc 100644 --- a/PHPCI/Plugin/Email.php +++ b/PHPCI/Plugin/Email.php @@ -63,13 +63,14 @@ class Email implements \PHPCI\Plugin */ public function execute() { + $addresses = $this->getEmailAddresses(); + // Without some email addresses in the yml file then we // can't do anything. - if (!isset($this->options['addresses'])) { + if (count($addresses) == 0) { return false; } - $addresses = $this->options['addresses']; $sendFailures = array(); if($this->phpci->getSuccessStatus()) { @@ -90,6 +91,14 @@ class Email implements \PHPCI\Plugin } // 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); } @@ -148,6 +157,8 @@ class Email implements \PHPCI\Plugin switch($configName) { case 'smtp_address': return "localhost"; + case 'default_mailto_address': + return null; case 'smtp_port': return '25'; case 'from_address': @@ -157,4 +168,21 @@ class Email implements \PHPCI\Plugin } } } + + 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; + } } \ No newline at end of file From 84370038aab354c86f8f25b089c779c5d204533a Mon Sep 17 00:00:00 2001 From: meadsteve Date: Tue, 4 Jun 2013 21:47:45 +0100 Subject: [PATCH 16/45] Added basic body and title for the email notifications. --- PHPCI/Builder.php | 7 ++++ PHPCI/Plugin/Email.php | 17 ++++++---- Tests/PHPCI/Plugin/Email.php | 65 ++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index b1f7c489..f943a092 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -135,6 +135,13 @@ 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 diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php index d4758ddc..ae7ced05 100644 --- a/PHPCI/Plugin/Email.php +++ b/PHPCI/Plugin/Email.php @@ -73,20 +73,22 @@ class Email implements \PHPCI\Plugin $sendFailures = array(); + $subjectTemplate = "PHPCI - %s - %s"; + $projectName = $this->phpci->getBuildProjectTitle(); + $logText = $this->phpci->getBuild()->getLog(); + if($this->phpci->getSuccessStatus()) { - $body = ""; $sendFailures = $this->sendSeparateEmails( $addresses, - "PASSED", - $body + sprintf($subjectTemplate, $projectName, "Passing Build"), + sprintf("Log Output:
%s
", $logText) ); } else { - $body = ""; $sendFailures = $this->sendSeparateEmails( $addresses, - "FAILED", - $body + sprintf($subjectTemplate, $projectName, "Failing Build"), + sprintf("Log Output:
%s
", $logText) ); } @@ -113,7 +115,8 @@ class Email implements \PHPCI\Plugin $message = \Swift_Message::newInstance($subject) ->setFrom($this->getMailConfig('from_address')) ->setTo($toAddresses) - ->setBody($body); + ->setBody($body) + ->setContentType("text/html"); $failedAddresses = array(); $this->mailer->send($message, $failedAddresses); diff --git a/Tests/PHPCI/Plugin/Email.php b/Tests/PHPCI/Plugin/Email.php index fdcb0a05..8000da7e 100644 --- a/Tests/PHPCI/Plugin/Email.php +++ b/Tests/PHPCI/Plugin/Email.php @@ -34,16 +34,38 @@ class EmailTest extends \PHPUnit_Framework_TestCase */ 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'), + array('getSystemConfig', + 'getBuildProjectTitle', + 'getBuild', + 'log'), array(), "mockBuilder", false ); - $this->mockCiBuilder->buildPath = "/"; + + $this->mockCiBuilder->buildPath = "/"; + $this->mockCiBuilder->expects($this->any()) ->method('getSystemConfig') ->with('phpci') @@ -52,6 +74,12 @@ class EmailTest extends \PHPUnit_Framework_TestCase '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', @@ -85,6 +113,35 @@ class EmailTest extends \PHPUnit_Framework_TestCase $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:
Build Log
", + "PHPCI - Test-Project - Passing Build", + $actualMail + ); + + $this->assertEquals($expectedReturn, $returnValue); + + + } + /** * @covers PHPUnit::sendEmail */ @@ -172,6 +229,10 @@ class EmailTest extends \PHPUnit_Framework_TestCase $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() From 76adf14b28320266335c23cc5df343d489387d73 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Wed, 5 Jun 2013 06:23:47 +0100 Subject: [PATCH 17/45] Initial summary changes --- PHPCI/Controller/IndexController.php | 2 +- PHPCI/Store/BuildStore.php | 2 +- PHPCI/View/Index/index.phtml | 6 +-- PHPCI/View/SummaryTable.phtml | 61 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 PHPCI/View/SummaryTable.phtml diff --git a/PHPCI/Controller/IndexController.php b/PHPCI/Controller/IndexController.php index c185d2f3..2404a047 100644 --- a/PHPCI/Controller/IndexController.php +++ b/PHPCI/Controller/IndexController.php @@ -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(); diff --git a/PHPCI/Store/BuildStore.php b/PHPCI/Store/BuildStore.php index 6b26c3c7..fca490f2 100644 --- a/PHPCI/Store/BuildStore.php +++ b/PHPCI/Store/BuildStore.php @@ -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()) { diff --git a/PHPCI/View/Index/index.phtml b/PHPCI/View/Index/index.phtml index 887b46d3..8ffa4b56 100644 --- a/PHPCI/View/Index/index.phtml +++ b/PHPCI/View/Index/index.phtml @@ -44,10 +44,10 @@ - + - - + + diff --git a/PHPCI/View/SummaryTable.phtml b/PHPCI/View/SummaryTable.phtml new file mode 100644 index 00000000..cacfd204 --- /dev/null +++ b/PHPCI/View/SummaryTable.phtml @@ -0,0 +1,61 @@ +"; +// var_dump($builds); +// echo ""; + +$maxbuildcount = 5; +$projects = array(); +$prevBuild = null; +$health = false; + +foreach($builds as $build): + + if ( is_null($prevBuild) || $build->getProjectId() !== $prevBuild->getProjectId() ) { + $health = false; + $projects[$build->getProjectId()]['count'] = 0; + $projects[$build->getProjectId()]['health'] = 0; + } + + if ( + $build->getStatus() < 2 || + ( + !is_null($prevBuild) && + $projects[$build->getProjectId()]['count'] >= $maxbuildcount && + $build->getProjectId() === $prevBuild->getProjectId() + ) + ) { + continue; + } + switch ((int)$build->getStatus()) { + case 2: + $projects[$build->getProjectId()]['health']++; + if ( empty($projects[$build->getProjectId()]['lastsuccess']) ) { + $projects[$build->getProjectId()]['lastsuccess'] = $build->getStarted(); + } + break; + case 3: + $projects[$build->getProjectId()]['health']--; + if ( empty($projects[$build->getProjectId()]['lastfailure']) ) { + $projects[$build->getProjectId()]['lastfailure'] = $build->getStarted(); + } + break; + } + $projects[$build->getProjectId()]['count']++; + $prevBuild = $build; +endforeach; + +// echo "
";
+// var_dump($projects);
+// echo "
"; + +foreach($projects as $projectId => $project): +?> + + + + + + + + + \ No newline at end of file From aef90eefa98282db6837741c1a82e15660359a8b Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Wed, 5 Jun 2013 06:45:04 +0100 Subject: [PATCH 18/45] Some more summary tweaks --- PHPCI/View/Index/index.phtml | 4 ++-- PHPCI/View/SummaryTable.phtml | 34 ++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/PHPCI/View/Index/index.phtml b/PHPCI/View/Index/index.phtml index 8ffa4b56..dcc26701 100644 --- a/PHPCI/View/Index/index.phtml +++ b/PHPCI/View/Index/index.phtml @@ -48,8 +48,8 @@ - - + + diff --git a/PHPCI/View/SummaryTable.phtml b/PHPCI/View/SummaryTable.phtml index cacfd204..e3bbee1d 100644 --- a/PHPCI/View/SummaryTable.phtml +++ b/PHPCI/View/SummaryTable.phtml @@ -14,33 +14,43 @@ foreach($builds as $build): $health = false; $projects[$build->getProjectId()]['count'] = 0; $projects[$build->getProjectId()]['health'] = 0; + $projects[$build->getProjectId()]['successes'] = 0; + $projects[$build->getProjectId()]['failures'] = 0; } - if ( - $build->getStatus() < 2 || - ( - !is_null($prevBuild) && - $projects[$build->getProjectId()]['count'] >= $maxbuildcount && - $build->getProjectId() === $prevBuild->getProjectId() - ) - ) { + if ($build->getStatus() < 2) { continue; } + 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->getStarted(); } break; case 3: $projects[$build->getProjectId()]['health']--; + $projects[$build->getProjectId()]['failures']++; + if ( empty($projects[$build->getProjectId()]['lastfailure']) ) { $projects[$build->getProjectId()]['lastfailure'] = $build->getStarted(); } break; } + $projects[$build->getProjectId()]['count']++; + $projects[$build->getProjectId()]['projectname'] = $build->getProject()->getTitle(); $prevBuild = $build; endforeach; @@ -52,10 +62,10 @@ foreach($projects as $projectId => $project): ?> - - - - + + + + \ No newline at end of file From fa721fe0ff3b989a5a288fb84896f820be3d2489 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Wed, 5 Jun 2013 06:49:49 +0100 Subject: [PATCH 19/45] build link --- PHPCI/View/Index/index.phtml | 4 ++-- PHPCI/View/SummaryTable.phtml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PHPCI/View/Index/index.phtml b/PHPCI/View/Index/index.phtml index dcc26701..903b0bc2 100644 --- a/PHPCI/View/Index/index.phtml +++ b/PHPCI/View/Index/index.phtml @@ -48,8 +48,8 @@ - - + + diff --git a/PHPCI/View/SummaryTable.phtml b/PHPCI/View/SummaryTable.phtml index e3bbee1d..f58c7345 100644 --- a/PHPCI/View/SummaryTable.phtml +++ b/PHPCI/View/SummaryTable.phtml @@ -66,6 +66,6 @@ foreach($projects as $projectId => $project): - + \ No newline at end of file From ab81c75e95ba86f1ecd43501c1c66a4aaee6072f Mon Sep 17 00:00:00 2001 From: Steve B Date: Wed, 5 Jun 2013 09:53:32 +0200 Subject: [PATCH 20/45] Update to composer.json to correct indentation. swiftmailer was added automatically by PHPStorm and the indentation didn't match the rest of the file. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d034e3c5..a4424830 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,6 @@ "symfony/yaml" : "2.2.x-dev", "symfony/console" : "2.2.*", "fabpot/php-cs-fixer" : "0.3.*@dev", - "swiftmailer/swiftmailer": "v5.0.0" + "swiftmailer/swiftmailer" : "v5.0.0" } } From ef310645efe906128a524225597303a50b2b5984 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Wed, 5 Jun 2013 09:46:42 +0100 Subject: [PATCH 21/45] added last build status background color --- PHPCI/View/SummaryTable.phtml | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/PHPCI/View/SummaryTable.phtml b/PHPCI/View/SummaryTable.phtml index f58c7345..de8923e7 100644 --- a/PHPCI/View/SummaryTable.phtml +++ b/PHPCI/View/SummaryTable.phtml @@ -10,17 +10,19 @@ $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 ($build->getStatus() < 2) { - continue; - } if ( !is_null($prevBuild) && $projects[$build->getProjectId()]['count'] >= $maxbuildcount && @@ -59,8 +61,30 @@ endforeach; // echo ""; 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; + } ?> - + From 05b32b6d53f2dbf048829a34e1f49b559025817c Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 5 Jun 2013 14:55:52 +0100 Subject: [PATCH 22/45] Adding patch to fix pagination, closes #73 --- PHPCI/View/Project/view.phtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PHPCI/View/Project/view.phtml b/PHPCI/View/Project/view.phtml index 59d07ced..17b0a1ab 100644 --- a/PHPCI/View/Project/view.phtml +++ b/PHPCI/View/Project/view.phtml @@ -61,14 +61,14 @@ $pages = ceil($total / 10); $pages = $pages == 0 ? 1 : $pages; - print '
  • «
  • '; + print '
  • «
  • '; for($i = 1; $i <= $pages; $i++) { - print '
  • ' . $i . '
  • '; + print '
  • ' . $i . '
  • '; } - print '
  • »
  • '; + print '
  • »
  • '; print ''; From 396428cc828ab526cef3df5f989ef52df63cb3b9 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Wed, 5 Jun 2013 17:13:00 +0100 Subject: [PATCH 23/45] ui tweaks --- PHPCI/View/BuildsTable.phtml | 2 +- assets/css/phpci.css | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/PHPCI/View/BuildsTable.phtml b/PHPCI/View/BuildsTable.phtml index 6b0c5b16..df34d97a 100644 --- a/PHPCI/View/BuildsTable.phtml +++ b/PHPCI/View/BuildsTable.phtml @@ -43,7 +43,7 @@ switch($build->getStatus()) } ?> $pluginstatus): ?> -
    '> +
    '>
    diff --git a/assets/css/phpci.css b/assets/css/phpci.css index 8d540519..1d1a16f9 100644 --- a/assets/css/phpci.css +++ b/assets/css/phpci.css @@ -15,9 +15,7 @@ body } .build-plugin-status { - text-align: center; - min-width: 80px; - float: left; + float: left!important; padding: 5px; margin-right: 5px; border: 1px solid black; From 9323797900702a26b61a14fcff854084e0c0b88b Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Wed, 5 Jun 2013 20:59:05 +0100 Subject: [PATCH 24/45] ui --- PHPCI/View/BuildsTable.phtml | 22 +++++++++++++++++++--- assets/css/phpci.css | 7 +------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/PHPCI/View/BuildsTable.phtml b/PHPCI/View/BuildsTable.phtml index df34d97a..34a5ca72 100644 --- a/PHPCI/View/BuildsTable.phtml +++ b/PHPCI/View/BuildsTable.phtml @@ -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; } @@ -38,14 +43,25 @@ switch($build->getStatus())
    diff --git a/assets/css/phpci.css b/assets/css/phpci.css index 1d1a16f9..cfb886d4 100644 --- a/assets/css/phpci.css +++ b/assets/css/phpci.css @@ -14,12 +14,7 @@ body padding: 10px; } -.build-plugin-status { - float: left!important; - padding: 5px; - margin-right: 5px; - border: 1px solid black; -} +td .label { margin-right: 5px; } .success-message { background-color: #4F8A10; From 8e200015b612e10b026f2a973033ec2025138f58 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Wed, 5 Jun 2013 22:34:21 +0100 Subject: [PATCH 25/45] linkificationism --- PHPCI/View/SummaryTable.phtml | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/PHPCI/View/SummaryTable.phtml b/PHPCI/View/SummaryTable.phtml index de8923e7..bcee508d 100644 --- a/PHPCI/View/SummaryTable.phtml +++ b/PHPCI/View/SummaryTable.phtml @@ -38,7 +38,7 @@ foreach($builds as $build): $projects[$build->getProjectId()]['successes']++; if ( empty($projects[$build->getProjectId()]['lastsuccess']) ) { - $projects[$build->getProjectId()]['lastsuccess'] = $build->getStarted(); + $projects[$build->getProjectId()]['lastsuccess'] = $build; } break; case 3: @@ -46,7 +46,7 @@ foreach($builds as $build): $projects[$build->getProjectId()]['failures']++; if ( empty($projects[$build->getProjectId()]['lastfailure']) ) { - $projects[$build->getProjectId()]['lastfailure'] = $build->getStarted(); + $projects[$build->getProjectId()]['lastfailure'] = $build; } break; } @@ -86,9 +86,25 @@ foreach($projects as $projectId => $project): ?> - - - + + + From 910e09eb52e777d0bb8d08cdad2ac7bb67817aca Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Sun, 9 Jun 2013 17:42:50 +0100 Subject: [PATCH 26/45] daemon work --- PHPCI/Command/DaemonCommand.php | 74 +++++++++++++++++++++++++++++++++ PHPCI/Command/RunCommand.php | 9 +++- console | 2 + 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 PHPCI/Command/DaemonCommand.php diff --git a/PHPCI/Command/DaemonCommand.php b/PHPCI/Command/DaemonCommand.php new file mode 100644 index 00000000..78513ced --- /dev/null +++ b/PHPCI/Command/DaemonCommand.php @@ -0,0 +1,74 @@ + /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 +* @package PHPCI +* @subpackage Console +*/ +class DaemonCommand extends Command +{ + protected function configure() + { + $this + ->setName('phpci:start-daemon') + ->setDescription('Starts the daemon to run commands.'); + } + + /** + * Loops through running. + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + + $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 $buildCount . ' ' . $this->sleep . ','; + 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); + } +} diff --git a/PHPCI/Command/RunCommand.php b/PHPCI/Command/RunCommand.php index b28d9832..abd30c6c 100644 --- a/PHPCI/Command/RunCommand.php +++ b/PHPCI/Command/RunCommand.php @@ -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; } /** diff --git a/console b/console index 4a0c8120..62d7258d 100755 --- a/console +++ b/console @@ -28,10 +28,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(); From a963a3f284bcab62ea955214e4f86be8ac2a17f5 Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Sun, 9 Jun 2013 20:11:22 +0100 Subject: [PATCH 27/45] MAjority of daemon work done, can start stop and status the daemon --- PHPCI/Command/DaemonCommand.php | 90 +++++++++++++++++++++++------- PHPCI/Command/DaemoniseCommand.php | 76 +++++++++++++++++++++++++ console | 1 + daemon/.gitignore | 2 + daemonise | 22 ++++++++ 5 files changed, 170 insertions(+), 21 deletions(-) create mode 100644 PHPCI/Command/DaemoniseCommand.php create mode 100644 daemon/.gitignore create mode 100755 daemonise diff --git a/PHPCI/Command/DaemonCommand.php b/PHPCI/Command/DaemonCommand.php index 78513ced..94ecb464 100644 --- a/PHPCI/Command/DaemonCommand.php +++ b/PHPCI/Command/DaemonCommand.php @@ -30,8 +30,13 @@ class DaemonCommand extends Command protected function configure() { $this - ->setName('phpci:start-daemon') - ->setDescription('Starts the daemon to run commands.'); + ->setName('phpci:daemon') + ->setDescription('Initiates the daemon to run commands.') + ->addArgument( + 'state', + InputArgument::REQUIRED, + 'start|stop|status' + ); } /** @@ -39,30 +44,73 @@ class DaemonCommand extends Command */ protected function execute(InputInterface $input, OutputInterface $output) { + $state = $input->getArgument('state'); - $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 $buildCount . ' ' . $this->sleep . ','; - sleep($this->sleep); + 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() diff --git a/PHPCI/Command/DaemoniseCommand.php b/PHPCI/Command/DaemoniseCommand.php new file mode 100644 index 00000000..f46e6948 --- /dev/null +++ b/PHPCI/Command/DaemoniseCommand.php @@ -0,0 +1,76 @@ + /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 +* @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); + } +} diff --git a/console b/console index 62d7258d..f571c454 100755 --- a/console +++ b/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. diff --git a/daemon/.gitignore b/daemon/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/daemon/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/daemonise b/daemonise new file mode 100755 index 00000000..63ac409a --- /dev/null +++ b/daemonise @@ -0,0 +1,22 @@ +#!/usr/bin/env php +add(new DaemoniseCommand); +$application->run(); From b2fc63511b30131d4f937f723ffe4c0df1c20c1d Mon Sep 17 00:00:00 2001 From: Gabriel Baker Date: Sun, 9 Jun 2013 20:29:49 +0100 Subject: [PATCH 28/45] summary tweaks --- PHPCI/View/SummaryTable.phtml | 169 +++++++++++++++++----------------- 1 file changed, 86 insertions(+), 83 deletions(-) diff --git a/PHPCI/View/SummaryTable.phtml b/PHPCI/View/SummaryTable.phtml index bcee508d..6a81de0d 100644 --- a/PHPCI/View/SummaryTable.phtml +++ b/PHPCI/View/SummaryTable.phtml @@ -10,102 +10,105 @@ $health = false; foreach($builds as $build): - if ($build->getStatus() < 2) { - continue; - } + 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) || $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; - } + 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']++; + 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()]['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; - } + 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; + $projects[$build->getProjectId()]['count']++; + $projects[$build->getProjectId()]['projectname'] = $build->getProject()->getTitle(); + $prevBuild = $build; endforeach; -// echo "
    ";
    -// var_dump($projects);
    -// echo "
    "; - foreach($projects as $projectId => $project): - switch($project['lastbuildstatus']) - { - case 0: - $cls = 'info'; - $status = 'Pending'; - break; + switch($project['lastbuildstatus']) + { + case 0: + $cls = 'info'; + $status = 'Pending'; + break; - case 1: - $cls = 'warning'; - $status = 'Running'; - break; + case 1: + $cls = 'warning'; + $status = 'Running'; + break; - case 2: - $cls = 'success'; - $status = 'Success'; - break; + case 2: + $cls = 'success'; + $status = 'Success'; + break; - case 3: - $cls = 'error'; - $status = 'Failed'; - 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')); ?>
    - - - - - - + + + + + + \ No newline at end of file From 5c1b5dc13f163f57ff1492bc9cb8de58a12904f6 Mon Sep 17 00:00:00 2001 From: Sanpi Date: Wed, 19 Jun 2013 11:46:12 +0200 Subject: [PATCH 29/45] Dot is allowed in github repository name --- PHPCI/Controller/ProjectController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 70f95ab1..27ec611e 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -282,7 +282,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; From 7f09e4df070233aefe304e7418ea26920e085bcb Mon Sep 17 00:00:00 2001 From: Sanpi Date: Wed, 19 Jun 2013 17:47:25 +0200 Subject: [PATCH 30/45] Allow arbitrary repository URL --- PHPCI/BuildFactory.php | 3 +++ PHPCI/Controller/ProjectController.php | 8 +++++++- PHPCI/Model/Build/RemoteGitBuild.php | 7 +++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/PHPCI/BuildFactory.php b/PHPCI/BuildFactory.php index ad4dd0a5..c4479b05 100644 --- a/PHPCI/BuildFactory.php +++ b/PHPCI/BuildFactory.php @@ -28,6 +28,9 @@ class BuildFactory { switch($base->getProject()->getType()) { + case 'remote': + $type = 'RemoteGitBuild'; + break; case 'local': $type = 'LocalBuild'; break; diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 70f95ab1..efad364d 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -252,12 +252,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 +276,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.'); diff --git a/PHPCI/Model/Build/RemoteGitBuild.php b/PHPCI/Model/Build/RemoteGitBuild.php index 0670f6db..d1fe1c74 100644 --- a/PHPCI/Model/Build/RemoteGitBuild.php +++ b/PHPCI/Model/Build/RemoteGitBuild.php @@ -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. From ff8bd75b22eccc37c53ba87ceedfa168b0f03390 Mon Sep 17 00:00:00 2001 From: Sanpi Date: Wed, 19 Jun 2013 11:29:52 +0200 Subject: [PATCH 31/45] Add atoum plugin --- PHPCI/Plugin/Atoum.php | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 PHPCI/Plugin/Atoum.php diff --git a/PHPCI/Plugin/Atoum.php b/PHPCI/Plugin/Atoum.php new file mode 100644 index 00000000..a97fa00a --- /dev/null +++ b/PHPCI/Plugin/Atoum.php @@ -0,0 +1,51 @@ +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); + } +} From 895928422e17f65b279b6873887d519080c5b0b5 Mon Sep 17 00:00:00 2001 From: Daniel Holmes Date: Sun, 30 Jun 2013 18:55:25 +1000 Subject: [PATCH 32/45] Allow for bare repositories --- PHPCI/Model/Build/LocalBuild.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 38e2a914..e917d2c3 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -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'); + if($gitConfig["core"]["bare"]) { + // Looks like we're right. We need to extract the archive! + $guid = uniqid(); + $builder->executeCommand('mkdir "/tmp/%s" && git archive master | tar -x -C "/tmp/%s"', $guid, $guid); + $reference = '/tmp/'.$guid; + } + } if (!is_file($reference . '/phpci.yml')) { $builder->logFailure('Project does not contain a phpci.yml file.'); From 62e8106130e4ff501437f1b0667d9a21d774998d Mon Sep 17 00:00:00 2001 From: Daniel Holmes Date: Sun, 30 Jun 2013 19:44:02 +1000 Subject: [PATCH 33/45] Tested And Resolved --- PHPCI/Model/Build/LocalBuild.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index e917d2c3..856a3f7c 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -31,9 +31,9 @@ class LocalBuild extends Build $buildPath = substr($buildPath, 0, -1); $yamlParser = new YamlParser(); - if(is_file($reference.'config')) { + 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'); + $gitConfig = parse_ini_file($reference.'/config',TRUE); if($gitConfig["core"]["bare"]) { // Looks like we're right. We need to extract the archive! $guid = uniqid(); From 9b458060fd9dbc8b97e8376581624c30a4173f6d Mon Sep 17 00:00:00 2001 From: Daniel Holmes Date: Mon, 1 Jul 2013 00:17:41 +1000 Subject: [PATCH 34/45] Final Version. Tested on ubuntu 12.04 64bit --- PHPCI/Model/Build/LocalBuild.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 856a3f7c..07698d42 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -37,7 +37,7 @@ class LocalBuild extends Build if($gitConfig["core"]["bare"]) { // Looks like we're right. We need to extract the archive! $guid = uniqid(); - $builder->executeCommand('mkdir "/tmp/%s" && git archive master | tar -x -C "/tmp/%s"', $guid, $guid); + $builder->executeCommand('mkdir "/tmp/%s" && git --git-dir="%s" archive master | tar -x -C "/tmp/%s"', $guid, $reference, $guid); $reference = '/tmp/'.$guid; } } From 34bb69ec5eca5a4529a9b0bcbc01b43387ad2871 Mon Sep 17 00:00:00 2001 From: Maks Rafalko Date: Mon, 15 Jul 2013 23:28:22 +0300 Subject: [PATCH 35/45] Added `exit` to correct redirect after `Build Now` is clicked Withow `exit` statement it's not redirected to new created build. --- PHPCI/Controller/ProjectController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 243342c6..bbc8a7b5 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -63,6 +63,7 @@ class ProjectController extends \PHPCI\Controller $build = $this->_buildStore->save($build); header('Location: '.PHPCI_URL.'build/view/' . $build->getId()); + exit; } /** From 2576f33029a9284c1648ad47d58579eedcf72fe3 Mon Sep 17 00:00:00 2001 From: Maks Rafalko Date: Mon, 15 Jul 2013 23:30:25 +0300 Subject: [PATCH 36/45] Added `exit` to correct redirect after `Rebuild` and `Delete build` is clicked Without `exit` it's not redirected. --- PHPCI/Controller/BuildController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php index b41287aa..56bde07c 100644 --- a/PHPCI/Controller/BuildController.php +++ b/PHPCI/Controller/BuildController.php @@ -79,6 +79,7 @@ class BuildController extends \PHPCI\Controller $build = $this->_buildStore->save($build); header('Location: '.PHPCI_URL.'build/view/' . $build->getId()); + exit; } /** @@ -94,6 +95,7 @@ class BuildController extends \PHPCI\Controller $this->_buildStore->delete($build); header('Location: '.PHPCI_URL.'project/view/' . $build->getProjectId()); + exit; } /** From dc77992fd2f975f7e0462a741f8c857eb43ee019 Mon Sep 17 00:00:00 2001 From: Maks Rafalko Date: Mon, 15 Jul 2013 23:56:51 +0300 Subject: [PATCH 37/45] Hide message when local repositary is used Hide message about hooks when local repositary is used --- PHPCI/View/Project/view.phtml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PHPCI/View/Project/view.phtml b/PHPCI/View/Project/view.phtml index 17b0a1ab..bb8aec03 100644 --- a/PHPCI/View/Project/view.phtml +++ b/PHPCI/View/Project/view.phtml @@ -19,8 +19,10 @@ -
    -

    To automatically build this project when new commits are pushed, add the URL below + getType(), array('github', 'bitbucket'))): ?> +
    +

    To automatically build this project when new commits are pushed, add the URL below + getType()) @@ -83,4 +85,4 @@ setInterval(function() $('#latest-builds').load('project/builds/getId(); ?>'); }, 10000); - \ No newline at end of file + From 6c76208992bf1bf7fc245b4806f97e6d75e86d3a Mon Sep 17 00:00:00 2001 From: Alexander Pirogov Date: Thu, 18 Jul 2013 14:14:22 +0300 Subject: [PATCH 38/45] added smtp_encryption config parameter --- PHPCI/Command/InstallCommand.php | 1 + PHPCI/Plugin/Email.php | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index ad9cbeb7..dea4e560 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -50,6 +50,7 @@ class InstallCommand extends Command $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); diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php index ae7ced05..798a01b5 100644 --- a/PHPCI/Plugin/Email.php +++ b/PHPCI/Plugin/Email.php @@ -140,7 +140,8 @@ class Email implements \PHPCI\Plugin /** @var \Swift_SmtpTransport $transport */ $transport = \Swift_SmtpTransport::newInstance( $this->getMailConfig('smtp_address'), - $this->getMailConfig('smtp_port') + $this->getMailConfig('smtp_port'), + $this->getMailConfig('smtp_encryption') ); $transport->setUsername($this->getMailConfig('smtp_username')); $transport->setPassword($this->getMailConfig('smtp_password')); @@ -164,6 +165,8 @@ class Email implements \PHPCI\Plugin return null; case 'smtp_port': return '25'; + case 'smtp_encryption': + return null; case 'from_address': return "notifications-ci@phptesting.org"; default: From a137e9c0c6e05878468a9028bb8817a471ee3620 Mon Sep 17 00:00:00 2001 From: Alexander Pirogov Date: Thu, 18 Jul 2013 16:10:55 +0300 Subject: [PATCH 39/45] added prefer_dist option to composer plugin --- PHPCI/Plugin/Composer.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PHPCI/Plugin/Composer.php b/PHPCI/Plugin/Composer.php index 42195f52..df2da277 100644 --- a/PHPCI/Plugin/Composer.php +++ b/PHPCI/Plugin/Composer.php @@ -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); } } From 2a0e6d2401328be10c8afdd38fae2c8287965ed7 Mon Sep 17 00:00:00 2001 From: Alexander Pirogov Date: Fri, 19 Jul 2013 16:40:16 +0300 Subject: [PATCH 40/45] added rules option to phpmd plugin --- PHPCI/Plugin/PhpMessDetector.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/PHPCI/Plugin/PhpMessDetector.php b/PHPCI/Plugin/PhpMessDetector.php index ea6ff959..d2a2e3dc 100644 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -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); } } From 585a60e9952295966eb060476b48d29ee90db63b Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 25 Jul 2013 12:36:46 +0100 Subject: [PATCH 41/45] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fe84080d..16284708 100644 --- a/README.md +++ b/README.md @@ -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 this is a beta-release project, so there will be bugs and 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: From 6793a5f373296146381d0c0bc453b06787379a33 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 25 Jul 2013 13:44:08 +0100 Subject: [PATCH 42/45] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 16284708..aa1eff8a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ 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 beta-release project, 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** From 549a022b0e3babc8f521141e5f7c9d1ce15c3a16 Mon Sep 17 00:00:00 2001 From: mrafalko Date: Thu, 25 Jul 2013 23:58:16 +0300 Subject: [PATCH 43/45] replaced alpha word with beta [main logo] --- PHPCI/View/layout.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PHPCI/View/layout.phtml b/PHPCI/View/layout.phtml index f5b95baf..2db749d3 100644 --- a/PHPCI/View/layout.phtml +++ b/PHPCI/View/layout.phtml @@ -17,7 +17,7 @@

    - + \ No newline at end of file From 3b5db87c319632a659a4208c498541da9b922f6e Mon Sep 17 00:00:00 2001 From: mrafalko Date: Fri, 26 Jul 2013 00:48:08 +0300 Subject: [PATCH 45/45] removed inline JS, added e.preventDefault to avoid redirecting to 'false' URL --- PHPCI/Controller/ProjectController.php | 1 + PHPCI/View/Build/view.phtml | 10 +++++++--- PHPCI/View/Project/view.phtml | 17 ++++++++++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index bbc8a7b5..eaad90a1 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -79,6 +79,7 @@ class ProjectController extends \PHPCI\Controller $this->_projectStore->delete($project); header('Location: '.PHPCI_URL); + exit; } /** diff --git a/PHPCI/View/Build/view.phtml b/PHPCI/View/Build/view.phtml index b5aa7324..f57a1a45 100644 --- a/PHPCI/View/Build/view.phtml +++ b/PHPCI/View/Build/view.phtml @@ -13,7 +13,7 @@
  • Rebuild
  • User()->getIsAdmin()): ?> -
  • Delete Build
  • +
  • Delete Build
  • @@ -73,8 +73,12 @@ }, 10000); - $(document).ready(function() - { + $(function() { updateBuildView(window.initial); + + $('#delete-build').on('click', function (e) { + e.preventDefault(); + confirmDelete("build/delete/getId(); ?>"); + }); }); \ No newline at end of file diff --git a/PHPCI/View/Project/view.phtml b/PHPCI/View/Project/view.phtml index bb8aec03..77d488fc 100644 --- a/PHPCI/View/Project/view.phtml +++ b/PHPCI/View/Project/view.phtml @@ -14,7 +14,7 @@ User()->getIsAdmin()): ?>
  • Edit Project
  • -
  • Delete Project
  • +
  • Delete Project
  • @@ -80,9 +80,16 @@
    IDHealth ProjectCommitBranchLast SuccessLast Failure Status
    format("d-m-Y H:i:s" ) ?>format("d-m-Y H:i:s" ) ?>
    Project Last Success Last FailureStatusSuccess/Failed BuildsTotal Builds
    format("d-m-Y H:i:s" ) ?>format("d-m-Y H:i:s" ) ?>format("Y-m-d H:i:s") ?>format("Y-m-d H:i:s") ?>/
    Project Last Success Last FailureSuccess/Failed BuildsTotal BuildsSuccess/Failures
    format("Y-m-d H:i:s") ?> format("Y-m-d H:i:s") ?> /build
    format("Y-m-d H:i:s") ?> getPlugins(), true); + if ( !is_array($plugins) ) { $plugins = array(); } + if ( 0 === count($plugins) ) { + ?> + + + + - $pluginstatus): ?> -
    '> + $pluginstatus): + $subcls = $pluginstatus?'label label-success':'label label-important'; + ?> + -
    +
    format("Y-m-d H:i:s") ?>format("Y-m-d H:i:s") ?> + + getId() ?>'> + getStarted()->format("Y-m-d H:i:s") ?> + + + + + getId() ?>'> + getStarted()->format("Y-m-d H:i:s") ?> + + + / build
    - - getId() ?>'> - getStarted()->format("Y-m-d H:i:s") ?> - - - - - getId() ?>'> - getStarted()->format("Y-m-d H:i:s") ?> - - - /build + + + + + + getId() ?>'> + getStarted()->format("Y-m-d H:i:s") ?> + + + + + getId() ?>'> + getStarted()->format("Y-m-d H:i:s") ?> + + + /build
    /buildbuild