Merge branch 'master' into phplint-output-block

This commit is contained in:
Stephen Ball 2015-10-08 18:30:48 +01:00
commit 34536a4d3d
30 changed files with 803 additions and 510 deletions

View file

@ -135,15 +135,17 @@ class Application extends b8\Application
*/
protected function setLayoutVariables(View &$layout)
{
/** @var \PHPCI\Store\ProjectStore $projectStore */
$projectStore = b8\Store\Factory::getStore('Project');
$layout->projects = $projectStore->getWhere(
array('archived' => (int)isset($_GET['archived'])),
50,
0,
array(),
array('title' => 'ASC')
);
$groups = array();
$groupList = b8\Store\Factory::getStore('ProjectGroup')->getWhere(array(), 100, 0, array(), array('title' => 'ASC'));
foreach ($groupList['items'] as $group) {
$thisGroup = array('title' => $group->getTitle());
$projects = b8\Store\Factory::getStore('Project')->getByGroupId($group->getId());
$thisGroup['projects'] = $projects['items'];
$groups[] = $thisGroup;
}
$layout->groups = $groups;
}
/**

View file

@ -0,0 +1,104 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2015, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Controller;
use b8;
use b8\Form;
use b8\Store;
use PHPCI\Controller;
use PHPCI\Model\ProjectGroup;
/**
* Project Controller - Allows users to create, edit and view projects.
* @author Dan Cryer <dan@block8.co.uk>
* @package PHPCI
* @subpackage Web
*/
class GroupController extends Controller
{
/**
* @var \PHPCI\Store\ProjectGroupStore
*/
protected $groupStore;
public function init()
{
$this->groupStore = b8\Store\Factory::getStore('ProjectGroup');
}
public function index()
{
$this->requireAdmin();
$groups = array();
$groupList = $this->groupStore->getWhere(array(), 100, 0, array(), array('title' => 'ASC'));
foreach ($groupList['items'] as $group) {
$thisGroup = array(
'title' => $group->getTitle(),
'id' => $group->getId(),
);
$projects = b8\Store\Factory::getStore('Project')->getByGroupId($group->getId());
$thisGroup['projects'] = $projects['items'];
$groups[] = $thisGroup;
}
$this->view->groups = $groups;
}
public function edit($id = null)
{
$this->requireAdmin();
if (!is_null($id)) {
$group = $this->groupStore->getById($id);
} else {
$group = new ProjectGroup();
}
if ($this->request->getMethod() == 'POST') {
$group->setTitle($this->getParam('title'));
$this->groupStore->save($group);
$response = new b8\Http\Response\RedirectResponse();
$response->setHeader('Location', PHPCI_URL.'group');
return $response;
}
$form = new Form();
$form->setMethod('POST');
$form->setAction(PHPCI_URL . 'group/edit' . (!is_null($id) ? '/' . $id : ''));
$title = new Form\Element\Text('title');
$title->setContainerClass('form-group');
$title->setClass('form-control');
$title->setLabel('Group Title');
$title->setValue($group->getTitle());
$submit = new Form\Element\Submit();
$submit->setValue('Save Group');
$form->addField($title);
$form->addField($submit);
$this->view->form = $form;
}
public function delete($id)
{
$this->requireAdmin();
$group = $this->groupStore->getById($id);
$this->groupStore->delete($group);
$response = new b8\Http\Response\RedirectResponse();
$response->setHeader('Location', PHPCI_URL.'group');
return $response;
}
}

View file

