diff --git a/PHPCI/Application.php b/PHPCI/Application.php index c0048adf..3378a050 100755 --- 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/BuildFactory.php b/PHPCI/BuildFactory.php index ad4dd0a5..c4479b05 100755 --- 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/Builder.php b/PHPCI/Builder.php index a7b60bc1..f943a092 100755 --- 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 @@ -125,6 +135,22 @@ class Builder return $this->build; } + /** + * @return string The title of the project being built. + */ + public function getBuildProjectTitle() { + return $this->getBuild()->getProject()->getTitle(); + } + + /** + * Indicates if the build has passed or failed. + * @return bool + */ + public function getSuccessStatus() + { + return $this->success; + } + /** * Run the active build. */ diff --git a/PHPCI/Command/DaemonCommand.php b/PHPCI/Command/DaemonCommand.php new file mode 100644 index 00000000..94ecb464 --- /dev/null +++ b/PHPCI/Command/DaemonCommand.php @@ -0,0 +1,122 @@ + /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:daemon') + ->setDescription('Initiates the daemon to run commands.') + ->addArgument( + 'state', + InputArgument::REQUIRED, + 'start|stop|status' + ); + } + + /** + * Loops through running. + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $state = $input->getArgument('state'); + + switch ($state) { + case 'start': + $this->startDaemon(); + break; + case 'stop': + $this->stopDaemon(); + break; + case 'status': + $this->statusDaemon(); + break; + default: + echo "Not a valid choice, please use start stop or status"; + break; + } + + } + + protected function startDaemon() + { + + if ( file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) { + echo "Already started\n"; + return "alreadystarted"; + } + + $logfile = PHPCI_DIR."/daemon/daemon.log"; + $cmd = "nohup %s/daemonise phpci:daemonise > %s 2>&1 &"; + $command = sprintf($cmd, PHPCI_DIR, $logfile); + exec($command); + } + + protected function stopDaemon() + { + + if ( !file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) { + echo "Not started\n"; + return "notstarted"; + } + + $cmd = "kill $(cat %s/daemon/daemon.pid)"; + $command = sprintf($cmd, PHPCI_DIR); + exec($command); + unlink(PHPCI_DIR.'/daemon/daemon.pid'); + } + + protected function statusDaemon() + { + + if ( !file_exists(PHPCI_DIR.'/daemon/daemon.pid') ) { + echo "Not running\n"; + return "notrunning"; + } + + $pid = trim(file_get_contents(PHPCI_DIR.'/daemon/daemon.pid')); + $pidcheck = sprintf("/proc/%s", $pid); + if ( is_dir($pidcheck) ) { + echo "Running\n"; + return "running"; + } + + unlink(PHPCI_DIR.'/daemon/daemon.pid'); + echo "Not running\n"; + return "notrunning"; + } + + /** + * Called when log entries are made in Builder / the plugins. + * @see \PHPCI\Builder::log() + */ + public function logCallback($log) + { + $this->output->writeln($log); + } +} 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/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index 35459aec..dea4e560 100755 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -48,6 +48,14 @@ class InstallCommand extends Command $conf['phpci']['github']['id'] = $this->ask('(Optional) Github Application ID: ', true); $conf['phpci']['github']['secret'] = $this->ask('(Optional) Github Application Secret: ', true); + $conf['phpci']['email_settings']['smtp_address'] = $this->ask('(Optional) Smtp server address: ', true); + $conf['phpci']['email_settings']['smtp_port'] = $this->ask('(Optional) Smtp port: ', true); + $conf['phpci']['email_settings']['smtp_encryption'] = $this->ask('(Optional) Smtp encryption: ', true); + $conf['phpci']['email_settings']['smtp_username'] = $this->ask('(Optional) Smtp Username: ', true); + $conf['phpci']['email_settings']['smtp_password'] = $this->ask('(Optional) Smtp Password: ', true); + $conf['phpci']['email_settings']['from_address'] = $this->ask('(Optional) Email address to send from: ', true); + $conf['phpci']['email_settings']['default_mailto_address'] = $this->ask('(Optional) Default address to email notifications to: ', true); + $dbUser = $conf['b8']['database']['username']; $dbPass = $conf['b8']['database']['password']; $dbHost = $conf['b8']['database']['servers']['write']; diff --git a/PHPCI/Command/RunCommand.php b/PHPCI/Command/RunCommand.php index b28d9832..abd30c6c 100755 --- 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/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php index 21de59c9..56bde07c 100755 --- 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; } /** @@ -86,14 +87,15 @@ class BuildController extends \PHPCI\Controller */ public function delete($buildId) { - if (!Registry::getInstance()->get('user')->getIsAdmin()) { + if (empty($_SESSION['user']) || !$_SESSION['user']->getIsAdmin()) { throw new \Exception('You do not have permission to do that.'); } - + $build = $this->_buildStore->getById($buildId); $this->_buildStore->delete($build); header('Location: '.PHPCI_URL.'project/view/' . $build->getProjectId()); + exit; } /** diff --git a/PHPCI/Controller/IndexController.php b/PHPCI/Controller/IndexController.php index c185d2f3..2404a047 100755 --- 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/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 70f95ab1..eaad90a1 100755 --- 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; } /** @@ -78,6 +79,7 @@ class ProjectController extends \PHPCI\Controller $this->_projectStore->delete($project); header('Location: '.PHPCI_URL); + exit; } /** @@ -252,12 +254,13 @@ class ProjectController extends \PHPCI\Controller 'choose' => 'Select repository type...', 'github' => 'Github', 'bitbucket' => 'Bitbucket', + 'remote' => 'Remote URL', 'local' => 'Local Path' ); $field = new Form\Element\Select('type'); $field->setRequired(true); - $field->setPattern('^(github|bitbucket|local)'); + $field->setPattern('^(github|bitbucket|remote|local)'); $field->setOptions($options); $field->setLabel('Where is your project hosted?'); $field->setClass('span4'); @@ -275,6 +278,11 @@ class ProjectController extends \PHPCI\Controller $type = $values['type']; switch($type) { + case 'remote': + if (!preg_match('/^(git|https?):\/\//', $val)) { + throw new \Exception('Repository URL must be start with git://, http:// or https://.'); + } + break; case 'local': if (!is_dir($val)) { throw new \Exception('The path you specified does not exist.'); @@ -282,7 +290,7 @@ class ProjectController extends \PHPCI\Controller break; case 'github': case 'bitbucket': - if (!preg_match('/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-]+$/', $val)) { + if (!preg_match('/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-\.]+$/', $val)) { throw new \Exception('Repository name must be in the format "owner/repo".'); } break; diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 38e2a914..07698d42 100755 --- 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',TRUE); + if($gitConfig["core"]["bare"]) { + // Looks like we're right. We need to extract the archive! + $guid = uniqid(); + $builder->executeCommand('mkdir "/tmp/%s" && git --git-dir="%s" archive master | tar -x -C "/tmp/%s"', $guid, $reference, $guid); + $reference = '/tmp/'.$guid; + } + } if (!is_file($reference . '/phpci.yml')) { $builder->logFailure('Project does not contain a phpci.yml file.'); diff --git a/PHPCI/Model/Build/RemoteGitBuild.php b/PHPCI/Model/Build/RemoteGitBuild.php index 0670f6db..d1fe1c74 100755 --- 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. 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); + } +} diff --git a/PHPCI/Plugin/Composer.php b/PHPCI/Plugin/Composer.php index 42195f52..df2da277 100755 --- 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); } } diff --git a/PHPCI/Plugin/Email.php b/PHPCI/Plugin/Email.php new file mode 100644 index 00000000..798a01b5 --- /dev/null +++ b/PHPCI/Plugin/Email.php @@ -0,0 +1,194 @@ + +* @package PHPCI +* @subpackage Plugins +*/ +class Email implements \PHPCI\Plugin +{ + + /** + * @var \PHPCI\Builder + */ + protected $phpci; + + /** + * @var array + */ + protected $options; + + /** + * @var array + */ + protected $emailConfig; + + /** + * @var \Swift_Mailer + */ + protected $mailer; + + public function __construct(\PHPCI\Builder $phpci, + array $options = array(), + \Swift_Mailer $mailer = null) + { + $phpCiSettings = $phpci->getSystemConfig('phpci'); + $this->phpci = $phpci; + $this->options = $options; + $this->emailConfig = isset($phpCiSettings['email_settings']) ? $phpCiSettings['email_settings'] : array(); + + // Either a mailer will have been passed in or we load from the + // config. + if ($mailer === null) { + $this->loadSwiftMailerFromConfig(); + } + else { + $this->mailer = $mailer; + } + } + + /** + * Connects to MySQL and runs a specified set of queries. + */ + public function execute() + { + $addresses = $this->getEmailAddresses(); + + // Without some email addresses in the yml file then we + // can't do anything. + if (count($addresses) == 0) { + return false; + } + + $sendFailures = array(); + + $subjectTemplate = "PHPCI - %s - %s"; + $projectName = $this->phpci->getBuildProjectTitle(); + $logText = $this->phpci->getBuild()->getLog(); + + if($this->phpci->getSuccessStatus()) { + $sendFailures = $this->sendSeparateEmails( + $addresses, + sprintf($subjectTemplate, $projectName, "Passing Build"), + sprintf("Log Output:
%s
", $logText) + ); + } + else { + $sendFailures = $this->sendSeparateEmails( + $addresses, + sprintf($subjectTemplate, $projectName, "Failing Build"), + sprintf("Log Output:
%s
", $logText) + ); + } + + // This is a success if we've not failed to send anything. + $this->phpci->log(sprintf( + "%d emails sent", + (count($addresses) - count($sendFailures))) + ); + $this->phpci->log(sprintf( + "%d emails failed to send", + count($sendFailures)) + ); + return (count($sendFailures) == 0); + } + + /** + * @param array|string $toAddresses Array or single address to send to + * @param string $subject Email subject + * @param string $body Email body + * @return array Array of failed addresses + */ + public function sendEmail($toAddresses, $subject, $body) + { + $message = \Swift_Message::newInstance($subject) + ->setFrom($this->getMailConfig('from_address')) + ->setTo($toAddresses) + ->setBody($body) + ->setContentType("text/html"); + $failedAddresses = array(); + $this->mailer->send($message, $failedAddresses); + + return $failedAddresses; + } + + public function sendSeparateEmails(array $toAddresses, $subject, $body) + { + $failures = array(); + foreach($toAddresses as $address) { + $newFailures = $this->sendEmail($address, $subject, $body); + foreach($newFailures as $failure) { + $failures[] = $failure; + } + } + return $failures; + } + + protected function loadSwiftMailerFromConfig() + { + /** @var \Swift_SmtpTransport $transport */ + $transport = \Swift_SmtpTransport::newInstance( + $this->getMailConfig('smtp_address'), + $this->getMailConfig('smtp_port'), + $this->getMailConfig('smtp_encryption') + ); + $transport->setUsername($this->getMailConfig('smtp_username')); + $transport->setPassword($this->getMailConfig('smtp_password')); + + $this->mailer = \Swift_Mailer::newInstance($transport); + } + + protected function getMailConfig($configName) + { + if (isset($this->emailConfig[$configName]) + && $this->emailConfig[$configName] != "") + { + return $this->emailConfig[$configName]; + } + // Check defaults + else { + switch($configName) { + case 'smtp_address': + return "localhost"; + case 'default_mailto_address': + return null; + case 'smtp_port': + return '25'; + case 'smtp_encryption': + return null; + case 'from_address': + return "notifications-ci@phptesting.org"; + default: + return ""; + } + } + } + + protected function getEmailAddresses() + { + $addresses = array(); + + if (isset($this->options['addresses'])) { + foreach ($this->options['addresses'] as $address) { + $addresses[] = $address; + } + } + + if (isset($this->options['default_mailto_address'])) { + $addresses[] = $this->options['default_mailto_address']; + return $addresses; + } + return $addresses; + } +} \ No newline at end of file diff --git a/PHPCI/Plugin/PhpMessDetector.php b/PHPCI/Plugin/PhpMessDetector.php index ea6ff959..d2a2e3dc 100755 --- 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); } } diff --git a/PHPCI/Store/BuildStore.php b/PHPCI/Store/BuildStore.php index 6b26c3c7..fca490f2 100755 --- 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/Build/view.phtml b/PHPCI/View/Build/view.phtml index b5aa7324..f57a1a45 100755 --- 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/BuildsTable.phtml b/PHPCI/View/BuildsTable.phtml index 8ced123f..34a5ca72 100755 --- 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; } @@ -35,7 +40,31 @@ switch($build->getStatus()) getProject()->getTitle(); ?> getCommitId(); ?> getBranch(); ?> - + + getPlugins(), true); + + if ( !is_array($plugins) ) { + $plugins = array(); + } + if ( 0 === count($plugins) ) { + ?> + + + + + $pluginstatus): + $subcls = $pluginstatus?'label label-success':'label label-important'; + ?> + + + + +
    +
    View diff --git a/PHPCI/View/Index/index.phtml b/PHPCI/View/Index/index.phtml index 887b46d3..903b0bc2 100755 --- a/PHPCI/View/Index/index.phtml +++ b/PHPCI/View/Index/index.phtml @@ -44,11 +44,11 @@ - + - - - + + + diff --git a/PHPCI/View/Project/view.phtml b/PHPCI/View/Project/view.phtml index 59d07ced..77d488fc 100755 --- a/PHPCI/View/Project/view.phtml +++ b/PHPCI/View/Project/view.phtml @@ -14,13 +14,15 @@ User()->getIsAdmin()): ?>
  • Edit Project
  • -
  • Delete Project
  • +
  • Delete Project
  • -
    -

    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()) @@ -61,14 +63,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 ''; @@ -78,9 +80,16 @@ - \ No newline at end of file + diff --git a/PHPCI/View/SummaryTable.phtml b/PHPCI/View/SummaryTable.phtml new file mode 100644 index 00000000..de374e2c --- /dev/null +++ b/PHPCI/View/SummaryTable.phtml @@ -0,0 +1,114 @@ +"; +// var_dump($builds); +// echo ""; + +$maxbuildcount = 5; +$projects = array(); +$prevBuild = null; +$health = false; + +foreach($builds as $build): + + if ($build->getStatus() < 2) { + continue; + } + + if ( is_null($prevBuild) || $build->getProjectId() !== $prevBuild->getProjectId() ) { + $health = false; + $projects[$build->getProjectId()]['count'] = 0; + $projects[$build->getProjectId()]['health'] = 0; + $projects[$build->getProjectId()]['successes'] = 0; + $projects[$build->getProjectId()]['failures'] = 0; + $projects[$build->getProjectId()]['lastbuildstatus'] = (int)$build->getStatus(); + } + + if ( + !is_null($prevBuild) && + $projects[$build->getProjectId()]['count'] >= $maxbuildcount && + $build->getProjectId() === $prevBuild->getProjectId() + ) { + $projects[$build->getProjectId()]['count']++; + continue; + } + + switch ((int)$build->getStatus()) { + case 2: + $projects[$build->getProjectId()]['health']++; + $projects[$build->getProjectId()]['successes']++; + + if ( empty($projects[$build->getProjectId()]['lastsuccess']) ) { + $projects[$build->getProjectId()]['lastsuccess'] = $build; + } + break; + case 3: + $projects[$build->getProjectId()]['health']--; + $projects[$build->getProjectId()]['failures']++; + + if ( empty($projects[$build->getProjectId()]['lastfailure']) ) { + $projects[$build->getProjectId()]['lastfailure'] = $build; + } + break; + } + + $projects[$build->getProjectId()]['count']++; + $projects[$build->getProjectId()]['projectname'] = $build->getProject()->getTitle(); + $prevBuild = $build; +endforeach; + +foreach($projects as $projectId => $project): + switch($project['lastbuildstatus']) + { + case 0: + $cls = 'info'; + $status = 'Pending'; + break; + + case 1: + $cls = 'warning'; + $status = 'Running'; + break; + + case 2: + $cls = 'success'; + $status = 'Success'; + break; + + case 3: + $cls = 'error'; + $status = 'Failed'; + break; + } + + $health = ($project['health'] < 0 ? 'Stormy': ($project['health'] < 5? 'Overcast': 'Sunny')); + $subcls = ($project['health'] < 0 ? 'important': ($project['health'] < 5? 'warning': 'success')); +?> + + + + + + + + + \ No newline at end of file diff --git a/PHPCI/View/layout.phtml b/PHPCI/View/layout.phtml index f5b95baf..2db749d3 100755 --- a/PHPCI/View/layout.phtml +++ b/PHPCI/View/layout.phtml @@ -17,7 +17,7 @@
    IDHealth ProjectCommitBranchStatusLast SuccessLast FailureSuccess/Failures
    + + + + + + getId() ?>'> + getStarted()->format("Y-m-d H:i:s") ?> + + + + + getId() ?>'> + getStarted()->format("Y-m-d H:i:s") ?> + + + /build