Merge pull request #4 from Block8/master

update me
This commit is contained in:
yourilima 2014-05-14 09:48:41 +02:00
commit 63988ec33a
124 changed files with 2897 additions and 1062 deletions

6
.gitignore vendored
View file

@ -10,4 +10,8 @@ config.php
PHPCI/config.yml
cache
/loggerconfig.php
/pluginconfig.php
/pluginconfig.php
PHPCI/Model/Migration.php
PHPCI/Model/Base/MigrationBase.php
PHPCI/Store/MigrationStore.php
PHPCI/Store/Base/MigrationStoreBase.php

18
Dockerfile Normal file
View file

@ -0,0 +1,18 @@
FROM ubuntu:14.04
MAINTAINER Dan Cryer dan.cryer@block8.co.uk
RUN echo "deb http://ppa.launchpad.net/ondrej/php5/ubuntu trusty main" >> /etc/apt/sources.list
RUN echo "deb http://archive.ubuntu.com/ubuntu/ precise universe" >> /etc/apt/sources.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C E5267A6C 0xcbcb082a1bb943db
RUN apt-get update
# Install PHP:
RUN apt-get install -qy git-core php5-common php5-cli php5-curl php5-imap php5-mcrypt php5-mysqlnd
# Give Git some fake user details to prevent it asking when trying to test merges:
RUN git config --global user.name "PHPCI"
RUN git config --global user.email "hello@php.ci"
ADD ./ /phpci
CMD /phpci/daemonise phpci:daemonise

View file

@ -1,4 +1,4 @@
Copyright (c) 2013, Block 8 Limited
Copyright (c) 2013-2014, Block 8 Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View file