@ -23,15 +23,20 @@ use PHPCI\Model\Build;
class HomeController extends \PHPCI\Controller
{
/**
* @var \b8\Store\BuildStore
* @var \PHPCI\Store\BuildStore
*/
protected $buildStore;
/**
* @var \b8\Store\ProjectStore
* @var \PHPCI\Store\ProjectStore
*/
protected $projectStore;
/**
* @var \PHPCI\Store\ProjectGroupStore
*/
protected $groupStore;
/**
* Initialise the controller, set up stores and services.
*/
@ -39,6 +44,7 @@ class HomeController extends \PHPCI\Controller
{
$this->buildStore = b8\Store\Factory::getStore('Build');
$this->projectStore = b8\Store\Factory::getStore('Project');
$this->groupStore = b8\Store\Factory::getStore('ProjectGroup');
}
/**
@ -47,15 +53,6 @@ class HomeController extends \PHPCI\Controller
public function index()
{
$this->layout->title = Lang::get('dashboard');
$projects = $this->projectStore->getWhere(
array('archived' => (int)isset($_GET['archived'])),
50,
0,
array(),
array('title' => 'ASC')
);
$builds = $this->buildStore->getLatestBuilds(null, 10);
foreach ($builds as &$build) {
@ -63,8 +60,7 @@ class HomeController extends \PHPCI\Controller
}
$this->view->builds = $builds;
$this->view->projects = $projects['items'];
$this->view->summary = $this->getSummaryHtml($projects);
$this->view->groups = $this->getGroupInfo();
return $this->view->render();
}
@ -102,7 +98,7 @@ class HomeController extends \PHPCI\Controller
$failures = array();
$counts = array();
foreach ($projects['items'] as $project) {
foreach ($projects as $project) {
$summaryBuilds[$project->getId()] = $this->buildStore->getLatestBuilds($project->getId());
$count = $this->buildStore->getWhere(
@ -122,7 +118,7 @@ class HomeController extends \PHPCI\Controller
}
$summaryView = new b8\View('SummaryTable');
$summaryView->projects = $projects['items'];
$summaryView->projects = $projects;
$summaryView->builds = $summaryBuilds;
$summaryView->successful = $successes;
$summaryView->failed = $failures;
@ -147,4 +143,21 @@ class HomeController extends \PHPCI\Controller
return $view->render();
}
protected function getGroupInfo()
{
$rtn = array();
$groups = $this->groupStore->getWhere(array(), 100, 0, array(), array('title' => 'ASC'));
foreach ($groups['items'] as $group) {
$thisGroup = array('title' => $group->getTitle());
$projects = $this->projectStore->getByGroupId($group->getId());
$thisGroup['projects'] = $projects['items'];
$thisGroup['summary'] = $this->getSummaryHtml($thisGroup['projects']);
$rtn[] = $thisGroup;
}
return $rtn;
}
}

View file

@ -23,24 +23,6 @@ use PHPCI\Plugin\Util\PluginInformationCollection;
*/
class PluginController extends \PHPCI\Controller
{
protected $required = array(
'php',
'ext-pdo',
'ext-pdo_mysql',
'block8/b8framework',
'ircmaxell/password-compat',
'swiftmailer/swiftmailer',
'symfony/yaml',
'symfony/console',
'psr/log',
'monolog/monolog',
'pimple/pimple',
'robmorgan/phinx',
);
protected $canInstall;
protected $composerPath;
/**
* List all enabled plugins, installed and recommend packages.
* @return string
@ -49,12 +31,8 @@ class PluginController extends \PHPCI\Controller
{
$this->requireAdmin();
$this->view->canWrite = is_writable(APPLICATION_PATH . 'composer.json');
$this->view->required = $this->required;
$json = $this->getComposerJson();
$this->view->installedPackages = $json['require'];
$this->view->suggestedPackages = $json['suggest'];
$pluginInfo = new PluginInformationCollection();
$pluginInfo->add(FilesPluginInformation::newFromDir(
@ -71,49 +49,6 @@ class PluginController extends \PHPCI\Controller
return $this->view->render();
}
/**
* Remove a given package.
*/
public function remove()
{
$this->requireAdmin();
$package = $this->getParam('package', null);
$json = $this->getComposerJson();
$response = new b8\Http\Response\RedirectResponse();
if (!in_array($package, $this->required)) {
unset($json['require'][$package]);
$this->setComposerJson($json);
$response->setHeader('Location', PHPCI_URL . 'plugin?r=' . $package);
return $response;
}
$response->setHeader('Location', PHPCI_URL);
return $response;
}
/**
* Install a given package.
*/
public function install()
{
$this->requireAdmin();
$package = $this->getParam('package', null);
$version = $this->getParam('version', '*');
$json = $this->getComposerJson();
$json['require'][$package] = $version;
$this->setComposerJson($json);
$response = new b8\Http\Response\RedirectResponse();
$response->setHeader('Location', PHPCI_URL . 'plugin?w=' . $package);
return $response;
}
/**
* Get the json-decoded contents of the composer.json file.
* @return mixed
@ -123,83 +58,4 @@ class PluginController extends \PHPCI\Controller
$json = file_get_contents(APPLICATION_PATH . 'composer.json');
return json_decode($json, true);
}
/**
* Convert array to json and save composer.json
*
* @param $array
*/
protected function setComposerJson($array)
{
if (defined('JSON_PRETTY_PRINT')) {
$json = json_encode($array, JSON_PRETTY_PRINT);
} else {
$json = json_encode($array);
}
file_put_contents(APPLICATION_PATH . 'composer.json', $json);
}
/**
* Find a system binary.
* @param $binary
* @return null|string
*/
protected function findBinary($binary)
{
if (is_string($binary)) {
$binary = array($binary);
}
foreach ($binary as $bin) {
// Check project root directory:
if (is_file(APPLICATION_PATH . $bin)) {
return APPLICATION_PATH . $bin;
}
// Check Composer bin dir:
if (is_file(APPLICATION_PATH . 'vendor/bin/' . $bin)) {
return APPLICATION_PATH . 'vendor/bin/' . $bin;
}
// Use "which"
$which = trim(shell_exec('which ' . $bin));
if (!empty($which)) {
return $which;
}
}
return null;
}
/**
* Perform a search on packagist.org.
*/
public function packagistSearch()
{
$searchQuery = $this->getParam('q', '');
$http = new \b8\HttpClient();
$http->setHeaders(array('User-Agent: PHPCI/1.0 (+https://www.phptesting.org)'));
$res = $http->get('https://packagist.org/search.json', array('q' => $searchQuery));
$response = new b8\Http\Response\JsonResponse();
$response->setContent($res['body']);
return $response;
}
/**
* Look up available versions of a given package on packagist.org
*/
public function packagistVersions()
{
$name = $this->getParam('p', '');
$http = new \b8\HttpClient();
$http->setHeaders(array('User-Agent: PHPCI/1.0 (+https://www.phptesting.org)'));
$res = $http->get('https://packagist.org/packages/'.$name.'.json');
$response = new b8\Http\Response\JsonResponse();
$response->setContent($res['body']);
return $response;
}
}

View file

@ -220,6 +220,7 @@ class ProjectController extends PHPCI\Controller
'build_config' => $this->getParam('build_config', null),
'allow_public_status' => $this->getParam('allow_public_status', 0),
'branch' => $this->getParam('branch', null),
'group' => $this->getParam('group_id', null),
);
$project = $this->projectService->createProject($title, $type, $reference, $options);
@ -284,6 +285,7 @@ class ProjectController extends PHPCI\Controller
'allow_public_status' => $this->getParam('allow_public_status', 0),
'archived' => $this->getParam('archived', 0),
'branch' => $this->getParam('branch', null),
'group' => $this->getParam('group_id', null),
);
$project = $this->projectService->updateProject($project, $title, $type, $reference, $options);
@ -352,6 +354,20 @@ class ProjectController extends PHPCI\Controller
$field->setClass('form-control')->setContainerClass('form-group')->setValue('master');
$form->addField($field);
$field = Form\Element\Select::create('group_id', 'Project Group', true);
$field->setClass('form-control')->setContainerClass('form-group')->setValue(1);
$groups = array();
$groupStore = b8\Store\Factory::getStore('ProjectGroup');
$groupList = $groupStore->getWhere(array(), 100, 0, array(), array('title' => 'ASC'));
foreach ($groupList['items'] as $group) {
$groups[$group->getId()] = $group->getTitle();
}
$field->setOptions($groups);
$form->addField($field);
$field = Form\Element\Checkbox::create('allow_public_status', Lang::get('allow_public_status'), false);
$field->setContainerClass('form-group');
$field->setCheckedValue(1);

