diff --git a/PHPCI/Command/CreateAdminCommand.php b/PHPCI/Command/CreateAdminCommand.php
index 30d800b1..fc40c307 100644
--- a/PHPCI/Command/CreateAdminCommand.php
+++ b/PHPCI/Command/CreateAdminCommand.php
@@ -9,6 +9,7 @@
namespace PHPCI\Command;
+use PHPCI\Service\UserService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -37,7 +38,9 @@ class CreateAdminCommand extends Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
-
+ $userStore = Factory::getStore('User');
+ $userService = new UserService($userStore);
+
require(PHPCI_DIR . 'bootstrap.php');
// Try to create a user account:
@@ -51,15 +54,7 @@ class CreateAdminCommand extends Command
$adminName = $this->ask('Admin name: ');
try {
- $user = new \PHPCI\Model\User();
- $user->setEmail($adminEmail);
- $user->setName($adminName);
- $user->setIsAdmin(1);
- $user->setHash(password_hash($adminPass, PASSWORD_DEFAULT));
-
- $store = \b8\Store\Factory::getStore('User');
- $store->save($user);
-
+ $userService->createUser($adminName, $adminEmail, $adminPass, 1);
print 'User account created!' . PHP_EOL;
} catch (\Exception $ex) {
print 'There was a problem creating your account. :(' . PHP_EOL;
diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php
index 43495dc0..e4af4722 100644
--- a/PHPCI/Command/InstallCommand.php
+++ b/PHPCI/Command/InstallCommand.php
@@ -21,7 +21,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Helper\DialogHelper;
-use PHPCI\Model\User;
+use PHPCI\Service\UserService;
/**
@@ -236,16 +236,11 @@ class InstallCommand extends Command
$adminName = $dialog->ask($output, 'Enter your name: ');
try {
- $user = new User();
- $user->setEmail($adminEmail);
- $user->setName($adminName);
- $user->setIsAdmin(1);
- $user->setHash(password_hash($adminPass, PASSWORD_DEFAULT));
-
$this->reloadConfig();
- $store = Factory::getStore('User');
- $store->save($user);
+ $userStore = Factory::getStore('User');
+ $userService = new UserService($userStore);
+ $userService->createUser($adminName, $adminEmail, $adminPass, 1);
$output->writeln('User account created!');
} catch (\Exception $ex) {
diff --git a/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php
index 145236d5..fb9957cb 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\Service\BuildService;
/**
* Build Controller - Allows users to run and view builds.
@@ -26,10 +27,16 @@ class BuildController extends \PHPCI\Controller
* @var \PHPCI\Store\BuildStore
*/
protected $buildStore;
+
+ /**
+ * @var \PHPCI\Service\BuildService
+ */
+ protected $buildService;
public function init()
{
- $this->buildStore = b8\Store\Factory::getStore('Build');
+ $this->buildStore = b8\Store\Factory::getStore('Build');
+ $this->buildService = new BuildService($this->buildStore);
}
/**
@@ -123,17 +130,7 @@ class BuildController extends \PHPCI\Controller
throw new NotFoundException('Build with ID: ' . $buildId . ' does not exist.');
}
- $build = new Build();
- $build->setProjectId($copy->getProjectId());
- $build->setCommitId($copy->getCommitId());
- $build->setStatus(Build::STATUS_NEW);
- $build->setBranch($copy->getBranch());
- $build->setCreated(new \DateTime());
- $build->setCommitterEmail($copy->getCommitterEmail());
- $build->setCommitMessage($copy->getCommitMessage());
- $build->setExtra(json_encode($copy->getExtra()));
-
- $build = $this->buildStore->save($build);
+ $build = $this->buildService->createDuplicateBuild($copy);
header('Location: '.PHPCI_URL.'build/view/' . $build->getId());
exit;
@@ -154,7 +151,7 @@ class BuildController extends \PHPCI\Controller
throw new NotFoundException('Build with ID: ' . $buildId . ' does not exist.');
}
- $this->buildStore->delete($build);
+ $this->buildService->deleteBuild($build);
header('Location: '.PHPCI_URL.'project/view/' . $build->getProjectId());
exit;
diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php
index 38986c59..56dc9ed0 100644
--- a/PHPCI/Controller/ProjectController.php
+++ b/PHPCI/Controller/ProjectController.php
@@ -20,6 +20,8 @@ use PHPCI\Helper\Github;
use PHPCI\Helper\SshKey;
use PHPCI\Model\Build;
use PHPCI\Model\Project;
+use PHPCI\Service\BuildService;
+use PHPCI\Service\ProjectService;
/**
* Project Controller - Allows users to create, edit and view projects.
@@ -29,20 +31,32 @@ use PHPCI\Model\Project;
*/
class ProjectController extends \PHPCI\Controller
{
+ /**
+ * @var \PHPCI\Store\ProjectStore
+ */
+ protected $projectStore;
+
+ /**
+ * @var \PHPCI\Service\ProjectService
+ */
+ protected $projectService;
+
/**
* @var \PHPCI\Store\BuildStore
*/
protected $buildStore;
/**
- * @var \PHPCI\Store\ProjectStore
+ * @var \PHPCI\Service\BuildService
*/
- protected $projectStore;
+ protected $buildService;
public function init()
{
$this->buildStore = Store\Factory::getStore('Build');
$this->projectStore = Store\Factory::getStore('Project');
+ $this->projectService = new ProjectService($this->projectStore);
+ $this->buildService = new BuildService($this->buildStore);
}
/**
@@ -88,15 +102,7 @@ class ProjectController extends \PHPCI\Controller
throw new NotFoundException('Project with id: ' . $projectId . ' not found');
}
- $build = new Build();
- $build->setProjectId($projectId);
- $build->setCommitId('Manual');
- $build->setStatus(Build::STATUS_NEW);
- $build->setBranch($project->getBranch());
- $build->setCreated(new \DateTime());
- $build->setCommitterEmail($_SESSION['user']->getEmail());
-
- $build = $this->buildStore->save($build);
+ $build = $this->buildService->createBuild($project, null, null, $_SESSION['user']->getEmail());
header('Location: '.PHPCI_URL.'build/view/' . $build->getId());
exit;
@@ -112,7 +118,7 @@ class ProjectController extends \PHPCI\Controller
}
$project = $this->projectStore->getById($projectId);
- $this->projectStore->delete($project);
+ $this->projectService->deleteProject($project);
header('Location: '.PHPCI_URL);
exit;
@@ -179,35 +185,24 @@ class ProjectController extends \PHPCI\Controller
return $view->render();
} else {
- return $this->addProject($form);
+ $title = $this->getParam('title', 'New Project');
+ $reference = $this->getParam('reference', null);
+ $type = $this->getParam('type', null);
+
+ $options = array(
+ 'ssh_private_key' => $this->getParam('key', null),
+ 'ssh_public_key' => $this->getParam('pubkey', null),
+ 'build_config' => $this->getParam('build_config', null),
+ 'allow_public_status' => $this->getParam('allow_public_status', 0),
+ 'branch' => $this->getParam('branch', null),
+ );
+
+ $project = $this->projectService->createProject($title, $type, $reference, $options);
+ header('Location: '.PHPCI_URL.'project/view/' . $project->getId());
+ die;
}
}
- protected function addProject(Form $form)
- {
- $values = $form->getValues();
-
- $matches = array();
- if ($values['type'] == "gitlab" && preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches)) {
- $info = array();
- $info['user'] = $matches[1];
- $info['domain'] = $matches[2];
- $values['access_information'] = serialize($info);
- $values['reference'] = $matches[3]."/".$matches[4];
- }
-
- $values['ssh_private_key'] = $values['key'];
- $values['ssh_public_key'] = $values['pubkey'];
-
- $project = new Project();
- $project->setValues($values);
-
- $project = $this->projectStore->save($project);
-
- header('Location: '.PHPCI_URL.'project/view/' . $project->getId());
- die;
- }
-
/**
* Edit a project. Handles both the form and processing.
*/
@@ -252,21 +247,19 @@ class ProjectController extends \PHPCI\Controller
return $view->render();
}
- $values = $form->getValues();
- $values['ssh_private_key'] = $values['key'];
- $values['ssh_public_key'] = $values['pubkey'];
+ $title = $this->getParam('title', 'New Project');
+ $reference = $this->getParam('reference', null);
+ $type = $this->getParam('type', null);
- if ($values['type'] == "gitlab") {
- preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches);
- $info = array();
- $info["user"] = $matches[1];
- $info["domain"] = $matches[2];
- $values['access_information'] = serialize($info);
- $values['reference'] = $matches[3] . "/" . $matches[4];
- }
+ $options = array(
+ 'ssh_private_key' => $this->getParam('key', null),
+ 'ssh_public_key' => $this->getParam('pubkey', null),
+ 'build_config' => $this->getParam('build_config', null),
+ 'allow_public_status' => $this->getParam('allow_public_status', 0),
+ 'branch' => $this->getParam('branch', null),
+ );
- $project->setValues($values);
- $project = $this->projectStore->save($project);
+ $project = $this->projectService->updateProject($project, $title, $type, $reference, $options);
header('Location: '.PHPCI_URL.'project/view/' . $project->getId());
die;
@@ -337,7 +330,7 @@ class ProjectController extends \PHPCI\Controller
$field = Form\Element\Checkbox::create('allow_public_status', $label, false);
$field->setContainerClass('form-group');
$field->setCheckedValue(1);
- $field->setValue(1);
+ $field->setValue(0);
$form->addField($field);
$field = new Form\Element\Submit();
diff --git a/PHPCI/Controller/SettingsController.php b/PHPCI/Controller/SettingsController.php
index 51edf749..34eac9be 100644
--- a/PHPCI/Controller/SettingsController.php
+++ b/PHPCI/Controller/SettingsController.php
@@ -81,6 +81,8 @@ class SettingsController extends Controller
public function email()
{
$this->settings['phpci']['email_settings'] = $this->getParams();
+ $this->settings['phpci']['email_settings']['smtp_encryption'] = $this->getParam('smtp_encryption', 0);
+
$error = $this->storeSettings();
if ($error) {
diff --git a/PHPCI/Controller/UserController.php b/PHPCI/Controller/UserController.php
index 86fa8662..2a675e9d 100644
--- a/PHPCI/Controller/UserController.php
+++ b/PHPCI/Controller/UserController.php
@@ -15,6 +15,7 @@ use b8\Exception\HttpException\NotFoundException;
use b8\Form;
use PHPCI\Controller;
use PHPCI\Model\User;
+use PHPCI\Service\UserService;
/**
* User Controller - Allows an administrator to view, add, edit and delete users.
@@ -29,9 +30,15 @@ class UserController extends Controller
*/
protected $userStore;
+ /**
+ * @var \PHPCI\Service\UserService
+ */
+ protected $userService;
+
public function init()
{
$this->userStore = b8\Store\Factory::getStore('User');
+ $this->userService = new UserService($this->userStore);
}
/**
@@ -53,16 +60,11 @@ class UserController extends Controller
$values = $user->getDataArray();
if ($this->request->getMethod() == 'POST') {
- $values = $this->getParams();
+ $name = $this->getParam('name', null);
+ $email = $this->getParam('email', null);
+ $password = $this->getParam('password', null);
- if (!empty($values['password'])) {
- $values['hash'] = password_hash($values['password'], PASSWORD_DEFAULT);
- }
-
- $this->view->updated = true;
-
- $user->setValues($values);
- $_SESSION['user'] = $this->userStore->save($user);
+ $_SESSION['user'] = $this->userService->updateUser($name, $email, $password);
}
$form = new Form();
@@ -132,13 +134,13 @@ class UserController extends Controller
return $view->render();
}
- $values = $form->getValues();
- $values['hash'] = password_hash($values['password'], PASSWORD_DEFAULT);
- $user = new User();
- $user->setValues($values);
+ $name = $this->getParam('name', null);
+ $email = $this->getParam('email', null);
+ $password = $this->getParam('password', null);
+ $isAdmin = (int)$this->getParam('is_admin', 0);
- $user = $this->userStore->save($user);
+ $this->userService->createUser($name, $email, $password, $isAdmin);
header('Location: '.PHPCI_URL.'user');
die;
@@ -172,18 +174,12 @@ class UserController extends Controller
return $view->render();
}
- if (!empty($values['password'])) {
- $values['hash'] = password_hash($values['password'], PASSWORD_DEFAULT);
- }
+ $name = $this->getParam('name', null);
+ $email = $this->getParam('email', null);
+ $password = $this->getParam('password', null);
+ $isAdmin = (int)$this->getParam('is_admin', 0);
- $user->setValues($values);
-
- $isAdmin = $this->getParam('is_admin');
- if (empty($isAdmin)) {
- $user->setIsAdmin(0);
- }
-
- $this->userStore->save($user);
+ $this->userService->updateUser($user, $name, $email, $password, $isAdmin);
header('Location: '.PHPCI_URL.'user');
die;
@@ -258,7 +254,7 @@ class UserController extends Controller
throw new NotFoundException('User with ID: ' . $userId . ' does not exist.');
}
- $this->userStore->delete($user);
+ $this->userService->deleteUser($user);
header('Location: '.PHPCI_URL.'user');
die;
diff --git a/PHPCI/Controller/WebhookController.php b/PHPCI/Controller/WebhookController.php
index e95a5597..4d4501ed 100644
--- a/PHPCI/Controller/WebhookController.php
+++ b/PHPCI/Controller/WebhookController.php
@@ -13,6 +13,7 @@ use b8;
use b8\Store;
use PHPCI\BuildFactory;
use PHPCI\Model\Build;
+use PHPCI\Service\BuildService;
/**
* Webhook Controller - Processes webhook pings from BitBucket, Github, Gitlab, etc.
@@ -29,9 +30,21 @@ class WebhookController extends \PHPCI\Controller
*/
protected $buildStore;
+ /**
+ * @var \PHPCI\Store\ProjectStore
+ */
+ protected $projectStore;
+
+ /**
+ * @var \PHPCI\Service\BuildService
+ */
+ protected $buildService;
+
public function init()
{
$this->buildStore = Store\Factory::getStore('Build');
+ $this->projectStore = Store\Factory::getStore('Project');
+ $this->buildService = new BuildService($this->buildStore);
}
/**
@@ -238,22 +251,15 @@ class WebhookController extends \PHPCI\Controller
return true;
}
- // If not, create a new build job for it:
- $build = new Build();
- $build->setProjectId($projectId);
- $build->setCommitId($commitId);
- $build->setStatus(Build::STATUS_NEW);
- $build->setLog('');
- $build->setCreated(new \DateTime());
- $build->setBranch($branch);
- $build->setCommitterEmail($committer);
- $build->setCommitMessage($commitMessage);
+ $project = $this->projectStore->getById($projectId);
- if (!is_null($extra)) {
- $build->setExtra(json_encode($extra));
+ if (empty($project)) {
+ throw new \Exception('Project does not exist:' . $projectId);
}
- $build = BuildFactory::getBuild($this->buildStore->save($build));
+ // If not, create a new build job for it:
+ $build = $this->buildService->createBuild($project, $commitId, $branch, $committer, $commitMessage, $extra);
+ $build = BuildFactory::getBuild($build);
// Send a status postback if the build type provides one:
$build->sendStatusPostback();
diff --git a/PHPCI/Helper/BaseCommandExecutor.php b/PHPCI/Helper/BaseCommandExecutor.php
index 554d9083..b1cdbc26 100644
--- a/PHPCI/Helper/BaseCommandExecutor.php
+++ b/PHPCI/Helper/BaseCommandExecutor.php
@@ -30,6 +30,7 @@ abstract class BaseCommandExecutor implements CommandExecutor
protected $verbose;
protected $lastOutput;
+ protected $lastError;
public $logExecOutput = true;
@@ -78,16 +79,40 @@ abstract class BaseCommandExecutor implements CommandExecutor
}
$status = 0;
- exec($command, $this->lastOutput, $status);
+ $descriptorSpec = array(
+ 0 => array("pipe", "r"), // stdin
+ 1 => array("pipe", "w"), // stdout
+ 2 => array("pipe", "w"), // stderr
+ );
- foreach ($this->lastOutput as &$lastOutput) {
- $lastOutput = trim($lastOutput, '"');
+ $pipes = array();
+
+ $process = proc_open($command, $descriptorSpec, $pipes, dirname($this->buildPath), null);
+
+ if (is_resource($process)) {
+ fclose($pipes[0]);
+
+ $this->lastOutput = stream_get_contents($pipes[1]);
+ $this->lastError = stream_get_contents($pipes[2]);
+
+ fclose($pipes[1]);
+ fclose($pipes[2]);
+
+ $status = proc_close($process);
}
- if ($this->logExecOutput && !empty($this->lastOutput) && ($this->verbose|| $status != 0)) {
+ $this->lastOutput = array_filter(explode(PHP_EOL, $this->lastOutput));
+
+ $shouldOutput = ($this->logExecOutput && ($this->verbose || $status != 0));
+
+ if ($shouldOutput && !empty($this->lastOutput)) {
$this->logger->log($this->lastOutput);
}
+ if (!empty($this->lastError)) {
+ $this->logger->log("\033[0;31m" . $this->lastError . "\033[0m", LogLevel::ERROR);
+ }
+
$rtn = false;
if ($status == 0) {
@@ -105,6 +130,14 @@ abstract class BaseCommandExecutor implements CommandExecutor
return implode(PHP_EOL, $this->lastOutput);
}
+ /**
+ * Returns the stderr output from the last command run.
+ */
+ public function getLastError()
+ {
+ return $this->lastError;
+ }
+
/**
* Find a binary required by a plugin.
* @param string $binary
@@ -170,8 +203,11 @@ abstract class BaseCommandExecutor implements CommandExecutor
$composer = $path.'/composer.json';
if (is_file($composer)) {
$json = json_decode(file_get_contents($composer));
+
if (isset($json->config->{"bin-dir"})) {
return $path.'/'.$json->config->{"bin-dir"};
+ } elseif (is_dir($path . '/vendor/bin')) {
+ return $path . '/vendor/bin';
}
}
}
diff --git a/PHPCI/Helper/MailerFactory.php b/PHPCI/Helper/MailerFactory.php
index 81d37831..b0ec4860 100644
--- a/PHPCI/Helper/MailerFactory.php
+++ b/PHPCI/Helper/MailerFactory.php
@@ -40,7 +40,7 @@ class MailerFactory
return \Swift_Mailer::newInstance($transport);
}
- protected function getMailConfig($configName)
+ public function getMailConfig($configName)
{
if (isset($this->emailConfig[$configName]) && $this->emailConfig[$configName] != "") {
return $this->emailConfig[$configName];
diff --git a/PHPCI/Helper/SshKey.php b/PHPCI/Helper/SshKey.php
index 087b0ed3..f36940ca 100644
--- a/PHPCI/Helper/SshKey.php
+++ b/PHPCI/Helper/SshKey.php
@@ -29,7 +29,7 @@ class SshKey
mkdir($tempPath);
}
- $return = array();
+ $return = array('private_key' => '', 'public_key' => '');
if ($this->canGenerateKeys()) {
shell_exec('ssh-keygen -q -t rsa -b 2048 -f '.$keyFile.' -N "" -C "deploy@phpci"');
@@ -37,15 +37,13 @@ class SshKey
$pub = file_get_contents($keyFile . '.pub');
$prv = file_get_contents($keyFile);
- if (empty($pub)) {
- $pub = '';
+ if (!empty($pub)) {
+ $return['public_key'] = $pub;
}
- if (empty($prv)) {
- $prv = '';
+ if (!empty($prv)) {
+ $return['private_key'] = $prv;
}
-
- $return = array('private_key' => $prv, 'public_key' => $pub);
}
return $return;
diff --git a/PHPCI/Helper/User.php b/PHPCI/Helper/User.php
index 726003fd..065deacf 100644
--- a/PHPCI/Helper/User.php
+++ b/PHPCI/Helper/User.php
@@ -20,6 +20,11 @@ class User
public function __call($method, $params = array())
{
$user = $_SESSION['user'];
+
+ if (!is_object($user)) {
+ return null;
+ }
+
return call_user_func_array(array($user, $method), $params);
}
}
diff --git a/PHPCI/Logging/BuildDBLogHandler.php b/PHPCI/Logging/BuildDBLogHandler.php
index 3c03c501..782471db 100644
--- a/PHPCI/Logging/BuildDBLogHandler.php
+++ b/PHPCI/Logging/BuildDBLogHandler.php
@@ -9,7 +9,7 @@
namespace PHPCI\Logging;
-use b8\Store;
+use b8\Store\Factory;
use Monolog\Handler\AbstractProcessingHandler;
use PHPCI\Model\Build;
@@ -40,5 +40,7 @@ class BuildDBLogHandler extends AbstractProcessingHandler
$this->logValue .= $message . PHP_EOL;
$this->build->setLog($this->logValue);
+
+ Factory::getStore('Build')->save($this->build);
}
}
diff --git a/PHPCI/Migrations/20140730143702_fix_database_columns.php b/PHPCI/Migrations/20140730143702_fix_database_columns.php
new file mode 100644
index 00000000..6594dd02
--- /dev/null
+++ b/PHPCI/Migrations/20140730143702_fix_database_columns.php
@@ -0,0 +1,49 @@
+table('build');
+ $build->changeColumn('project_id', 'integer', array('null' => false));
+ $build->changeColumn('commit_id', 'string', array('limit' => 50, 'null' => false));
+ $build->changeColumn('status', 'integer', array('null' => false));
+ $build->changeColumn('log', 'text', array('null' => true, 'default' => ''));
+ $build->changeColumn('branch', 'string', array('limit' => 50, 'null' => false, 'default' => 'master'));
+ $build->changeColumn('created', 'datetime', array('null' => true));
+ $build->changeColumn('started', 'datetime', array('null' => true));
+ $build->changeColumn('finished', 'datetime', array('null' => true));
+ $build->changeColumn('committer_email', 'string', array('limit' => 512, 'null' => true));
+ $build->changeColumn('commit_message', 'text', array('null' => true));
+ $build->changeColumn('extra', 'text', array('null' => true));
+
+ $buildMeta = $this->table('build_meta');
+ $buildMeta->changeColumn('project_id', 'integer', array('null' => false));
+ $buildMeta->changeColumn('build_id', 'integer', array('null' => false));
+ $buildMeta->changeColumn('meta_key', 'string', array('limit' => 250, 'null' => false));
+ $buildMeta->changeColumn('meta_value', 'text', array('null' => false));
+
+ $project = $this->table('project');
+ $project->changeColumn('title', 'string', array('limit' => 250, 'null' => false));
+ $project->changeColumn('reference', 'string', array('limit' => 250, 'null' => false));
+ $project->changeColumn('branch', 'string', array('limit' => 50, 'null' => false, 'default' => 'master'));
+ $project->changeColumn('ssh_private_key', 'text', array('null' => true, 'default' => null));
+ $project->changeColumn('ssh_public_key', 'text', array('null' => true, 'default' => null));
+ $project->changeColumn('type', 'string', array('limit' => 50, 'null' => false));
+ $project->changeColumn('access_information', 'string', array('limit' => 250, 'null' => true, 'default' => null));
+ $project->changeColumn('last_commit', 'string', array('limit' => 250, 'null' => true, 'default' => null));
+ $project->changeColumn('ssh_public_key', 'text', array('null' => true, 'default' => null));
+ $project->changeColumn('allow_public_status', 'integer', array('null' => false, 'default' => 0));
+
+ $user = $this->table('user');
+ $user->changeColumn('email', 'string', array('limit' => 250, 'null' => false));
+ $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));
+ }
+}
diff --git a/PHPCI/Model/Base/ProjectBase.php b/PHPCI/Model/Base/ProjectBase.php
index b56279b5..5e1f4f37 100644
--- a/PHPCI/Model/Base/ProjectBase.php
+++ b/PHPCI/Model/Base/ProjectBase.php
@@ -36,6 +36,7 @@ class ProjectBase extends Model
'id' => null,
'title' => null,
'reference' => null,
+ 'branch' => null,
'ssh_private_key' => null,
'ssh_public_key' => null,
'type' => null,
@@ -200,17 +201,15 @@ class ProjectBase extends Model
}
/**
- * Get the value of Branch / branch.
- *
- * @return string
- */
+ * Get the value of Branch / branch.
+ *
+ * @return string
+ */
public function getBranch()
{
- if (empty($this->data['branch'])) {
- return $this->getType() === 'hg' ? 'default' : 'master';
- } else {
- return $this->data['branch'];
- }
+ $rtn = $this->data['branch'];
+
+ return $rtn;
}
/**
@@ -365,6 +364,7 @@ class ProjectBase extends Model
*/
public function setBranch($value)
{
+ $this->_validateNotNull('Branch', $value);
$this->_validateString('Branch', $value);
if ($this->data['branch'] === $value) {
diff --git a/PHPCI/Model/Build.php b/PHPCI/Model/Build.php
index 4ca3cf9e..0286b3b8 100644
--- a/PHPCI/Model/Build.php
+++ b/PHPCI/Model/Build.php
@@ -38,15 +38,6 @@ class Build extends BuildBase
return '#';
}
- /**
- * @return string
- */
- public function getProjectTitle()
- {
- $project = $this->getProject();
- return $project ? $project->getTitle() : "";
- }
-
/**
* Get link to branch from another source (i.e. Github)
*/
@@ -55,6 +46,11 @@ class Build extends BuildBase
return '#';
}
+ public function getFileLinkTemplate()
+ {
+ return null;
+ }
+
/**
* Send status updates to any relevant third parties (i.e. Github)
*/
@@ -63,6 +59,15 @@ class Build extends BuildBase
return;
}
+ /**
+ * @return string
+ */
+ public function getProjectTitle()
+ {
+ $project = $this->getProject();
+ return $project ? $project->getTitle() : "";
+ }
+
/**
* Store build metadata
*/
@@ -160,11 +165,6 @@ class Build extends BuildBase
return $config;
}
- public function getFileLinkTemplate()
- {
- return null;
- }
-
public function getExtra($key = null)
{
$data = json_decode($this->data['extra'], true);
diff --git a/PHPCI/Model/Build/GithubBuild.php b/PHPCI/Model/Build/GithubBuild.php
index 6d3f217b..e0ff0fc0 100644
--- a/PHPCI/Model/Build/GithubBuild.php
+++ b/PHPCI/Model/Build/GithubBuild.php
@@ -109,8 +109,19 @@ class GithubBuild extends RemoteGitBuild
public function getFileLinkTemplate()
{
- $link = 'https://github.com/' . $this->getProject()->getReference() . '/';
- $link .= 'blob/' . $this->getBranch() . '/';
+ $reference = $this->getProject()->getReference();
+ $branch = $this->getBranch();
+
+ if ($this->getExtra('build_type') == 'pull_request') {
+ $matches = array();
+ preg_match('/\/([a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-]+)/', $this->getExtra('remote_url'), $matches);
+
+ $reference = $matches[1];
+ $branch = $this->getExtra('remote_branch');
+ }
+
+ $link = 'https://github.com/' . $reference . '/';
+ $link .= 'blob/' . $branch . '/';
$link .= '{FILE}';
$link .= '#L{LINE}';
diff --git a/PHPCI/Model/Build/GitlabBuild.php b/PHPCI/Model/Build/GitlabBuild.php
index 83053090..086bc046 100644
--- a/PHPCI/Model/Build/GitlabBuild.php
+++ b/PHPCI/Model/Build/GitlabBuild.php
@@ -61,7 +61,17 @@ class GitlabBuild extends RemoteGitBuild
if (!empty($key)) {
$user = $this->getProject()->getAccessInformation("user");
$domain = $this->getProject()->getAccessInformation("domain");
- return $user . '@' . $domain . ':' . $this->getProject()->getReference() . '.git';
+ $port = $this->getProject()->getAccessInformation('port');
+
+ $url = $user . '@' . $domain . ':';
+
+ if (!empty($port)) {
+ $url .= $port . '/';
+ }
+
+ $url .= $this->getProject()->getReference() . '.git';
+
+ return $url;
}
}
}
diff --git a/PHPCI/Model/Project.php b/PHPCI/Model/Project.php
index 55df01c5..702d9c89 100644
--- a/PHPCI/Model/Project.php
+++ b/PHPCI/Model/Project.php
@@ -44,9 +44,25 @@ class Project extends ProjectBase
return null;
}
+ public function setAccessInformation($value)
+ {
+ if (is_array($value)) {
+ $value = json_encode($value);
+ }
+
+ parent::setAccessInformation($value);
+ }
+
public function getAccessInformation($key = null)
{
- $data = unserialize($this->data['access_information']);
+ $info = $this->data['access_information'];
+
+ // Handle old-format (serialized) access information first:
+ if (!empty($info) && substr($info, 0, 1) != '{') {
+ $data = unserialize($info);
+ } else {
+ $data = json_decode($info, true);
+ }
if (is_null($key)) {
$rtn = $data;
@@ -58,4 +74,18 @@ class Project extends ProjectBase
return $rtn;
}
+
+ /**
+ * Get the value of Branch / branch.
+ *
+ * @return string
+ */
+ public function getBranch()
+ {
+ if (empty($this->data['branch'])) {
+ return $this->getType() === 'hg' ? 'default' : 'master';
+ } else {
+ return $this->data['branch'];
+ }
+ }
}
diff --git a/PHPCI/Plugin/PhpLoc.php b/PHPCI/Plugin/PhpLoc.php
index 26ec8204..6e402cc7 100644
--- a/PHPCI/Plugin/PhpLoc.php
+++ b/PHPCI/Plugin/PhpLoc.php
@@ -43,7 +43,11 @@ class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
{
$this->phpci = $phpci;
$this->build = $build;
- $this->directory = isset($options['directory']) ? $options['directory'] : $phpci->buildPath;
+ $this->directory = $phpci->buildPath;
+
+ if (isset($options['directory'])) {
+ $this->directory .= $options['directory'];
+ }
}
/**
diff --git a/PHPCI/Service/BuildService.php b/PHPCI/Service/BuildService.php
new file mode 100644
index 00000000..300df728
--- /dev/null
+++ b/PHPCI/Service/BuildService.php
@@ -0,0 +1,111 @@
+buildStore = $buildStore;
+ }
+
+ /**
+ * @param Project $project
+ * @param string|null $commitId
+ * @param string|null $branch
+ * @param string|null $committerEmail
+ * @param string|null $commitMessage
+ * @param string|null $extra
+ * @return \PHPCI\Model\Build
+ */
+ public function createBuild(
+ Project $project,
+ $commitId = null,
+ $branch = null,
+ $committerEmail = null,
+ $commitMessage = null,
+ $extra = null
+ ) {
+ $build = new Build();
+ $build->setCreated(new \DateTime());
+ $build->setProject($project);
+ $build->setStatus(0);
+
+ if (!is_null($commitId)) {
+ $build->setCommitId($commitId);
+ } else {
+ $build->setCommitId('Manual');
+ }
+
+ if (!is_null($branch)) {
+ $build->setBranch($branch);
+ } else {
+ $build->setBranch($project->getBranch());
+ }
+
+ if (!is_null($committerEmail)) {
+ $build->setCommitterEmail($committerEmail);
+ }
+
+ if (!is_null($commitMessage)) {
+ $build->setCommitMessage($commitMessage);
+ }
+
+ if (!is_null($extra)) {
+ $build->setExtra(json_encode($extra));
+ }
+
+ return $this->buildStore->save($build);
+ }
+
+ /**
+ * @param Build $copyFrom
+ * @return \PHPCI\Model\Build
+ */
+ public function createDuplicateBuild(Build $copyFrom)
+ {
+ $data = $copyFrom->getDataArray();
+
+ // Clean up unwanted properties from the original build:
+ unset($data['id']);
+ unset($data['status']);
+ unset($data['log']);
+ unset($data['started']);
+ unset($data['finished']);
+
+ $build = new Build();
+ $build->setValues($data);
+ $build->setCreated(new \DateTime());
+
+ return $this->buildStore->save($build);
+ }
+
+ /**
+ * Delete a given build.
+ * @param Build $build
+ * @return bool
+ */
+ public function deleteBuild(Build $build)
+ {
+ return $this->buildStore->delete($build);
+ }
+}
diff --git a/PHPCI/Service/ProjectService.php b/PHPCI/Service/ProjectService.php
new file mode 100644
index 00000000..1bc1b248
--- /dev/null
+++ b/PHPCI/Service/ProjectService.php
@@ -0,0 +1,124 @@
+projectStore = $projectStore;
+ }
+
+ /**
+ * Create a new project model and use the project store to save it.
+ * @param string $title
+ * @param string $type
+ * @param string $reference
+ * @param array $options
+ * @return \PHPCI\Model\Project
+ */
+ public function createProject($title, $type, $reference, $options = array())
+ {
+ // Create base project and use updateProject() to set its properties:
+ $project = new Project();
+ return $this->updateProject($project, $title, $type, $reference, $options);
+ }
+
+ /**
+ * Update the properties of a given project.
+ * @param Project $project
+ * @param string $title
+ * @param string $type
+ * @param string $reference
+ * @param array $options
+ * @return \PHPCI\Model\Project
+ */
+ public function updateProject(Project $project, $title, $type, $reference, $options = array())
+ {
+ // Set basic properties:
+ $project->setTitle($title);
+ $project->setType($type);
+ $project->setReference($reference);
+ $project->setAllowPublicStatus(0);
+
+ // Handle extra project options:
+ if (array_key_exists('ssh_private_key', $options)) {
+ $project->setSshPrivateKey($options['ssh_private_key']);
+ }
+
+ if (array_key_exists('ssh_public_key', $options)) {
+ $project->setSshPublicKey($options['ssh_public_key']);
+ }
+
+ if (array_key_exists('build_config', $options)) {
+ $project->setBuildConfig($options['build_config']);
+ }
+
+ if (array_key_exists('allow_public_status', $options)) {
+ $project->setAllowPublicStatus((int)$options['allow_public_status']);
+ }
+
+ if (array_key_exists('branch', $options)) {
+ $project->setBranch($options['branch']);
+ }
+
+ // Allow certain project types to set access information:
+ $this->processAccessInformation($project);
+
+ // Save and return the project:
+ return $this->projectStore->save($project);
+ }
+
+ /**
+ * Delete a given project.
+ * @param Project $project
+ * @return bool
+ */
+ public function deleteProject(Project $project)
+ {
+ return $this->projectStore->delete($project);
+ }
+
+ /**
+ * In circumstances where it is necessary, populate access information based on other project properties.
+ * @see ProjectService::createProject()
+ * @param Project $project
+ */
+ protected function processAccessInformation(Project &$project)
+ {
+ $matches = array();
+ $reference = $project->getReference();
+
+ if ($project->getType() == 'gitlab') {
+ $info = array();
+
+ if (preg_match('`^(.*)@(.*):([0-9]+)?/?(.*)/(.*)\.git`', $reference, $matches)) {
+ $info['user'] = $matches[1];
+ $info['domain'] = $matches[2];
+ $info['port'] = $matches[3];
+
+ $project->setReference($matches[4] . '/' . $matches[5]);
+ }
+
+ $project->setAccessInformation($info);
+ }
+ }
+}
diff --git a/PHPCI/Service/UserService.php b/PHPCI/Service/UserService.php
new file mode 100644
index 00000000..8f20044f
--- /dev/null
+++ b/PHPCI/Service/UserService.php
@@ -0,0 +1,61 @@
+store = $store;
+ }
+
+ public function createUser($name, $emailAddress, $password, $isAdmin = false)
+ {
+ $user = new User();
+ $user->setName($name);
+ $user->setEmail($emailAddress);
+ $user->setHash(password_hash($password, PASSWORD_DEFAULT));
+ $user->setIsAdmin(($isAdmin ? 1 : 0));
+
+ return $this->store->save($user);
+ }
+
+ public function updateUser(User $user, $name, $emailAddress, $password = null, $isAdmin = null)
+ {
+ $user->setName($name);
+ $user->setEmail($emailAddress);
+
+ if (!empty($password)) {
+ $user->setHash(password_hash($password, PASSWORD_DEFAULT));
+ }
+
+ if (!is_null($isAdmin)) {
+ $user->setIsAdmin(($isAdmin ? 1 : 0));
+ }
+
+ return $this->store->save($user);
+ }
+
+ public function deleteUser(User $user)
+ {
+ return $this->store->delete($user);
+ }
+}
diff --git a/PHPCI/View/BuildStatus/view.phtml b/PHPCI/View/BuildStatus/view.phtml
index 2b81cf45..e8536bf6 100644
--- a/PHPCI/View/BuildStatus/view.phtml
+++ b/PHPCI/View/BuildStatus/view.phtml
@@ -165,21 +165,7 @@
getBranch(); ?> |
- getPlugins(), true);
-
- if ( !is_array($plugins) ) {
- $plugins = array();
- }
- if ( 0 === count($plugins) ) {
- ?>
- $pluginstatus):
- $subcls = $pluginstatus?'label label-success':'label label-danger';
- ?> Build()->formatPluginName($plugin); ?>
-
+
|
diff --git a/PHPCI/View/Home/index.phtml b/PHPCI/View/Home/index.phtml
index a103b413..bcac0775 100644
--- a/PHPCI/View/Home/index.phtml
+++ b/PHPCI/View/Home/index.phtml
@@ -66,12 +66,26 @@