@ -2,14 +2,15 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI;
use b8;
use b8\Exception\HttpException;
use b8\Http\Response;
use b8\Http\Response\RedirectResponse;
use b8\View;
@ -51,6 +52,7 @@ class Application extends b8\Application
$response->setResponseCode(401);
$response->setContent('');
} else {
$_SESSION['login_redirect'] = substr($request->getPath(), 1);
$response = new RedirectResponse($response);
$response->setHeader('Location', PHPCI_URL.'session/login');
}
@ -69,7 +71,25 @@ class Application extends b8\Application
*/
public function handleRequest()
{
$this->response = parent::handleRequest();
try {
$this->response = parent::handleRequest();
} catch (HttpException $ex) {
$this->config->set('page_title', 'Error');
$view = new View('exception');
$view->exception = $ex;
$this->response->setResponseCode($ex->getErrorCode());
$this->response->setContent($view->render());
} catch (\Exception $ex) {
$this->config->set('page_title', 'Error');
$view = new View('exception');
$view->exception = $ex;
$this->response->setResponseCode(500);
$this->response->setContent($view->render());
}
if (View::exists('layout') && $this->response->hasLayout()) {
$view = new View('layout');

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI;
@ -21,11 +21,16 @@ class BuildFactory
/**
* @param $buildId
* @return Build
* @throws \Exception
*/
public static function getBuildById($buildId)
{
$build = Factory::getStore('Build')->getById($buildId);
if (empty($build)) {
throw new \Exception('Build ID ' . $buildId . ' does not exist.');
}
return self::getBuild($build);
}

View file

@ -2,15 +2,14 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI;
use PHPCI\Helper\BuildInterpolator;
use PHPCI\Helper\CommandExecutor;
use PHPCI\Helper\MailerFactory;
use PHPCI\Logging\BuildLogger;
use PHPCI\Model\Build;
@ -118,7 +117,12 @@ class Builder implements LoggerAwareInterface
$pluginFactory->addConfigFromFile(PHPCI_DIR . "/pluginconfig.php");
$this->pluginExecutor = new Plugin\Util\Executor($pluginFactory, $this->buildLogger);
$this->commandExecutor = new CommandExecutor(
$executorClass = 'PHPCI\Helper\UnixCommandExecutor';
if (IS_WIN) {
$executorClass = 'PHPCI\Helper\WindowsCommandExecutor';
}
$this->commandExecutor = new $executorClass(
$this->buildLogger,
PHPCI_DIR,
$this->quiet,
@ -126,7 +130,6 @@ class Builder implements LoggerAwareInterface
);
$this->interpolator = new BuildInterpolator();
}
/**
@ -242,7 +245,7 @@ class Builder implements LoggerAwareInterface
*/
public function executeCommand()
{
return $this->commandExecutor->buildAndExecuteCommand(func_get_args());
return $this->commandExecutor->executeCommand(func_get_args());
}
/**

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;

View file

@ -1,12 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
* nohup PHPCI_DIR/console phpci:start-daemon > /dev/null 2>&1 &
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;

View file

@ -1,12 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
* nohup PHPCI_DIR/console phpci:start-daemon > /dev/null 2>&1 &
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;
@ -76,6 +75,7 @@ class DaemoniseCommand extends Command
$this->run = true;
$this->sleep = 0;
$runner = new RunCommand($this->logger);
$runner->setBaxBuilds(1);
$emptyInput = new ArgvInput(array());

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;
@ -37,7 +37,13 @@ class GenerateCommand extends Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$gen = new CodeGenerator(Database::getConnection(), ['default' => 'PHPCI'], ['default' => PHPCI_DIR], false);
$gen = new CodeGenerator(
Database::getConnection(),
array('default' => 'PHPCI'),
array('default' => PHPCI_DIR),
false
);
$gen->generateModels();
$gen->generateStores();
}

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;
@ -204,19 +204,7 @@ class InstallCommand extends Command
{
$output->write('Setting up your database... ');
// Load PHPCI's bootstrap file:
require(PHPCI_DIR . 'bootstrap.php');
try {
// Set up the database, based on table data from the models:
$gen = new Database\Generator(Database::getConnection(), 'PHPCI', './PHPCI/Model/Base/');
$gen->generate();
} catch (Exception $ex) {
$output->writeln('');
$output->writeln('<error>PHPCI failed to set up the database.</error>');
$output->writeln('<error>' . $ex->getMessage() . '</error>');
die;
}
shell_exec(PHPCI_DIR . 'vendor/bin/phinx migrate -c "' . PHPCI_DIR . 'phinx.php"');
$output->writeln('<info>OK</info>');
}

View file

@ -1,11 +1,10 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;
@ -42,6 +42,11 @@ class RunCommand extends Command
*/
protected $logger;
/**
* @var int
*/
protected $maxBuilds = null;
/**
* @param \Monolog\Logger $logger
* @param string $name
@ -52,7 +57,6 @@ class RunCommand extends Command
$this->logger = $logger;
}
protected function configure()
{
$this
@ -69,7 +73,7 @@ class RunCommand extends Command
// For verbose mode we want to output all informational and above
// messages to the symphony output interface.
if ($input->getOption('verbose')) {
if ($input->hasOption('verbose')) {
$this->logger->pushHandler(
new OutputLogHandler($this->output, Logger::INFO)
);
@ -79,7 +83,7 @@ class RunCommand extends Command
$this->logger->addInfo("Finding builds to process");
$store = Factory::getStore('Build');
$result = $store->getByStatus(0);
$result = $store->getByStatus(0, $this->maxBuilds);
$this->logger->addInfo(sprintf("Found %d builds", count($result['items'])));
$builds = 0;
@ -113,4 +117,9 @@ class RunCommand extends Command
return $builds;
}
public function setBaxBuilds($numBuilds)
{
$this->maxBuilds = (int)$numBuilds;
}
}

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Command;
@ -50,11 +50,9 @@ class UpdateCommand extends Command
{
$this->verifyInstalled($output);
$output->writeln('Updating PHPCI database.');
$output->write('Updating PHPCI database: ');
// Update the database:
$gen = new \b8\Database\Generator(\b8\Database::getConnection(), 'PHPCI', './PHPCI/Model/Base/');
$gen->generate();
shell_exec(PHPCI_DIR . 'vendor/bin/phinx migrate -c "' . PHPCI_DIR . 'phinx.php"');
$output->writeln('<info>Done!</info>');
}

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI;

View file

@ -1,15 +1,16 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, 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\Exception\HttpException\NotFoundException;
use PHPCI\BuildFactory;
use PHPCI\Model\Build;
@ -36,7 +37,16 @@ class BuildController extends \PHPCI\Controller
*/
public function view($buildId)
{
$build = BuildFactory::getBuildById($buildId);
try {
$build = BuildFactory::getBuildById($buildId);
} catch (\Exception $ex) {
$build = null;
}
if (empty($build)) {
throw new NotFoundException('Build with ID: ' . $buildId . ' does not exist.');
}
$this->view->plugins = $this->getUiPlugins();
$this->view->build = $build;
$this->view->data = $this->getBuildData($build);
@ -95,7 +105,6 @@ class BuildController extends \PHPCI\Controller
$data = array();
$data['status'] = (int)$build->getStatus();
$data['log'] = $this->cleanLog($build->getLog());
$data['plugins'] = json_decode($build->getPlugins(), true);
$data['created'] = !is_null($build->getCreated()) ? $build->getCreated()->format('Y-m-d H:i:s') : null;
$data['started'] = !is_null($build->getStarted()) ? $build->getStarted()->format('Y-m-d H:i:s') : null;
$data['finished'] = !is_null($build->getFinished()) ? $build->getFinished()->format('Y-m-d H:i:s') : null;
@ -110,6 +119,10 @@ class BuildController extends \PHPCI\Controller
{
$copy = BuildFactory::getBuildById($buildId);
if (empty($copy)) {
throw new NotFoundException('Build with ID: ' . $buildId . ' does not exist.');
}
$build = new Build();
$build->setProjectId($copy->getProjectId());
$build->setCommitId($copy->getCommitId());
@ -134,11 +147,10 @@ class BuildController extends \PHPCI\Controller
throw new \Exception('You do not have permission to do that.');
}
$build = BuildFactory::getBuildById($buildId);
$build = BuildFactory::getBuildById($buildId);
if (!$build) {
$this->response->setResponseCode(404);
return '404 - Not Found';
if (empty($build)) {
throw new NotFoundException('Build with ID: ' . $buildId . ' does not exist.');
}
$this->buildStore->delete($build);

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Controller;
@ -65,7 +65,8 @@ class BuildStatusController extends \PHPCI\Controller
public function view($projectId)
{
$project = $this->projectStore->getById($projectId);
if (!$project) {
if (empty($project)) {
throw new NotFoundException('Project with id: ' . $projectId . ' not found');
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Controller;

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Controller;
@ -37,20 +37,6 @@ class PluginController extends \PHPCI\Controller
protected $canInstall;
protected $composerPath;
public function init()
{
parent::init();
$this->canInstall = function_exists('shell_exec');
if ($this->canInstall) {
$this->composerPath = $this->findBinary(array('composer', 'composer.phar'));
if (!$this->composerPath) {
$this->canInstall = false;
}
}
}
public function index()
{
if (!$_SESSION['user']->getIsAdmin()) {
@ -58,7 +44,6 @@ class PluginController extends \PHPCI\Controller
}
$this->view->canWrite = is_writable(APPLICATION_PATH . 'composer.json');
$this->view->canInstall = $this->canInstall;
$this->view->required = $this->required;
$json = $this->getComposerJson();
@ -93,13 +78,6 @@ class PluginController extends \PHPCI\Controller
unset($json['require'][$package]);
$this->setComposerJson($json);
if ($this->canInstall) {
$home = 'COMPOSER_HOME='.APPLICATION_PATH . ' ';
$action = ' update --working-dir=' . APPLICATION_PATH;
$toLog = APPLICATION_PATH . '/phpci_composer_remove.log 2>&1 &';
shell_exec($home . $this->composerPath . $action . ' > /' . $toLog);
}
header('Location: ' . PHPCI_URL . 'plugin?r=' . $package);
die;
}
@ -121,16 +99,6 @@ class PluginController extends \PHPCI\Controller
$json['require'][$package] = $version;
$this->setComposerJson($json);
if ($this->canInstall) {
$home = 'COMPOSER_HOME='.APPLICATION_PATH . ' ';
$action = ' update --working-dir=' . APPLICATION_PATH;
$toLog = ' > /' . APPLICATION_PATH . '/phpci_composer_install.log 2>&1 &';
shell_exec($home . $this->composerPath . $action . $toLog);
header('Location: ' . PHPCI_URL . 'plugin?i=' . $package);
die;
}
header('Location: ' . PHPCI_URL . 'plugin?w=' . $package);
die;
}
@ -179,7 +147,7 @@ class PluginController extends \PHPCI\Controller
{
$searchQuery = $this->getParam('q', '');
$http = new \b8\HttpClient();
$http->setHeaders(array('User-Agent: PHPCI/1.0 (+http://www.phptesting.org)'));
$http->setHeaders(array('User-Agent: PHPCI/1.0 (+https://www.phptesting.org)'));
$res = $http->get('https://packagist.org/search.json', array('q' => $searchQuery));
die(json_encode($res['body']));
@ -189,7 +157,7 @@ class PluginController extends \PHPCI\Controller
{
$name = $this->getParam('p', '');
$http = new \b8\HttpClient();
$http->setHeaders(array('User-Agent: PHPCI/1.0 (+http://www.phptesting.org)'));
$http->setHeaders(array('User-Agent: PHPCI/1.0 (+https://www.phptesting.org)'));
$res = $http->get('https://packagist.org/packages/'.$name.'.json');
die(json_encode($res['body']));

View file

@ -1,25 +1,25 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, 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\Controller;
use b8\Form;
use b8\Exception\HttpException\ForbiddenException;
use b8\Exception\HttpException\NotFoundException;
use b8\Store;
use PHPCI\BuildFactory;
use PHPCI\Helper\Github;
use PHPCI\Helper\SshKey;
use PHPCI\Model\Build;
use PHPCI\Model\Project;
use b8;
use b8\Config;
use b8\Controller;
use b8\Store;
use b8\Form;
use b8\Exception\HttpException\NotFoundException;
/**
* Project Controller - Allows users to create, edit and view projects.
@ -41,8 +41,8 @@ class ProjectController extends \PHPCI\Controller
public function init()
{
$this->buildStore = Store\Factory::getStore('Build');
$this->projectStore = Store\Factory::getStore('Project');
$this->buildStore = Store\Factory::getStore('Build');
$this->projectStore = Store\Factory::getStore('Project');
}
/**
@ -51,17 +51,18 @@ class ProjectController extends \PHPCI\Controller
public function view($projectId)
{
$project = $this->projectStore->getById($projectId);
if (!$project) {
if (empty($project)) {
throw new NotFoundException('Project with id: ' . $projectId . ' not found');
}
$page = $this->getParam('p', 1);
$builds = $this->getLatestBuildsHtml($projectId, (($page - 1) * 10));
$page = $this->getParam('p', 1);
$builds = $this->getLatestBuildsHtml($projectId, (($page - 1) * 10));
$this->view->builds = $builds[0];
$this->view->total = $builds[1];
$this->view->project = $project;
$this->view->page = $page;
$this->view->builds = $builds[0];
$this->view->total = $builds[1];
$this->view->project = $project;
$this->view->page = $page;
$this->config->set('page_title', $project->getTitle());
@ -76,6 +77,10 @@ class ProjectController extends \PHPCI\Controller
/* @var \PHPCI\Model\Project $project */
$project = $this->projectStore->getById($projectId);
if (empty($project)) {
throw new NotFoundException('Project with id: ' . $projectId . ' not found');
}
$build = new Build();
$build->setProjectId($projectId);
$build->setCommitId('Manual');
@ -96,7 +101,7 @@ class ProjectController extends \PHPCI\Controller
public function delete($projectId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
throw new ForbiddenException('You do not have permission to do that.');
}
$project = $this->projectStore->getById($projectId);
@ -120,10 +125,10 @@ class ProjectController extends \PHPCI\Controller
*/
protected function getLatestBuildsHtml($projectId, $start = 0)
{
$criteria = array('project_id' => $projectId);
$order = array('id' => 'DESC');
$builds = $this->buildStore->getWhere($criteria, 10, $start, array(), $order);
$view = new b8\View('BuildsTable');
$criteria = array('project_id' => $projectId);
$order = array('id' => 'DESC');
$builds = $this->buildStore->getWhere($criteria, 10, $start, array(), $order);
$view = new b8\View('BuildsTable');
foreach ($builds['items'] as &$build) {
$build = BuildFactory::getBuild($build);
@ -142,7 +147,7 @@ class ProjectController extends \PHPCI\Controller
$this->config->set('page_title', 'Add Project');
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
throw new ForbiddenException('You do not have permission to do that.');
}
$method = $this->request->getMethod();
@ -173,27 +178,17 @@ class ProjectController extends \PHPCI\Controller
$values = $form->getValues();
if ($values['type'] == "gitlab") {
preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches);
$matches = array();
if ($values['type'] == "gitlab" && preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches)) {
$info = array();
if (isset($matches[1])) {
$info["user"] = $matches[1];
}
if (isset($matches[2])) {
$info["domain"] = $matches[2];
}
$info['user'] = $matches[1];
$info['domain'] = $matches[2];
$values['access_information'] = serialize($info);
if (isset($matches[3]) && isset($matches[4])) {
$values['reference'] = $matches[3]."/".$matches[4];
}
$values['reference'] = $matches[3]."/".$matches[4];
}
$values['git_key'] = $values['key'];
$values['public_key'] = $values['pubkey'];
$values['ssh_private_key'] = $values['key'];
$values['ssh_public_key'] = $values['pubkey'];
$project = new Project();
$project->setValues($values);
@ -210,31 +205,33 @@ class ProjectController extends \PHPCI\Controller
public function edit($projectId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
throw new ForbiddenException('You do not have permission to do that.');
}
$method = $this->request->getMethod();
$project = $this->projectStore->getById($projectId);
$method = $this->request->getMethod();
$project = $this->projectStore->getById($projectId);
if (empty($project)) {
throw new NotFoundException('Project with id: ' . $projectId . ' not found');
}
$this->config->set('page_title', 'Edit: ' . $project->getTitle());
$values = $project->getDataArray();
$values['key'] = $values['ssh_private_key'];
$values['pubkey'] = $values['ssh_public_key'];
if ($values['type'] == "gitlab") {
$accessInfo = $project->getAccessInformation();
$reference = $accessInfo["user"].'@'.$accessInfo["domain"].':' . $project->getReference().".git";
$values['reference'] = $reference;
}
if ($method == 'POST') {
$values = $this->getParams();
} else {
$values = $project->getDataArray();
$values['key'] = $values['git_key'];
$values['pubkey'] = $values['public_key'];
if ($values['type'] == "gitlab") {
$accessInfo = $project->getAccessInformation();
$reference = $accessInfo["user"].'@'.$accessInfo["domain"].':' . $project->getReference().".git";
$values['reference'] = $reference;
}
}
$form = $this->projectForm($values, 'edit/' . $projectId);
$form = $this->projectForm($values, 'edit/' . $projectId);
if ($method != 'POST' || ($method == 'POST' && !$form->validate())) {
$view = new b8\View('ProjectForm');
@ -247,8 +244,8 @@ class ProjectController extends \PHPCI\Controller
}
$values = $form->getValues();
$values['git_key'] = $values['key'];
$values['public_key'] = $values['pubkey'];
$values['ssh_private_key'] = $values['key'];
$values['ssh_public_key'] = $values['pubkey'];
if ($values['type'] == "gitlab") {
preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches);

View file

@ -1,15 +1,16 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Controller;
use b8;
use PHPCI\Helper\Email;
/**
* Session Controller - Handles user login / logout.
@ -42,7 +43,7 @@ class SessionController extends \PHPCI\Controller
if ($user && password_verify($this->getParam('password', ''), $user->getHash())) {
$_SESSION['user_id'] = $user->getId();
header('Location: ' . PHPCI_URL);
header('Location: ' . $this->getLoginRedirect());
die;
} else {
$isLoginFailure = true;
@ -88,4 +89,86 @@ class SessionController extends \PHPCI\Controller
header('Location: ' . PHPCI_URL);
die;
}
public function forgotPassword()
{
if ($this->request->getMethod() == 'POST') {
$email = $this->getParam('email', null);
$user = $this->userStore->getByEmail($email);
if (empty($user)) {
$this->view->error = 'No user exists with that email address, please try again.';
return $this->view->render();
}
$key = md5(date('Y-m-d') . $user->getHash());
$url = PHPCI_URL;
$name = $user->getName();
$userId = $user->getId();
$message = <<<MSG
Hi {$name},
You have received this email because you, or someone else, has requested a password reset for PHPCI.
If this was you, please click the following link to reset your password: {$url}session/reset-password/{$userId}/{$key}
Otherwise, please ignore this email and no action will be taken.
Thank you,
PHPCI
MSG;
$email = new Email();
$email->setEmailTo($user->getEmail(), $user->getName());
$email->setSubject('Password reset');
$email->setBody($message);
$email->send();
$this->view->emailed = true;
}
return $this->view->render();
}
public function resetPassword($userId, $key)
{
$user = $this->userStore->getById($userId);
$userKey = md5(date('Y-m-d') . $user->getHash());
if (empty($user) || $key != $userKey) {
$this->view->error = 'Invalid password reset request.';
return $this->view->render();
}
if ($this->request->getMethod() == 'POST') {
$hash = password_hash($this->getParam('password'), PASSWORD_DEFAULT);
$user->setHash($hash);
$_SESSION['user'] = $this->userStore->save($user);
$_SESSION['user_id'] = $user->getId();
header('Location: ' . PHPCI_URL);
die;
}
$this->view->id = $userId;
$this->view->key = $key;
return $this->view->render();
}
protected function getLoginRedirect()
{
$rtn = PHPCI_URL;
if (!empty($_SESSION['login_redirect'])) {
$rtn .= $_SESSION['login_redirect'];
$_SESSION['login_redirect'] = null;
}
return $rtn;
}
}

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Controller;
@ -48,6 +48,7 @@ class SettingsController extends Controller
$this->view->github = $this->getGithubForm();
$this->view->emailSettings = $this->getEmailForm($emailSettings);
$this->view->isWriteable = $this->canWriteConfig();
if (!empty($this->settings['phpci']['github']['token'])) {
$this->view->githubUser = $this->getGithubUser($this->settings['phpci']['github']['token']);
@ -242,4 +243,9 @@ class SettingsController extends Controller
return $user['body'];
}
protected function canWriteConfig()
{
return is_writeable(APPLICATION_PATH . 'PHPCI/config.yml');
}
}

View file

@ -1,15 +1,17 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, 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\Exception\HttpException\ForbiddenException;
use b8\Exception\HttpException\NotFoundException;
use b8\Form;
use PHPCI\Controller;
use PHPCI\Model\User;
@ -29,7 +31,7 @@ class UserController extends Controller
public function init()
{
$this->userStore = b8\Store\Factory::getStore('User');
$this->userStore = b8\Store\Factory::getStore('User');
}
/**
@ -45,18 +47,72 @@ class UserController extends Controller
return $this->view->render();
}
public function profile()
{
$user = $_SESSION['user'];
$values = $user->getDataArray();
if ($this->request->getMethod() == 'POST') {
$values = $this->getParams();
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);
}
$form = new Form();
$form->setAction(PHPCI_URL.'user/profile');
$form->setMethod('POST');
$name = new Form\Element\Text('name');
$name->setClass('form-control');
$name->setContainerClass('form-group');
$name->setLabel('Name');
$name->setRequired(true);
$form->addField($name);
$email = new Form\Element\Email('email');
$email->setClass('form-control');
$email->setContainerClass('form-group');
$email->setLabel('Email Address');
$email->setRequired(true);
$form->addField($email);
$password = new Form\Element\Password('password');
$password->setClass('form-control');
$password->setContainerClass('form-group');
$password->setLabel('Password (leave blank if you don\'t want to change it)');
$password->setRequired(false);
$form->addField($password);
$submit = new Form\Element\Submit();
$submit->setClass('btn btn-success');
$submit->setValue('Save &raquo;');
$form->addField($submit);
$form->setValues($values);
$this->view->form = $form;
return $this->view->render();
}
/**
* Add a user - handles both form and processing.
*/
public function add()
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
throw new ForbiddenException('You do not have permission to do that.');
}
$this->config->set('page_title', 'Add User');
$method = $this->request->getMethod();
if ($method == 'POST') {
@ -77,7 +133,6 @@ class UserController extends Controller
}
$values = $form->getValues();
$values['is_admin'] = $values['admin'] ? 1 : 0;
$values['hash'] = password_hash($values['password'], PASSWORD_DEFAULT);
$user = new User();
@ -95,42 +150,40 @@ class UserController extends Controller
public function edit($userId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
throw new ForbiddenException('You do not have permission to do that.');
}
$method = $this->request->getMethod();
$user = $this->userStore->getById($userId);
$method = $this->request->getMethod();
$user = $this->userStore->getById($userId);
$this->config->set('page_title', 'Edit: ' . $user->getName());
if ($method == 'POST') {
$values = $this->getParams();
} else {
$values = $user->getDataArray();
$values['admin'] = $values['is_admin'];
if (empty($user)) {
throw new NotFoundException('User with ID: ' . $userId . ' does not exist.');
}
$form = $this->userForm($values, 'edit/' . $userId);
$values = array_merge($user->getDataArray(), $this->getParams());
$form = $this->userForm($values, 'edit/' . $userId);
if ($method != 'POST' || ($method == 'POST' && !$form->validate())) {
$view = new b8\View('UserForm');
$view->type = 'edit';
$view->user = $user;
$view->form = $form;
$view = new b8\View('UserForm');
$view->type = 'edit';
$view->user = $user;
$view->form = $form;
return $view->render();
}
$values = $form->getValues();
$values['is_admin'] = $values['admin'] ? 1 : 0;
if (!empty($values['password'])) {
$values['hash'] = password_hash($values['password'], PASSWORD_DEFAULT);
}
$user->setValues($values);
$user = $this->userStore->save($user);
$isAdmin = $this->getParam('is_admin');
if (empty($isAdmin)) {
$user->setIsAdmin(0);
}
$this->userStore->save($user);
header('Location: '.PHPCI_URL.'user');
die;
@ -161,13 +214,20 @@ class UserController extends Controller
$form->addField($field);
$field = new Form\Element\Password('password');
$field->setRequired(true);
$field->setLabel('Password' . ($type == 'edit' ? ' (leave blank to keep current password)' : ''));
if ($type == 'add') {
$field->setRequired(true);
$field->setLabel('Password');
} else {
$field->setRequired(false);
$field->setLabel('Password (leave blank to keep current password)');
}
$field->setClass('form-control');
$field->setContainerClass('form-group');
$form->addField($field);
$field = new Form\Element\Checkbox('admin');
$field = new Form\Element\Checkbox('is_admin');
$field->setRequired(false);
$field->setCheckedValue(1);
$field->setLabel('Is this user an administrator?');
@ -189,10 +249,15 @@ class UserController extends Controller
public function delete($userId)
{
if (!$_SESSION['user']->getIsAdmin()) {
throw new \Exception('You do not have permission to do that.');
throw new ForbiddenException('You do not have permission to do that.');
}
$user = $this->userStore->getById($userId);
if (empty($user)) {
throw new NotFoundException('User with ID: ' . $userId . ' does not exist.');
}
$this->userStore->delete($user);
header('Location: '.PHPCI_URL.'user');

View file

@ -2,15 +2,16 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Controller;
use b8;
use b8\Store;
use PHPCI\BuildFactory;
use PHPCI\Model\Build;
/**
@ -42,21 +43,16 @@ class WebhookController extends \PHPCI\Controller
foreach ($payload['commits'] as $commit) {
try {
$email = $commit['raw_author'];
$email = substr($email, 0, strpos($email, '>'));
$email = substr($email, strpos($email, '<') + 1);
$build = new Build();
$build->setProjectId($project);
$build->setCommitId($commit['raw_node']);
$build->setCommitterEmail($email);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$build->setBranch($commit['branch']);
$build->setCommitMessage($commit['message']);
$this->buildStore->save($build);
$this->createBuild($project, $commit['raw_node'], $commit['branch'], $email, $commit['message']);
} catch (\Exception $ex) {
header('HTTP/1.1 500 Internal Server Error');
header('Ex: ' . $ex->getMessage());
die('FAIL');
}
}
@ -74,36 +70,22 @@ class WebhookController extends \PHPCI\Controller
$commit = $this->getParam('commit');
try {
$build = new Build();
$build->setProjectId($project);
if ($branch !== null && trim($branch) !== '') {
$build->setBranch($branch);
} else {
$build->setBranch('master');
if (empty($branch)) {
$branch = 'master';
}
if ($commit !== null && trim($commit) !== '') {
$build->setCommitId($commit);
if (empty($commit)) {
$commit = null;
}
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$this->createBuild($project, $commit, $branch, null, null);
} catch (\Exception $ex) {
header('HTTP/1.1 400 Bad Request');
header('Ex: ' . $ex->getMessage());
die('FAIL');
}
try {
$this->buildStore->save($build); /** bugfix: Errors with PHPCI GitHub hook #296 */
} catch (\Exception $ex) {
header('HTTP/1.1 500 Internal Server Error');
header('Ex: ' . $ex->getMessage());
die('FAIL');
}
die('OK');
}
@ -112,11 +94,27 @@ class WebhookController extends \PHPCI\Controller
*/
public function github($project)
{
$payload = json_decode($this->getParam('payload'), true);
$payload = json_decode($this->getParam('payload'), true);
// Handle Pull Request web hooks:
if (array_key_exists('pull_request', $payload)) {
return $this->githubPullRequest($project, $payload);
}
// Handle Push web hooks:
if (array_key_exists('commits', $payload)) {
return $this->githubCommitRequest($project, $payload);
}
header('HTTP/1.1 200 OK');
die('This request type is not supported, this is not an error.');
}
protected function githubCommitRequest($project, array $payload)
{
// Github sends a payload when you close a pull request with a
// non-existant commit. We don't want this.
if ($payload['after'] === '0000000000000000000000000000000000000000') {
if (array_key_exists('after', $payload) && $payload['after'] === '0000000000000000000000000000000000000000') {
die('OK');
}
@ -130,32 +128,16 @@ class WebhookController extends \PHPCI\Controller
continue;
}
$build = new Build();
$build->setProjectId($project);
$build->setCommitId($commit['id']);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$build->setBranch(str_replace('refs/heads/', '', $payload['ref']));
$build->setCommitterEmail($commit['committer']['email']);
$build->setCommitMessage($commit['message']);
$build = $this->buildStore->save($build);
$build->sendStatusPostback();
$branch = str_replace('refs/heads/', '', $payload['ref']);
$committer = $commit['committer']['email'];
$this->createBuild($project, $commit['id'], $branch, $committer, $commit['message']);
}
} elseif (substr($payload['ref'], 0, 10) == 'refs/tags/') {
// If we don't, but we're dealing with a tag, add that instead:
$build = new Build();
$build->setProjectId($project);
$build->setCommitId($payload['after']);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$build->setBranch(str_replace('refs/tags/', 'Tag: ', $payload['ref']));
$build->setCommitterEmail($payload['pusher']['email']);
$build->setCommitMessage($payload['head_commit']['message']);
$build = $this->buildStore->save($build);
$build->sendStatusPostback();
$branch = str_replace('refs/tags/', 'Tag: ', $payload['ref']);
$committer = $payload['pusher']['email'];
$message = $payload['head_commit']['message'];
$this->createBuild($project, $payload['after'], $branch, $committer, $message);
}
} catch (\Exception $ex) {
@ -167,6 +149,57 @@ class WebhookController extends \PHPCI\Controller
die('OK');
}
protected function githubPullRequest($projectId, array $payload)
{
// We only want to know about open pull requests:
if (!in_array($payload['action'], array('opened', 'synchronize', 'reopened'))) {
die('OK');
}
try {
$headers = array();
$token = \b8\Config::getInstance()->get('phpci.github.token');
if (!empty($token)) {
$headers[] = 'Authorization: token ' . $token;
}
$url = $payload['pull_request']['commits_url'];
$http = new \b8\HttpClient();
$http->setHeaders($headers);
$response = $http->get($url);
// Check we got a success response:
if (!$response['success']) {
header('HTTP/1.1 500 Internal Server Error');
header('Ex: Could not get commits, failed API request.');
die('FAIL');
}
foreach ($response['body'] as $commit) {
$branch = str_replace('refs/heads/', '', $payload['pull_request']['base']['ref']);
$committer = $commit['commit']['author']['email'];
$message = $commit['commit']['message'];
$extra = array(
'build_type' => 'pull_request',
'pull_request_id' => $payload['pull_request']['id'],
'pull_request_number' => $payload['number'],
'remote_branch' => $payload['pull_request']['head']['ref'],
'remote_url' => $payload['pull_request']['head']['repo']['clone_url'],
);
$this->createBuild($projectId, $commit['sha'], $branch, $committer, $message, $extra);
}
} catch (\Exception $ex) {
header('HTTP/1.1 500 Internal Server Error');
header('Ex: ' . $ex->getMessage());
die('FAIL');
}
die('OK');
}
/**
* Called by Gitlab Webhooks:
*/
@ -181,17 +214,9 @@ class WebhookController extends \PHPCI\Controller
// If we have a list of commits, then add them all as builds to be tested:
foreach ($payload['commits'] as $commit) {
$build = new Build();
$build->setProjectId($project);
$build->setCommitId($commit['id']);
$build->setStatus(Build::STATUS_NEW);
$build->setLog('');
$build->setCreated(new \DateTime());
$build->setBranch(str_replace('refs/heads/', '', $payload['ref']));
$build->setCommitterEmail($commit['author']['email']);
$build->setCommitMessage($commit['message']);
$build = $this->buildStore->save($build);
$build->sendStatusPostback();
$branch = str_replace('refs/heads/', '', $payload['ref']);
$committer = $commit['author']['email'];
$this->createBuild($project, $commit['id'], $branch, $committer, $commit['message']);
}
}
@ -203,4 +228,36 @@ class WebhookController extends \PHPCI\Controller
die('OK');
}
protected function createBuild($projectId, $commitId, $branch, $committer, $commitMessage, $extra = null)
{
// Check if a build already exists for this commit ID:
$builds = $this->buildStore->getByProjectAndCommit($projectId, $commitId);
if ($builds['count']) {
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);
if (!is_null($extra)) {
$build->setExtra(json_encode($extra));
}
$build = BuildFactory::getBuild($this->buildStore->save($build));
// Send a status postback if the build type provides one:
$build->sendStatusPostback();
return true;
}
}

View file

@ -0,0 +1,108 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;
use \PHPCI\Logging\BuildLogger;
abstract class BaseCommandExecutor implements CommandExecutor
{
/**
* @var \PHPCI\Logging\BuildLogger
*/
protected $logger;
/**
* @var bool
*/
protected $quiet;
/**
* @var bool
*/
protected $verbose;
protected $lastOutput;
public $logExecOutput = true;
/**
* The path which findBinary will look in.
* @var string
*/
protected $rootDir;
/**
* @param BuildLogger $logger
* @param string $rootDir
* @param bool $quiet
* @param bool $verbose
*/
public function __construct(BuildLogger $logger, $rootDir, &$quiet = false, &$verbose = false)
{
$this->logger = $logger;
$this->quiet = $quiet;
$this->verbose = $verbose;
$this->lastOutput = array();
$this->rootDir = $rootDir;
}
/**
* Executes shell commands.
* @param array $args
* @return bool Indicates success
*/
public function executeCommand($args = array())
{
$this->lastOutput = array();
$command = call_user_func_array('sprintf', $args);
if ($this->quiet) {
$this->logger->log('Executing: ' . $command);
}
$status = 0;
exec($command, $this->lastOutput, $status);
foreach ($this->lastOutput as &$lastOutput) {
$lastOutput = trim($lastOutput, '"');
}
if ($this->logExecOutput && !empty($this->lastOutput) && ($this->verbose|| $status != 0)) {
$this->logger->log($this->lastOutput);
}
$rtn = false;
if ($status == 0) {
$rtn = true;
}
return $rtn;
}
/**
* Returns the output from the last command run.
*/
public function getLastOutput()
{
return implode(PHP_EOL, $this->lastOutput);
}
/**
* Find a binary required by a plugin.
* @param string $binary
* @return null|string
*/
abstract public function findBinary($binary);
}

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;

View file

@ -1,144 +1,32 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;
use \PHPCI\Logging\BuildLogger;
use Psr\Log\LogLevel;
class CommandExecutor
interface CommandExecutor
{
/**
* @var \PHPCI\Logging\BuildLogger
*/
protected $logger;
/**
* @var bool
*/
protected $quiet;
/**
* @var bool
*/
protected $verbose;
protected $lastOutput;
public $logExecOutput = true;
/**
* The path which findBinary will look in.
* @var string
*/
protected $rootDir;
/**
* @param BuildLogger $logger
* @param $rootDir
* @param bool $quiet
* @param bool $verbose
*/
public function __construct(BuildLogger $logger, $rootDir, &$quiet = false, &$verbose = false)
{
$this->logger = $logger;
$this->quiet = $quiet;
$this->verbose = $verbose;
$this->lastOutput = array();
$this->rootDir = $rootDir;
}
/**
* Executes shell commands. Accepts multiple arguments the first
* is the template and everything else is inserted in. c.f. sprintf
* @return bool Indicates success
*/
public function executeCommand()
{
return $this->buildAndExecuteCommand(func_get_args());
}
/**
* Executes shell commands.
* @param array $args
* @return bool Indicates success
*/
public function buildAndExecuteCommand($args = array())
{
$this->lastOutput = array();
$command = call_user_func_array('sprintf', $args);
if ($this->quiet) {
$this->logger->log('Executing: ' . $command);
}
$status = 0;
exec($command, $this->lastOutput, $status);
foreach ($this->lastOutput as &$lastOutput) {
$lastOutput = trim($lastOutput, '"');
}
if ($this->logExecOutput && !empty($this->lastOutput) && ($this->verbose|| $status != 0)) {
$this->logger->log($this->lastOutput);
}
$rtn = false;
if ($status == 0) {
$rtn = true;
}
return $rtn;
}
public function executeCommand();
/**
* Returns the output from the last command run.
*/
public function getLastOutput()
{
return implode(PHP_EOL, $this->lastOutput);
}
public function getLastOutput();
/**
* Find a binary required by a plugin.
* @param $binary
* @param string $binary
* @return null|string
*/
public function findBinary($binary)
{
if (is_string($binary)) {
$binary = array($binary);
}
foreach ($binary as $bin) {
$this->logger->log("Looking for binary: " . $bin, LogLevel::DEBUG);
// Check project root directory:
if (is_file($this->rootDir . $bin)) {
$this->logger->log("Found in root: " . $bin, LogLevel::DEBUG);
return $this->rootDir . $bin;
}
// Check Composer bin dir:
if (is_file($this->rootDir . 'vendor/bin/' . $bin)) {
$this->logger->log("Found in vendor/bin: " . $bin, LogLevel::DEBUG);
return $this->rootDir . 'vendor/bin/' . $bin;
}
// Use "where" for windows and "which" for other OS
$findCmd = IS_WIN ? 'where' : 'which';
$findCmdResult = trim(shell_exec($findCmd . ' ' . $bin));
if (!empty($findCmdResult)) {
$this->logger->log("Found in " . $findCmdResult, LogLevel::DEBUG);
return $findCmdResult;
}
}
return null;
}
public function findBinary($binary);
}

134
PHPCI/Helper/Email.php Normal file
View file

@ -0,0 +1,134 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;
use b8\Config;
use PHPCI\Helper\MailerFactory;
class Email
{
const DEFAULT_FROM = 'PHPCI <no-reply@phptesting.org>';
protected $emailTo = array();
protected $emailCc = array();
protected $subject = 'Email from PHPCI';
protected $body = '';
protected $isHtml = false;
protected $config;
public function __construct()
{
$this->config = Config::getInstance();
}
public function setEmailTo($email, $name = null)
{
$this->emailTo[$email] = $name;
return $this;
}
public function addCc($email, $name = null)
{
$this->emailCc[$email] = $name;
return $this;
}
public function setSubject($subject)
{
$this->subject = $subject;
return $this;
}
public function setBody($body)
{
$this->body = $body;
return $this;
}
public function setIsHtml($isHtml = false)
{
$this->isHtml = $isHtml;
return $this;
}
public function send()
{
$smtpServer = $this->config->get('phpci.email_settings.smtp_address');
if (empty($smtpServer)) {
return $this->sendViaMail();
} else {
return $this->sendViaSwiftMailer();
}
}
protected function sendViaMail()
{
$headers = '';
if ($this->isHtml) {
$headers = 'Content-Type: text/html' . PHP_EOL;
}
$headers .= 'From: ' . $this->getFrom() . PHP_EOL;
$emailTo = array();
foreach ($this->emailTo as $email => $name) {
$thisTo = $email;
if (!is_null($name)) {
$thisTo = '"' . $name . '" <' . $thisTo . '>';
}
$emailTo[] = $thisTo;
}
$emailTo = implode(', ', $emailTo);
return mail($emailTo, $this->subject, $this->body, $headers);
}
protected function sendViaSwiftMailer()
{
$factory = new MailerFactory($this->config->get('phpci'));
$mailer = $factory->getSwiftMailerFromConfig();
$message = \Swift_Message::newInstance($this->subject)
->setFrom($this->getFrom())
->setTo($this->emailTo)
->setBody($this->body);
if ($this->isHtml) {
$message->setContentType('text/html');
}
if (is_array($this->emailCc) && count($this->emailCc)) {
$message->setCc($this->emailCc);
}
return $mailer->send($message);
}
protected function getFrom()
{
$email = $this->config->get('phpci.email_settings.from_address', self::DEFAULT_FROM);
if (empty($email)) {
$email = self::DEFAULT_FROM;
}
return $email;
}
}

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;

View file

@ -0,0 +1,53 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;
use Psr\Log\LogLevel;
class UnixCommandExecutor extends BaseCommandExecutor
{
/**
* Find a binary required by a plugin.
* @param string $binary
* @return null|string
*/
public function findBinary($binary)
{
$binaryPath = null;
if (is_string($binary)) {
$binary = array($binary);
}
foreach ($binary as $bin) {
$this->logger->log("Looking for binary: " . $bin, LogLevel::DEBUG);
if (is_file($this->rootDir . $bin)) {
$this->logger->log("Found in root: " . $bin, LogLevel::DEBUG);
$binaryPath = $this->rootDir . $bin;
break;
}
if (is_file($this->rootDir . 'vendor/bin/' . $bin)) {
$this->logger->log("Found in vendor/bin: " . $bin, LogLevel::DEBUG);
$binaryPath = $this->rootDir . 'vendor/bin/' . $bin;
break;
}
$findCmdResult = trim(shell_exec('which ' . $bin));
if (!empty($findCmdResult)) {
$this->logger->log("Found in " . $findCmdResult, LogLevel::DEBUG);
$binaryPath = $findCmdResult;
break;
}
}
return $binaryPath;
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;

View file

@ -0,0 +1,53 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Helper;
use Psr\Log\LogLevel;
class WindowsCommandExecutor extends BaseCommandExecutor
{
/**
* Find a binary required by a plugin.
* @param string $binary
* @return null|string
*/
public function findBinary($binary)
{
$binaryPath = null;
if (is_string($binary)) {
$binary = array($binary);
}
foreach ($binary as $bin) {
$this->logger->log("Looking for binary: " . $bin, LogLevel::DEBUG);
if (is_file($this->rootDir . $bin)) {
$this->logger->log("Found in root: " . $bin, LogLevel::DEBUG);
$binaryPath = $this->rootDir . $bin;
break;
}
if (is_file($this->rootDir . 'vendor/bin/' . $bin)) {
$this->logger->log("Found in vendor/bin: " . $bin, LogLevel::DEBUG);
$binaryPath = $this->rootDir . 'vendor/bin/' . $bin;
break;
}
$findCmdResult = trim(shell_exec('where ' . $bin));
if (!empty($findCmdResult)) {
$this->logger->log("Found in " . $findCmdResult, LogLevel::DEBUG);
$binaryPath = $findCmdResult;
break;
}
}
return $binaryPath;
}
}

View file

@ -1,8 +1,14 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Logging;
use b8\Store;
use Monolog\Handler\AbstractProcessingHandler;
use PHPCI\Model\Build;

View file

@ -1,8 +1,14 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Logging;
use PHPCI\Model\Build;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Logging;

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Logging;

View file

@ -1,9 +1,14 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Logging;
use Monolog\Logger;
class LoggerConfig

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Logging;
@ -8,7 +15,6 @@ use Symfony\Component\Console\Output\OutputInterface;
class OutputLogHandler extends AbstractProcessingHandler
{
/**
* @var OutputInterface
*/
@ -23,7 +29,6 @@ class OutputLogHandler extends AbstractProcessingHandler
$this->output = $output;
}
protected function write(array $record)
{
$this->output->writeln((string)$record['formatted']);

View file

@ -0,0 +1,218 @@
<?php
use Phinx\Migration\AbstractMigration;
/**
* Initial migration to create a PHPCI v1.2 database.
*/
class InitialMigration extends AbstractMigration
{
/**
* Migrate Up.
*/
public function up()
{
// Set up tables:
$this->createBuildTable();
$this->createBuildMetaTable();
$this->createProjectTable();
$this->createUserTable();
// Set up foreign keys:
$build = $this->table('build');
if (!$build->hasForeignKey('project_id')) {
$build->addForeignKey('project_id', 'project', 'id', array('delete'=> 'CASCADE', 'update' => 'CASCADE'));
}
$build->save();
$buildMeta = $this->table('build_meta');
if (!$buildMeta->hasForeignKey('build_id')) {
$buildMeta->addForeignKey('build_id', 'build', 'id', array('delete'=> 'CASCADE', 'update' => 'CASCADE'));
}
if (!$buildMeta->hasForeignKey('project_id')) {
$buildMeta->addForeignKey('project_id', 'project', 'id', array('delete'=> 'CASCADE', 'update' => 'CASCADE'));
}
$buildMeta->save();
}
/**
* Migrate Down.
*/
public function down()
{
}
protected function createBuildTable()
{
$table = $this->table('build');
if (!$table->hasColumn('project_id')) {
$table->addColumn('project_id', 'integer');
}
if (!$table->hasColumn('commit_id')) {
$table->addColumn('commit_id', 'string', array('limit' => 50));
}
if (!$table->hasColumn('status')) {
$table->addColumn('status', 'integer', array('limit' => 4));
}
if (!$table->hasColumn('log')) {
$table->addColumn('log', 'text');
}
if (!$table->hasColumn('branch')) {
$table->addColumn('branch', 'string', array('limit' => 50));
}
if (!$table->hasColumn('created')) {
$table->addColumn('created', 'datetime');
}
if (!$table->hasColumn('started')) {
$table->addColumn('started', 'datetime');
}
if (!$table->hasColumn('finished')) {
$table->addColumn('finished', 'datetime');
}
if (!$table->hasColumn('committer_email')) {
$table->addColumn('committer_email', 'string', array('limit' => 250));
}
if (!$table->hasColumn('commit_message')) {
$table->addColumn('commit_message', 'text');
}
if (!$table->hasColumn('extra')) {
$table->addColumn('extra', 'text');
}
if ($table->hasColumn('plugins')) {
$table->removeColumn('plugins');
}
if (!$table->hasIndex(array('project_id'))) {
$table->addIndex(array('project_id'));
}
if (!$table->hasIndex(array('status'))) {
$table->addIndex(array('status'));
}
$table->save();
}
protected function createBuildMetaTable()
{
$table = $this->table('build_meta');
if (!$table->hasColumn('project_id')) {
$table->addColumn('project_id', 'integer');
}
if (!$table->hasColumn('build_id')) {
$table->addColumn('build_id', 'integer');
}
if (!$table->hasColumn('meta_key')) {
$table->addColumn('meta_key', 'string', array('limit' => 250));
}
if (!$table->hasColumn('meta_value')) {
$table->addColumn('meta_value', 'text');
}
if (!$table->hasIndex(array('build_id', 'meta_key'))) {
$table->addIndex(array('build_id', 'meta_key'));
}
$table->save();
}
protected function createProjectTable()
{
$table = $this->table('project');
if (!$table->hasColumn('title')) {
$table->addColumn('title', 'string', array('limit' => 250));
}
if (!$table->hasColumn('reference')) {
$table->addColumn('reference', 'string', array('limit' => 250));
}
if (!$table->hasColumn('git_key')) {
$table->addColumn('git_key', 'text');
}
if (!$table->hasColumn('public_key')) {
$table->addColumn('public_key', 'text');
}
if (!$table->hasColumn('type')) {
$table->addColumn('type', 'string', array('limit' => 50));
}
if (!$table->hasColumn('access_information')) {
$table->addColumn('access_information', 'string', array('limit' => 250));
}
if (!$table->hasColumn('last_commit')) {
$table->addColumn('last_commit', 'string', array('limit' => 250));
}
if (!$table->hasColumn('build_config')) {
$table->addColumn('build_config', 'text');
}
if (!$table->hasColumn('allow_public_status')) {
$table->addColumn('allow_public_status', 'integer');
}
if ($table->hasColumn('token')) {
$table->removeColumn('token');
}
if (!$table->hasIndex(array('title'))) {
$table->addIndex(array('title'));
}
$table->save();
}
protected function createUserTable()
{
$table = $this->table('user');
if (!$table->hasColumn('email')) {
$table->addColumn('email', 'string', array('limit' => 250));
}
if (!$table->hasColumn('hash')) {
$table->addColumn('hash', 'string', array('limit' => 250));
}
if (!$table->hasColumn('name')) {
$table->addColumn('name', 'string', array('limit' => 250));
}
if (!$table->hasColumn('is_admin')) {
$table->addColumn('is_admin', 'integer');
}
if (!$table->hasIndex(array('email'))) {
$table->addIndex(array('email'));
}
$table->save();
}
}

View file

@ -0,0 +1,26 @@
<?php
use Phinx\Migration\AbstractMigration;
class ChangeBuildKeysMigration extends AbstractMigration
{
/**
* Migrate Up.
*/
public function up()
{
$project = $this->table('project');
$project->renameColumn('git_key', 'ssh_private_key');
$project->renameColumn('public_key', 'ssh_public_key');
}
/**
* Migrate Down.
*/
public function down()
{
$project = $this->table('project');
$project->renameColumn('ssh_private_key', 'git_key');
$project->renameColumn('ssh_public_key', 'public_key');
}
}

View file

@ -1,4 +1,12 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI;
abstract class Model extends \b8\Model

View file

@ -42,9 +42,9 @@ class BuildBase extends Model
'created' => null,
'started' => null,
'finished' => null,
'plugins' => null,
'committer_email' => null,
'commit_message' => null,
'extra' => null,
);
/**
@ -61,9 +61,9 @@ class BuildBase extends Model
'created' => 'getCreated',
'started' => 'getStarted',
'finished' => 'getFinished',
'plugins' => 'getPlugins',
'committer_email' => 'getCommitterEmail',
'commit_message' => 'getCommitMessage',
'extra' => 'getExtra',
// Foreign key getters:
'Project' => 'getProject',
@ -83,9 +83,9 @@ class BuildBase extends Model
'created' => 'setCreated',
'started' => 'setStarted',
'finished' => 'setFinished',
'plugins' => 'setPlugins',
'committer_email' => 'setCommitterEmail',
'commit_message' => 'setCommitMessage',
'extra' => 'setExtra',
// Foreign key setters:
'Project' => 'setProject',
@ -143,11 +143,6 @@ class BuildBase extends Model
'nullable' => true,
'default' => null,
),
'plugins' => array(
'type' => 'text',
'nullable' => true,
'default' => null,
),
'committer_email' => array(
'type' => 'varchar',
'length' => 512,
@ -159,6 +154,11 @@ class BuildBase extends Model
'nullable' => true,
'default' => null,
),
'extra' => array(
'type' => 'longtext',
'nullable' => true,
'default' => null,
),
);
/**
@ -303,18 +303,6 @@ class BuildBase extends Model
return $rtn;
}
/**
* Get the value of Plugins / plugins.
*
* @return string
*/
public function getPlugins()
{
$rtn = $this->data['plugins'];
return $rtn;
}
/**
* Get the value of CommitterEmail / committer_email.
*
@ -339,6 +327,18 @@ class BuildBase extends Model
return $rtn;
}
/**
* Get the value of Extra / extra.
*
* @return string
*/
public function getExtra()
{
$rtn = $this->data['extra'];
return $rtn;
}
/**
* Set the value of Id / id.
*
@ -509,24 +509,6 @@ class BuildBase extends Model
$this->_setModified('finished');
}
/**
* Set the value of Plugins / plugins.
*
* @param $value string
*/
public function setPlugins($value)
{
$this->_validateString('Plugins', $value);
if ($this->data['plugins'] === $value) {
return;
}
$this->data['plugins'] = $value;
$this->_setModified('plugins');
}
/**
* Set the value of CommitterEmail / committer_email.
*
@ -563,6 +545,24 @@ class BuildBase extends Model
$this->_setModified('commit_message');
}
/**
* Set the value of Extra / extra.
*
* @param $value string
*/
public function setExtra($value)
{
$this->_validateString('Extra', $value);
if ($this->data['extra'] === $value) {
return;
}
$this->data['extra'] = $value;
$this->_setModified('extra');
}
/**
* Get the Project model for this Build by Id.
*

View file

@ -52,6 +52,7 @@ class BuildMetaBase extends Model
'meta_value' => 'getMetaValue',
// Foreign key getters:
'Project' => 'getProject',
'Build' => 'getBuild',
);
@ -67,6 +68,7 @@ class BuildMetaBase extends Model
'meta_value' => 'setMetaValue',
// Foreign key setters:
'Project' => 'setProject',
'Build' => 'setBuild',
);
@ -98,7 +100,7 @@ class BuildMetaBase extends Model
'default' => null,
),
'meta_value' => array(
'type' => 'text',
'type' => 'longtext',
'nullable' => true,
'default' => null,
),
@ -110,12 +112,20 @@ class BuildMetaBase extends Model
public $indexes = array(
'PRIMARY' => array('unique' => true, 'columns' => 'id'),
'idx_meta_id' => array('unique' => true, 'columns' => 'build_id, meta_key'),
'project_id' => array('columns' => 'project_id'),
);
/**
* @var array
*/
public $foreignKeys = array(
'build_meta_ibfk_1' => array(
'local_col' => 'project_id',
'update' => 'CASCADE',
'delete' => 'CASCADE',
'table' => 'project',
'col' => 'id'
),
'fk_meta_build_id' => array(
'local_col' => 'build_id',
'update' => 'CASCADE',
@ -281,6 +291,63 @@ class BuildMetaBase extends Model
$this->_setModified('meta_value');
}
/**
* Get the Project model for this BuildMeta 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;
}
$cacheKey = 'Cache.Project.' . $key;
$rtn = $this->cache->get($cacheKey, null);
if (empty($rtn)) {
$rtn = Factory::getStore('Project', 'PHPCI')->getById($key);
$this->cache->set($cacheKey, $rtn);
}
return $rtn;
}
/**
* Set Project - Accepts an ID, an array representing a Project or a Project model.
*
* @param $value mixed
*/
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);
}
/**
* Set Project - Accepts a Project model.
*
* @param $value \PHPCI\Model\Project
*/
public function setProjectObject(\PHPCI\Model\Project $value)
{
return $this->setProjectId($value->getId());
}
/**
* Get the Build model for this BuildMeta by Id.
*

View file

@ -36,10 +36,9 @@ class ProjectBase extends Model
'id' => null,
'title' => null,
'reference' => null,
'git_key' => null,
'public_key' => null,
'ssh_private_key' => null,
'ssh_public_key' => null,
'type' => null,
'token' => null,
'access_information' => null,
'last_commit' => null,
'build_config' => null,
@ -54,10 +53,9 @@ class ProjectBase extends Model
'id' => 'getId',
'title' => 'getTitle',
'reference' => 'getReference',
'git_key' => 'getGitKey',
'public_key' => 'getPublicKey',
'ssh_private_key' => 'getSshPrivateKey',
'ssh_public_key' => 'getSshPublicKey',
'type' => 'getType',
'token' => 'getToken',
'access_information' => 'getAccessInformation',
'last_commit' => 'getLastCommit',
'build_config' => 'getBuildConfig',
@ -74,10 +72,9 @@ class ProjectBase extends Model
'id' => 'setId',
'title' => 'setTitle',
'reference' => 'setReference',
'git_key' => 'setGitKey',
'public_key' => 'setPublicKey',
'ssh_private_key' => 'setSshPrivateKey',
'ssh_public_key' => 'setSshPublicKey',
'type' => 'setType',
'token' => 'setToken',
'access_information' => 'setAccessInformation',
'last_commit' => 'setLastCommit',
'build_config' => 'setBuildConfig',
@ -107,12 +104,12 @@ class ProjectBase extends Model
'length' => 250,
'default' => null,
),
'git_key' => array(
'ssh_private_key' => array(
'type' => 'text',
'nullable' => true,
'default' => null,
),
'public_key' => array(
'ssh_public_key' => array(
'type' => 'text',
'nullable' => true,
'default' => null,
@ -122,12 +119,6 @@ class ProjectBase extends Model
'length' => 50,
'default' => 1,
),
'token' => array(
'type' => 'varchar',
'length' => 50,
'nullable' => true,
'default' => null,
),
'access_information' => array(
'type' => 'varchar',
'length' => 250,
@ -202,25 +193,25 @@ class ProjectBase extends Model
}
/**
* Get the value of GitKey / git_key.
* Get the value of SshPrivateKey / ssh_private_key.
*
* @return string
*/
public function getGitKey()
public function getSshPrivateKey()
{
$rtn = $this->data['git_key'];
$rtn = $this->data['ssh_private_key'];
return $rtn;
}
/**
* Get the value of PublicKey / public_key.
* Get the value of SshPublicKey / ssh_public_key.
*
* @return string
*/
public function getPublicKey()
public function getSshPublicKey()
{
$rtn = $this->data['public_key'];
$rtn = $this->data['ssh_public_key'];
return $rtn;
}
@ -237,18 +228,6 @@ class ProjectBase extends Model
return $rtn;
}
/**
* Get the value of Token / token.
*
* @return string
*/
public function getToken()
{
$rtn = $this->data['token'];
return $rtn;
}
/**
* Get the value of AccessInformation / access_information.
*
@ -358,39 +337,39 @@ class ProjectBase extends Model
}
/**
* Set the value of GitKey / git_key.
* Set the value of SshPrivateKey / ssh_private_key.
*
* @param $value string
*/
public function setGitKey($value)
public function setSshPrivateKey($value)
{
$this->_validateString('GitKey', $value);
$this->_validateString('SshPrivateKey', $value);
if ($this->data['git_key'] === $value) {
if ($this->data['ssh_private_key'] === $value) {
return;
}
$this->data['git_key'] = $value;
$this->data['ssh_private_key'] = $value;
$this->_setModified('git_key');
$this->_setModified('ssh_private_key');
}
/**
* Set the value of PublicKey / public_key.
* Set the value of SshPublicKey / ssh_public_key.
*
* @param $value string
*/
public function setPublicKey($value)
public function setSshPublicKey($value)
{
$this->_validateString('PublicKey', $value);
$this->_validateString('SshPublicKey', $value);
if ($this->data['public_key'] === $value) {
if ($this->data['ssh_public_key'] === $value) {
return;
}
$this->data['public_key'] = $value;
$this->data['ssh_public_key'] = $value;
$this->_setModified('public_key');
$this->_setModified('ssh_public_key');
}
/**
@ -413,24 +392,6 @@ class ProjectBase extends Model
$this->_setModified('type');
}
/**
* Set the value of Token / token.
*
* @param $value string
*/
public function setToken($value)
{
$this->_validateString('Token', $value);
if ($this->data['token'] === $value) {
return;
}
$this->data['token'] = $value;
$this->_setModified('token');
}
/**
* Set the value of AccessInformation / access_information.
*
@ -516,4 +477,16 @@ class ProjectBase extends Model
{
return Factory::getStore('Build', 'PHPCI')->getByProjectId($this->getId());
}
/**
* Get BuildMeta models by ProjectId for this Project.
*
* @uses \PHPCI\Store\BuildMetaStore::getByProjectId()
* @uses \PHPCI\Model\BuildMeta
* @return \PHPCI\Model\BuildMeta[]
*/
public function getProjectBuildMetas()
{
return Factory::getStore('BuildMeta', 'PHPCI')->getByProjectId($this->getId());
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model;
@ -122,7 +122,7 @@ class Build extends BuildBase
$config = array(
'build_settings' => array(
'ignore' => array(
'vendor/',
'vendor',
)
)
);
@ -164,4 +164,19 @@ class Build extends BuildBase
{
return null;
}
public function getExtra($key = null)
{
$data = json_decode($this->data['extra'], true);
if (is_null($key)) {
$rtn = $data;
} elseif (isset($data[$key])) {
$rtn = $data[$key];
} else {
$rtn = null;
}
return $rtn;
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model\Build;
@ -41,7 +41,7 @@ class BitbucketBuild extends RemoteGitBuild
*/
protected function getCloneUrl()
{
$key = trim($this->getProject()->getGitKey());
$key = trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
return 'git@bitbucket.org:' . $this->getProject()->getReference() . '.git';

View file

@ -1,14 +1,15 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model\Build;
use PHPCI\Builder;
use PHPCI\Model\Build\RemoteGitBuild;
/**
@ -85,7 +86,7 @@ class GithubBuild extends RemoteGitBuild
*/
protected function getCloneUrl()
{
$key = trim($this->getProject()->getGitKey());
$key = trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
return 'git@github.com:' . $this->getProject()->getReference() . '.git';
@ -115,4 +116,29 @@ class GithubBuild extends RemoteGitBuild
return $link;
}
protected function postCloneSetup(Builder $builder, $cloneTo)
{
$buildType = $this->getExtra('build_type');
$success = true;
try {
if (!empty($buildType) && $buildType == 'pull_request') {
$remoteUrl = $this->getExtra('remote_url');
$remoteBranch = $this->getExtra('remote_branch');
$cmd = 'cd "%s" && git checkout -b phpci/' . $this->getId() . ' %s && git pull -q --no-edit %s %s';
$success = $builder->executeCommand($cmd, $cloneTo, $this->getBranch(), $remoteUrl, $remoteBranch);
}
} catch (\Exception $ex) {
$success = false;
}
if ($success) {
$success = parent::postCloneSetup($builder, $cloneTo);
}
return $success;
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model\Build;
@ -56,7 +56,7 @@ class GitlabBuild extends RemoteGitBuild
*/
protected function getCloneUrl()
{
$key = trim($this->getProject()->getGitKey());
$key = trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
$user = $this->getProject()->getAccessInformation("user");

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model\Build;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model\Build;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model\Build;
@ -33,7 +33,7 @@ class RemoteGitBuild extends Build
*/
public function createWorkingCopy(Builder $builder, $buildPath)
{
$key = trim($this->getProject()->getGitKey());
$key = trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
$success = $this->cloneBySsh($builder, $buildPath);
@ -65,12 +65,8 @@ class RemoteGitBuild extends Build
$cmd .= ' -b %s %s "%s"';
$success = $builder->executeCommand($cmd, $this->getBranch(), $this->getCloneUrl(), $cloneTo);
if (!empty($commit) && $commit != 'Manual') {
$cmd = 'cd "%s" && git checkout %s';
if (IS_WIN) {
$cmd = 'cd /d "%s" && git checkout %s';
}
$builder->executeCommand($cmd, $cloneTo, $this->getCommitId());
if ($success) {
$success = $this->postCloneSetup($builder, $cloneTo);
}
return $success;
@ -104,15 +100,8 @@ class RemoteGitBuild extends Build
$success = $builder->executeCommand($cmd, $this->getBranch(), $this->getCloneUrl(), $cloneTo);
// Checkout a specific commit if we need to:
$commit = $this->getCommitId();
if (!empty($commit) && $commit != 'Manual') {
$cmd = 'cd "%s" && git checkout %s';
if (IS_WIN) {
$cmd = 'cd /d "%s" && git checkout %s';
}
$builder->executeCommand($cmd, $cloneTo, $this->getCommitId());
if ($success) {
$success = $this->postCloneSetup($builder, $cloneTo);
}
// Remove the key file and git wrapper:
@ -122,6 +111,24 @@ class RemoteGitBuild extends Build
return $success;
}
protected function postCloneSetup(Builder $builder, $cloneTo)
{
$success = true;
$commit = $this->getCommitId();
if (!empty($commit) && $commit != 'Manual') {
$cmd = 'cd "%s" && git checkout %s';
if (IS_WIN) {
$cmd = 'cd /d "%s" && git checkout %s';
}
$success = $builder->executeCommand($cmd, $cloneTo, $this->getCommitId());
}
return $success;
}
/**
* Create an SSH key file on disk for this build.
* @param $cloneTo
@ -133,7 +140,7 @@ class RemoteGitBuild extends Build
$keyFile = $keyPath . '.key';
// Write the contents of this project's git key to the file:
file_put_contents($keyFile, $this->getProject()->getGitKey());
file_put_contents($keyFile, $this->getProject()->getSshPrivateKey());
chmod($keyFile, 0600);
// Return the filename:

View file

@ -1,7 +1,10 @@
<?php
/**
* BuildMeta model for table: build_meta
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Model;

View file

@ -1,15 +1,14 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI;
use PHPCI\Builder;
use PHPCI\Model\Build;
/**

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -38,6 +38,9 @@ class CleanBuild implements \PHPCI\Plugin
public function execute()
{
$cmd = 'rm -Rf "%s"';
if (IS_WIN) {
$cmd = 'rmdir /S /Q "%s"';
}
$this->phpci->executeCommand($cmd, $this->phpci->buildPath . 'composer.phar');
$this->phpci->executeCommand($cmd, $this->phpci->buildPath . 'composer.lock');

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -40,12 +40,24 @@ class Composer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$path = $phpci->buildPath;
$this->phpci = $phpci;
$path = $phpci->buildPath;
$this->phpci = $phpci;
$this->build = $build;
$this->directory = isset($options['directory']) ? $path . '/' . $options['directory'] : $path;
$this->action = isset($options['action']) ? $options['action'] : 'install';
$this->preferDist = isset($options['prefer_dist']) ? $options['prefer_dist'] : true;
$this->directory = $path;
$this->action = 'install';
$this->preferDist = false;
if (array_key_exists('directory', $options)) {
$this->directory = $path . '/' . $options['directory'];
}
if (array_key_exists('action', $options)) {
$this->action = $options['action'];
}
if (array_key_exists('prefer_dist', $options)) {
$this->preferDist = (bool)$options['prefer_dist'];
}
}
/**
@ -59,12 +71,24 @@ class Composer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$this->phpci->logFailure('Could not find Composer.');
return false;
}
$cmd = '';
if (IS_WIN) {
$cmd = 'php ';
}
$cmd .= $composerLocation . ' --no-ansi --no-interaction ';
$cmd .= ($this->preferDist ? '--prefer-dist' : null) . ' --working-dir="%s" %s';
if ($this->preferDist) {
$this->phpci->log('Using --prefer-dist flag');
$cmd .= '--prefer-dist';
} else {
$this->phpci->log('Using --prefer-source flag');
$cmd .= '--prefer-source';
}
$cmd .= ' --working-dir="%s" %s';
return $this->phpci->executeCommand($cmd, $this->directory, $this->action);
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -46,11 +46,17 @@ class CopyBuild implements \PHPCI\Plugin
}
$cmd = 'mkdir -p "%s" && cp -R "%s" "%s"';
if (IS_WIN) {
$cmd = 'mkdir -p "%s" && xcopy /E "%s" "%s"';
}
$success = $this->phpci->executeCommand($cmd, $this->directory, $build, $this->directory);
if ($this->ignore) {
foreach ($this->phpci->ignore as $file) {
$cmd = 'rm -Rf "%s/%s"';
if (IS_WIN) {
$cmd = 'rmdir /S /Q "%s\%s"';
}
$this->phpci->executeCommand($cmd, $this->directory, $file);
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -80,8 +80,9 @@ class Git implements \PHPCI\Plugin
protected function runMergeAction($options)
{
if (array_key_exists('branch', $options)) {
$cmd = 'git checkout %s && git merge ' . $this->build->getBranch();
return $this->phpci->executeCommand($cmd, $this->directory, $options['branch']);
$cmd = 'cd "%s" && git checkout %s && git merge "%s"';
$path = $this->phpci->buildPath;
return $this->phpci->executeCommand($cmd, $path, $options['branch'], $this->build->getBranch());
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -0,0 +1,63 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
use PHPCI\Builder;
use PHPCI\Model\Build;
/**
* Hipchat Plugin
* @author James Inman <james@jamesinman.co.uk>
* @package PHPCI
* @subpackage Plugins
*/
class HipchatNotify implements \PHPCI\Plugin
{
private $authToken;
private $userAgent;
private $cookie;
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->userAgent = "PHPCI/1.0 (+http://www.phptesting.org/)";
$this->cookie = "phpcicookie";
if (is_array($options) && isset($options['authToken']) && isset($options['room'])) {
$this->authToken = $options['authToken'];
$this->room = $options['room'];
if (isset($options['message'])) {
$this->message = $options['message'];
} else {
$this->message = '%PROJECT_TITLE% built at %BUILD_URI%';
}
} else {
throw new \Exception('Please define room and authToken for hipchat_notify plugin!');
}
}
public function execute()
{
$hipChat = new \HipChat\HipChat($this->authToken);
$message = $this->phpci->interpolate($this->message);
if (is_array($this->room)) {
foreach ($this->room as $room) {
$hipChat->message_room($room, 'PHPCI', $message);
}
} else {
$hipChat->message_room($this->room, 'PHPCI', $message);
}
}
}

View file

@ -1,4 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -22,24 +22,41 @@ use PHPCI\Model\Build;
*/
class Mysql implements \PHPCI\Plugin
{
/**
* @var \PHPCI\Builder
*/
protected $phpci;
/**
* @var \PHPCI\Model\Build
*/
protected $build;
/**
* @var array
*/
protected $queries = array();
/**
* @var string
*/
protected $host;
/**
* @var string
*/
protected $user;
/**
* @var string
*/
protected $pass;
/**
* Database Connection
* @var PDO
* @param Builder $phpci
* @param Build $build
* @param array $options
*/
protected $pdo;
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
@ -74,19 +91,18 @@ class Mysql implements \PHPCI\Plugin
/**
* Connects to MySQL and runs a specified set of queries.
* @return boolean
*/
public function execute()
{
$success = true;
try {
$opts = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$this->pdo = new PDO('mysql:host=' . $this->host, $this->user, $this->pass, $opts);
$pdo = new PDO('mysql:host=' . $this->host, $this->user, $this->pass, $opts);
foreach ($this->queries as $query) {
if (!is_array($query)) {
// Simple query
$this->pdo->query($this->phpci->interpolate($query));
$pdo->query($this->phpci->interpolate($query));
} elseif (isset($query['import'])) {
// SQL file execution
$this->executeFile($query['import']);
@ -98,10 +114,14 @@ class Mysql implements \PHPCI\Plugin
$this->phpci->logFailure($ex->getMessage());
return false;
}
return $success;
return true;
}
/**
* @param string $query
* @return boolean
* @throws \Exception
*/
protected function executeFile($query)
{
if (!isset($query['file'])) {

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -21,18 +21,45 @@ use PHPCI\Model\Build;
*/
class Pgsql implements \PHPCI\Plugin
{
/**
* @var \PHPCI\Builder
*/
protected $phpci;
/**
* @var \PHPCI\Model\Build
*/
protected $build;
/**
* @var array
*/
protected $queries = array();
/**
* @var string
*/
protected $host;
/**
* @var string
*/
protected $user;
/**
* @var string
*/
protected $pass;
/**
* @param Builder $phpci
* @param Build $build
* @param array $options
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->phpci = $phpci;
$this->build = $build;
$this->queries = $options;
$buildSettings = $phpci->getConfig('build_settings');
@ -47,6 +74,7 @@ class Pgsql implements \PHPCI\Plugin
/**
* Connects to PgSQL and runs a specified set of queries.
* @return boolean
*/
public function execute()
{
@ -61,7 +89,6 @@ class Pgsql implements \PHPCI\Plugin
$this->phpci->logFailure($ex->getMessage());
return false;
}
return true;
}
}

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -109,14 +109,6 @@ class PhpCodeSniffer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$this->suffixes = (array)$options['suffixes'];
}
if (isset($options['directory'])) {
$this->directory = $options['directory'];
}
if (isset($options['standard'])) {
$this->standard = $options['standard'];
}
if (!empty($options['tab_width'])) {
$this->tab_width = ' --tab-width='.$options['tab_width'];
}
@ -125,20 +117,15 @@ class PhpCodeSniffer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$this->encoding = ' --encoding=' . $options['encoding'];
}
if (isset($options['path'])) {
$this->path = $options['path'];
}
$this->setOptions($options);
}
if (isset($options['ignore'])) {
$this->ignore = $options['ignore'];
}
if (isset($options['allowed_warnings'])) {
$this->allowed_warnings = (int)$options['allowed_warnings'];
}
if (isset($options['allowed_errors'])) {
$this->allowed_errors = (int)$options['allowed_errors'];
protected function setOptions($options)
{
foreach (array('directory', 'standard', 'path', 'ignore', 'allowed_warnings', 'allowed_errors') as $key) {
if (array_key_exists($key, $options)) {
$this->{$key} = $options[$key];
}
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -0,0 +1,147 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
use PHPCI;
use PHPCI\Builder;
use PHPCI\Model\Build;
/**
* PHP Docblock Checker Plugin - Checks your PHP files for appropriate uses of Docblocks
* @author Dan Cryer <dan@block8.co.uk>
* @package PHPCI
* @subpackage Plugins
*/
class PhpDocblockChecker implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
{
/**
* @var \PHPCI\Builder
*/
protected $phpci;
/**
* @var \PHPCI\Model\Build
*/
protected $build;
/**
* @var string Based on the assumption the root may not hold the code to be
* tested, extends the build path.
*/
protected $path;
/**
* @var array - paths to ignore
*/
protected $ignore;
protected $skipClasses = false;
protected $skipMethods = false;
public static function canExecute($stage, Builder $builder, Build $build)
{
if ($stage == 'test') {
return true;
}
return false;
}
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->ignore = $phpci->ignore;
$this->path = '';
$this->allowed_warnings = 0;
if (isset($options['zero_config']) && $options['zero_config']) {
$this->allowed_warnings = -1;
}
if (array_key_exists('skip_classes', $options)) {
$this->skipClasses = true;
}
if (array_key_exists('skip_methods', $options)) {
$this->skipMethods = true;
}
if (!empty($options['path'])) {
$this->path = $options['path'];
}
if (array_key_exists('allowed_warnings', $options)) {
$this->allowed_warnings = (int)$options['allowed_warnings'];
}
}
/**
* Runs PHP Mess Detector in a specified directory.
*/
public function execute()
{
// Check that the binary exists:
$checker = $this->phpci->findBinary('phpdoccheck');
if (!$checker) {
$this->phpci->logFailure('Could not find phpdoccheck.');
return false;
}
// Build ignore string:
$ignore = '';
if (count($this->ignore)) {
$ignore = ' --exclude="' . implode(',', $this->ignore) . '"';
}
// Are we skipping any checks?
$add = '';
if ($this->skipClasses) {
$add .= ' --skip-classes';
}
if ($this->skipMethods) {
$add .= ' --skip-methods';
}
// Build command string:
$path = $this->phpci->buildPath . $this->path;
$cmd = $checker . ' --json --directory="%s"%s%s';
// Disable exec output logging, as we don't want the XML report in the log:
$this->phpci->logExecOutput(false);
// Run checker:
$this->phpci->executeCommand(
$cmd,
$path,
$ignore,
$add
);
// Re-enable exec output logging:
$this->phpci->logExecOutput(true);
$output = json_decode($this->phpci->getLastOutput());
$errors = count($output);
$success = true;
$this->build->storeMeta('phpdoccheck-warnings', $errors);
$this->build->storeMeta('phpdoccheck-data', $output);
if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) {
$success = false;
}
return $success;
}
}

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -68,7 +68,7 @@ class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
return false;
}
$success = $this->phpci->executeCommand($phploc . ' %s "%s"', $ignore, $this->phpci->buildPath);
$success = $this->phpci->executeCommand($phploc . ' %s "%s"', $ignore, $this->directory);
$output = $this->phpci->getLastOutput();
if (preg_match_all('/\((LOC|CLOC|NCLOC|LLOC)\)\s+([0-9]+)/', $output, $matches)) {

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -97,67 +97,24 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
*/
public function execute()
{
$ignore = '';
if (count($this->ignore)) {
$ignore = ' --exclude ' . implode(',', $this->ignore);
}
$suffixes = '';
if (count($this->suffixes)) {
$suffixes = ' --suffixes ' . implode(',', $this->suffixes);
}
if (!empty($this->rules) && !is_array($this->rules)) {
$this->phpci->logFailure('The "rules" option must be an array.');
if (!$this->tryAndProcessRules()) {
return false;
}
foreach ($this->rules as &$rule) {
if (strpos($rule, '/') !== false) {
$rule = $this->phpci->buildPath . $rule;
}
}
$phpmdBinaryPath = $this->phpci->findBinary('phpmd');
$phpmd = $this->phpci->findBinary('phpmd');
if (!$phpmd) {
if (!$phpmdBinaryPath) {
$this->phpci->logFailure('Could not find phpmd.');
return false;
}
$path = $this->phpci->buildPath . $this->path;
if (!empty($this->path) && $this->path{0} == '/') {
$path = $this->path;
}
$cmd = $phpmd . ' "%s" xml %s %s %s';
$this->executePhpMd($phpmdBinaryPath);
// Disable exec output logging, as we don't want the XML report in the log:
$this->phpci->logExecOutput(false);
// Run PHPMD:
$this->phpci->executeCommand(
$cmd,
$path,
implode(',', $this->rules),
$ignore,
$suffixes
);
// Re-enable exec output logging:
$this->phpci->logExecOutput(true);
$success = true;
list($errors, $data) = $this->processReport(trim($this->phpci->getLastOutput()));
$this->build->storeMeta('phpmd-warnings', $errors);
list($errorCount, $data) = $this->processReport(trim($this->phpci->getLastOutput()));
$this->build->storeMeta('phpmd-warnings', $errorCount);
$this->build->storeMeta('phpmd-data', $data);
if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) {
$success = false;
}
return $success;
return $this->wasLastExecSuccessful($errorCount);
}
protected function overrideSetting($options, $key)
@ -200,4 +157,79 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
return array($warnings, $data);
}
protected function tryAndProcessRules()
{
if (!empty($this->rules) && !is_array($this->rules)) {
$this->phpci->logFailure('The "rules" option must be an array.');
return false;
}
foreach ($this->rules as &$rule) {
if (strpos($rule, '/') !== false) {
$rule = $this->phpci->buildPath . $rule;
}
}
return true;
}
protected function executePhpMd($binaryPath)
{
$cmd = $binaryPath . ' "%s" xml %s %s %s';
$path = $this->getTargetPath();
$ignore = '';
if (count($this->ignore)) {
$ignore = ' --exclude ' . implode(',', $this->ignore);
}
$suffixes = '';
if (count($this->suffixes)) {
$suffixes = ' --suffixes ' . implode(',', $this->suffixes);
}
// Disable exec output logging, as we don't want the XML report in the log:
$this->phpci->logExecOutput(false);
// Run PHPMD:
$this->phpci->executeCommand(
$cmd,
$path,
implode(',', $this->rules),
$ignore,
$suffixes
);
// Re-enable exec output logging:
$this->phpci->logExecOutput(true);
}
protected function getTargetPath()
{
$path = $this->phpci->buildPath . $this->path;
if (!empty($this->path) && $this->path{0} == '/') {
$path = $this->path;
return $path;
}
return $path;
}
/**
* Returns a boolean indicating if the error count can be considered a success.
*
* @param int $errorCount
* @return bool
*/
protected function wasLastExecSuccessful($errorCount)
{
$success = true;
if ($this->allowed_warnings != -1 && $errorCount > $this->allowed_warnings) {
$success = false;
return $success;
}
return $success;
}
}

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -58,7 +58,7 @@ class PhpSpec implements PHPCI\Plugin
return false;
}
$success = $this->phpci->executeCommand($phpspec . ' --format=pretty --no-code-generation');
$success = $this->phpci->executeCommand($phpspec . ' --format=pretty --no-code-generation run');
chdir($curdir);

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -101,7 +101,7 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
}
if (isset($options['args'])) {
$this->args = $options['args'];
$this->args = $this->phpci->interpolate($options['args']);
}
if (isset($options['path'])) {
@ -132,9 +132,16 @@ class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin
$success &= $this->runDir($this->directory);
}
$output = $this->phpci->getLastOutput();
$tapParser = new TapParser($output);
$output = $tapParser->parse();
$tapString = $this->phpci->getLastOutput();
try {
$tapParser = new TapParser($tapString);
$output = $tapParser->parse();
} catch (\Exception $ex) {
$this->phpci->logFailure($tapString);
throw $ex;
}
$failures = $tapParser->getTotalFailures();
$this->build->storeMeta('phpunit-errors', $failures);

View file

@ -2,9 +2,9 @@
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;

81
PHPCI/Plugin/Sqlite.php Normal file
View file

@ -0,0 +1,81 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
use PDO;
use PHPCI\Builder;
use PHPCI\Model\Build;
/**
* SQLite Plugin Provides access to a SQLite database.
* @author Corpsee <poisoncorpsee@gmail.com>
* @package PHPCI
* @subpackage Plugins
*/
class Sqlite implements \PHPCI\Plugin
{
/**
* @var \PHPCI\Builder
*/
protected $phpci;
/**
* @var \PHPCI\Model\Build
*/
protected $build;
/**
* @var array
*/
protected $queries = array();
/**
* @var string
*/
protected $path;
/**
* @param Builder $phpci
* @param Build $build
* @param array $options
*/
public function __construct(Builder $phpci, Build $build, array $options = array())
{
$this->phpci = $phpci;
$this->build = $build;
$this->queries = $options;
$buildSettings = $phpci->getConfig('build_settings');
if (isset($buildSettings['sqlite'])) {
$sql = $buildSettings['sqlite'];
$this->path = $sql['path'];
}
}
/**
* Connects to SQLite and runs a specified set of queries.
* @return boolean
*/
public function execute()
{
try {
$opts = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$pdo = new PDO('sqlite:' . $this->path, $opts);
foreach ($this->queries as $query) {
$pdo->query($query);
}
} catch (\Exception $ex) {
$this->phpci->logFailure($ex->getMessage());
return false;
}
return true;
}
}

View file

@ -7,12 +7,12 @@ class TapParser
const TEST_COUNTS_PATTERN = '/([0-9]+)\.\.([0-9]+)/';
const TEST_LINE_PATTERN = '/(ok|not ok)\s+[0-9]+\s+\-\s+([^\n]+)::([^\n]+)/';
const TEST_MESSAGE_PATTERN = '/message\:\s+\'([^\']+)\'/';
const TEST_COVERAGE_PATTERN = '/Generating code coverage report/';
/**
* @var string
*/
protected $tapString;
protected $failures = 0;
/**
@ -43,16 +43,23 @@ class TapParser
throw new \Exception('TapParser only supports TAP version 13');
}
if (preg_match(self::TEST_COVERAGE_PATTERN, $lines[count($lines) - 1])) {
array_pop($lines);
if ($lines[count($lines) - 1] == "") {
array_pop($lines);
}
}
$matches = array();
$totalTests = 0;
if (preg_match(self::TEST_COUNTS_PATTERN, $lines[0], $matches)) {
array_shift($lines);
$totalTests = (int)$matches[2];
$totalTests = (int) $matches[2];
}
if (preg_match(self::TEST_COUNTS_PATTERN, $lines[count($lines) - 1], $matches)) {
array_pop($lines);
$totalTests = (int)$matches[2];
$totalTests = (int) $matches[2];
}
$rtn = $this->processTestLines($lines);

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Plugin;
@ -52,7 +52,10 @@ class Wipe implements \PHPCI\Plugin
return true;
}
if (is_dir($this->directory)) {
$cmd = 'rm -rf %s*';
$cmd = 'rm -Rf "%s"';
if (IS_WIN) {
$cmd = 'rmdir /S /Q "%s"';
}
$success = $this->phpci->executeCommand($cmd, $this->directory);
}
return $success;

View file

@ -1,4 +1,12 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI;
abstract class Store extends \b8\Store

View file

@ -44,6 +44,38 @@ class BuildMetaStoreBase extends Store
return null;
}
public function getByProjectId($value, $limit = null, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$add = '';
if ($limit) {
$add .= ' LIMIT ' . $limit;
}
$count = null;
$query = 'SELECT * FROM `build_meta` WHERE `project_id` = :project_id' . $add;
$stmt = Database::getConnection($useConnection)->prepare($query);
$stmt->bindValue(':project_id', $value);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new BuildMeta($item);
};
$rtn = array_map($map, $res);
return array('items' => $rtn, 'count' => $count);
} else {
return array('items' => array(), 'count' => 0);
}
}
public function getByBuildId($value, $limit = null, $useConnection = 'read')
{
if (is_null($value)) {

View file

@ -1,7 +1,10 @@
<?php
/**
* BuildMeta store for table: build_meta
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Store;

View file

@ -1,14 +1,16 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Store;
use b8\Database;
use PHPCI\Model\Build;
use PHPCI\Store\Base\BuildStoreBase;
/**
@ -22,7 +24,7 @@ class BuildStore extends BuildStoreBase
public function getLatestBuilds($projectId)
{
$query = 'SELECT * FROM build WHERE project_id = :pid ORDER BY id DESC LIMIT 5';
$stmt = \b8\Database::getConnection('read')->prepare($query);
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':pid', $projectId);
if ($stmt->execute()) {
@ -39,6 +41,28 @@ class BuildStore extends BuildStoreBase
}
}
public function getByProjectAndCommit($projectId, $commitId)
{
$query = 'SELECT * FROM `build` WHERE `project_id` = :project_id AND `commit_id` = :commit_id';
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':project_id', $projectId);
$stmt->bindValue(':commit_id', $commitId);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new Build($item);
};
$rtn = array_map($map, $res);
return array('items' => $rtn, 'count' => count($rtn));
} else {
return array('items' => array(), 'count' => 0);
}
}
public function getMeta($key, $projectId, $buildId = null, $numResults = 1)
{
$select = '`build_id`, `meta_key`, `meta_value`';
@ -46,7 +70,7 @@ class BuildStore extends BuildStoreBase
$where = '`meta_key` = :key AND `project_id` = :projectId ' . $and;
$query = 'SELECT '.$select.' FROM `build_meta` WHERE '.$where.' ORDER BY id DESC LIMIT :numResults';
$stmt = \b8\Database::getConnection('read')->prepare($query);
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':key', $key, \PDO::PARAM_STR);
$stmt->bindValue(':projectId', (int)$projectId, \PDO::PARAM_INT);
$stmt->bindValue(':buildId', (int)$buildId, \PDO::PARAM_INT);
@ -77,7 +101,7 @@ class BuildStore extends BuildStoreBase
$cols = '`project_id`, `build_id`, `meta_key`, `meta_value`';
$query = 'REPLACE INTO build_meta ('.$cols.') VALUES (:projectId, :buildId, :key, :value)';
$stmt = \b8\Database::getConnection('read')->prepare($query);
$stmt = Database::getConnection('read')->prepare($query);
$stmt->bindValue(':key', $key, \PDO::PARAM_STR);
$stmt->bindValue(':projectId', (int)$projectId, \PDO::PARAM_INT);
$stmt->bindValue(':buildId', (int)$buildId, \PDO::PARAM_INT);

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Store;

View file

@ -1,11 +1,11 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2013, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link http://www.phptesting.org/
*/
* PHPCI - Continuous Integration for PHP
*
* @copyright Copyright 2014, Block 8 Limited.
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
* @link https://www.phptesting.org/
*/
namespace PHPCI\Store;

View file

@ -61,21 +61,7 @@ switch($build->getStatus())
<td><a href="<?php print $build->getBranchLink(); ?>"><?php print $build->getBranch(); ?></a></td>
<td>
<?php
$plugins = json_decode($build->getPlugins(), true);
if ( !is_array($plugins) ) {
$plugins = array();
}
if ( 0 === count($plugins) ) {
?> <span class='label label-<?php echo $subcls ?>'><?php echo $status ?></span> <?php
}
?>
<?php
foreach($plugins as $plugin => $pluginstatus):
$subcls = $pluginstatus?'label label-success':'label label-danger';
?> <span class='<?php echo $subcls ?>'><?php print $this->Build()->formatPluginName($plugin); ?></span> <?php endforeach; ?>
<br style='clear:both;' />
<span class='label label-<?php echo $subcls ?>'><?php echo $status ?></span>
</td>
<td>
<div class="btn-group">

View file

@ -1,15 +1,15 @@
<div style="background: #900; padding: 25px;">
<div style="background: #fff; padding: 15px; border-radius: 5px">
<div style="font-family: arial, verdana, sans-serif; font-size: 25px; margin-bottom: 15px">
<?= $project->getTitle(); ?> - Build #<?= $build->getId(); ?>
<?php print $project->getTitle(); ?> - Build #<?php print $build->getId(); ?>
</div>
<div style="font-family: arial, verdana, sans-serif; font-size: 15px">
<p>Your commit <strong><?= $build->getCommitId(); ?></strong> caused a failed build in project <strong><?= $project->getTitle(); ?></strong>.</p>
<p>Your commit <strong><?php print $build->getCommitId(); ?></strong> caused a failed build in project <strong><?php print $project->getTitle(); ?></strong>.</p>
<p style="margin: 10px; background: #fafafa"><?= $build->getCommitMessage(); ?></p>
<p style="margin: 10px; background: #fafafa"><?php print $build->getCommitMessage(); ?></p>
<p>Please review <a href="<?= $build->getCommitLink(); ?>">your commit</a> and the <a href="<?= PHPCI_URL . 'build/view/' . $build->getId(); ?>">build log</a>.</p>
<p>Please review <a href="<?php print $build->getCommitLink(); ?>">your commit</a> and the <a href="<?php print PHPCI_URL . 'build/view/' . $build->getId(); ?>">build log</a>.</p>
</div>
</div>
</div>

View file

@ -1,8 +1,4 @@
<h1 id="title">Packages and Provided Plugins</h1>
<?php if (!$canInstall): ?>
<p class="alert alert-danger">PHPCI cannot automatically install/remove plugins for you, as either the <strong>shell_exec()</strong>
function is disabled or PHPCI could not find Composer. PHPCI will update composer.json for you, but you will need to run Composer manually to make the changes.</p>
<?php endif; ?>
<?php if (!$canWrite): ?>
<p class="alert alert-danger">PHPCI cannot update composer.json for you as it is not writable.</p>
@ -12,12 +8,8 @@
<p class="alert alert-success"><strong><?php echo $_GET['r']; ?></strong> has been removed.</p>
<?php endif; ?>
<?php if (isset($_GET['i'])): ?>
<p class="alert alert-success"><strong><?php echo $_GET['i']; ?></strong> has been installed.</p>
<?php endif; ?>
<?php if (isset($_GET['w'])): ?>
<p class="alert alert-success"><strong><?php echo $_GET['w']; ?></strong> has been added to composer.json and will be installed next time you run composer update.</p>
<p class="alert alert-success"><strong><?php echo $_GET['w']; ?></strong> has been added to composer.json for you and will be installed next time you run composer update.</p>
<?php endif; ?>
<div class="box">
@ -34,9 +26,9 @@
<tbody>
<?php foreach ($plugins as $plugin): ?>
<tr>
<td><?= $plugin->name; ?></td>
<td><?= $plugin->class; ?></td>
<td><?= $plugin->source; ?></td>
<td><?php print $plugin->name; ?></td>
<td><?php print $plugin->class; ?></td>
<td><?php print $plugin->source; ?></td>
</tr>
<?php endforeach; ?>
</tbody>

88
PHPCI/View/Session.phtml Normal file
View file

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Log in to PHPCI</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="<?php echo PHPCI_URL ?>assets/css/bootstrap.min.css">
<script src="//code.jquery.com/jquery-1.8.1.min.js"></script>
<script src="<?php echo PHPCI_URL ?>assets/js/bootstrap.min.js"></script>
<style type="text/css">
html {
min-height: 100%;
}
body
{
background: #224466; /* Old browsers */
background: -moz-radial-gradient(center, ellipse cover, #224466 0%, #112233 100%); /* FF3.6+ */
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#224466), color-stop(100%,#112233)); /* Chrome,Safari4+ */
background: -webkit-radial-gradient(center, ellipse cover, #224466 0%,#112233 100%); /* Chrome10+,Safari5.1+ */
background: -o-radial-gradient(center, ellipse cover, #224466 0%,#112233 100%); /* Opera 12+ */
background: -ms-radial-gradient(center, ellipse cover, #224466 0%,#112233 100%); /* IE10+ */
background: radial-gradient(ellipse at center, #224466 0%,#112233 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#224466', endColorstr='#112233',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
min-height: 100%;
font-family: Roboto, Arial, Sans-Serif;
font-style: normal;
font-weight: 300;
padding-top: 0px;
}
#login-box
{
background: #fcfcfc; /* Old browsers */
background: -moz-linear-gradient(top, #fcfcfc 50%, #e0e0e0 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(50%,#fcfcfc), color-stop(100%,#e0e0e0)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #fcfcfc 50%,#e0e0e0 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #fcfcfc 50%,#e0e0e0 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #fcfcfc 50%,#e0e0e0 100%); /* IE10+ */
background: linear-gradient(to bottom, #fcfcfc 50%,#e0e0e0 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfcfc', endColorstr='#e0e0e0',GradientType=0 ); /* IE6-9 */
border-radius: 5px;
box-shadow: 0 0 30px rgba(0,0,0, 0.3);
margin: 0 auto;
padding: 15px 30px;
text-align: left;
width: 350px;
}
#logo {
background: transparent url('http://www.block8.co.uk/badge-dark-muted.png') no-repeat top left;
display: inline-block;
height: 26px;
margin: 40px auto;
width: 90px;
}
#logo:hover {
background-image: url('http://www.block8.co.uk/badge-dark.png');
}
#phpci-logo img {
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="container">
<div class="row" style="margin-top: 10%; text-align: center">
<a id="phpci-logo" href="http://www.phptesting.org">
<img src="<?php print PHPCI_URL; ?>/assets/img/logo-large.png">
</a>
<div class="" id="login-box">
<?php print $content; ?>
</div>
<a id="logo" href="http://www.block8.co.uk/"></a>
</div>
</div>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show more