View file

@ -0,0 +1,29 @@
<?php
use Phinx\Migration\AbstractMigration;
class AddProjectGroups extends AbstractMigration
{
public function change()
{
$table = $this->table('project_group');
$table->addColumn('title', 'string', array('limit' => 100, 'null' => false));
$table->save();
$group = new \PHPCI\Model\ProjectGroup();
$group->setTitle('Projects');
/** @var \PHPCI\Model\ProjectGroup $group */
$group = \b8\Store\Factory::getStore('ProjectGroup')->save($group);
$table = $this->table('project');
$table->addColumn('group_id', 'integer', array(
'signed' => true,
'null' => false,
'default' => $group->getId(),
));
$table->addForeignKey('group_id', 'project_group', 'id', array('delete'=> 'RESTRICT', 'update' => 'CASCADE'));
$table->save();
}
}

View file

@ -118,7 +118,7 @@ class BuildBase extends Model
'default' => null,
),
'log' => array(
'type' => 'text',
'type' => 'mediumtext',
'nullable' => true,
'default' => null,
),

View file

@ -99,7 +99,7 @@ class BuildMetaBase extends Model
'default' => null,
),
'meta_value' => array(
'type' => 'text',
'type' => 'mediumtext',
'default' => null,
),
);

View file

@ -45,6 +45,7 @@ class ProjectBase extends Model
'ssh_public_key' => null,
'allow_public_status' => null,
'archived' => null,
'group_id' => null,
);
/**
@ -64,8 +65,10 @@ class ProjectBase extends Model
'ssh_public_key' => 'getSshPublicKey',
'allow_public_status' => 'getAllowPublicStatus',
'archived' => 'getArchived',
'group_id' => 'getGroupId',
// Foreign key getters:
'Group' => 'getGroup',
);
/**
@ -85,8 +88,10 @@ class ProjectBase extends Model
'ssh_public_key' => 'setSshPublicKey',
'allow_public_status' => 'setAllowPublicStatus',
'archived' => 'setArchived',
'group_id' => 'setGroupId',
// Foreign key setters:
'Group' => 'setGroup',
);
/**
@ -153,10 +158,14 @@ class ProjectBase extends Model
),
'archived' => array(
'type' => 'tinyint',
'length' => 4,
'nullable' => true,
'length' => 1,
'default' => null,
),
'group_id' => array(
'type' => 'int',
'length' => 11,
'default' => 1,
),
);
/**
@ -165,12 +174,20 @@ class ProjectBase extends Model
public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'idx_project_title' => array('columns' => 'title'),
'group_id' => array('columns' => 'group_id'),
);
/**
* @var array
*/
public $foreignKeys = array(
'project_ibfk_1' => array(
'local_col' => 'group_id',
'update' => 'CASCADE',
'delete' => '',
'table' => 'project_group',
'col' => 'id'
),
);
/**
@ -317,6 +334,18 @@ class ProjectBase extends Model
return $rtn;
}
/**
* Get the value of GroupId / group_id.
*
* @return int
*/
public function getGroupId()
{
$rtn = $this->data['group_id'];
return $rtn;
}
/**
* Set the value of Id / id.
*
@ -530,10 +559,12 @@ class ProjectBase extends Model
/**
* Set the value of Archived / archived.
*
* Must not be null.
* @param $value int
*/
public function setArchived($value)
{
$this->_validateNotNull('Archived', $value);
$this->_validateInt('Archived', $value);
if ($this->data['archived'] === $value) {
@ -545,6 +576,83 @@ class ProjectBase extends Model
$this->_setModified('archived');
}
/**
* Set the value of GroupId / group_id.
*
* Must not be null.
* @param $value int
*/
public function setGroupId($value)
{
$this->_validateNotNull('GroupId', $value);
$this->_validateInt('GroupId', $value);
if ($this->data['group_id'] === $value) {
return;
}
$this->data['group_id'] = $value;
$this->_setModified('group_id');
}
/**
* Get the ProjectGroup model for this Project by Id.
*
* @uses \PHPCI\Store\ProjectGroupStore::getById()
* @uses \PHPCI\Model\ProjectGroup
* @return \PHPCI\Model\ProjectGroup
*/
public function getGroup()
{
$key = $this->getGroupId();
if (empty($key)) {
return null;
}
$cacheKey = 'Cache.ProjectGroup.' . $key;
$rtn = $this->cache->get($cacheKey, null);
if (empty($rtn)) {
$rtn = Factory::getStore('ProjectGroup', 'PHPCI')->getById($key);
$this->cache->set($cacheKey, $rtn);
}
return $rtn;
}
/**
* Set Group - Accepts an ID, an array representing a ProjectGroup or a ProjectGroup model.
*
* @param $value mixed
*/
public function setGroup($value)
{
// Is this an instance of ProjectGroup?
if ($value instanceof \PHPCI\Model\ProjectGroup) {
return $this->setGroupObject($value);
}
// Is this an array representing a ProjectGroup item?
if (is_array($value) && !empty($value['id'])) {
return $this->setGroupId($value['id']);
}
// Is this a scalar value representing the ID of this foreign key?
return $this->setGroupId($value);
}
/**
* Set Group - Accepts a ProjectGroup model.
*
* @param $value \PHPCI\Model\ProjectGroup
*/
public function setGroupObject(\PHPCI\Model\ProjectGroup $value)
{
return $this->setGroupId($value->getId());
}
/**
* Get Build models by ProjectId for this Project.
*

View file

@ -0,0 +1,168 @@
<?php
/**
* ProjectGroup base model for table: project_group
*/
namespace PHPCI\Model\Base;
use PHPCI\Model;
use b8\Store\Factory;
/**
* ProjectGroup Base Model
*/
class ProjectGroupBase extends Model
{
/**
* @var array
*/
public static $sleepable = array();
/**
* @var string
*/
protected $tableName = 'project_group';
/**
* @var string
*/
protected $modelName = 'ProjectGroup';
/**
* @var array
*/
protected $data = array(
'id' => null,
'title' => null,
);
/**
* @var array
*/
protected $getters = array(
// Direct property getters:
'id' => 'getId',
'title' => 'getTitle',
// Foreign key getters:
);
/**
* @var array
*/
protected $setters = array(
// Direct property setters:
'id' => 'setId',
'title' => 'setTitle',
// Foreign key setters:
);
/**
* @var array
*/
public $columns = array(
'id' => array(
'type' => 'int',
'length' => 11,
'primary_key' => true,
'auto_increment' => true,
'default' => null,
),
'title' => array(
'type' => 'varchar',
'length' => 100,
'default' => null,
),
);
/**
* @var array
*/
public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
);
/**
* @var array
*/
public $foreignKeys = array(
);
/**
* Get the value of Id / id.
*
* @return int
*/
public function getId()
{
$rtn = $this->data['id'];
return $rtn;
}
/**
* Get the value of Title / title.
*
* @return string
*/
public function getTitle()
{
$rtn = $this->data['title'];
return $rtn;
}
/**
* Set the value of Id / id.
*
* Must not be null.
* @param $value int
*/
public function setId($value)
{
$this->_validateNotNull('Id', $value);
$this->_validateInt('Id', $value);
if ($this->data['id'] === $value) {
return;
}
$this->data['id'] = $value;
$this->_setModified('id');
}
/**
* Set the value of Title / title.
*
* Must not be null.
* @param $value string
*/
public function setTitle($value)
{
$this->_validateNotNull('Title', $value);
$this->_validateString('Title', $value);
if ($this->data['title'] === $value) {
return;
}
$this->data['title'] = $value;
$this->_setModified('title');
}
/**
* Get Project models by GroupId for this ProjectGroup.
*
* @uses \PHPCI\Store\ProjectStore::getByGroupId()
* @uses \PHPCI\Model\Project
* @return \PHPCI\Model\Project[]
*/
public function getGroupProjects()
{
return Factory::getStore('Project', 'PHPCI')->getByGroupId($this->getId());
}
}

