diff --git a/PHPCI/Application.php b/PHPCI/Application.php index 646645af..16fab7cf 100644 --- a/PHPCI/Application.php +++ b/PHPCI/Application.php @@ -14,6 +14,7 @@ use b8\Exception\HttpException; use b8\Http\Response; use b8\Http\Response\RedirectResponse; use b8\View; +use PHPCI\Model\Build; /** * PHPCI Front Controller @@ -91,18 +92,30 @@ class Application extends b8\Application $this->response->setContent($view->render()); } - if (View::exists('layout') && $this->response->hasLayout()) { - $view = new View('layout'); - $pageTitle = $this->config->get('page_title', null); + if ($this->response->hasLayout()) { + $this->setLayoutVariables($this->controller->layout); - if (!is_null($pageTitle)) { - $view->title = $pageTitle; - } - - $view->content = $this->response->getContent(); - $this->response->setContent($view->render()); + $this->controller->layout->content = $this->response->getContent(); + $this->response->setContent($this->controller->layout->render()); } return $this->response; } + + protected function loadController($class) + { + $controller = parent::loadController($class); + $controller->layout = new View('layout'); + $controller->layout->title = 'PHPCI'; + $controller->layout->breadcrumb = array(); + + return $controller; + } + + protected function setLayoutVariables(View &$layout) + { + /** @var \PHPCI\Store\ProjectStore $projectStore */ + $projectStore = b8\Store\Factory::getStore('Project'); + $layout->projects = $projectStore->getAll(); + } } diff --git a/PHPCI/Command/DaemoniseCommand.php b/PHPCI/Command/DaemoniseCommand.php index d2f1f236..915890bd 100644 --- a/PHPCI/Command/DaemoniseCommand.php +++ b/PHPCI/Command/DaemoniseCommand.php @@ -76,6 +76,7 @@ class DaemoniseCommand extends Command $this->sleep = 0; $runner = new RunCommand($this->logger); $runner->setMaxBuilds(1); + $runner->setIsDaemon(true); $emptyInput = new ArgvInput(array()); diff --git a/PHPCI/Command/RunCommand.php b/PHPCI/Command/RunCommand.php index f6aa1288..b384100d 100644 --- a/PHPCI/Command/RunCommand.php +++ b/PHPCI/Command/RunCommand.php @@ -48,6 +48,11 @@ class RunCommand extends Command */ protected $maxBuilds = null; + /** + * @var bool + */ + protected $isFromDaemon = false; + /** * @param \Monolog\Logger $logger * @param string $name @@ -62,8 +67,7 @@ class RunCommand extends Command { $this ->setName('phpci:run-builds') - ->setDescription('Run all pending PHPCI builds.') - ->addOption('verbose', 'v', InputOption::VALUE_NONE); + ->setDescription('Run all pending PHPCI builds.'); } /** @@ -75,7 +79,7 @@ class RunCommand extends Command // For verbose mode we want to output all informational and above // messages to the symphony output interface. - if ($input->getOption('verbose')) { + if ($input->hasOption('verbose') && $input->getOption('verbose')) { $this->logger->pushHandler( new OutputLogHandler($this->output, Logger::INFO) ); @@ -91,13 +95,17 @@ class RunCommand extends Command $builds = 0; - foreach ($result['items'] as $build) { - + while (count($result['items'])) { + $build = array_shift($result['items']); $build = BuildFactory::getBuild($build); // Skip build (for now) if there's already a build running in that project: - if (in_array($build->getProjectId(), $running)) { + if (!$this->isFromDaemon && in_array($build->getProjectId(), $running)) { $this->logger->addInfo('Skipping Build #'.$build->getId() . ' - Project build already in progress.'); + $result['items'][] = $build; + + // Re-run build validator: + $running = $this->validateRunningBuilds(); continue; } @@ -117,6 +125,7 @@ class RunCommand extends Command $this->logger->popHandler($buildDbLog); } catch (\Exception $ex) { $build->setStatus(Build::STATUS_FAILED); + $build->setFinished(new \DateTime()); $build->setLog($build->getLog() . PHP_EOL . PHP_EOL . $ex->getMessage()); $store->save($build); } @@ -133,6 +142,11 @@ class RunCommand extends Command $this->maxBuilds = (int)$numBuilds; } + public function setIsDaemon($fromDaemon) + { + $this->isFromDaemon = (bool)$fromDaemon; + } + protected function validateRunningBuilds() { /** @var \PHPCI\Store\BuildStore $store */ @@ -152,6 +166,7 @@ class RunCommand extends Command if (($now - $start) > $timeout) { $this->logger->addInfo('Build #'.$build->getId().' marked as failed due to timeout.'); $build->setStatus(Build::STATUS_FAILED); + $build->setFinished(new \DateTime()); $store->save($build); $this->removeBuildDirectory($build); continue; diff --git a/PHPCI/Controller.php b/PHPCI/Controller.php index 69be68ee..57ed81f2 100644 --- a/PHPCI/Controller.php +++ b/PHPCI/Controller.php @@ -72,10 +72,23 @@ class Controller extends \b8\Controller return $this->response; } + /** + * Require that the currently logged in user is an administrator. + * @throws ForbiddenException + */ protected function requireAdmin() { - if (!$_SESSION['phpci_user']->getIsAdmin()) { + if (!$this->currentUserIsAdmin()) { throw new ForbiddenException('You do not have permission to do that.'); } } + + /** + * Check if the currently logged in user is an administrator. + * @return bool + */ + protected function currentUserIsAdmin() + { + return $_SESSION['phpci_user']->getIsAdmin(); + } } diff --git a/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php index 79e9eb94..a46a094a 100644 --- a/PHPCI/Controller/BuildController.php +++ b/PHPCI/Controller/BuildController.php @@ -13,6 +13,7 @@ use b8; use b8\Exception\HttpException\NotFoundException; use PHPCI\BuildFactory; use PHPCI\Model\Build; +use PHPCI\Model\Project; use PHPCI\Service\BuildService; /** @@ -58,8 +59,22 @@ class BuildController extends \PHPCI\Controller $this->view->build = $build; $this->view->data = $this->getBuildData($build); - $title = 'Build #' . $build->getId() . ' - ' . $build->getProjectTitle(); - $this->config->set('page_title', $title); + $this->layout->title = 'Build #' . $build->getId(); + $this->layout->subtitle = $build->getProjectTitle(); + + $nav = array( + 'title' => 'Build '.$build->getId(), + 'icon' => 'cog', + 'links' => array( + 'build/rebuild/' . $build->getId() => 'Rebuild Now', + ), + ); + + if ($this->currentUserIsAdmin()) { + $nav['links']['build/delete/' . $build->getId()] = 'Delete Build'; + } + + $this->layout->nav = $nav; } protected function getUiPlugins() @@ -141,9 +156,7 @@ class BuildController extends \PHPCI\Controller */ public function delete($buildId) { - if (empty($_SESSION['phpci_user']) || !$_SESSION['phpci_user']->getIsAdmin()) { - throw new \Exception('You do not have permission to do that.'); - } + $this->requireAdmin(); $build = BuildFactory::getBuildById($buildId); @@ -168,4 +181,36 @@ class BuildController extends \PHPCI\Controller return $log; } + + public function latest() + { + $rtn = array( + 'pending' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_NEW)), + 'running' => $this->formatBuilds($this->buildStore->getByStatus(Build::STATUS_RUNNING)), + ); + + if ($this->request->isAjax()) { + die(json_encode($rtn)); + } + } + + protected function formatBuilds($builds) + { + Project::$sleepable = array('id', 'title', 'reference', 'type'); + + $rtn = array('count' => $builds['count'], 'items' => array()); + + foreach ($builds['items'] as $build) { + $item = $build->toArray(1); + + $header = new b8\View('Build/header-row'); + $header->build = $build; + + $item['header_row'] = $header->render(); + $rtn['items'][$item['id']] = $item; + } + + ksort($rtn['items']); + return $rtn; + } } diff --git a/PHPCI/Controller/HomeController.php b/PHPCI/Controller/HomeController.php index a4f8003d..0bb176dc 100644 --- a/PHPCI/Controller/HomeController.php +++ b/PHPCI/Controller/HomeController.php @@ -11,6 +11,7 @@ namespace PHPCI\Controller; use b8; use PHPCI\BuildFactory; +use PHPCI\Model\Build; /** * Home Controller - Displays the PHPCI Dashboard. @@ -41,14 +42,20 @@ class HomeController extends \PHPCI\Controller */ public function index() { + $this->layout->title = 'Dashboard'; + $projects = $this->projectStore->getWhere(array(), 50, 0, array(), array('title' => 'ASC')); - $this->view->builds = $this->getLatestBuildsHtml(); + $builds = $this->buildStore->getLatestBuilds(null, 10); + + foreach ($builds as &$build) { + $build = BuildFactory::getBuild($build); + } + + $this->view->builds = $builds; $this->view->projects = $projects['items']; $this->view->summary = $this->getSummaryHtml($projects); - $this->config->set('page_title', 'Dashboard'); - return $this->view->render(); } @@ -69,13 +76,24 @@ class HomeController extends \PHPCI\Controller protected function getSummaryHtml($projects) { $summaryBuilds = array(); + $successes = array(); + $failures = array(); + foreach ($projects['items'] as $project) { $summaryBuilds[$project->getId()] = $this->buildStore->getLatestBuilds($project->getId()); + + $success = $this->buildStore->getLastBuildByStatus($project->getId(), Build::STATUS_SUCCESS); + $failure = $this->buildStore->getLastBuildByStatus($project->getId(), Build::STATUS_FAILED); + + $successes[$project->getId()] = $success; + $failures[$project->getId()] = $failure; } $summaryView = new b8\View('SummaryTable'); $summaryView->projects = $projects['items']; $summaryView->builds = $summaryBuilds; + $summaryView->successful = $successes; + $summaryView->failed = $failures; return $summaryView->render(); } diff --git a/PHPCI/Controller/PluginController.php b/PHPCI/Controller/PluginController.php index 777c846f..de9f5e0f 100644 --- a/PHPCI/Controller/PluginController.php +++ b/PHPCI/Controller/PluginController.php @@ -24,6 +24,10 @@ use PHPCI\Plugin\Util\PluginInformationCollection; class PluginController extends \PHPCI\Controller { protected $required = array( + 'php', + 'ext-mcrypt', + 'ext-pdo', + 'ext-pdo_mysql', 'block8/b8framework', 'ircmaxell/password-compat', 'swiftmailer/swiftmailer', @@ -31,7 +35,8 @@ class PluginController extends \PHPCI\Controller 'symfony/console', 'psr/log', 'monolog/monolog', - 'pimple/pimple' + 'pimple/pimple', + 'robmorgan/phinx', ); protected $canInstall; @@ -39,9 +44,7 @@ class PluginController extends \PHPCI\Controller public function index() { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new \Exception('You do not have permission to do that.'); - } + $this->requireAdmin(); $this->view->canWrite = is_writable(APPLICATION_PATH . 'composer.json'); $this->view->required = $this->required; @@ -60,16 +63,14 @@ class PluginController extends \PHPCI\Controller $this->view->plugins = $pluginInfo->getInstalledPlugins(); - $this->config->set('page_title', 'Plugins'); + $this->layout->title = 'Plugins'; return $this->view->render(); } public function remove() { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new \Exception('You do not have permission to do that.'); - } + $this->requireAdmin(); $package = $this->getParam('package', null); $json = $this->getComposerJson(); @@ -88,9 +89,7 @@ class PluginController extends \PHPCI\Controller public function install() { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new \Exception('You do not have permission to do that.'); - } + $this->requireAdmin(); $package = $this->getParam('package', null); $version = $this->getParam('version', '*'); diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 1e2c68d1..69d8b95e 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -62,8 +62,9 @@ class ProjectController extends \PHPCI\Controller /** * View a specific project. */ - public function view($projectId, $branch = '') + public function view($projectId) { + $branch = $this->getParam('branch', ''); $project = $this->projectStore->getById($projectId); if (empty($project)) { @@ -87,7 +88,8 @@ class ProjectController extends \PHPCI\Controller $this->view->page = $page; $this->view->pages = $pages; - $this->config->set('page_title', $project->getTitle()); + $this->layout->title = $project->getTitle(); + $this->layout->subtitle = $this->view->branch; return $this->view->render(); } @@ -120,9 +122,7 @@ class ProjectController extends \PHPCI\Controller */ public function delete($projectId) { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new ForbiddenException('You do not have permission to do that.'); - } + $this->requireAdmin(); $project = $this->projectStore->getById($projectId); $this->projectService->deleteProject($project); @@ -134,8 +134,9 @@ class ProjectController extends \PHPCI\Controller /** * AJAX get latest builds. */ - public function builds($projectId, $branch = '') + public function builds($projectId) { + $branch = $this->getParam('branch', ''); $builds = $this->getLatestBuildsHtml($projectId, urldecode($branch)); die($builds[0]); } @@ -173,7 +174,7 @@ class ProjectController extends \PHPCI\Controller */ public function add() { - $this->config->set('page_title', 'Add Project'); + $this->layout->title = 'Add Project'; $this->requireAdmin(); $method = $this->request->getMethod(); @@ -224,9 +225,7 @@ class ProjectController extends \PHPCI\Controller */ public function edit($projectId) { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new ForbiddenException('You do not have permission to do that.'); - } + $this->requireAdmin(); $method = $this->request->getMethod(); $project = $this->projectStore->getById($projectId); diff --git a/PHPCI/Controller/SessionController.php b/PHPCI/Controller/SessionController.php index a9b60333..f7bfa982 100644 --- a/PHPCI/Controller/SessionController.php +++ b/PHPCI/Controller/SessionController.php @@ -40,7 +40,7 @@ class SessionController extends \PHPCI\Controller if ($this->request->getMethod() == 'POST') { $user = $this->userStore->getByEmail($this->getParam('email')); - + if ($user && password_verify($this->getParam('password', ''), $user->getHash())) { $_SESSION['phpci_user_id'] = $user->getId(); header('Location: ' . $this->getLoginRedirect()); diff --git a/PHPCI/Controller/SettingsController.php b/PHPCI/Controller/SettingsController.php index 0bb79577..09dd6bf3 100644 --- a/PHPCI/Controller/SettingsController.php +++ b/PHPCI/Controller/SettingsController.php @@ -38,6 +38,9 @@ class SettingsController extends Controller public function index() { + $this->requireAdmin(); + + $this->layout->title = 'Settings'; $this->view->settings = $this->settings; $emailSettings = array(); @@ -64,6 +67,8 @@ class SettingsController extends Controller public function github() { + $this->requireAdmin(); + $this->settings['phpci']['github']['id'] = $this->getParam('githubid', ''); $this->settings['phpci']['github']['secret'] = $this->getParam('githubsecret', ''); $error = $this->storeSettings(); @@ -79,6 +84,8 @@ class SettingsController extends Controller public function email() { + $this->requireAdmin(); + $this->settings['phpci']['email_settings'] = $this->getParams(); $this->settings['phpci']['email_settings']['smtp_encryption'] = $this->getParam('smtp_encryption', 0); @@ -95,6 +102,8 @@ class SettingsController extends Controller public function build() { + $this->requireAdmin(); + $this->settings['phpci']['build'] = $this->getParams(); $error = $this->storeSettings(); diff --git a/PHPCI/Controller/UserController.php b/PHPCI/Controller/UserController.php index 182cc3f0..583381f6 100644 --- a/PHPCI/Controller/UserController.php +++ b/PHPCI/Controller/UserController.php @@ -49,7 +49,7 @@ class UserController extends Controller $users = $this->userStore->getWhere(array(), 1000, 0, array(), array('email' => 'ASC')); $this->view->users = $users; - $this->config->set('page_title', 'Users'); + $this->layout->title = 'Users'; return $this->view->render(); } @@ -58,6 +58,8 @@ class UserController extends Controller { $user = $_SESSION['phpci_user']; + $this->layout->title = 'Edit Profile'; + if ($this->request->getMethod() == 'POST') { $name = $this->getParam('name', null); $email = $this->getParam('email', null); @@ -65,6 +67,8 @@ class UserController extends Controller $_SESSION['phpci_user'] = $this->userService->updateUser($user, $name, $email, $password); $user = $_SESSION['phpci_user']; + + $this->view->updated = 1; } $values = $user->getDataArray(); @@ -111,11 +115,9 @@ class UserController extends Controller */ public function add() { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new ForbiddenException('You do not have permission to do that.'); - } + $this->requireAdmin(); - $this->config->set('page_title', 'Add User'); + $this->layout->title = 'Add User'; $method = $this->request->getMethod(); @@ -153,9 +155,7 @@ class UserController extends Controller */ public function edit($userId) { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new ForbiddenException('You do not have permission to do that.'); - } + $this->requireAdmin(); $method = $this->request->getMethod(); $user = $this->userStore->getById($userId); @@ -164,6 +164,9 @@ class UserController extends Controller throw new NotFoundException('User with ID: ' . $userId . ' does not exist.'); } + $this->layout->title = $user->getName(); + $this->layout->subtitle = 'Edit User'; + $values = array_merge($user->getDataArray(), $this->getParams()); $form = $this->userForm($values, 'edit/' . $userId); @@ -246,10 +249,8 @@ class UserController extends Controller */ public function delete($userId) { - if (!$_SESSION['phpci_user']->getIsAdmin()) { - throw new ForbiddenException('You do not have permission to do that.'); - } - + $this->requireAdmin(); + $user = $this->userStore->getById($userId); if (empty($user)) { diff --git a/PHPCI/Migrations/20140730143702_fix_database_columns.php b/PHPCI/Migrations/20140730143702_fix_database_columns.php index 6594dd02..809fc878 100644 --- a/PHPCI/Migrations/20140730143702_fix_database_columns.php +++ b/PHPCI/Migrations/20140730143702_fix_database_columns.php @@ -9,6 +9,13 @@ class FixDatabaseColumns extends AbstractMigration */ public function up() { + $dbAdapter = $this->getAdapter(); + + if ($dbAdapter instanceof \Phinx\Db\Adapter\PdoAdapter) { + $pdo = $dbAdapter->getConnection(); + $pdo->exec('SET foreign_key_checks = 0'); + } + $build = $this->table('build'); $build->changeColumn('project_id', 'integer', array('null' => false)); $build->changeColumn('commit_id', 'string', array('limit' => 50, 'null' => false)); @@ -45,5 +52,10 @@ class FixDatabaseColumns extends AbstractMigration $user->changeColumn('hash', 'string', array('limit' => 250, 'null' => false)); $user->changeColumn('is_admin', 'integer', array('null' => false, 'default' => 0)); $user->changeColumn('name', 'string', array('limit' => 250, 'null' => false)); + + if ($dbAdapter instanceof \Phinx\Db\Adapter\PdoAdapter) { + $pdo = $dbAdapter->getConnection(); + $pdo->exec('SET foreign_key_checks = 1'); + } } } diff --git a/PHPCI/Model/Base/BuildBase.php b/PHPCI/Model/Base/BuildBase.php index 97b427b5..119290e2 100644 --- a/PHPCI/Model/Base/BuildBase.php +++ b/PHPCI/Model/Base/BuildBase.php @@ -110,16 +110,15 @@ class BuildBase extends Model 'commit_id' => array( 'type' => 'varchar', 'length' => 50, - 'nullable' => true, 'default' => null, ), 'status' => array( - 'type' => 'tinyint', - 'length' => 4, + 'type' => 'int', + 'length' => 11, 'default' => null, ), 'log' => array( - 'type' => 'longtext', + 'type' => 'text', 'nullable' => true, 'default' => null, ), @@ -155,7 +154,7 @@ class BuildBase extends Model 'default' => null, ), 'extra' => array( - 'type' => 'longtext', + 'type' => 'text', 'nullable' => true, 'default' => null, ), @@ -382,10 +381,12 @@ class BuildBase extends Model /** * Set the value of CommitId / commit_id. * + * Must not be null. * @param $value string */ public function setCommitId($value) { + $this->_validateNotNull('CommitId', $value); $this->_validateString('CommitId', $value); if ($this->data['commit_id'] === $value) { diff --git a/PHPCI/Model/Base/BuildMetaBase.php b/PHPCI/Model/Base/BuildMetaBase.php index a979e1d9..0ac8fa93 100644 --- a/PHPCI/Model/Base/BuildMetaBase.php +++ b/PHPCI/Model/Base/BuildMetaBase.php @@ -91,17 +91,15 @@ class BuildMetaBase extends Model 'build_id' => array( 'type' => 'int', 'length' => 11, - 'nullable' => true, 'default' => null, ), 'meta_key' => array( 'type' => 'varchar', - 'length' => 255, + 'length' => 250, 'default' => null, ), 'meta_value' => array( - 'type' => 'longtext', - 'nullable' => true, + 'type' => 'text', 'default' => null, ), ); @@ -238,10 +236,12 @@ class BuildMetaBase extends Model /** * Set the value of BuildId / build_id. * + * Must not be null. * @param $value int */ public function setBuildId($value) { + $this->_validateNotNull('BuildId', $value); $this->_validateInt('BuildId', $value); if ($this->data['build_id'] === $value) { @@ -276,10 +276,12 @@ class BuildMetaBase extends Model /** * Set the value of MetaValue / meta_value. * + * Must not be null. * @param $value string */ public function setMetaValue($value) { + $this->_validateNotNull('MetaValue', $value); $this->_validateString('MetaValue', $value); if ($this->data['meta_value'] === $value) { diff --git a/PHPCI/Model/Base/ProjectBase.php b/PHPCI/Model/Base/ProjectBase.php index 5e1f4f37..305cafbf 100644 --- a/PHPCI/Model/Base/ProjectBase.php +++ b/PHPCI/Model/Base/ProjectBase.php @@ -38,11 +38,11 @@ class ProjectBase extends Model 'reference' => null, 'branch' => null, 'ssh_private_key' => null, - 'ssh_public_key' => null, 'type' => null, 'access_information' => null, 'last_commit' => null, 'build_config' => null, + 'ssh_public_key' => null, 'allow_public_status' => null, ); @@ -56,11 +56,11 @@ class ProjectBase extends Model 'reference' => 'getReference', 'branch' => 'getBranch', 'ssh_private_key' => 'getSshPrivateKey', - 'ssh_public_key' => 'getSshPublicKey', 'type' => 'getType', 'access_information' => 'getAccessInformation', 'last_commit' => 'getLastCommit', 'build_config' => 'getBuildConfig', + 'ssh_public_key' => 'getSshPublicKey', 'allow_public_status' => 'getAllowPublicStatus', // Foreign key getters: @@ -76,11 +76,11 @@ class ProjectBase extends Model 'reference' => 'setReference', 'branch' => 'setBranch', 'ssh_private_key' => 'setSshPrivateKey', - 'ssh_public_key' => 'setSshPublicKey', 'type' => 'setType', 'access_information' => 'setAccessInformation', 'last_commit' => 'setLastCommit', 'build_config' => 'setBuildConfig', + 'ssh_public_key' => 'setSshPublicKey', 'allow_public_status' => 'setAllowPublicStatus', // Foreign key setters: @@ -109,23 +109,18 @@ class ProjectBase extends Model ), 'branch' => array( 'type' => 'varchar', - 'length' => 250, - 'default' => null, + 'length' => 50, + 'default' => 'master', ), 'ssh_private_key' => array( 'type' => 'text', 'nullable' => true, 'default' => null, ), - 'ssh_public_key' => array( - 'type' => 'text', - 'nullable' => true, - 'default' => null, - ), 'type' => array( 'type' => 'varchar', 'length' => 50, - 'default' => 1, + 'default' => null, ), 'access_information' => array( 'type' => 'varchar', @@ -144,9 +139,14 @@ class ProjectBase extends Model 'nullable' => true, 'default' => null, ), + 'ssh_public_key' => array( + 'type' => 'text', + 'nullable' => true, + 'default' => null, + ), 'allow_public_status' => array( - 'type' => 'tinyint', - 'length' => 4, + 'type' => 'int', + 'length' => 11, ), ); @@ -224,18 +224,6 @@ class ProjectBase extends Model return $rtn; } - /** - * Get the value of SshPublicKey / ssh_public_key. - * - * @return string - */ - public function getSshPublicKey() - { - $rtn = $this->data['ssh_public_key']; - - return $rtn; - } - /** * Get the value of Type / type. * @@ -284,6 +272,18 @@ class ProjectBase extends Model return $rtn; } + /** + * Get the value of SshPublicKey / ssh_public_key. + * + * @return string + */ + public function getSshPublicKey() + { + $rtn = $this->data['ssh_public_key']; + + return $rtn; + } + /** * Get the value of AllowPublicStatus / allow_public_status. * @@ -394,24 +394,6 @@ class ProjectBase extends Model $this->_setModified('ssh_private_key'); } - /** - * Set the value of SshPublicKey / ssh_public_key. - * - * @param $value string - */ - public function setSshPublicKey($value) - { - $this->_validateString('SshPublicKey', $value); - - if ($this->data['ssh_public_key'] === $value) { - return; - } - - $this->data['ssh_public_key'] = $value; - - $this->_setModified('ssh_public_key'); - } - /** * Set the value of Type / type. * @@ -486,6 +468,24 @@ class ProjectBase extends Model $this->_setModified('build_config'); } + /** + * Set the value of SshPublicKey / ssh_public_key. + * + * @param $value string + */ + public function setSshPublicKey($value) + { + $this->_validateString('SshPublicKey', $value); + + if ($this->data['ssh_public_key'] === $value) { + return; + } + + $this->data['ssh_public_key'] = $value; + + $this->_setModified('ssh_public_key'); + } + /** * Set the value of AllowPublicStatus / allow_public_status. * diff --git a/PHPCI/Model/Base/UserBase.php b/PHPCI/Model/Base/UserBase.php index 514a0db9..e9be15a0 100644 --- a/PHPCI/Model/Base/UserBase.php +++ b/PHPCI/Model/Base/UserBase.php @@ -90,14 +90,12 @@ class UserBase extends Model 'default' => null, ), 'is_admin' => array( - 'type' => 'tinyint', - 'length' => 1, - 'default' => null, + 'type' => 'int', + 'length' => 11, ), 'name' => array( 'type' => 'varchar', 'length' => 250, - 'nullable' => true, 'default' => null, ), ); @@ -259,10 +257,12 @@ class UserBase extends Model /** * Set the value of Name / name. * + * Must not be null. * @param $value string */ public function setName($value) { + $this->_validateNotNull('Name', $value); $this->_validateString('Name', $value); if ($this->data['name'] === $value) { diff --git a/PHPCI/Model/Project.php b/PHPCI/Model/Project.php index 702d9c89..98283d77 100644 --- a/PHPCI/Model/Project.php +++ b/PHPCI/Model/Project.php @@ -88,4 +88,28 @@ class Project extends ProjectBase return $this->data['branch']; } } + + public function getIcon() + { + switch ($this->getType()) { + case 'github': + $icon = 'github'; + break; + + case 'bitbucket': + $icon = 'bitbucket'; + break; + + case 'git': + case 'gitlab': + $icon = 'git'; + break; + + default: + $icon = 'cog'; + break; + } + + return $icon; + } } diff --git a/PHPCI/Store/Base/BuildMetaStoreBase.php b/PHPCI/Store/Base/BuildMetaStoreBase.php index bc1589cc..f6158c13 100644 --- a/PHPCI/Store/Base/BuildMetaStoreBase.php +++ b/PHPCI/Store/Base/BuildMetaStoreBase.php @@ -56,7 +56,6 @@ class BuildMetaStoreBase extends Store $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `build_meta` WHERE `project_id` = :project_id' . $add; $stmt = Database::getConnection($useConnection)->prepare($query); @@ -70,6 +69,9 @@ class BuildMetaStoreBase extends Store }; $rtn = array_map($map, $res); + $count = count($rtn); + + return array('items' => $rtn, 'count' => $count); } else { return array('items' => array(), 'count' => 0); @@ -88,7 +90,6 @@ class BuildMetaStoreBase extends Store $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `build_meta` WHERE `build_id` = :build_id' . $add; $stmt = Database::getConnection($useConnection)->prepare($query); @@ -102,6 +103,9 @@ class BuildMetaStoreBase extends Store }; $rtn = array_map($map, $res); + $count = count($rtn); + + return array('items' => $rtn, 'count' => $count); } else { return array('items' => array(), 'count' => 0); diff --git a/PHPCI/Store/Base/BuildStoreBase.php b/PHPCI/Store/Base/BuildStoreBase.php index b67d5f73..20927caa 100644 --- a/PHPCI/Store/Base/BuildStoreBase.php +++ b/PHPCI/Store/Base/BuildStoreBase.php @@ -56,7 +56,6 @@ class BuildStoreBase extends Store $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `build` WHERE `project_id` = :project_id' . $add; $stmt = Database::getConnection($useConnection)->prepare($query); @@ -70,6 +69,9 @@ class BuildStoreBase extends Store }; $rtn = array_map($map, $res); + $count = count($rtn); + + return array('items' => $rtn, 'count' => $count); } else { return array('items' => array(), 'count' => 0); @@ -88,7 +90,6 @@ class BuildStoreBase extends Store $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `build` WHERE `status` = :status' . $add; $stmt = Database::getConnection($useConnection)->prepare($query); @@ -102,6 +103,9 @@ class BuildStoreBase extends Store }; $rtn = array_map($map, $res); + $count = count($rtn); + + return array('items' => $rtn, 'count' => $count); } else { return array('items' => array(), 'count' => 0); diff --git a/PHPCI/Store/Base/ProjectStoreBase.php b/PHPCI/Store/Base/ProjectStoreBase.php index 410a305e..dda946a5 100644 --- a/PHPCI/Store/Base/ProjectStoreBase.php +++ b/PHPCI/Store/Base/ProjectStoreBase.php @@ -56,7 +56,6 @@ class ProjectStoreBase extends Store $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `project` WHERE `title` = :title' . $add; $stmt = Database::getConnection($useConnection)->prepare($query); @@ -70,6 +69,9 @@ class ProjectStoreBase extends Store }; $rtn = array_map($map, $res); + $count = count($rtn); + + return array('items' => $rtn, 'count' => $count); } else { return array('items' => array(), 'count' => 0); diff --git a/PHPCI/Store/BuildStore.php b/PHPCI/Store/BuildStore.php index a1da7cb1..b28142a7 100644 --- a/PHPCI/Store/BuildStore.php +++ b/PHPCI/Store/BuildStore.php @@ -10,6 +10,7 @@ namespace PHPCI\Store; use b8\Database; +use PHPCI\BuildFactory; use PHPCI\Model\Build; use PHPCI\Store\Base\BuildStoreBase; @@ -21,11 +22,22 @@ use PHPCI\Store\Base\BuildStoreBase; */ class BuildStore extends BuildStoreBase { - public function getLatestBuilds($projectId) + public function getLatestBuilds($projectId = null, $limit = 5) { - $query = 'SELECT * FROM build WHERE project_id = :pid ORDER BY id DESC LIMIT 5'; + $where = ''; + + if (!is_null($projectId)) { + $where = ' WHERE `project_id` = :pid '; + } + + $query = 'SELECT * FROM build '.$where.' ORDER BY id DESC LIMIT :limit'; $stmt = Database::getConnection('read')->prepare($query); - $stmt->bindValue(':pid', $projectId); + + if (!is_null($projectId)) { + $stmt->bindValue(':pid', $projectId); + } + + $stmt->bindValue(':limit', $limit, \PDO::PARAM_INT); if ($stmt->execute()) { $res = $stmt->fetchAll(\PDO::FETCH_ASSOC); @@ -41,6 +53,21 @@ class BuildStore extends BuildStoreBase } } + public function getLastBuildByStatus($projectId = null, $status = Build::STATUS_SUCCESS) + { + $query = 'SELECT * FROM build WHERE project_id = :pid AND status = :status ORDER BY id DESC LIMIT 1'; + $stmt = Database::getConnection('read')->prepare($query); + $stmt->bindValue(':pid', $projectId); + $stmt->bindValue(':status', $status); + + if ($stmt->execute()) { + $res = $stmt->fetch(\PDO::FETCH_ASSOC); + return new Build($res); + } else { + return array(); + } + } + public function getByProjectAndCommit($projectId, $commitId) { $query = 'SELECT * FROM `build` WHERE `project_id` = :project_id AND `commit_id` = :commit_id'; diff --git a/PHPCI/Store/ProjectStore.php b/PHPCI/Store/ProjectStore.php index 6f81b8f4..4657fb8d 100644 --- a/PHPCI/Store/ProjectStore.php +++ b/PHPCI/Store/ProjectStore.php @@ -10,6 +10,7 @@ namespace PHPCI\Store; use b8\Database; +use PHPCI\Model\Project; use PHPCI\Store\Base\ProjectStoreBase; /** @@ -39,4 +40,26 @@ class ProjectStore extends ProjectStoreBase return array(); } } + + public function getAll() + { + $query = 'SELECT * FROM `project` ORDER BY `title` ASC'; + $stmt = Database::getConnection('read')->prepare($query); + + if ($stmt->execute()) { + $res = $stmt->fetchAll(\PDO::FETCH_ASSOC); + + $map = function ($item) { + return new Project($item); + }; + $rtn = array_map($map, $res); + + $count = count($rtn); + + + return array('items' => $rtn, 'count' => $count); + } else { + return array('items' => array(), 'count' => 0); + } + } } diff --git a/PHPCI/View/Build/header-row.phtml b/PHPCI/View/Build/header-row.phtml new file mode 100644 index 00000000..83bd4524 --- /dev/null +++ b/PHPCI/View/Build/header-row.phtml @@ -0,0 +1,20 @@ +
Branch: getBranch(); ?>
+ +