Initial commit.

This commit is contained in:
Dan Cryer 2013-05-03 16:02:53 +01:00
commit 2c860e8009
43 changed files with 12560 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.idea
vendor/
composer.lock
config.php

16
PHPCI/Application.php Normal file
View file

@ -0,0 +1,16 @@
<?php
namespace PHPCI;
use b8,
b8\Registry;
class Application extends b8\Application
{
public function handleRequest()
{
$view = new b8\View('Layout');
$view->content = parent::handleRequest();
return $view->render();
}
}

246
PHPCI/Builder.php Normal file
View file

@ -0,0 +1,246 @@
<?php
namespace PHPCI;
use PHPCI\Model\Build;
use b8\Store;
class Builder
{
public $buildPath;
public $ignore = array();
protected $ciDir;
protected $directory;
protected $success = true;
protected $log = '';
protected $verbose = false;
protected $build;
public function __construct(Build $build)
{
$this->build = $build;
}
public function execute()
{
$this->build->setStatus(1);
$this->build = Store\Factory::getStore('Build')->save($this->build);
if($this->setupBuild())
{
$this->executeEvent('prepare');
$this->executePlugins();
$this->log('');
$this->executeEvent('on_complete');
if($this->success)
{
$this->executeEvent('on_success');
$this->logSuccess('BUILD SUCCESSFUL!');
$this->build->setStatus(2);
}
else
{
$this->executeEvent('on_failure');
$this->logFailure('BUILD FAILED!');
$this->build->setStatus(3);
}
$this->log('');
}
$this->removeBuild();
$this->build->setLog($this->log);
Store\Factory::getStore('Build')->save($this->build);
}
public function executeCommand($command)
{
$this->log('Executing: ' . $command, ' ');
$output = '';
$status = 0;
exec($command, $output, $status);
if(!empty($output) && ($this->verbose || $status != 0))
{
$this->log($output, ' ');
}
return ($status == 0) ? true : false;
}
protected function log($message, $prefix = '')
{
if(is_array($message))
{
$message = array_map(function($item) use ($prefix)
{
return $prefix . $item;
}, $message);
$message = implode(PHP_EOL, $message);
$this->log .= $message;
print $message . PHP_EOL;
}
else
{
$message = $prefix . $message . PHP_EOL;
$this->log .= $message;
print $message;
}
}
protected function logSuccess($message)
{
$this->log("\033[0;32m" . $message . "\033[0m");
}
protected function logFailure($message)
{
$this->log("\033[0;31m" . $message . "\033[0m");
}
protected function executeEvent($event)
{
$this->log('RUNNING '.strtoupper($event).' ACTIONS:');
if(!isset($this->config[$event]))
{
return;
}
if(is_string($this->config[$event]))
{
if(!$this->executeCommand($this->config[$event]))
{
$this->success = false;
}
return;
}
if(is_array($this->config[$event]))
{
foreach($this->config[$event] as $command)
{
if(!$this->executeCommand($command))
{
$this->success = false;
}
}
}
}
protected function setupBuild()
{
$commitId = $this->build->getCommitId();
$url = $this->build->getProject()->getGitUrl();
$key = $this->build->getProject()->getGitKey();
$this->ciDir = realpath(dirname(__FILE__) . '/../') . '/';
$this->buildPath = $this->ciDir . 'build/' . $commitId . '/';
$keyFile = $this->ciDir . 'build/' . $commitId . '.key';
mkdir($this->buildPath, 0777, true);
file_put_contents($keyFile, $key);
$this->executeCommand('ssh-agent ssh-add '.$keyFile.' && git clone -b ' .$this->build->getBranch() . ' ' .$url.' '.$this->buildPath.' && ssh-agent -k');
unlink($keyFile);
if(!is_file($this->buildPath . 'phpci.yml'))
{
$this->logFailure('Project does not contain a phpci.yml file.');
return false;
}
$this->config = yaml_parse_file($this->buildPath . 'phpci.yml');
if(!isset($this->config['verbose']) || !$this->config['verbose'])
{
$this->verbose = false;
}
else
{
$this->verbose = true;
}
if(isset($this->config['ignore']))
{
$this->ignore = $this->config['ignore'];
}
$this->log('Set up build: ' . $this->buildPath);
return true;
}
protected function removeBuild()
{
$this->log('Removing build.');
shell_exec('rm -Rf ' . $this->buildPath);
}
protected function executePlugins()
{
foreach($this->config['plugins'] as $plugin => $options)
{
$this->log('');
$this->log('RUNNING PLUGIN: ' . $plugin);
// Is this plugin allowed to fail?
if(!isset($options['allow_failures']))
{
$options['allow_failures'] = false;
}
$class = str_replace('_', ' ', $plugin);
$class = ucwords($class);
$class = 'PHPCI\\Plugin\\' . str_replace(' ', '', $class);
if(!class_exists($class))
{
$this->logFailure('Plugin does not exist: ' . $plugin);
if(!$options['allow_failures'])
{
$this->success = false;
}
continue;
}
try
{
$plugin = new $class($this, $options);
if(!$plugin->execute())
{
if(!$options['allow_failures'])
{
$this->success = false;
}
$this->logFailure('PLUGIN STATUS: FAILED');
continue;
}
}
catch(\Exception $ex)
{
$this->logFailure('EXCEPTION: ' . $ex->getMessage());
if(!$options['allow_failures'])
{
$this->success = false;
continue;
}
}
$this->logSuccess('PLUGIN STATUS: SUCCESS!');
}
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace PHPCI\Controller;
use b8,
b8\Store,
PHPCI\Model\Build;
class GithubController extends b8\Controller
{
public function init()
{
$this->_buildStore = Store\Factory::getStore('Build');
}
public function index()
{
$payload = json_decode($this->getParam('payload'));
$build = new Build();
$build->setProjectId($this->getParam('project'));
$build->setCommitId($payload['after']);
$build->setStatus(0);
$build->setLog('');
$build->setBranch(str_replace('refs/heads/', '', $payload['ref']));
$this->_buildStore->save($build);
die('OK');
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace PHPCI\Controller;
use b8;
class IndexController extends b8\Controller
{
public function init()
{
$this->_buildStore = b8\Store\Factory::getStore('Build');
$this->_projectStore = b8\Store\Factory::getStore('Project');
}
public function index()
{
$builds = $this->_buildStore->getWhere(array(), 10, 0, array(), array('id' => 'DESC'));
$projects = $this->_projectStore->getWhere(array(), 50, 0, array(), array('title' => 'ASC'));
$view = new b8\View('Index');
$view->builds = $builds['items'];
$view->projects = $projects['items'];
return $view->render();
}
}

View file

@ -0,0 +1,289 @@
<?php
/**
* Build base model for table: build
*/
namespace PHPCI\Model\Base;
use b8\Model;
/**
* Build Base Model
*/
class BuildBase extends Model
{
public static $sleepable= array();
protected $_tableName = 'build';
protected $_modelName = 'Build';
protected $_data = array(
'id' => null,
'project_id' => null,
'commit_id' => null,
'status' => null,
'log' => null,
'branch' => null,
);
protected $_getters = array(
'id' => 'getId',
'project_id' => 'getProjectId',
'commit_id' => 'getCommitId',
'status' => 'getStatus',
'log' => 'getLog',
'branch' => 'getBranch',
'Project' => 'getProject',
);
protected $_setters = array(
'id' => 'setId',
'project_id' => 'setProjectId',
'commit_id' => 'setCommitId',
'status' => 'setStatus',
'log' => 'setLog',
'branch' => 'setBranch',
'Project' => 'setProject',
);
public $columns = array(
'id' => array(
'type' => 'int',
'length' => '11',
'primary_key' => true,
'auto_increment' => true,
),
'project_id' => array(
'type' => 'int',
'length' => '11',
),
'commit_id' => array(
'type' => 'varchar',
'length' => '50',
),
'status' => array(
'type' => 'tinyint',
'length' => '4',
),
'log' => array(
'type' => 'text',
'length' => '',
'nullable' => true,
),
'branch' => array(
'type' => 'varchar',
'length' => '50',
),
);
public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'project_id' => array('columns' => 'project_id'),
'idx_status' => array('columns' => 'status'),
);
public $foreignKeys = array(
'build_ibfk_1' => array('local_col' => 'project_id', 'update' => 'CASCADE', 'delete' => 'CASCADE', 'table' => 'project', 'col' => 'id'),
);
public function getId()
{
$rtn = $this->_data['id'];
return $rtn;
}
public function getProjectId()
{
$rtn = $this->_data['project_id'];
return $rtn;
}
public function getCommitId()
{
$rtn = $this->_data['commit_id'];
return $rtn;
}
public function getStatus()
{
$rtn = $this->_data['status'];
return $rtn;
}
public function getLog()
{
$rtn = $this->_data['log'];
return $rtn;
}
public function getBranch()
{
$rtn = $this->_data['branch'];
return $rtn;
}
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');
}
public function setProjectId($value)
{
$this->_validateNotNull('ProjectId', $value);
$this->_validateInt('ProjectId', $value);
if($this->_data['project_id'] == $value)
{
return;
}
$this->_data['project_id'] = $value;
$this->_setModified('project_id');
}
public function setCommitId($value)
{
$this->_validateNotNull('CommitId', $value);
$this->_validateString('CommitId', $value);
if($this->_data['commit_id'] == $value)
{
return;
}
$this->_data['commit_id'] = $value;
$this->_setModified('commit_id');
}
public function setStatus($value)
{
$this->_validateNotNull('Status', $value);
$this->_validateInt('Status', $value);
if($this->_data['status'] == $value)
{
return;
}
$this->_data['status'] = $value;
$this->_setModified('status');
}
public function setLog($value)
{
$this->_validateString('Log', $value);
if($this->_data['log'] == $value)
{
return;
}
$this->_data['log'] = $value;
$this->_setModified('log');
}
public function setBranch($value)
{
$this->_validateNotNull('Branch', $value);
$this->_validateString('Branch', $value);
if($this->_data['branch'] == $value)
{
return;
}
$this->_data['branch'] = $value;
$this->_setModified('branch');
}
/**
* Get the Project model for this Build by Id.
*
* @uses \PHPCI\Store\ProjectStore::getById()
* @uses \PHPCI\Model\Project
* @return \PHPCI\Model\Project
*/
public function getProject()
{
$key = $this->getProjectId();
if(empty($key))
{
return null;
}
return \b8\Store\Factory::getStore('Project')->getById($key);
}
public function setProject($value)
{
// Is this an instance of Project?
if($value instanceof \PHPCI\Model\Project)
{
return $this->setProjectObject($value);
}
// Is this an array representing a Project item?
if(is_array($value) && !empty($value['id']))
{
return $this->setProjectId($value['id']);
}
// Is this a scalar value representing the ID of this foreign key?
return $this->setProjectId($value);
}
public function setProjectObject(\PHPCI\Model\Project $value)
{
return $this->setProjectId($value->getId());
}
}

View file

@ -0,0 +1,188 @@
<?php
/**
* Project base model for table: project
*/
namespace PHPCI\Model\Base;
use b8\Model;
/**
* Project Base Model
*/
class ProjectBase extends Model
{
public static $sleepable= array();
protected $_tableName = 'project';
protected $_modelName = 'Project';
protected $_data = array(
'id' => null,
'title' => null,
'git_url' => null,
'git_key' => null,
);
protected $_getters = array(
'id' => 'getId',
'title' => 'getTitle',
'git_url' => 'getGitUrl',
'git_key' => 'getGitKey',
);
protected $_setters = array(
'id' => 'setId',
'title' => 'setTitle',
'git_url' => 'setGitUrl',
'git_key' => 'setGitKey',
);
public $columns = array(
'id' => array(
'type' => 'int',
'length' => '11',
'primary_key' => true,
'auto_increment' => true,
),
'title' => array(
'type' => 'varchar',
'length' => '250',
),
'git_url' => array(
'type' => 'varchar',
'length' => '1024',
),
'git_key' => array(
'type' => 'text',
'length' => '',
),
);
public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
);
public $foreignKeys = array(
);
public function getId()
{
$rtn = $this->_data['id'];
return $rtn;
}
public function getTitle()
{
$rtn = $this->_data['title'];
return $rtn;
}
public function getGitUrl()
{
$rtn = $this->_data['git_url'];
return $rtn;
}
public function getGitKey()
{
$rtn = $this->_data['git_key'];
return $rtn;
}
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');
}
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');
}
public function setGitUrl($value)
{
$this->_validateNotNull('GitUrl', $value);
$this->_validateString('GitUrl', $value);
if($this->_data['git_url'] == $value)
{
return;
}
$this->_data['git_url'] = $value;
$this->_setModified('git_url');
}
public function setGitKey($value)
{
$this->_validateNotNull('GitKey', $value);
$this->_validateString('GitKey', $value);
if($this->_data['git_key'] == $value)
{
return;
}
$this->_data['git_key'] = $value;
$this->_setModified('git_key');
}
/**
* Get Build models by ProjectId for this Project.
*
* @uses \PHPCI\Store\BuildStore::getByProjectId()
* @uses \PHPCI\Model\Build
* @return \PHPCI\Model\Build[]
*/
public function getProjectBuilds()
{
return \b8\Store\Factory::getStore('Build')->getByProjectId($this->getId());
}
}