View file

@ -106,6 +106,8 @@ class UserBase extends Model
public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'idx_email' => array('unique' => true, 'columns' => 'email'),
'email' => array('unique' => true, 'columns' => 'email'),
'name' => array('unique' => true, 'columns' => 'name'),
);
/**

View file

@ -99,6 +99,11 @@ class Build extends BuildBase
{
$build_config = null;
// Try getting the project build config from the database:
if (empty($build_config)) {
$build_config = $this->getProject()->getBuildConfig();
}
// Try .phpci.yml
if (is_file($buildPath . '/.phpci.yml')) {
$build_config = file_get_contents($buildPath . '/.phpci.yml');
@ -109,11 +114,6 @@ class Build extends BuildBase
$build_config = file_get_contents($buildPath . '/phpci.yml');
}
// Try getting the project build config from the database:
if (empty($build_config)) {
$build_config = $this->getProject()->getBuildConfig();
}
// Fall back to zero config plugins:
if (empty($build_config)) {
$build_config = $this->getZeroConfigPlugins($builder);

View file

@ -0,0 +1,18 @@
<?php
/**
* ProjectGroup model for table: project_group
*/
namespace PHPCI\Model;
use PHPCI\Model\Base\ProjectGroupBase;
/**
* ProjectGroup Model
* @uses PHPCI\Model\Base\ProjectGroupBase
*/
class ProjectGroup extends ProjectGroupBase
{
// This class has been left blank so that you can modify it - changes in this file will not be overwritten.
}

