Merge branch 'master' of github.com:Block8/PHPCI

This commit is contained in:
Dan Cryer 2015-02-20 12:46:50 +00:00
commit faac320e59
13 changed files with 714 additions and 312 deletions

View file

@ -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('<error>%s</error>', Lang::get('failed_to_create')));
$output->writeln(sprintf('<error>%s</error>', $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;
}
}

View file

@ -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;

View file

@ -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();
}

View file

@ -183,6 +183,7 @@ PHPCI',
'phpmd' => 'PHP Mess Detector',
'phpspec' => 'PHP Spec',
'phpunit' => 'PHP Unit',
'technical_debt' => 'Technical Debt',
'file' => 'File',
'line' => 'Line',

View file

@ -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')."<br><pre>%s</pre>", $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;

208
PHPCI/Plugin/TechnicalDebt.php Executable file
View file

@ -0,0 +1,208 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
use PHPCI;
use PHPCI\Builder;
use PHPCI\Model\Build;
/**
* Technical Debt Plugin - Checks for existence of "TODO", "FIXME", etc.
*
* @author James Inman <james@jamesinman.co.uk>
* @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);
}
}

View file

@ -0,0 +1,15 @@
<div style="background: #900; padding: 25px;">
<div style="background: #fff; padding: 15px; border-radius: 5px">
<div style="font-family: arial, verdana, sans-serif; font-size: 25px; margin-bottom: 15px">
<?php print $project->getTitle(); ?> - Build #<?php print $build->getId(); ?>
</div>
<div style="font-family: arial, verdana, sans-serif; font-size: 15px">
<p>Your commit <strong><?php print $build->getCommitId(); ?></strong> genrate a successfull build in project <strong><?php print $project->getTitle(); ?></strong>.</p>
<p style="margin: 10px; background: #fafafa"><?php print $build->getCommitMessage(); ?></p>
<pre><?php print $build->getLog(); ?></pre>
<p>You can review <a href="<?php print $build->getCommitLink(); ?>">your commit</a> and the <a href="<?php print PHPCI_URL . 'build/view/' . $build->getId(); ?>">build log</a>.</p>
</div>
</div>
</div>