20
PHPCI/Model/Build.php Normal file
View file

@ -0,0 +1,20 @@
<?php
/**
* Build model for table: build
*/
namespace PHPCI\Model;
require_once(APPLICATION_PATH . 'PHPCI/Model/Base/BuildBase.php');
use PHPCI\Model\Base\BuildBase;
/**
* Build Model
* @uses PHPCI\Model\Base\BuildBase
*/
class Build extends BuildBase
{
// This class has been left blank so that you can modify it - changes in this file will not be overwritten.
}

20
PHPCI/Model/Project.php Normal file
View file

@ -0,0 +1,20 @@
<?php
/**
* Project model for table: project
*/
namespace PHPCI\Model;
require_once(APPLICATION_PATH . 'PHPCI/Model/Base/ProjectBase.php');
use PHPCI\Model\Base\ProjectBase;
/**
* Project Model
* @uses PHPCI\Model\Base\ProjectBase
*/
class Project extends ProjectBase
{
// This class has been left blank so that you can modify it - changes in this file will not be overwritten.
}

9
PHPCI/Plugin.php Normal file
View file

@ -0,0 +1,9 @@
<?php
namespace PHPCI;
interface Plugin
{
public function __construct(\PHPCI\Builder $phpci, array $options = array());
public function execute();
}