View file

@ -50,12 +50,57 @@ class Executor
public function executePlugins(&$config, $stage)
{
$success = true;
// Ignore any stages for which we don't have plugins set:
if (!array_key_exists($stage, $config) || !is_array($config[$stage])) {
return $success;
/** @var \PHPCI\Model\Build $build */
$build = $this->pluginFactory->getResourceFor('PHPCI\Model\Build');
$branch = $build->getBranch();
$pluginsToExecute = array();
// If we have global plugins to execute for this stage, add them to the list to be executed:
if (array_key_exists($stage, $config) && is_array($config[$stage])) {
$pluginsToExecute[] = $config[$stage];
}
foreach ($config[$stage] as $plugin => $options) {
// If we have branch-specific plugins to execute, add them to the list to be executed:
if (isset($config['branch-' . $branch][$stage]) && is_array($config['branch-' . $branch][$stage])) {
$branchConfig = $config['branch-' . $branch];
$runOption = isset($branchConfig['run-option']) ? $branchConfig['run-option'] : 'after';
$plugins = $config['branch-' . $branch][$stage];
switch ($runOption) {
case 'replace':
$pluginsToExecute = array();
$pluginsToExecute[] = $plugins;
break;
case 'before':
array_unshift($pluginsToExecute, $plugins);
break;
case 'after':
array_push($pluginsToExecute, $plugins);
break;
default:
array_push($pluginsToExecute, $plugins);
break;
}
}
foreach ($pluginsToExecute as $pluginSet) {
if (!$this->doExecutePlugins($pluginSet, $stage)) {
$success = false;
}
}
return $success;
}
protected function doExecutePlugins(&$plugins, $stage)
{
$success = true;
foreach ($plugins as $plugin => $options) {
$this->logger->log(Lang::get('running_plugin', $plugin));
$this->setPluginStatus($stage, $plugin, Build::STATUS_RUNNING);

View file

@ -89,6 +89,10 @@ class ProjectService
$project->setBranch($options['branch']);
}
if (array_key_exists('group', $options)) {
$project->setGroup($options['group']);
}
// Allow certain project types to set access information:
$this->processAccessInformation($project);

View file

@ -20,24 +20,11 @@ class BuildMetaStoreBase extends Store
protected $modelName = '\PHPCI\Model\BuildMeta';
protected $primaryKey = 'id';
/**
* Returns a BuildMeta model by primary key.
* @param mixed $value
* @param string $useConnection
* @return \@appNamespace\Model\BuildMeta|null
*/
public function getByPrimaryKey($value, $useConnection = 'read')
{
return $this->getById($value, $useConnection);
}
/**
* Returns a BuildMeta model by Id.
* @param mixed $value
* @param string $useConnection
* @throws HttpException
* @return \@appNamespace\Model\BuildMeta|null
*/
public function getById($value, $useConnection = 'read')
{
if (is_null($value)) {
@ -57,14 +44,6 @@ class BuildMetaStoreBase extends Store
return null;
}
/**
* Returns an array of BuildMeta models by ProjectId.
* @param mixed $value
* @param int $limit
* @param string $useConnection
* @throws HttpException
* @return array
*/
public function getByProjectId($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {
@ -93,14 +72,6 @@ class BuildMetaStoreBase extends Store
}
}
/**
* Returns an array of BuildMeta models by BuildId.
* @param mixed $value
* @param int $limit
* @param string $useConnection
* @throws HttpException
* @return array
*/
public function getByBuildId($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {

View file

@ -20,24 +20,11 @@ class BuildStoreBase extends Store
protected $modelName = '\PHPCI\Model\Build';
protected $primaryKey = 'id';
/**
* Returns a Build model by primary key.
* @param mixed $value
* @param string $useConnection
* @return \@appNamespace\Model\Build|null
*/
public function getByPrimaryKey($value, $useConnection = 'read')
{
return $this->getById($value, $useConnection);
}
/**
* Returns a Build model by Id.
* @param mixed $value
* @param string $useConnection
* @throws HttpException
* @return \@appNamespace\Model\Build|null
*/
public function getById($value, $useConnection = 'read')
{
if (is_null($value)) {
@ -57,14 +44,6 @@ class BuildStoreBase extends Store
return null;
}
/**
* Returns an array of Build models by ProjectId.
* @param mixed $value
* @param int $limit
* @param string $useConnection
* @throws HttpException
* @return array
*/
public function getByProjectId($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {
@ -93,14 +72,6 @@ class BuildStoreBase extends Store
}
}
/**
* Returns an array of Build models by Status.
* @param mixed $value
* @param int $limit
* @param string $useConnection
* @throws HttpException
* @return array
*/
public function getByStatus($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {

View file

@ -0,0 +1,46 @@
<?php
/**
* ProjectGroup base store for table: project_group
*/
namespace PHPCI\Store\Base;
use b8\Database;
use b8\Exception\HttpException;
use PHPCI\Store;
use PHPCI\Model\ProjectGroup;
/**
* ProjectGroup Base Store
*/
class ProjectGroupStoreBase extends Store
{
protected $tableName = 'project_group';
protected $modelName = '\PHPCI\Model\ProjectGroup';
protected $primaryKey = 'id';
public function getByPrimaryKey($value, $useConnection = 'read')
{
return $this->getById($value, $useConnection);
}
public function getById($value, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM `project_group` WHERE `id` = :id LIMIT 1';
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':id', $value);
if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new ProjectGroup($data);
}
}
return null;
}
}

View file

@ -20,24 +20,11 @@ class ProjectStoreBase extends Store
protected $modelName = '\PHPCI\Model\Project';
protected $primaryKey = 'id';
/**
* Returns a Project model by primary key.
* @param mixed $value
* @param string $useConnection
* @return \@appNamespace\Model\Project|null
*/
public function getByPrimaryKey($value, $useConnection = 'read')
{
return $this->getById($value, $useConnection);
}
/**
* Returns a Project model by Id.
* @param mixed $value
* @param string $useConnection
* @throws HttpException
* @return \@appNamespace\Model\Project|null
*/
public function getById($value, $useConnection = 'read')
{
if (is_null($value)) {
@ -57,14 +44,6 @@ class ProjectStoreBase extends Store
return null;
}
/**
* Returns an array of Project models by Title.
* @param mixed $value
* @param int $limit
* @param string $useConnection
* @throws HttpException
* @return array
*/
public function getByTitle($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {
@ -92,4 +71,32 @@ class ProjectStoreBase extends Store
return array('items' => array(), 'count' => 0);
}
}
public function getByGroupId($value, $limit = 1000, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM `project` WHERE `group_id` = :group_id LIMIT :limit';
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':group_id', $value);
$stmt->bindValue(':limit', (int)$limit, \PDO::PARAM_INT);
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);
}
}
}

View file

@ -20,24 +20,11 @@ class UserStoreBase extends Store
protected $modelName = '\PHPCI\Model\User';
protected $primaryKey = 'id';
/**
* Returns a User model by primary key.
* @param mixed $value
* @param string $useConnection
* @return \@appNamespace\Model\User|null
*/
public function getByPrimaryKey($value, $useConnection = 'read')
{
return $this->getById($value, $useConnection);
}
/**
* Returns a User model by Id.
* @param mixed $value
* @param string $useConnection
* @throws HttpException
* @return \@appNamespace\Model\User|null
*/
public function getById($value, $useConnection = 'read')
{
if (is_null($value)) {
@ -57,13 +44,6 @@ class UserStoreBase extends Store
return null;
}
/**
* Returns a User model by Email.
* @param string $value
* @param string $useConnection
* @throws HttpException
* @return \@appNamespace\Model\User|null
*/
public function getByEmail($value, $useConnection = 'read')
{
if (is_null($value)) {
@ -82,23 +62,16 @@ class UserStoreBase extends Store
return null;
}
/**
* Returns a User model by Email.
* @param string $value
* @param string $useConnection
* @throws HttpException
* @return \@appNamespace\Model\User|null
*/
public function getByLoginOrEmail($value, $useConnection = 'read')
public function getByName($value, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM `user` WHERE `name` = :value OR `email` = :value LIMIT 1';
$query = 'SELECT * FROM `user` WHERE `name` = :name LIMIT 1';
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':value', $value);
$stmt->bindValue(':name', $value);
if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {

View file

@ -0,0 +1,18 @@
<?php
/**
* ProjectGroup store for table: project_group
*/
namespace PHPCI\Store;
use PHPCI\Store\Base\ProjectGroupStoreBase;
/**
* ProjectGroup Store
* @uses PHPCI\Store\Base\ProjectGroupStoreBase
*/
class ProjectGroupStore extends ProjectGroupStoreBase
{
// This class has been left blank so that you can modify it - changes in this file will not be overwritten.
}

View file

@ -0,0 +1,9 @@
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Add / Edit Group</h3>
</div>
<div class="box-body">
<?php print $form; ?>
</div>
</div>

View file

@ -0,0 +1,41 @@
<div class="clearfix" style="margin-bottom: 20px;">
<a class="btn btn-success pull-right" href="<?php print PHPCI_URL . 'group/edit'; ?>">
Add Group
</a>
</div>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Project Groups</h3>
</div>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th style="width: 100px;">Projects</th>
<th style="width: 150px"></th>
</tr>
</thead>
<tbody>
<?php foreach($groups as $group): ?>
<tr>
<td><?php print $group['title']; ?></td>
<td><?php print count($group['projects']); ?></td>
<td>
<a class="btn btn-sm btn-default" href="<?php print PHPCI_URL . 'group/edit/' . $group['id']; ?>">
Edit
</a>
<?php if (!count($group['projects'])): ?>
<a class="btn btn-sm btn-danger delete-group" href="<?php print PHPCI_URL . 'group/delete/' . $group['id']; ?>">
Delete
</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>

View file

@ -2,7 +2,17 @@
<div class="row">
<div class="col-sm-5">
<?php print $summary; ?>
<?php foreach ($groups as $group): ?>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"><?php print $group['title']; ?></h3>
</div>
<div class="box-body">
<?php print $group['summary']; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="col-sm-7 pull-left">

View file

@ -1,45 +1,40 @@
<?php use PHPCI\Helper\Lang; ?>
<?php if (!$canWrite): ?>
<p class="alert alert-danger"><?php Lang::out('cannot_update_composer'); ?></p>
<?php endif; ?>
<?php if (isset($_GET['r'])): ?>
<p class="alert alert-success"><?php Lang::out('x_has_been_removed', $_GET['r']); ?></p>
<?php endif; ?>
<?php if (isset($_GET['w'])): ?>
<p class="alert alert-success"><?php Lang::out('x_has_been_added', $_GET['w']); ?></p>
<?php endif; ?>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"><?php Lang::out('enabled_plugins'); ?></h3>
</div>
<table class="table">
<thead>
<tr>
<th><?php Lang::out('name'); ?></th>
<th><?php Lang::out('class'); ?></th>
<th><?php Lang::out('provided_by_package'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($plugins as $plugin): ?>
<tr>
<td><?php print $plugin->name; ?></td>
<td><?php print $plugin->class; ?></td>
<td><?php print $plugin->source; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="alert alert-danger">
<p><strong>Adding requirements to the PHPCI composer.json file is no longer recommended as a method of installing your required testing tools.</strong><br>
For this reason, we have removed the ability for PHPCI to modify the composer.json file for you.
We recommend that you install testing tools using your project's own composer.json file, by adding them to the "require-dev" section of the file.</p>
</div>
<div class="row">
<div class="col-lg-6">
<div class="col-md-6">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"><?php Lang::out('enabled_plugins'); ?></h3>
</div>
<table class="table">
<thead>
<tr>
<th><?php Lang::out('name'); ?></th>
<th><?php Lang::out('class'); ?></th>
<th><?php Lang::out('provided_by_package'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($plugins as $plugin): ?>
<tr>
<td><?php print $plugin->name; ?></td>
<td><?php print $plugin->class; ?></td>
<td><?php print $plugin->source; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="col-md-6">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"><?php Lang::out('installed_packages'); ?></h3>
@ -58,44 +53,6 @@
<tr>
<td><?php echo $package; ?></td>
<td><?php echo $version; ?></td>
<td>
<?php if (!in_array($package, $required) && $canWrite): ?>
<a class="btn btn-danger btn-small" href="<?php echo PHPCI_URL ?>plugin/remove?package=<?php echo $package; ?>"><?php Lang::out('remove'); ?></a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="col-lg-6">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"><?php Lang::out('suggested_packages'); ?></h3>
</div>
<table class="table">
<thead>
<tr>
<th><?php Lang::out('title'); ?></th>
<th><?php Lang::out('description'); ?></th>
<th width="1"></th>
</tr>
</thead>
<tbody>
<?php foreach ($suggestedPackages as $package => $version): ?>
<?php if (in_array($package, array_keys($installedPackages))) { continue; } ?>
<tr>
<td><?php echo $package; ?></td>
<td><?php echo $version; ?></td>
<td>
<?php if ($canWrite): ?>
<button data-name="<?php echo $package; ?>" class="install-package btn btn-success btn-small"><?php Lang::out('install'); ?></button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
@ -105,108 +62,3 @@
</div>
</div>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title"><?php Lang::out('search_packagist_for_more'); ?></h3>
</div>
<div class="box-body">
<div class="input-group">
<input id="search-query" type="text" class="form-control">
<span class="input-group-btn">
<button id="search-button" class="btn btn-success" type="button"><?php Lang::out('search'); ?></button>
</span>
</div>
<div id="results" style="margin-top: 15px; display: none;">
<table class="table">
<thead>
<tr>
<th><?php Lang::out('title'); ?></th>
<th><?php Lang::out('description'); ?></th>
<th width="1"></th>
</tr>
</thead>
<tbody id="search-results">
</tbody>
</table>
</div>
</div>
</div>
<script>
var canWrite = <?php print $canWrite ? 'true' : 'false'; ?>;
$('#search-button').on('click', function() {
$('#loading').show();
$.getJSON('<?php print PHPCI_URL; ?>plugin/packagist-search', {q: $('#search-query').val()}, function(data) {
$('#loading').hide();
$('#results').show();
var results = $('#search-results').empty();
for (var i in data.results) {
var thisRes = data.results[i];
var thisRow = $('<tr></tr>');
thisRow.append($('<td></td>').text(thisRes.name));
thisRow.append($('<td></td>').text(thisRes.description));
var inst = $('<button></button>').data('name', thisRes.name).addClass('btn btn-small btn-success').html(Lang.get('install'));
inst.on('click', versionChooser);
thisRow.append($('<td></td>').append(inst));
results.append(thisRow);
}
});
});
$('.install-package').on('click', versionChooser);
function versionChooser()
{
$('#loading').show();
var thisName = $(this).data('name');
$.getJSON('<?php print PHPCI_URL; ?>plugin/packagist-versions', {p: thisName}, function(data) {
var versions = data.package.versions;
var vkeys = Object.keys(versions).sort().reverse();
$('#version-list ul').empty();
for (var i in vkeys) {
var url = '<?php print PHPCI_URL; ?>plugin/install?package=' + thisName + '&version=' + vkeys[i];
var li = $('<li></li>');
var a = $('<a></a>').attr('href', url).text(vkeys[i]);
li.append(a);
$('#version-list ul').append(li);
}
$('#version-list').modal('show');
$('#loading').hide();
});
}
</script>
<div class="modal fade" id="version-list">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title"><?php Lang::out('version'); ?></h4>
</div>
<div class="modal-body">
<ul></ul>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

View file

@ -5,8 +5,16 @@
</script>
<div class="clearfix" style="margin-bottom: 20px;">
<a class="btn btn-default" href="<?php print PHPCI_URL . 'project/edit/' . $project->getId(); ?>">
<?php Lang::out('edit_project'); ?>
</a>
<a class="btn btn-danger" href="javascript:confirmDelete('<?php print PHPCI_URL . 'project/delete/' . $project->getId(); ?>', '<?php print Lang::out('project'); ?>', true">
<?php Lang::out('delete_project'); ?>
</a>
<div class="pull-right btn-group">
<a class="btn btn-success" href="<?php print PHPCI_URL . 'project/build/' . $project->getId(); ?>/<?php echo urlencode($branch) ?>">
<a class="btn btn-success" href="<?php print PHPCI_URL . 'project/build/' . $project->getId(); ?><?php echo !empty($branch) ? '/' . urlencode($branch) : '' ?>">
<?php Lang::out('build_now'); ?>
</a>

View file

@ -83,7 +83,7 @@ foreach($projects as $project):
?>
<?php
if (count($projects) > 10) {
if (count($projects) > 5) {
$containerClass = 'small-box-minimal';
} else {
$containerClass = 'small-box-full';
@ -92,7 +92,7 @@ foreach($projects as $project):
<div class="small-box <?php print $containerClass; ?> bg-<?php print $subcls; ?>">
<?php if (count($projects) > 10): ?>
<?php if (count($projects) > 5): ?>
<div class="inner">
<h4>

View file

@ -159,6 +159,12 @@
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>group">
<i class="fa fa-angle-double-right"></i> Project Groups
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>settings">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('settings'); ?>
@ -180,41 +186,57 @@
</li>
<?php endif; ?>
<?php foreach ($projects['items'] as $project): ?>
<?php foreach ($groups as $group): ?>
<li class="treeview">
<a href="#">
<i class="fa fa-<?php print $project->getIcon(); ?>"></i>
<span><?php print $project->getTitle(); ?></span>
<i class="fa fa-folder"></i>
<span><?php print $group['title']; ?></span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<?php if (count($group['projects'])): ?>
<ul class="treeview-menu">
<?php foreach($group['projects'] as $project): ?>
<li>
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('view'); ?>
<i class="fa fa-<?php print $project->getIcon(); ?>"></i>
<span><?php print $project->getTitle(); ?></span>
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>project/build/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('build_now'); ?>
</a>
</li>
<?php /* <ul class="treeview-menu">
<?php if ($this->User()->getIsAdmin()): ?>
<li>
<a href="<?php print PHPCI_URL; ?>project/edit/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('edit_project'); ?>
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>project/view/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('view'); ?>
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>project/delete/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('delete_project'); ?>
</a>
<li>
<a href="<?php print PHPCI_URL; ?>project/build/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('build_now'); ?>
</a>
</li>
<?php if ($this->User()->getIsAdmin()): ?>
<li>
<a href="<?php print PHPCI_URL; ?>project/edit/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('edit_project'); ?>
</a>
</li>
<li>
<a href="<?php print PHPCI_URL; ?>project/delete/<?php print $project->getId(); ?>">
<i class="fa fa-angle-double-right"></i> <?php Lang::out('delete_project'); ?>
</a>
</li>
<?php endif; ?>
</ul>
*/ ?>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</li>
<?php endforeach; ?>

View file

@ -109,7 +109,7 @@ class BuildWorker
if (!array_key_exists('type', $jobData) || $jobData['type'] !== 'phpci.build') {
// Probably not from PHPCI.
$pheanstalk->release($job);
$pheanstalk->delete($job);
continue;
}
@ -124,9 +124,9 @@ class BuildWorker
Database::reset($config);
}
$build = BuildFactory::getBuildById($jobData['build_id']);
if (empty($build)) {
try {
$build = BuildFactory::getBuildById($jobData['build_id']);
} catch (\Exception $ex) {
$this->logger->addWarning('Build #' . $jobData['build_id'] . ' does not exist in the database.');
$pheanstalk->delete($job);
}

20
composer.lock generated
View file

@ -1097,16 +1097,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "2.2.3",
"version": "2.2.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "ef1ca6835468857944d5c3b48fa503d5554cff2f"
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef1ca6835468857944d5c3b48fa503d5554cff2f",
"reference": "ef1ca6835468857944d5c3b48fa503d5554cff2f",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
"shasum": ""
},
"require": {
@ -1155,7 +1155,7 @@
"testing",
"xunit"
],
"time": "2015-09-14 06:51:16"
"time": "2015-10-06 15:47:00"
},
{
"name": "phpunit/php-file-iterator",
@ -1337,16 +1337,16 @@
},
{
"name": "phpunit/phpunit",
"version": "4.8.10",
"version": "4.8.11",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "463163747474815c5ccd4ae12b5b355ec12158e8"
"reference": "bdd199472410fd7e32751f9c814c7e06f2c21bd5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/463163747474815c5ccd4ae12b5b355ec12158e8",
"reference": "463163747474815c5ccd4ae12b5b355ec12158e8",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bdd199472410fd7e32751f9c814c7e06f2c21bd5",
"reference": "bdd199472410fd7e32751f9c814c7e06f2c21bd5",
"shasum": ""
},
"require": {
@ -1405,7 +1405,7 @@
"testing",
"xunit"
],
"time": "2015-10-01 09:14:30"
"time": "2015-10-07 10:39:46"
},
{
"name": "phpunit/phpunit-mock-objects",