diff --git a/.gitignore b/.gitignore index 79784a60..63e81c5b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ PHPCI/Model/Base/MigrationBase.php PHPCI/Store/MigrationStore.php PHPCI/Store/Base/MigrationStoreBase.php local_vars.php +Tests/PHPCI/config.yml diff --git a/PHPCI/Command/CreateAdminCommand.php b/PHPCI/Command/CreateAdminCommand.php index 3b69afd3..265f03b4 100644 --- a/PHPCI/Command/CreateAdminCommand.php +++ b/PHPCI/Command/CreateAdminCommand.php @@ -9,21 +9,36 @@ namespace PHPCI\Command; -use PHPCI\Helper\Lang; use PHPCI\Service\UserService; +use PHPCI\Helper\Lang; +use PHPCI\Store\UserStore; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use b8\Store\Factory; /** -* Create admin command - creates an admin user -* @author Wogan May (@woganmay) -* @package PHPCI -* @subpackage Console -*/ + * Create admin command - creates an admin user + * @author Wogan May (@woganmay) + * @package PHPCI + * @subpackage Console + */ class CreateAdminCommand extends Command { + /** + * @var UserStore + */ + protected $userStore; + + /** + * @param UserStore $userStore + */ + public function __construct(UserStore $userStore) + { + parent::__construct(); + + $this->userStore = $userStore; + } + protected function configure() { $this @@ -32,92 +47,36 @@ class CreateAdminCommand extends Command } /** - * Creates an admin user in the existing PHPCI database - */ + * Creates an admin user in the existing PHPCI database + * + * {@inheritDoc} + */ protected function execute(InputInterface $input, OutputInterface $output) { - $userStore = Factory::getStore('User'); - $userService = new UserService($userStore); + $userService = new UserService($this->userStore); - require(PHPCI_DIR . 'bootstrap.php'); + /** @var $dialog \Symfony\Component\Console\Helper\DialogHelper */ + $dialog = $this->getHelperSet()->get('dialog'); - // Try to create a user account: - $adminEmail = $this->ask(Lang::get('enter_email'), true, FILTER_VALIDATE_EMAIL); + // Function to validate mail address. + $mailValidator = function ($answer) { + if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) { + throw new \InvalidArgumentException(Lang::get('must_be_valid_email')); + } - if (empty($adminEmail)) { - return; - } + return $answer; + }; - $adminPass = $this->ask(Lang::get('enter_pass')); - $adminName = $this->ask(Lang::get('enter_name')); + $adminEmail = $dialog->askAndValidate($output, Lang::get('enter_email'), $mailValidator, false); + $adminName = $dialog->ask($output, Lang::get('enter_name')); + $adminPass = $dialog->askHiddenResponse($output, Lang::get('enter_password')); try { - $userService->createUser($adminName, $adminEmail, $adminPass, 1); - print Lang::get('user_created') . PHP_EOL; - } catch (\Exception $ex) { - print Lang::get('failed_to_create') . PHP_EOL; - print $ex->getMessage(); - print PHP_EOL; + $userService->createUser($adminName, $adminEmail, $adminPass, true); + $output->writeln(Lang::get('user_created')); + } catch (\Exception $e) { + $output->writeln(sprintf('%s', Lang::get('failed_to_create'))); + $output->writeln(sprintf('%s', $e->getMessage())); } } - - protected function ask($question, $emptyOk = false, $validationFilter = null) - { - print $question . ' '; - - $rtn = ''; - $stdin = fopen('php://stdin', 'r'); - $rtn = fgets($stdin); - fclose($stdin); - - $rtn = trim($rtn); - - if (!$emptyOk && empty($rtn)) { - $rtn = $this->ask($question, $emptyOk, $validationFilter); - } elseif (!is_null($validationFilter) && ! empty($rtn)) { - if (! $this -> controlFormat($rtn, $validationFilter, $statusMessage)) { - print $statusMessage; - $rtn = $this->ask($question, $emptyOk, $validationFilter); - } - } - - return $rtn; - } - protected function controlFormat($valueToInspect, $filter, &$statusMessage) - { - $filters = !(is_array($filter))? array($filter) : $filter; - $statusMessage = ''; - $status = true; - $options = array(); - - foreach ($filters as $filter) { - if (! is_int($filter)) { - $regexp = $filter; - $filter = FILTER_VALIDATE_REGEXP; - $options = array( - 'options' => array( - 'regexp' => $regexp, - ) - ); - } - if (! filter_var($valueToInspect, $filter, $options)) { - $status = false; - - switch ($filter) - { - case FILTER_VALIDATE_URL: - $statusMessage = Lang::get('must_be_valid_url') . PHP_EOL; - break; - case FILTER_VALIDATE_EMAIL: - $statusMessage = Lang::get('must_be_valid_email') . PHP_EOL; - break; - case FILTER_VALIDATE_REGEXP: - $statusMessage = Lang::get('incorrect_format') . PHP_EOL; - break; - } - } - } - - return $status; - } } diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index d262b9f0..04e0f2dd 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -95,7 +95,7 @@ class InstallCommand extends Command $this->writeConfigFile($conf); $this->setupDatabase($output); - $admin = $this->getAdminInforamtion($input, $output); + $admin = $this->getAdminInformation($input, $output); $this->createAdminUser($admin, $output); } @@ -160,7 +160,7 @@ class InstallCommand extends Command * @param OutputInterface $output * @return array */ - protected function getAdminInforamtion(InputInterface $input, OutputInterface $output) + protected function getAdminInformation(InputInterface $input, OutputInterface $output) { $admin = array(); @@ -172,7 +172,7 @@ class InstallCommand extends Command // Function to validate mail address. $mailValidator = function ($answer) { if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) { - throw new Exception(Lang::get('must_be_valid_email')); + throw new \InvalidArgumentException(Lang::get('must_be_valid_email')); } return $answer; diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index b263f06e..8457a7bb 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -268,7 +268,7 @@ class ProjectController extends PHPCI\Controller $view->type = 'edit'; $view->project = $project; $view->form = $form; - $view->key = null; + $view->key = $values['pubkey']; return $view->render(); } diff --git a/PHPCI/Languages/lang.en.php b/PHPCI/Languages/lang.en.php index 9718e442..5f21d3dc 100644 --- a/PHPCI/Languages/lang.en.php +++ b/PHPCI/Languages/lang.en.php @@ -183,6 +183,7 @@ PHPCI', 'phpmd' => 'PHP Mess Detector', 'phpspec' => 'PHP Spec', 'phpunit' => 'PHP Unit', + 'technical_debt' => 'Technical Debt', 'file' => 'File', 'line' => 'Line', diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php index 7c5171d6..9e361d91 100644 --- a/PHPCI/Plugin/Email.php +++ b/PHPCI/Plugin/Email.php @@ -13,6 +13,7 @@ use b8\View; use PHPCI\Builder; use PHPCI\Helper\Lang; use PHPCI\Model\Build; +use PHPCI\Helper\Email as EmailHelper; /** * Email Plugin - Provides simple email capability to PHPCI. @@ -27,21 +28,16 @@ class Email implements \PHPCI\Plugin */ protected $phpci; + /** + * @var \PHPCI\Model\Build + */ + protected $build; + /** * @var array */ protected $options; - /** - * @var \Swift_Mailer - */ - protected $mailer; - - /** - * @var string - */ - protected $fromAddress; - /** * Set up the plugin, configure options, etc. * @param Builder $phpci @@ -52,25 +48,16 @@ class Email implements \PHPCI\Plugin public function __construct( Builder $phpci, Build $build, - \Swift_Mailer $mailer, array $options = array() ) { $this->phpci = $phpci; $this->build = $build; $this->options = $options; - - $phpCiSettings = $phpci->getSystemConfig('phpci'); - - $this->fromAddress = isset($phpCiSettings['email_settings']['from_address']) - ? $phpCiSettings['email_settings']['from_address'] - : "notifications-ci@phptesting.org"; - - $this->mailer = $mailer; } /** - * Connects to MySQL and runs a specified set of queries. - */ + * Send a notification mail. + */ public function execute() { $addresses = $this->getEmailAddresses(); @@ -81,79 +68,73 @@ class Email implements \PHPCI\Plugin return false; } - $subjectTemplate = "PHPCI - %s - %s"; - $projectName = $this->phpci->getBuildProjectTitle(); - $logText = $this->build->getLog(); + $buildStatus = $this->build->isSuccessful() ? "Passing Build" : "Failing Build"; + $projectName = $this->build->getProject()->getTitle(); + $mailTemplate = $this->build->isSuccessful() ? 'Email/success' : 'Email/failed'; - if ($this->build->isSuccessful()) { - $sendFailures = $this->sendSeparateEmails( - $addresses, - sprintf($subjectTemplate, $projectName, Lang::get('passing_build')), - sprintf(Lang::get('log_output')."
%s
", $logText) - ); - } else { - $view = new View('Email/failed'); - $view->build = $this->build; - $view->project = $this->build->getProject(); + $view = new View($mailTemplate); + $view->build = $this->build; + $view->project = $this->build->getProject(); + $body = $view->render(); - $emailHtml = $view->render(); - - $sendFailures = $this->sendSeparateEmails( - $addresses, - sprintf($subjectTemplate, $projectName, Lang::get('failing_build')), - $emailHtml - ); - } + $sendFailures = $this->sendSeparateEmails( + $addresses, + sprintf("PHPCI - %s - %s", $projectName, $buildStatus), + $body + ); // This is a success if we've not failed to send anything. + $this->phpci->log(sprintf("%d emails sent", (count($addresses) - $sendFailures))); + $this->phpci->log(sprintf("%d emails failed to send", $sendFailures)); - $this->phpci->log(Lang::get('n_emails_sent', (count($addresses) - count($sendFailures)))); - $this->phpci->log(Lang::get('n_emails_failed', count($sendFailures))); - - return (count($sendFailures) == 0); + return ($sendFailures === 0); } /** - * @param string[]|string $toAddresses Array or single address to send to + * @param string $toAddress Single address to send to * @param string[] $ccList * @param string $subject Email subject * @param string $body Email body * @return array Array of failed addresses */ - public function sendEmail($toAddresses, $ccList, $subject, $body) + public function sendEmail($toAddress, $ccList, $subject, $body) { - $message = \Swift_Message::newInstance($subject) - ->setFrom($this->fromAddress) - ->setTo($toAddresses) - ->setBody($body) - ->setContentType("text/html"); + $email = new EmailHelper(); + + $email->setEmailTo($toAddress, $toAddress); + $email->setSubject($subject); + $email->setBody($body); + $email->setHtml(true); if (is_array($ccList) && count($ccList)) { - $message->setCc($ccList); + foreach ($ccList as $address) { + $email->addCc($address, $address); + } } - $failedAddresses = array(); - $this->mailer->send($message, $failedAddresses); - - return $failedAddresses; + return $email->send(); } /** - * Send out build status emails. + * Send an email to a list of specified subjects. + * * @param array $toAddresses - * @param $subject - * @param $body - * @return array + * List of destinatary of message. + * @param string $subject + * Mail subject + * @param string $body + * Mail body + * + * @return int number of failed messages */ public function sendSeparateEmails(array $toAddresses, $subject, $body) { - $failures = array(); + $failures = 0; $ccList = $this->getCcAddresses(); foreach ($toAddresses as $address) { - $newFailures = $this->sendEmail($address, $ccList, $subject, $body); - foreach ($newFailures as $failure) { - $failures[] = $failure; + if (!$this->sendEmail($address, $ccList, $subject, $body)) { + $failures++; } } return $failures; diff --git a/PHPCI/Plugin/TechnicalDebt.php b/PHPCI/Plugin/TechnicalDebt.php new file mode 100755 index 00000000..fed76566 --- /dev/null +++ b/PHPCI/Plugin/TechnicalDebt.php @@ -0,0 +1,208 @@ + +* @package PHPCI +* @subpackage Plugins +*/ +class TechnicalDebt implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin +{ + /** + * @var \PHPCI\Builder + */ + protected $phpci; + + /** + * @var array + */ + protected $suffixes; + + /** + * @var string + */ + protected $directory; + + /** + * @var int + */ + protected $allowed_errors; + + /** + * @var int + */ + protected $allowed_warnings; + + /** + * @var string, based on the assumption the root may not hold the code to be + * tested, extends the base path + */ + protected $path; + + /** + * @var array - paths to ignore + */ + protected $ignore; + + /** + * @var array - terms to search for + */ + protected $searches; + + + /** + * Check if this plugin can be executed. + * + * @param $stage + * @param Builder $builder + * @param Build $build + * @return bool + */ + public static function canExecute($stage, Builder $builder, Build $build) + { + if ($stage == 'test') { + return true; + } + + return false; + } + + /** + * @param \PHPCI\Builder $phpci + * @param \PHPCI\Model\Build $build + * @param array $options + */ + public function __construct(Builder $phpci, Build $build, array $options = array()) + { + $this->phpci = $phpci; + $this->build = $build; + $this->suffixes = array('php'); + $this->directory = $phpci->buildPath; + $this->path = ''; + $this->ignore = $this->phpci->ignore; + $this->allowed_warnings = 0; + $this->allowed_errors = 0; + $this->searches = array('TODO', 'FIXME', 'TO DO', 'FIX ME'); + + if (isset($options['searches']) && is_array($options['searches'])) { + $this->searches = $options['searches']; + } + + if (isset($options['zero_config']) && $options['zero_config']) { + $this->allowed_warnings = -1; + $this->allowed_errors = -1; + } + } + + /** + * Handle this plugin's options. + * @param $options + */ + protected function setOptions($options) + { + foreach (array('directory', 'path', 'ignore', 'allowed_warnings', 'allowed_errors') as $key) { + if (array_key_exists($key, $options)) { + $this->{$key} = $options[$key]; + } + } + } + + /** + * Runs the plugin + */ + public function execute() + { + $success = true; + $this->phpci->logExecOutput(false); + + list($errorCount, $data) = $this->getErrorList(); + + $this->phpci->log("Found $errorCount instances of " . implode(', ', $this->searches)); + + $this->build->storeMeta('technical_debt-warnings', $errorCount); + $this->build->storeMeta('technical_debt-data', $data); + + if ($this->allowed_errors != -1 && $errorCount > $this->allowed_errors) { + $success = false; + } + + return $success; + } + + /** + * Gets the number and list of errors returned from the search + * + * @return array + */ + public function getErrorList() + { + $dirIterator = new \RecursiveDirectoryIterator($this->directory); + $iterator = new \RecursiveIteratorIterator($dirIterator, \RecursiveIteratorIterator::SELF_FIRST); + $files = []; + + $ignores = $this->ignore; + $ignores[] = 'phpci.yml'; + + foreach ($iterator as $file) { + $filePath = $file->getRealPath(); + $skipFile = false; + foreach ($ignores as $ignore) { + if (stripos($filePath, $ignore) !== false) { + $skipFile = true; + break; + } + } + + // Ignore hidden files, else .git, .sass_cache, etc. all get looped over + if (stripos($filePath, '/.') !== false) { + $skipFile = true; + } + + if ($skipFile == false) { + $files[] = $file->getRealPath(); + } + } + + $files = array_filter(array_unique($files)); + $errorCount = 0; + $data = array(); + + foreach ($files as $file) { + foreach ($this->searches as $search) { + $fileContent = file_get_contents($file); + $allLines = explode(PHP_EOL, $fileContent); + $beforeString = strstr($fileContent, $search, true); + + if (false !== $beforeString) { + $lines = explode(PHP_EOL, $beforeString); + $lineNumber = count($lines); + $content = trim($allLines[$lineNumber - 1]); + + $errorCount++; + $this->phpci->log("Found $search on line $lineNumber of $file:\n$content"); + $data[] = array( + 'file' => str_replace($this->directory, '', $file), + 'line' => $lineNumber, + 'message' => $content + ); + } + } + } + + return array($errorCount, $data); + } +} diff --git a/PHPCI/View/Email/success.phtml b/PHPCI/View/Email/success.phtml new file mode 100644 index 00000000..a6dfccea --- /dev/null +++ b/PHPCI/View/Email/success.phtml @@ -0,0 +1,15 @@ +
+
+
+ getTitle(); ?> - Build #getId(); ?> +
+ +
+

Your commit getCommitId(); ?> genrate a successfull build in project getTitle(); ?>.

+ +

getCommitMessage(); ?>

+
getLog(); ?>
+

You can review your commit and the build log.

+
+
+
diff --git a/Tests/PHPCI/Command/CreateAdminCommandTest.php b/Tests/PHPCI/Command/CreateAdminCommandTest.php new file mode 100644 index 00000000..738d8f8a --- /dev/null +++ b/Tests/PHPCI/Command/CreateAdminCommandTest.php @@ -0,0 +1,78 @@ +command = $this->getMockBuilder('PHPCI\\Command\\CreateAdminCommand') + ->setConstructorArgs([$this->getMock('PHPCI\\Store\\UserStore')]) + ->setMethods(['reloadConfig']) + ->getMock() + ; + + $this->dialog = $this->getMockBuilder('Symfony\\Component\\Console\\Helper\\DialogHelper') + ->setMethods([ + 'ask', + 'askAndValidate', + 'askHiddenResponse', + ]) + ->getMock() + ; + + $this->application = new Application(); + } + + /** + * @return CommandTester + */ + protected function getCommandTester() + { + $this->application->getHelperSet()->set($this->dialog, 'dialog'); + $this->application->add($this->command); + $command = $this->application->find('phpci:create-admin'); + $commandTester = new CommandTester($command); + + return $commandTester; + } + + public function testExecute() + { + $this->dialog->expects($this->at(0))->method('askAndValidate')->will($this->returnValue('test@example.com')); + $this->dialog->expects($this->at(1))->method('ask')->will($this->returnValue('A name')); + $this->dialog->expects($this->at(2))->method('askHiddenResponse')->will($this->returnValue('foobar123')); + + $commandTester = $this->getCommandTester(); + $commandTester->execute([]); + + $this->assertEquals('User account created!' . PHP_EOL, $commandTester->getDisplay()); + } +} diff --git a/Tests/PHPCI/Plugin/EmailTest.php b/Tests/PHPCI/Plugin/EmailTest.php index 0fa2d8f0..965b23c4 100644 --- a/Tests/PHPCI/Plugin/EmailTest.php +++ b/Tests/PHPCI/Plugin/EmailTest.php @@ -10,7 +10,7 @@ namespace PHPCI\Plugin\Tests; use PHPCI\Plugin\Email as EmailPlugin; - +use PHPCI\Model\Build; /** * Unit test for the PHPUnit plugin. @@ -30,20 +30,50 @@ class EmailTest extends \PHPUnit_Framework_TestCase protected $mockCiBuilder; /** - * @var \PHPUnit_Framework_MockObject_MockObject $mockMailer - */ - protected $mockMailer; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject $mockMailer + * @var \PHPUnit_Framework_MockObject_MockObject $mockBuild */ protected $mockBuild; + /** + * @var \PHPUnit_Framework_MockObject_MockObject $mockProject + */ + protected $mockProject; + + /** + * @var int buildStatus + */ + protected $buildStatus; + + /** + * @var array $message; + */ + protected $message; + + /** + * @var bool $mailDelivered + */ + protected $mailDelivered; + public function setUp() { + $this->message = array(); + $this->mailDelivered = true; + + $this->mockProject = $this->getMock( + '\PHPCI\Model\Project', + array('getTitle'), + array(), + "mockProject", + false + ); + + $this->mockProject->expects($this->any()) + ->method('getTitle') + ->will($this->returnValue("Test-Project")); + $this->mockBuild = $this->getMock( '\PHPCI\Model\Build', - array('getLog', 'getStatus'), + array('getLog', 'getStatus', 'getProject', 'getCommitterEmail'), array(), "mockBuild", false @@ -55,17 +85,22 @@ class EmailTest extends \PHPUnit_Framework_TestCase $this->mockBuild->expects($this->any()) ->method('getStatus') - ->will($this->returnValue(\PHPCI\Model\Build::STATUS_SUCCESS)); + ->will($this->returnCallback(function () { + return $this->buildStatus; + })); + + $this->mockBuild->expects($this->any()) + ->method('getProject') + ->will($this->returnValue($this->mockProject)); $this->mockBuild->expects($this->any()) ->method('getCommitterEmail') - ->will($this->returnValue("committer@test.com")); + ->will($this->returnValue('committer-email@example.com')); $this->mockCiBuilder = $this->getMock( '\PHPCI\Builder', array( 'getSystemConfig', - 'getBuildProjectTitle', 'getBuild', 'log' ), @@ -88,40 +123,52 @@ class EmailTest extends \PHPUnit_Framework_TestCase ) ) ); - $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()) + protected function loadEmailPluginWithOptions($arrOptions = array(), $buildStatus = null, $mailDelivered = true) { - $this->testedEmailPlugin = new EmailPlugin( - $this->mockCiBuilder, - $this->mockBuild, - $this->mockMailer, - $arrOptions + $this->mailDelivered = $mailDelivered; + + if (is_null($buildStatus)) { + $this->buildStatus = Build::STATUS_SUCCESS; + } else { + $this->buildStatus = $buildStatus; + } + + // Reset current message. + $this->message = array(); + + $this->testedEmailPlugin = $this->getMock( + '\PHPCI\Plugin\Email', + array('sendEmail'), + array( + $this->mockCiBuilder, + $this->mockBuild, + $arrOptions + ) ); + + $this->testedEmailPlugin->expects($this->any()) + ->method('sendEmail') + ->will($this->returnCallback(function ($to, $cc, $subject, $body) { + $this->message['to'][] = $to; + $this->message['cc'] = $cc; + $this->message['subject'] = $subject; + $this->message['body'] = $body; + + return $this->mailDelivered; + })); } /** * @covers PHPUnit::execute */ - public function testExecute_ReturnsFalseWithoutArgs() + public function testReturnsFalseWithoutArgs() { + $this->loadEmailPluginWithOptions(); + $returnValue = $this->testedEmailPlugin->execute(); + // As no addresses will have been mailed as non are configured. $expectedReturn = false; @@ -131,30 +178,35 @@ class EmailTest extends \PHPUnit_Framework_TestCase /** * @covers PHPUnit::execute */ - public function testExecute_BuildsBasicEmails() + public function testBuildsBasicEmails() { $this->loadEmailPluginWithOptions( array( 'addresses' => array('test-receiver@example.com') - ) + ), + Build::STATUS_SUCCESS ); - /** @var \Swift_Message $actualMail */ - $actualMail = null; - $this->catchMailPassedToSend($actualMail); + $this->testedEmailPlugin->execute(); - $returnValue = $this->testedEmailPlugin->execute(); - $expectedReturn = true; + $this->assertContains('test-receiver@example.com', $this->message['to']); + } - $this->assertSystemMail( - 'test-receiver@example.com', - 'test-from-address@example.com', - "Log Output:
Build Log
", - "PHPCI - Test-Project - Passing Build", - $actualMail + /** + * @covers PHPUnit::execute + */ + public function testBuildsDefaultEmails() + { + $this->loadEmailPluginWithOptions( + array( + 'default_mailto_address' => 'default-mailto-address@example.com' + ), + Build::STATUS_SUCCESS ); - $this->assertEquals($expectedReturn, $returnValue); + $this->testedEmailPlugin->execute(); + + $this->assertContains('default-mailto-address@example.com', $this->message['to']); } /** @@ -168,17 +220,13 @@ class EmailTest extends \PHPUnit_Framework_TestCase ) ); - $actualMails = []; - $this->catchMailPassedToSend($actualMails); - $returnValue = $this->testedEmailPlugin->execute(); $this->assertTrue($returnValue); - $this->assertCount(2, $actualMails); + $this->assertCount(2, $this->message['to']); - $actualTos = array(key($actualMails[0]->getTo()), key($actualMails[1]->getTo())); - $this->assertContains('test-receiver@example.com', $actualTos); - $this->assertContains('test-receiver2@example.com', $actualTos); + $this->assertContains('test-receiver@example.com', $this->message['to']); + $this->assertContains('test-receiver2@example.com', $this->message['to']); } /** @@ -193,133 +241,164 @@ class EmailTest extends \PHPUnit_Framework_TestCase ) ); - $actualMails = []; - $this->catchMailPassedToSend($actualMails); - $returnValue = $this->testedEmailPlugin->execute(); $this->assertTrue($returnValue); - $actualTos = array(key($actualMails[0]->getTo()), key($actualMails[1]->getTo())); - $this->assertContains('test-receiver@example.com', $actualTos); - $this->assertContains('committer@test.com', $actualTos); + $this->assertContains('test-receiver@example.com', $this->message['to']); + $this->assertContains('committer@test.com', $this->message['to']); } /** - * @covers PHPUnit::sendEmail + * @covers PHPUnit::execute */ - public function testSendEmail_CallsMailerSend() + public function testCcDefaultEmails() { - $this->mockMailer->expects($this->once()) - ->method('send'); - $this->testedEmailPlugin->sendEmail("test@email.com", array(), "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, array(), $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, array(), $subject, $body); - - $this->assertSystemMail( - $toAddress, - 'test-from-address@example.com', - $body, - $subject, - $actualMail + $this->loadEmailPluginWithOptions( + array( + 'default_mailto_address' => 'default-mailto-address@example.com', + 'cc' => array( + 'cc-email-1@example.com', + 'cc-email-2@example.com', + 'cc-email-3@example.com', + ), + ), + Build::STATUS_SUCCESS ); - } - /** - * @param \Swift_Message $actualMail passed by ref and populated with - * the message object the mock mailer - * receives. - */ - protected function catchMailPassedToSend(&$actualMail) - { - $this->mockMailer->expects(is_array($actualMail) ? $this->atLeast(1) : $this->once()) - ->method('send') - ->will( - $this->returnCallback( - function ($passedMail) use (&$actualMail) { - if(is_array($actualMail)) { - $actualMail[] = $passedMail; - } else { - $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->testedEmailPlugin->execute(); $this->assertEquals( - array($expectedToAddress => null), - $actualMail->getTo() - ); - - $this->assertEquals( - $expectedBody, - $actualMail->getBody() - ); - - $this->assertEquals( - $expectedSubject, - $actualMail->getSubject() + array( + 'cc-email-1@example.com', + 'cc-email-2@example.com', + 'cc-email-3@example.com', + ), + $this->message['cc'] ); } -} \ No newline at end of file + + /** + * @covers PHPUnit::execute + */ + public function testBuildsCommitterEmails() + { + $this->loadEmailPluginWithOptions( + array( + 'committer' => true + ), + Build::STATUS_SUCCESS + ); + + $this->testedEmailPlugin->execute(); + + $this->assertContains('committer-email@example.com', $this->message['to']); + } + + /** + * @covers PHPUnit::execute + */ + public function testMailSuccessfulBuildHaveProjectName() + { + $this->loadEmailPluginWithOptions( + array( + 'addresses' => array('test-receiver@example.com') + ), + Build::STATUS_SUCCESS + ); + + $this->testedEmailPlugin->execute(); + + $this->assertContains('Test-Project', $this->message['subject']); + $this->assertContains('Test-Project', $this->message['body']); + } + + /** + * @covers PHPUnit::execute + */ + public function testMailFailingBuildHaveProjectName() + { + $this->loadEmailPluginWithOptions( + array( + 'addresses' => array('test-receiver@example.com') + ), + Build::STATUS_FAILED + ); + + $this->testedEmailPlugin->execute(); + + $this->assertContains('Test-Project', $this->message['subject']); + $this->assertContains('Test-Project', $this->message['body']); + } + + /** + * @covers PHPUnit::execute + */ + public function testMailSuccessfulBuildHaveStatus() + { + $this->loadEmailPluginWithOptions( + array( + 'addresses' => array('test-receiver@example.com') + ), + Build::STATUS_SUCCESS + ); + + $this->testedEmailPlugin->execute(); + + $this->assertContains('Passing', $this->message['subject']); + $this->assertContains('successfull', $this->message['body']); + } + + /** + * @covers PHPUnit::execute + */ + public function testMailFailingBuildHaveStatus() + { + $this->loadEmailPluginWithOptions( + array( + 'addresses' => array('test-receiver@example.com') + ), + Build::STATUS_FAILED + ); + + $this->testedEmailPlugin->execute(); + + $this->assertContains('Failing', $this->message['subject']); + $this->assertContains('failed', $this->message['body']); + } + + /** + * @covers PHPUnit::execute + */ + public function testMailDeliverySuccess() + { + $this->loadEmailPluginWithOptions( + array( + 'addresses' => array('test-receiver@example.com') + ), + Build::STATUS_FAILED, + true + ); + + $returnValue = $this->testedEmailPlugin->execute(); + + $this->assertEquals(true, $returnValue); + } + + /** + * @covers PHPUnit::execute + */ + public function testMailDeliveryFail() + { + $this->loadEmailPluginWithOptions( + array( + 'addresses' => array('test-receiver@example.com') + ), + Build::STATUS_FAILED, + false + ); + + $returnValue = $this->testedEmailPlugin->execute(); + + $this->assertEquals(false, $returnValue); + } +} diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index a8b71034..601c7d7b 100644 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -13,12 +13,6 @@ date_default_timezone_set(@date_default_timezone_get()); // Load Composer autoloader: require_once(dirname(__DIR__) . '/vendor/autoload.php'); -// Load configuration if present: -$conf = array(); -$conf['b8']['app']['namespace'] = 'PHPCI'; -$conf['b8']['app']['default_controller'] = 'Home'; -$conf['b8']['view']['path'] = dirname(__DIR__) . '/PHPCI/View/'; - // If the PHPCI config file is not where we expect it, try looking in // env for an alternative config path. $configFile = dirname(__FILE__) . '/../PHPCI/config.yml'; @@ -31,6 +25,12 @@ if (!file_exists($configFile)) { } } +// Load configuration if present: +$conf = array(); +$conf['b8']['app']['namespace'] = 'PHPCI'; +$conf['b8']['app']['default_controller'] = 'Home'; +$conf['b8']['view']['path'] = dirname(__DIR__) . '/PHPCI/View/'; + $config = new b8\Config($conf); if (file_exists($configFile)) { diff --git a/console b/console index 43fc2b8f..782cc2d0 100755 --- a/console +++ b/console @@ -20,6 +20,7 @@ use PHPCI\Command\DaemonCommand; use PHPCI\Command\PollCommand; use PHPCI\Command\CreateAdminCommand; use Symfony\Component\Console\Application; +use b8\Store\Factory; $application = new Application(); @@ -29,6 +30,6 @@ $application->add(new UpdateCommand($loggerConfig->getFor('UpdateCommand'))); $application->add(new GenerateCommand); $application->add(new DaemonCommand($loggerConfig->getFor('DaemonCommand'))); $application->add(new PollCommand($loggerConfig->getFor('PollCommand'))); -$application->add(new CreateAdminCommand); +$application->add(new CreateAdminCommand(Factory::getStore('User'))); -$application->run(); \ No newline at end of file +$application->run(); diff --git a/public/assets/js/build-plugins/technical_debt.js b/public/assets/js/build-plugins/technical_debt.js new file mode 100755 index 00000000..a187401d --- /dev/null +++ b/public/assets/js/build-plugins/technical_debt.js @@ -0,0 +1,79 @@ +var TechnicalDebtPlugin = ActiveBuild.UiPlugin.extend({ + id: 'build-technical_debt', + css: 'col-lg-6 col-md-12 col-sm-12 col-xs-12', + title: Lang.get('technical_debt'), + lastData: null, + box: true, + rendered: false, + + register: function() { + var self = this; + var query = ActiveBuild.registerQuery('technical_debt-data', -1, {key: 'technical_debt-data'}) + + $(window).on('technical_debt-data', function(data) { + self.onUpdate(data); + }); + + $(window).on('build-updated', function() { + if (!self.rendered) { + query(); + } + }); + }, + + render: function() { + return $('
' + + '' + + '' + + ' ' + + ' ' + + ' ' + + '' + + '
'+Lang.get('file')+''+Lang.get('line')+''+Lang.get('message')+'
'); + }, + + onUpdate: function(e) { + if (!e.queryData) { + $('#build-technical_debt').hide(); + return; + } + + this.rendered = true; + this.lastData = e.queryData; + + var errors = this.lastData[0].meta_value; + var tbody = $('#technical_debt-data tbody'); + tbody.empty(); + + if (errors.length == 0) { + $('#build-technical_debt').hide(); + return; + } + + for (var i in errors) { + var file = errors[i].file; + + if (ActiveBuild.fileLinkTemplate) { + var fileLink = ActiveBuild.fileLinkTemplate.replace('{FILE}', file); + fileLink = fileLink.replace('{LINE}', errors[i].line); + + file = '' + file + ''; + } + + var row = $('' + + ''+file+'' + + ''+errors[i].line+'' + + ''+errors[i].message+''); + + if (errors[i].type == 'ERROR') { + row.addClass('danger'); + } + + tbody.append(row); + } + + $('#build-technical_debt').show(); + } +}); + +ActiveBuild.registerPlugin(new TechnicalDebtPlugin());