22
PHPCI/Plugin/Composer.php Normal file
View file

@ -0,0 +1,22 @@
<?php
namespace PHPCI\Plugin;
class Composer implements \PHPCI\Plugin
{
protected $directory;
protected $action;
protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array())
{
$this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath;
$this->action = isset($options['action']) ? $options['action'] : 'update';
}
public function execute()
{
return $this->phpci->executeCommand('composer --working-dir=' . $this->directory . ' ' . $this->action);
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace PHPCI\Plugin;
class PhpCodeSniffer implements \PHPCI\Plugin
{
protected $directory;
protected $args;
protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array())
{
$this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath;
$this->standard = isset($options['standard']) ? $options['standard'] : 'PSR2';
}
public function execute()
{
if(count($this->phpci->ignore))
{
$ignore = array_map(function($item)
{
return substr($item, -1) == '/' ? $item . '*' : $item . '/*';
}, $this->phpci->ignore);
$ignore = ' --ignore=' . implode(',', $ignore);
}
return $this->phpci->executeCommand('phpcs --standard=' . $this->standard . $ignore. ' ' . $this->phpci->buildPath);
}
}

32
PHPCI/Plugin/PhpCpd.php Normal file
View file

@ -0,0 +1,32 @@
<?php
namespace PHPCI\Plugin;
class PhpCpd implements \PHPCI\Plugin
{
protected $directory;
protected $args;
protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array())
{
$this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath;
$this->standard = isset($options['standard']) ? $options['standard'] : 'PSR2';
}
public function execute()
{
if(count($this->phpci->ignore))
{
$ignore = array_map(function($item)
{
return ' --exclude ' . (substr($item, -1) == '/' ? $item . '' : $item . '/');
}, $this->phpci->ignore);
$ignore = ' ' . implode('', $ignore);
}
return $this->phpci->executeCommand('phpcpd ' . $ignore . ' ' . $this->phpci->buildPath);
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace PHPCI\Plugin;
class PhpMessDetector implements \PHPCI\Plugin
{
protected $directory;
public function __construct(\PHPCI\Builder $phpci, array $options = array())
{
$this->phpci = $phpci;
}
public function execute()
{
if(count($this->phpci->ignore))
{
$ignore = array_map(function($item)
{
return substr($item, -1) == '/' ? $item . '*' : $item . '/*';
}, $this->phpci->ignore);
$ignore = ' --exclude ' . implode(',', $ignore);
}
return $this->phpci->executeCommand('phpmd ' . $this->phpci->buildPath . ' text codesize,unusedcode,naming' . $ignore);
}
}

22
PHPCI/Plugin/PhpUnit.php Normal file
View file

@ -0,0 +1,22 @@
<?php
namespace PHPCI\Plugin;
class PhpUnit implements \PHPCI\Plugin
{
protected $directory;
protected $args;
protected $phpci;
public function __construct(\PHPCI\Builder $phpci, array $options = array())
{
$this->phpci = $phpci;
$this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath;
$this->args = isset($options['args']) ? $options['args'] : '';
}
public function execute()
{
return $this->phpci->executeCommand('phpunit ' . $this->args . ' ' . $this->phpci->buildPath . $this->directory);
}
}

View file

@ -0,0 +1,141 @@
<?php
/**
* Build base store for table: build
*/
namespace PHPCI\Store\Base;
use b8\Store;
/**
* Build Base Store
*/
class BuildStoreBase extends Store
{
protected $_tableName = 'build';
protected $_modelName = '\PHPCI\Model\Build';
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 \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$stmt = \b8\Database::getConnection($useConnection)->prepare('SELECT * FROM build WHERE id = :id LIMIT 1');
$stmt->bindValue(':id', $value);
if($stmt->execute())
{
if($data = $stmt->fetch(\PDO::FETCH_ASSOC))
{
return new \PHPCI\Model\Build($data);
}
}
return null;
}
public function getByProjectId($value, $limit = null, $useConnection = 'read')
{
if(is_null($value))
{
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$add = '';
if($limit)
{
$add .= ' LIMIT ' . $limit;
}
$stmt = \b8\Database::getConnection($useConnection)->prepare('SELECT COUNT(*) AS cnt FROM build WHERE project_id = :project_id' . $add);
$stmt->bindValue(':project_id', $value);
if($stmt->execute())
{
$res = $stmt->fetch(\PDO::FETCH_ASSOC);
$count = (int)$res['cnt'];
}
else
{
$count = 0;
}
$stmt = \b8\Database::getConnection('read')->prepare('SELECT * FROM build WHERE project_id = :project_id' . $add);
$stmt->bindValue(':project_id', $value);
if($stmt->execute())
{
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$rtn = array_map(function($item)
{
return new \PHPCI\Model\Build($item);
}, $res);
return array('items' => $rtn, 'count' => $count);
}
else
{
return array('items' => array(), 'count' => 0);
}
}
public function getByStatus($value, $limit = null, $useConnection = 'read')
{
if(is_null($value))
{
throw new \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$add = '';
if($limit)
{
$add .= ' LIMIT ' . $limit;
}
$stmt = \b8\Database::getConnection($useConnection)->prepare('SELECT COUNT(*) AS cnt FROM build WHERE status = :status' . $add);
$stmt->bindValue(':status', $value);
if($stmt->execute())
{
$res = $stmt->fetch(\PDO::FETCH_ASSOC);
$count = (int)$res['cnt'];
}
else
{
$count = 0;
}
$stmt = \b8\Database::getConnection('read')->prepare('SELECT * FROM build WHERE status = :status' . $add);
$stmt->bindValue(':status', $value);
if($stmt->execute())
{
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$rtn = array_map(function($item)
{
return new \PHPCI\Model\Build($item);
}, $res);
return array('items' => $rtn, 'count' => $count);
}
else
{
return array('items' => array(), 'count' => 0);
}
}
}

View file

@ -0,0 +1,47 @@
<?php
/**
* Project base store for table: project
*/
namespace PHPCI\Store\Base;
use b8\Store;
/**
* Project Base Store
*/
class ProjectStoreBase extends Store
{
protected $_tableName = 'project';
protected $_modelName = '\PHPCI\Model\Project';
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 \b8\Exception\HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$stmt = \b8\Database::getConnection($useConnection)->prepare('SELECT * FROM project WHERE id = :id LIMIT 1');
$stmt->bindValue(':id', $value);
if($stmt->execute())
{
if($data = $stmt->fetch(\PDO::FETCH_ASSOC))
{
return new \PHPCI\Model\Project($data);
}
}
return null;
}
}

View file

@ -0,0 +1,20 @@
<?php
/**
* Build store for table: build
*/
namespace PHPCI\Store;
require_once(APPLICATION_PATH . 'PHPCI/Store/Base/BuildStoreBase.php');
use PHPCI\Store\Base\BuildStoreBase;
/**
* Build Store
* @uses PHPCI\Store\Base\BuildStoreBase
*/
class BuildStore extends BuildStoreBase
{
// 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,20 @@
<?php
/**
* Project store for table: project
*/
namespace PHPCI\Store;
require_once(APPLICATION_PATH . 'PHPCI/Store/Base/ProjectStoreBase.php');
use PHPCI\Store\Base\ProjectStoreBase;
/**
* Project Store
* @uses PHPCI\Store\Base\ProjectStoreBase
*/
class ProjectStore extends ProjectStoreBase
{
// This class has been left blank so that you can modify it - changes in this file will not be overwritten.
}

27
PHPCI/View/Index.phtml Normal file
View file

@ -0,0 +1,27 @@
<div class="row">
<div class="span3">
<ul>
<?php foreach($projects as $project): ?>
<li><a href="/project/view/<?= $project->getId(); ?>"><?= $project->getTitle(); ?></a></li>
<?php endforeach; ?>
</ul>
</div>
<div class="span9">
<table width="100%" class="table-striped table-bordered">
<tr>
<th>Project</th>
<th>Commit</th>
<th>Branch</th>
<th>Status</th>
</tr>
<?php foreach($builds as $build): ?>
<tr>
<td><?= $build->getProject()->getTitle(); ?></th>
<td><?= $build->getCommitId(); ?></th>
<td><?= $build->getBranch(); ?></th>
<td><?= $build->getStatus(); ?></th>
</tr>
<?php endforeach; ?>
</table>
</div>
</div>

39
PHPCI/View/Layout.phtml Normal file
View file

@ -0,0 +1,39 @@
<html>
<head>
<title>PHPCI</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="/assets/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/assets/css/bootstrap-responsive.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="/assets/js/bootstrap.min.js"></script>
<style>
body
{
background: #246;
padding-top: 70px;
}
#content
{
background: #fff;
border: 10px solid #369;
padding: 10px;
}
</style>
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="/">PHPCI</a>
</div>
</div>
</div>
<div id="content" class="container">
<?= $content; ?>
</div>
</body>
</html>

BIN
assets/.DS_Store vendored Normal file

Binary file not shown.

1109
assets/css/bootstrap-responsive.css vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

6158
assets/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load diff

9
assets/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/js/.DS_Store vendored Normal file

Binary file not shown.

2276
assets/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load diff

6
assets/js/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
assets/js/stars/delete.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

View file

@ -0,0 +1,118 @@
/*
* Metadata - jQuery plugin for parsing metadata from elements
*
* Copyright (c) 2006 John Resig, Yehuda Katz, Jörn Zaefferer, Paul McLanahan
*
* Licensed under http://en.wikipedia.org/wiki/MIT_License
*
*
*/
/**
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
* in the JSON will become a property of the element itself.
*
* There are three supported types of metadata storage:
*
* attr: Inside an attribute. The name parameter indicates *which* attribute.
*
* class: Inside the class attribute, wrapped in curly braces: { }
*
* elem: Inside a child element (e.g. a script tag). The
* name parameter indicates *which* element.
*
* The metadata for an element is loaded the first time the element is accessed via jQuery.
*
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
*
* @name $.metadata.setType
*
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
* @before $.metadata.setType("class")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from the class attribute
*
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
* @before $.metadata.setType("attr", "data")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from a "data" attribute
*
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
* @before $.metadata.setType("elem", "script")
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
* @desc Reads metadata from a nested script element
*
* @param String type The encoding type
* @param String name The name of the attribute to be used to get metadata (optional)
* @cat Plugins/Metadata
* @descr Sets the type of encoding to be used when loading metadata for the first time
* @type undefined
* @see metadata()
*/
(function($) {
$.extend({
metadata : {
defaults : {
type: 'class',
name: 'metadata',
cre: /({.*})/,
single: 'metadata'
},
setType: function( type, name ){
this.defaults.type = type;
this.defaults.name = name;
},
get: function( elem, opts ){
var settings = $.extend({},this.defaults,opts);
// check for empty string in single property
if ( !settings.single.length ) settings.single = 'metadata';
var data = $.data(elem, settings.single);
// returned cached data if it already exists
if ( data ) return data;
data = "{}";
if ( settings.type == "class" ) {
var m = settings.cre.exec( elem.className );
if ( m )
data = m[1];
} else if ( settings.type == "elem" ) {
if( !elem.getElementsByTagName ) return;
var e = elem.getElementsByTagName(settings.name);
if ( e.length )
data = $.trim(e[0].innerHTML);
} else if ( elem.getAttribute != undefined ) {
var attr = elem.getAttribute( settings.name );
if ( attr )
data = attr;
}
if ( data.indexOf( '{' ) <0 )
data = "{" + data + "}";
data = eval("(" + data + ")");
$.data( elem, settings.single, data );
return data;
}
}
});
/**
* Returns the metadata object for the first member of the jQuery object.
*
* @name metadata
* @descr Returns element's metadata object
* @param Object opts An object contianing settings to override the defaults
* @type jQuery
* @cat Plugins/Metadata
*/
$.fn.metadata = function( opts ){
return $.metadata.get( this[0], opts );
};
})(jQuery);

1127
assets/js/stars/jquery.form.js Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
/* jQuery.Rating Plugin CSS - http://www.fyneworks.com/jquery/star-rating/ */
div.rating-cancel,div.star-rating{float:left;width:17px;height:15px;text-indent:-999em;cursor:pointer;display:block;background:transparent;overflow:hidden}
div.rating-cancel,div.rating-cancel a{background:url(delete.gif) no-repeat 0 -16px}
div.star-rating,div.star-rating a{background:url(star.gif) no-repeat 0 0px}
div.rating-cancel a,div.star-rating a{display:block;width:16px;height:100%;background-position:0 0px;border:0}
div.star-rating-on a{background-position:0 -16px!important}
div.star-rating-hover a{background-position:0 -32px}
/* Read Only CSS */
div.star-rating-readonly a{cursor:default !important}
/* Partial Star CSS */
div.star-rating{background:transparent!important;overflow:hidden!important}
/* END jQuery.Rating Plugin CSS */

376
assets/js/stars/jquery.rating.js Executable file
View file

@ -0,0 +1,376 @@
/*
### jQuery Star Rating Plugin v4.11 - 2013-03-14 ###
* Home: http://www.fyneworks.com/jquery/star-rating/
* Code: http://code.google.com/p/jquery-star-rating-plugin/
*
* Licensed under http://en.wikipedia.org/wiki/MIT_License
###
*/
/*# AVOID COLLISIONS #*/
;if(window.jQuery) (function($){
/*# AVOID COLLISIONS #*/
// IE6 Background Image Fix
if ((!$.support.opacity && !$.support.style)) try { document.execCommand("BackgroundImageCache", false, true)} catch(e) { };
// Thanks to http://www.visualjquery.com/rating/rating_redux.html
// plugin initialization
$.fn.rating = function(options){
if(this.length==0) return this; // quick fail
// Handle API methods
if(typeof arguments[0]=='string'){
// Perform API methods on individual elements
if(this.length>1){
var args = arguments;
return this.each(function(){
$.fn.rating.apply($(this), args);
});
};
// Invoke API method handler
$.fn.rating[arguments[0]].apply(this, $.makeArray(arguments).slice(1) || []);
// Quick exit...
return this;
};
// Initialize options for this call
var options = $.extend(
{}/* new object */,
$.fn.rating.options/* default options */,
options || {} /* just-in-time options */
);
// Allow multiple controls with the same name by making each call unique
$.fn.rating.calls++;
// loop through each matched element
this
.not('.star-rating-applied')
.addClass('star-rating-applied')
.each(function(){
// Load control parameters / find context / etc
var control, input = $(this);
var eid = (this.name || 'unnamed-rating').replace(/\[|\]/g, '_').replace(/^\_+|\_+$/g,'');
var context = $(this.form || document.body);
// FIX: http://code.google.com/p/jquery-star-rating-plugin/issues/detail?id=23
var raters = context.data('rating');
if(!raters || raters.call!=$.fn.rating.calls) raters = { count:0, call:$.fn.rating.calls };
var rater = raters[eid] || context.data('rating'+eid);
// if rater is available, verify that the control still exists
if(rater) control = rater.data('rating');
if(rater && control)//{// save a byte!
// add star to control if rater is available and the same control still exists
control.count++;
//}// save a byte!
else{
// create new control if first star or control element was removed/replaced
// Initialize options for this rater
control = $.extend(
{}/* new object */,
options || {} /* current call options */,
($.metadata? input.metadata(): ($.meta?input.data():null)) || {}, /* metadata options */
{ count:0, stars: [], inputs: [] }
);
// increment number of rating controls
control.serial = raters.count++;
// create rating element
rater = $('<span class="star-rating-control"/>');
input.before(rater);
// Mark element for initialization (once all stars are ready)
rater.addClass('rating-to-be-drawn');
// Accept readOnly setting from 'disabled' property
if(input.attr('disabled') || input.hasClass('disabled')) control.readOnly = true;
// Accept required setting from class property (class='required')
if(input.hasClass('required')) control.required = true;
// Create 'cancel' button
rater.append(
control.cancel = $('<div class="rating-cancel"><a title="' + control.cancel + '">' + control.cancelValue + '</a></div>')
.on('mouseover',function(){
$(this).rating('drain');
$(this).addClass('star-rating-hover');
//$(this).rating('focus');
})
.on('mouseout',function(){
$(this).rating('draw');
$(this).removeClass('star-rating-hover');
//$(this).rating('blur');
})
.on('click',function(){
$(this).rating('select');
})
.data('rating', control)
);
}; // first element of group
// insert rating star (thanks Jan Fanslau rev125 for blind support https://code.google.com/p/jquery-star-rating-plugin/issues/detail?id=125)
var star = $('<div role="text" aria-label="'+ this.title +'" class="star-rating rater-'+ control.serial +'"><a title="' + (this.title || this.value) + '">' + this.value + '</a></div>');
rater.append(star);
// inherit attributes from input element
if(this.id) star.attr('id', this.id);
if(this.className) star.addClass(this.className);
// Half-stars?
if(control.half) control.split = 2;
// Prepare division control
if(typeof control.split=='number' && control.split>0){
var stw = ($.fn.width ? star.width() : 0) || control.starWidth;
var spi = (control.count % control.split), spw = Math.floor(stw/control.split);
star
// restrict star's width and hide overflow (already in CSS)
.width(spw)
// move the star left by using a negative margin
// this is work-around to IE's stupid box model (position:relative doesn't work)
.find('a').css({ 'margin-left':'-'+ (spi*spw) +'px' })
};
// readOnly?
if(control.readOnly)//{ //save a byte!
// Mark star as readOnly so user can customize display
star.addClass('star-rating-readonly');
//} //save a byte!
else//{ //save a byte!
// Enable hover css effects
star.addClass('star-rating-live')
// Attach mouse events
.on('mouseover',function(){
$(this).rating('fill');
$(this).rating('focus');
})
.on('mouseout',function(){
$(this).rating('draw');
$(this).rating('blur');
})
.on('click',function(){
$(this).rating('select');
})
;
//}; //save a byte!
// set current selection
if(this.checked) control.current = star;
// set current select for links
if(this.nodeName=="A"){
if($(this).hasClass('selected'))
control.current = star;
};
// hide input element
input.hide();
// backward compatibility, form element to plugin
input.on('change.rating',function(event){
if(event.selfTriggered) return false;
$(this).rating('select');
});
// attach reference to star to input element and vice-versa
star.data('rating.input', input.data('rating.star', star));
// store control information in form (or body when form not available)
control.stars[control.stars.length] = star[0];
control.inputs[control.inputs.length] = input[0];
control.rater = raters[eid] = rater;
control.context = context;
input.data('rating', control);
rater.data('rating', control);
star.data('rating', control);
context.data('rating', raters);
context.data('rating'+eid, rater); // required for ajax forms
}); // each element
// Initialize ratings (first draw)
$('.rating-to-be-drawn').rating('draw').removeClass('rating-to-be-drawn');
return this; // don't break the chain...
};
/*--------------------------------------------------------*/
/*
### Core functionality and API ###
*/
$.extend($.fn.rating, {
// Used to append a unique serial number to internal control ID
// each time the plugin is invoked so same name controls can co-exist
calls: 0,
focus: function(){
var control = this.data('rating'); if(!control) return this;
if(!control.focus) return this; // quick fail if not required
// find data for event
var input = $(this).data('rating.input') || $( this.tagName=='INPUT' ? this : null );
// focus handler, as requested by focusdigital.co.uk
if(control.focus) control.focus.apply(input[0], [input.val(), $('a', input.data('rating.star'))[0]]);
}, // $.fn.rating.focus
blur: function(){
var control = this.data('rating'); if(!control) return this;
if(!control.blur) return this; // quick fail if not required
// find data for event
var input = $(this).data('rating.input') || $( this.tagName=='INPUT' ? this : null );
// blur handler, as requested by focusdigital.co.uk
if(control.blur) control.blur.apply(input[0], [input.val(), $('a', input.data('rating.star'))[0]]);
}, // $.fn.rating.blur
fill: function(){ // fill to the current mouse position.
var control = this.data('rating'); if(!control) return this;
// do not execute when control is in read-only mode
if(control.readOnly) return;
// Reset all stars and highlight them up to this element
this.rating('drain');
this.prevAll().addBack().filter('.rater-'+ control.serial).addClass('star-rating-hover');
},// $.fn.rating.fill
drain: function() { // drain all the stars.
var control = this.data('rating'); if(!control) return this;
// do not execute when control is in read-only mode
if(control.readOnly) return;
// Reset all stars
control.rater.children().filter('.rater-'+ control.serial).removeClass('star-rating-on').removeClass('star-rating-hover');
},// $.fn.rating.drain
draw: function(){ // set value and stars to reflect current selection
var control = this.data('rating'); if(!control) return this;
// Clear all stars
this.rating('drain');
// Set control value
var current = $( control.current );//? control.current.data('rating.input') : null );
var starson = current.length ? current.prevAll().addBack().filter('.rater-'+ control.serial) : null;
if(starson) starson.addClass('star-rating-on');
// Show/hide 'cancel' button
control.cancel[control.readOnly || control.required?'hide':'show']();
// Add/remove read-only classes to remove hand pointer
this.siblings()[control.readOnly?'addClass':'removeClass']('star-rating-readonly');
},// $.fn.rating.draw
select: function(value,wantCallBack){ // select a value
var control = this.data('rating'); if(!control) return this;
// do not execute when control is in read-only mode
if(control.readOnly) return;
// clear selection
control.current = null;
// programmatically (based on user input)
if(typeof value!='undefined' || this.length>1){
// select by index (0 based)
if(typeof value=='number')
return $(control.stars[value]).rating('select',undefined,wantCallBack);
// select by literal value (must be passed as a string
if(typeof value=='string'){
//return
$.each(control.stars, function(){
//console.log($(this).data('rating.input'), $(this).data('rating.input').val(), value, $(this).data('rating.input').val()==value?'BINGO!':'');
if($(this).data('rating.input').val()==value) $(this).rating('select',undefined,wantCallBack);
});
// don't break the chain
return this;
};
}
else{
control.current = this[0].tagName=='INPUT' ?
this.data('rating.star') :
(this.is('.rater-'+ control.serial) ? this : null);
};
// Update rating control state
this.data('rating', control);
// Update display
this.rating('draw');
// find current input and its sibblings
var current = $( control.current ? control.current.data('rating.input') : null );
var lastipt = $( control.inputs ).filter(':checked');
var deadipt = $( control.inputs ).not(current);
// check and uncheck elements as required
deadipt.prop('checked',false);//.removeAttr('checked');
current.prop('checked',true);//.attr('checked','checked');
// trigger change on current or last selected input
$(current.length? current : lastipt ).trigger({ type:'change', selfTriggered:true });
// click callback, as requested here: http://plugins.jquery.com/node/1655
if((wantCallBack || wantCallBack == undefined) && control.callback) control.callback.apply(current[0], [current.val(), $('a', control.current)[0]]);// callback event
// don't break the chain
return this;
},// $.fn.rating.select
readOnly: function(toggle, disable){ // make the control read-only (still submits value)
var control = this.data('rating'); if(!control) return this;
// setread-only status
control.readOnly = toggle || toggle==undefined ? true : false;
// enable/disable control value submission
if(disable) $(control.inputs).attr("disabled", "disabled");
else $(control.inputs).removeAttr("disabled");
// Update rating control state
this.data('rating', control);
// Update display
this.rating('draw');
},// $.fn.rating.readOnly
disable: function(){ // make read-only and never submit value
this.rating('readOnly', true, true);
},// $.fn.rating.disable
enable: function(){ // make read/write and submit value
this.rating('readOnly', false, false);
}// $.fn.rating.select
});
/*--------------------------------------------------------*/
/*
### Default Settings ###
eg.: You can override default control like this:
$.fn.rating.options.cancel = 'Clear';
*/
$.fn.rating.options = { //$.extend($.fn.rating, { options: {
cancel: 'Cancel Rating', // advisory title for the 'cancel' link
cancelValue: '', // value to submit when user click the 'cancel' link
split: 0, // split the star into how many parts?
// Width of star image in case the plugin can't work it out. This can happen if
// the jQuery.dimensions plugin is not available OR the image is hidden at installation
starWidth: 16//,
//NB.: These don't need to be pre-defined (can be undefined/null) so let's save some code!
//half: false, // just a shortcut to control.split = 2
//required: false, // disables the 'cancel' button so user can only select one of the specified values
//readOnly: false, // disable rating plugin interaction/ values cannot be.one('change', //focus: function(){}, // executed when stars are focused
//blur: function(){}, // executed when stars are focused
//callback: function(){}, // executed when a star is clicked
}; //} });
/*--------------------------------------------------------*/
// auto-initialize plugin
$(function(){
$('input[type=radio].star').rating();
});
/*# AVOID COLLISIONS #*/
})(jQuery);
/*# AVOID COLLISIONS #*/

View file

@ -0,0 +1,9 @@
/*
### jQuery Star Rating Plugin v4.11 - 2013-03-14 ###
* Home: http://www.fyneworks.com/jquery/star-rating/
* Code: http://code.google.com/p/jquery-star-rating-plugin/
*
* Licensed under http://en.wikipedia.org/wiki/MIT_License
###
*/
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';5(1W.1C)(8($){5((!$.1s.1V&&!$.1s.1U))2d{1j.1X("1T",C,s)}1R(e){};$.o.4=8(j){5(3.u==0)9 3;5(M V[0]==\'1m\'){5(3.u>1){7 k=V;9 3.18(8(){$.o.4.K($(3),k)})};$.o.4[V[0]].K(3,$.27(V).26(1)||[]);9 3};7 j=$.1b({},$.o.4.1w,j||{});$.o.4.P++;3.1y(\'.l-4-1g\').p(\'l-4-1g\').18(8(){7 b,m=$(3);7 c=(3.2g||\'28-4\').1f(/\\[|\\]/g,\'Y\').1f(/^\\Y+|\\Y+$/g,\'\');7 d=$(3.2h||1j.1H);7 e=d.6(\'4\');5(!e||e.1o!=$.o.4.P)e={E:0,1o:$.o.4.P};7 f=e[c]||d.6(\'4\'+c);5(f)b=f.6(\'4\');5(f&&b)b.E++;R{b=$.1b({},j||{},($.1d?m.1d():($.25?m.6():w))||{},{E:0,L:[],v:[]});b.z=e.E++;f=$(\'<1G 13="l-4-1I"/>\');m.1J(f);f.p(\'4-12-11-10\');5(m.Z(\'G\')||m.14(\'G\'))b.n=s;5(m.14(\'1c\'))b.1c=s;f.1r(b.D=$(\'<W 13="4-D"><a U="\'+b.D+\'">\'+b.1B+\'</a></W>\').q(\'1e\',8(){$(3).4(\'N\');$(3).p(\'l-4-T\')}).q(\'1h\',8(){$(3).4(\'x\');$(3).I(\'l-4-T\')}).q(\'1i\',8(){$(3).4(\'y\')}).6(\'4\',b))};7 g=$(\'<W 20="21" 22-24="\'+3.U+\'" 13="l-4 t-\'+b.z+\'"><a U="\'+(3.U||3.1k)+\'">\'+3.1k+\'</a></W>\');f.1r(g);5(3.X)g.Z(\'X\',3.X);5(3.1x)g.p(3.1x);5(b.29)b.B=2;5(M b.B==\'1l\'&&b.B>0){7 h=($.o.15?g.15():0)||b.1n;7 i=(b.E%b.B),17=1K.1L(h/b.B);g.15(17).1M(\'a\').1N({\'1O-1P\':\'-\'+(i*17)+\'1Q\'})};5(b.n)g.p(\'l-4-1p\');R g.p(\'l-4-1S\').q(\'1e\',8(){$(3).4(\'1q\');$(3).4(\'J\')}).q(\'1h\',8(){$(3).4(\'x\');$(3).4(\'H\')}).q(\'1i\',8(){$(3).4(\'y\')});5(3.S)b.r=g;5(3.1Y=="A"){5($(3).14(\'1Z\'))b.r=g};m.1t();m.q(\'1u.4\',8(a){5(a.1v)9 C;$(3).4(\'y\')});g.6(\'4.m\',m.6(\'4.l\',g));b.L[b.L.u]=g[0];b.v[b.v.u]=m[0];b.t=e[c]=f;b.23=d;m.6(\'4\',b);f.6(\'4\',b);g.6(\'4\',b);d.6(\'4\',e);d.6(\'4\'+c,f)});$(\'.4-12-11-10\').4(\'x\').I(\'4-12-11-10\');9 3};$.1b($.o.4,{P:0,J:8(){7 a=3.6(\'4\');5(!a)9 3;5(!a.J)9 3;7 b=$(3).6(\'4.m\')||$(3.19==\'1a\'?3:w);5(a.J)a.J.K(b[0],[b.Q(),$(\'a\',b.6(\'4.l\'))[0]])},H:8(){7 a=3.6(\'4\');5(!a)9 3;5(!a.H)9 3;7 b=$(3).6(\'4.m\')||$(3.19==\'1a\'?3:w);5(a.H)a.H.K(b[0],[b.Q(),$(\'a\',b.6(\'4.l\'))[0]])},1q:8(){7 a=3.6(\'4\');5(!a)9 3;5(a.n)9;3.4(\'N\');3.1z().1A().O(\'.t-\'+a.z).p(\'l-4-T\')},N:8(){7 a=3.6(\'4\');5(!a)9 3;5(a.n)9;a.t.2a().O(\'.t-\'+a.z).I(\'l-4-q\').I(\'l-4-T\')},x:8(){7 a=3.6(\'4\');5(!a)9 3;3.4(\'N\');7 b=$(a.r);7 c=b.u?b.1z().1A().O(\'.t-\'+a.z):w;5(c)c.p(\'l-4-q\');a.D[a.n||a.1c?\'1t\':\'2b\']();3.2c()[a.n?\'p\':\'I\'](\'l-4-1p\')},y:8(a,b){7 c=3.6(\'4\');5(!c)9 3;5(c.n)9;c.r=w;5(M a!=\'F\'||3.u>1){5(M a==\'1l\')9 $(c.L[a]).4(\'y\',F,b);5(M a==\'1m\'){$.18(c.L,8(){5($(3).6(\'4.m\').Q()==a)$(3).4(\'y\',F,b)});9 3}}R{c.r=3[0].19==\'1a\'?3.6(\'4.l\'):(3.2e(\'.t-\'+c.z)?3:w)};3.6(\'4\',c);3.4(\'x\');7 d=$(c.r?c.r.6(\'4.m\'):w);7 e=$(c.v).O(\':S\');7 f=$(c.v).1y(d);f.1D(\'S\',C);d.1D(\'S\',s);$(d.u?d:e).2f({1E:\'1u\',1v:s});5((b||b==F)&&c.1F)c.1F.K(d[0],[d.Q(),$(\'a\',c.r)[0]]);9 3},n:8(a,b){7 c=3.6(\'4\');5(!c)9 3;c.n=a||a==F?s:C;5(b)$(c.v).Z("G","G");R $(c.v).2i("G");3.6(\'4\',c);3.4(\'x\')},2j:8(){3.4(\'n\',s,s)},2k:8(){3.4(\'n\',C,C)}});$.o.4.1w={D:\'2l 2m\',1B:\'\',B:0,1n:16};$(8(){$(\'m[1E=2n].l\').4()})})(1C);',62,148,'|||this|rating|if|data|var|function|return||||||||||||star|input|readOnly|fn|addClass|on|current|true|rater|length|inputs|null|draw|select|serial||split|false|cancel|count|undefined|disabled|blur|removeClass|focus|apply|stars|typeof|drain|filter|calls|val|else|checked|hover|title|arguments|div|id|_|attr|drawn|be|to|class|hasClass|width||spw|each|tagName|INPUT|extend|required|metadata|mouseover|replace|applied|mouseout|click|document|value|number|string|starWidth|call|readonly|fill|append|support|hide|change|selfTriggered|options|className|not|prevAll|addBack|cancelValue|jQuery|prop|type|callback|span|body|control|before|Math|floor|find|css|margin|left|px|catch|live|BackgroundImageCache|style|opacity|window|execCommand|nodeName|selected|role|text|aria|context|label|meta|slice|makeArray|unnamed|half|children|show|siblings|try|is|trigger|name|form|removeAttr|disable|enable|Cancel|Rating|radio'.split('|'),0,{}))

BIN
assets/js/stars/star.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

28
bootstrap.php Normal file
View file

@ -0,0 +1,28 @@
<?php
spl_autoload_register(function ($class)
{
$file = str_replace(array('\\', '_'), '/', $class);
$file .= '.php';
if(substr($file, 0, 1) == '/')
{
$file = substr($file, 1);
}
if(is_file(dirname(__FILE__) . '/' . $file))
{
include(dirname(__FILE__) . '/' . $file);
return;
}
}, true, true);
define('APPLICATION_PATH', dirname(__FILE__) . '/');
require_once('vendor/autoload.php');
require_once('config.php');
b8\Registry::getInstance()->set('app_namespace', 'PHPCI');
b8\Registry::getInstance()->set('DefaultController', 'Index');
b8\Registry::getInstance()->set('ViewPath', dirname(__FILE__) . '/PHPCI/View/');

15
composer.json Normal file
View file

@ -0,0 +1,15 @@
{
"name": "block8/phpci",
"description": "Simple continuous integration for PHP projects.",
"authors": [
{
"name": "Dan Cryer",
"email": "dan.cryer@block8.co.uk"
}
],
"require": {
"block8/b8framework": "dev-master"
}
}

15
cron.php Normal file
View file

@ -0,0 +1,15 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'on');
require_once('bootstrap.php');
$store = b8\Store\Factory::getStore('Build');
$result = $store->getByStatus(0);
foreach($result['items'] as $build)
{
$builder = new PHPCI\Builder($build);
$builder->execute();
}

7
generate.php Normal file
View file

@ -0,0 +1,7 @@
<?php
require_once('bootstrap.php');
$gen = new b8\Database\CodeGenerator(b8\Database::getConnection(), 'PHPCI', './PHPCI/');
$gen->generateModels();
$gen->generateStores();

9
index.php Normal file
View file

@ -0,0 +1,9 @@
<?php
error_reporting(E_ALL & ~E_NOTICE);
ini_set('display_errors', 'on');
require_once('bootstrap.php');
$fc = new PHPCI\Application();
print $fc->handleRequest();