From e7dcd82125411c54dd6c4a49a8c1fbe504507beb Mon Sep 17 00:00:00 2001 From: Pavel Pavlov Date: Wed, 26 Feb 2014 15:50:01 +0400 Subject: [PATCH 001/119] This fixes #276 : Delete Build button not functioning in view build --- PHPCI/View/Build/view.phtml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/PHPCI/View/Build/view.phtml b/PHPCI/View/Build/view.phtml index 1af884be..c06ce531 100644 --- a/PHPCI/View/Build/view.phtml +++ b/PHPCI/View/Build/view.phtml @@ -18,7 +18,7 @@ @@ -43,5 +43,13 @@ foreach ($plugins as $plugin) { From 6d4e49d07b66762215034d9712ee575bfd7f7c13 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sun, 2 Mar 2014 19:59:52 +0000 Subject: [PATCH 002/119] Add code to allow configuration for the plugin factory to be stored on a per install basis. --- PHPCI/Plugin/Util/Factory.php | 22 +++++++++++++++ .../PHPCI/Plugin/Util/ExamplePluginConfig.php | 22 +++++++++++++++ Tests/PHPCI/Plugin/Util/FactoryTest.php | 27 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php diff --git a/PHPCI/Plugin/Util/Factory.php b/PHPCI/Plugin/Util/Factory.php index 0e526023..8adfd99d 100644 --- a/PHPCI/Plugin/Util/Factory.php +++ b/PHPCI/Plugin/Util/Factory.php @@ -37,6 +37,28 @@ class Factory { ); } + /** + * Trys to get a function from the file path specified. If the + * file returns a function then $this will be passed to it. + * This enables the config file to call any public methods. + * + * @param $configPath + * @return bool - true if the function exists else false. + */ + public function addConfigFromFile($configPath) + { + // The file is expected to return a function which can + // act on the pluginFactory to register any resources needed. + if (file_exists($configPath)) { + $configFunction = require($configPath); + if (is_callable($configFunction)) { + $configFunction($this); + return true; + } + } + return false; + } + public function getLastOptions() { return $this->currentPluginOptions; } diff --git a/Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php b/Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php new file mode 100644 index 00000000..4e4279b9 --- /dev/null +++ b/Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php @@ -0,0 +1,22 @@ +registerResource( + // This function will be called when the resource is needed. + function() { + return array( + 'Foo' => "Stuff", + 'Bar' => "More Stuff" + ); + }, + + // In addition to the function for building the resource the system + // also needs to be told when to load the resource. Either or both + // of the following arguments can be used (null to ignore) + + // This resource will only be given when the argument name is: + "ResourceArray", + + // The resource will only be given when the type hint is: + PHPCI\Plugin\Util\Factory::TYPE_ARRAY + ); +}; \ No newline at end of file diff --git a/Tests/PHPCI/Plugin/Util/FactoryTest.php b/Tests/PHPCI/Plugin/Util/FactoryTest.php index 3265e07c..72ed714b 100644 --- a/Tests/PHPCI/Plugin/Util/FactoryTest.php +++ b/Tests/PHPCI/Plugin/Util/FactoryTest.php @@ -148,6 +148,33 @@ class FactoryTest extends \PHPUnit_Framework_TestCase { $this->assertArrayHasKey('thing', $plugin->Options); } + public function testAddConfigFromFile_ReturnsTrueForValidFile() + { + $result = $this->testedFactory->addConfigFromFile( + realpath(__DIR__ . "/ExamplePluginConfig.php") + ); + + $this->assertTrue($result); + } + + public function testAddConfigFromFile_RegistersResources() + { + $this->testedFactory->addConfigFromFile( + realpath(__DIR__ . "/ExamplePluginConfig.php") + ); + + $namespace = '\\PHPCI\\Plugin\\Tests\\Util\\'; + $pluginName = $namespace . 'ExamplePluginWithSingleRequiredArg'; + + $plugin = $this->testedFactory->buildPlugin($pluginName); + + // The Example config file defines an array as the resource. + $this->assertEquals( + array("bar" => "Hello"), + $plugin->RequiredArgument + ); + } + /** * Registers mocked Builder and Build classes so that realistic plugins * can be tested. From 20d5e5a6b294e8b2709d0418b74d119c4b741a01 Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sun, 2 Mar 2014 20:00:43 +0000 Subject: [PATCH 003/119] Add code to builder so pluginconfig.php is loaded if found in the root --- .gitignore | 3 ++- PHPCI/Builder.php | 14 ++++++++++++-- pluginconfig.php.example | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 pluginconfig.php.example diff --git a/.gitignore b/.gitignore index 620cd6ce..d8c5ef7b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ config.php .htaccess PHPCI/config.yml cache -/loggerconfig.php \ No newline at end of file +/loggerconfig.php +/pluginconfig.php \ No newline at end of file diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index 7b36d55b..4e02e1b3 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -14,6 +14,7 @@ use PHPCI\Helper\MailerFactory; use PHPCI\Model\Build; use b8\Store; use b8\Config; +use PHPCI\Plugin\Util\Factory; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; @@ -114,7 +115,10 @@ class Builder implements LoggerAwareInterface, BuildLogger } $this->build = $build; $this->store = Store\Factory::getStore('Build'); - $this->pluginExecutor = new Plugin\Util\Executor($this->buildPluginFactory($build), $this); + + $pluginFactory = $this->buildPluginFactory($build); + $pluginFactory->addConfigFromFile(PHPCI_DIR . "/pluginconfig.php"); + $this->pluginExecutor = new Plugin\Util\Executor($pluginFactory, $this); $this->commandExecutor = new CommandExecutor($this, PHPCI_DIR, $this->quiet, $this->verbose); } @@ -394,9 +398,15 @@ class Builder implements LoggerAwareInterface, BuildLogger return $this->logger; } + /** + * Returns a configured instance of the plugin factory. + * + * @param Build $build + * @return Factory + */ private function buildPluginFactory(Build $build) { - $pluginFactory = new Plugin\Util\Factory(); + $pluginFactory = new Factory(); $self = $this; $pluginFactory->registerResource( diff --git a/pluginconfig.php.example b/pluginconfig.php.example new file mode 100644 index 00000000..4e4279b9 --- /dev/null +++ b/pluginconfig.php.example @@ -0,0 +1,22 @@ +registerResource( + // This function will be called when the resource is needed. + function() { + return array( + 'Foo' => "Stuff", + 'Bar' => "More Stuff" + ); + }, + + // In addition to the function for building the resource the system + // also needs to be told when to load the resource. Either or both + // of the following arguments can be used (null to ignore) + + // This resource will only be given when the argument name is: + "ResourceArray", + + // The resource will only be given when the type hint is: + PHPCI\Plugin\Util\Factory::TYPE_ARRAY + ); +}; \ No newline at end of file From 3c1cb07e97df1f6fa6def58b5be4dd5530f944cb Mon Sep 17 00:00:00 2001 From: meadsteve Date: Sun, 2 Mar 2014 20:10:48 +0000 Subject: [PATCH 004/119] Update test ExamplePluginConfg.php to match test. --- Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php b/Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php index 4e4279b9..0b883071 100644 --- a/Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php +++ b/Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php @@ -4,19 +4,10 @@ return function (PHPCI\Plugin\Util\Factory $factory) { // This function will be called when the resource is needed. function() { return array( - 'Foo' => "Stuff", - 'Bar' => "More Stuff" + 'bar' => "Hello", ); }, - - // In addition to the function for building the resource the system - // also needs to be told when to load the resource. Either or both - // of the following arguments can be used (null to ignore) - - // This resource will only be given when the argument name is: - "ResourceArray", - - // The resource will only be given when the type hint is: - PHPCI\Plugin\Util\Factory::TYPE_ARRAY + "requiredArgument", + null ); }; \ No newline at end of file From 24b5bc549da89f4c6d7ea50ad7c5d7782ae089a8 Mon Sep 17 00:00:00 2001 From: "steve.brazier" Date: Mon, 10 Mar 2014 12:08:16 +0000 Subject: [PATCH 005/119] Add debug logging to findBinary() --- PHPCI/Helper/CommandExecutor.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PHPCI/Helper/CommandExecutor.php b/PHPCI/Helper/CommandExecutor.php index 9b7fe442..a422d970 100644 --- a/PHPCI/Helper/CommandExecutor.php +++ b/PHPCI/Helper/CommandExecutor.php @@ -4,6 +4,7 @@ namespace PHPCI\Helper; use \PHPCI\Logging\BuildLogger; +use Psr\Log\LogLevel; class CommandExecutor { @@ -112,13 +113,16 @@ class CommandExecutor } 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; } @@ -127,6 +131,7 @@ class CommandExecutor $findCmdResult = trim(shell_exec($findCmd . ' ' . $bin)); if (!empty($findCmdResult)) { + $this->logger->log("Found in " . $findCmdResult, LogLevel::DEBUG); return $findCmdResult; } } From 9c24fbaecb86aeba670c1ec553250e97ae5090b3 Mon Sep 17 00:00:00 2001 From: "steve.brazier" Date: Mon, 10 Mar 2014 12:27:17 +0000 Subject: [PATCH 006/119] Psr\Log\LoggerInterface to the types that the plugin factory supplies by default. --- PHPCI/Builder.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index eb3e08e9..d112cc93 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -353,6 +353,15 @@ class Builder implements LoggerAwareInterface 'PHPCI\Model\Build' ); + $logger = $this->logger; + $pluginFactory->registerResource( + function () use ($logger) { + return $logger; + }, + null, + 'Psr\Log\LoggerInterface' + ); + $pluginFactory->registerResource( function () use ($self) { $factory = new MailerFactory($self->getSystemConfig('phpci')); From 851f6378990a826186a0c16a686a91ad19aea22f Mon Sep 17 00:00:00 2001 From: "steve.brazier" Date: Mon, 10 Mar 2014 12:28:42 +0000 Subject: [PATCH 007/119] format tidy up of buildPluginFactory() --- PHPCI/Builder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index d112cc93..ba6d2e3a 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -338,7 +338,7 @@ class Builder implements LoggerAwareInterface $self = $this; $pluginFactory->registerResource( - function () use($self) { + function () use ($self) { return $self; }, null, @@ -346,7 +346,7 @@ class Builder implements LoggerAwareInterface ); $pluginFactory->registerResource( - function () use($build) { + function () use ($build) { return $build; }, null, From af22da6a1c644226a45af8107cb5f3774ea886ec Mon Sep 17 00:00:00 2001 From: Corpsee Date: Wed, 12 Mar 2014 22:22:57 +0700 Subject: [PATCH 008/119] Fixed CommitId link --- PHPCI/View/BuildsTable.phtml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/PHPCI/View/BuildsTable.phtml b/PHPCI/View/BuildsTable.phtml index a9351353..9c1b3aea 100644 --- a/PHPCI/View/BuildsTable.phtml +++ b/PHPCI/View/BuildsTable.phtml @@ -46,7 +46,19 @@ switch($build->getStatus()) print ' - '; } ?> - getCommitId(); ?> + + + getCommitId() !== 'Manual') { + print ''; + } + print $build->getCommitId(); + if ($build->getCommitId() !== 'Manual') { + print ''; + } + ?> + + getBranch(); ?> Date: Wed, 12 Mar 2014 23:04:56 +0700 Subject: [PATCH 009/119] Fixed git checkout for commitId = 'Manual' --- PHPCI/Model/Build/RemoteGitBuild.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PHPCI/Model/Build/RemoteGitBuild.php b/PHPCI/Model/Build/RemoteGitBuild.php index 35aa8c90..43d1e6f7 100644 --- a/PHPCI/Model/Build/RemoteGitBuild.php +++ b/PHPCI/Model/Build/RemoteGitBuild.php @@ -65,7 +65,11 @@ class RemoteGitBuild extends Build protected function cloneByHttp(Builder $builder, $cloneTo) { $success = $builder->executeCommand('git clone -b %s %s "%s"', $this->getBranch(), $this->getCloneUrl(), $cloneTo); - $builder->executeCommand('cd "%s" && git checkout %s', $cloneTo, $this->getCommitId()); + + if (!empty($commit) && $commit != 'Manual') { + $builder->executeCommand('cd "%s" && git checkout %s', $cloneTo, $this->getCommitId()); + } + return $success; } From 18701544a0cee53fb6a78cee607fde0baa213559 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Thu, 13 Mar 2014 00:37:57 +0700 Subject: [PATCH 010/119] Fixed 'cd' command for windows --- PHPCI/Helper/CommandExecutor.php | 2 +- PHPCI/Model/Build/RemoteGitBuild.php | 12 ++++++++++-- PHPCI/Plugin/Codeception.php | 3 +++ PHPCI/Plugin/Composer.php | 2 +- PHPCI/Plugin/Grunt.php | 9 ++++++++- vars.php | 5 +++++ 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/PHPCI/Helper/CommandExecutor.php b/PHPCI/Helper/CommandExecutor.php index a422d970..70bfcff5 100644 --- a/PHPCI/Helper/CommandExecutor.php +++ b/PHPCI/Helper/CommandExecutor.php @@ -127,7 +127,7 @@ class CommandExecutor } // Use "where" for windows and "which" for other OS - $findCmd = (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') ? 'which' : 'where'; + $findCmd = IS_WIN ? 'which' : 'where'; $findCmdResult = trim(shell_exec($findCmd . ' ' . $bin)); if (!empty($findCmdResult)) { diff --git a/PHPCI/Model/Build/RemoteGitBuild.php b/PHPCI/Model/Build/RemoteGitBuild.php index 43d1e6f7..4faf2557 100644 --- a/PHPCI/Model/Build/RemoteGitBuild.php +++ b/PHPCI/Model/Build/RemoteGitBuild.php @@ -67,7 +67,11 @@ class RemoteGitBuild extends Build $success = $builder->executeCommand('git clone -b %s %s "%s"', $this->getBranch(), $this->getCloneUrl(), $cloneTo); if (!empty($commit) && $commit != 'Manual') { - $builder->executeCommand('cd "%s" && git checkout %s', $cloneTo, $this->getCommitId()); + $cmd = 'cd "%s" && git checkout %s'; + if (IS_WIN) { + $cmd = 'cd /d "%s" && git checkout %s'; + } + $builder->executeCommand($cmd, $cloneTo, $this->getCommitId()); } return $success; @@ -97,7 +101,11 @@ class RemoteGitBuild extends Build $commit = $this->getCommitId(); if (!empty($commit) && $commit != 'Manual') { - $builder->executeCommand('cd "%s" && git checkout %s', $cloneTo, $this->getCommitId()); + $cmd = 'cd "%s" && git checkout %s'; + if (IS_WIN) { + $cmd = 'cd /d "%s" && git checkout %s'; + } + $builder->executeCommand($cmd, $cloneTo, $this->getCommitId()); } // Remove the key file: diff --git a/PHPCI/Plugin/Codeception.php b/PHPCI/Plugin/Codeception.php index bd168145..802d3540 100644 --- a/PHPCI/Plugin/Codeception.php +++ b/PHPCI/Plugin/Codeception.php @@ -70,6 +70,9 @@ class Codeception implements \PHPCI\Plugin } $cmd = 'cd "%s" && ' . $codecept . ' run -c "%s"'; + if (IS_WIN) { + $cmd = 'cd /d "%s" && ' . $codecept . ' run -c "%s"'; + } $success = $this->phpci->executeCommand($cmd, $this->phpci->buildPath, $this->phpci->buildPath . $configPath); return $success; diff --git a/PHPCI/Plugin/Composer.php b/PHPCI/Plugin/Composer.php index 0b89afe0..d40ac100 100644 --- a/PHPCI/Plugin/Composer.php +++ b/PHPCI/Plugin/Composer.php @@ -46,7 +46,7 @@ class Composer implements \PHPCI\Plugin return false; } $cmd = ''; - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + if (IS_WIN) { $cmd = 'php '; } $cmd .= $composerLocation . ' --no-ansi --no-interaction '; diff --git a/PHPCI/Plugin/Grunt.php b/PHPCI/Plugin/Grunt.php index 477a4849..ddbe7aa3 100644 --- a/PHPCI/Plugin/Grunt.php +++ b/PHPCI/Plugin/Grunt.php @@ -60,12 +60,19 @@ class Grunt implements \PHPCI\Plugin public function execute() { // if npm does not work, we cannot use grunt, so we return false - if (!$this->phpci->executeCommand('cd %s && npm install', $this->directory)) { + $cmd = 'cd %s && npm install'; + if (IS_WIN) { + $cmd = 'cd /d %s && npm install'; + } + if (!$this->phpci->executeCommand($cmd, $this->directory)) { return false; } // build the grunt command $cmd = 'cd %s && ' . $this->grunt; + if (IS_WIN) { + $cmd = 'cd /d %s && ' . $this->grunt; + } $cmd .= ' --no-color'; $cmd .= ' --gruntfile %s'; $cmd .= ' %s'; // the task that will be executed diff --git a/vars.php b/vars.php index 5725805e..46b88c79 100644 --- a/vars.php +++ b/vars.php @@ -25,3 +25,8 @@ if (!defined('ENABLE_SHELL_PLUGIN')) { if (!defined('PHPCI_IS_CONSOLE')) { define('PHPCI_IS_CONSOLE', false); } + +$isWin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true : false; +if (!defined('IS_WIN')) { + define('IS_WIN', $isWin); +} From 656e0a882ee91f5f4cb708d102ef4970dc721b57 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Fri, 14 Mar 2014 00:06:59 +0700 Subject: [PATCH 011/119] Change 'cp' command to 'copy' for windows --- PHPCI/Model/Build/LocalBuild.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 8e6984c6..485376ad 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -45,7 +45,11 @@ class LocalBuild extends Build if (isset($buildSettings['prefer_symlink']) && $buildSettings['prefer_symlink'] === true) { return $this->handleSymlink($builder, $reference, $buildPath); } else { - $builder->executeCommand('cp -Rf "%s" "%s/"', $reference, $buildPath); + $cmd = 'cp -Rf "%s" "%s/"'; + if (IS_WIN) { + $cmd = 'copy /Y "%s" "%s/"'; + } + $builder->executeCommand($cmd, $reference, $buildPath); } return true; From 7a910631e65af0b8b76cc0e7e350bad24ea452b9 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Sat, 15 Mar 2014 12:18:12 +0700 Subject: [PATCH 012/119] Added database-based yml build config --- PHPCI/Controller/ProjectController.php | 8 ++++ PHPCI/Model/Base/ProjectBase.php | 58 +++++++++++++++++++++----- PHPCI/Model/Build/LocalBuild.php | 17 ++++---- PHPCI/Model/Build/MercurialBuild.php | 19 +++++---- PHPCI/Model/Build/RemoteGitBuild.php | 18 ++++---- 5 files changed, 88 insertions(+), 32 deletions(-) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 19fb3149..94390582 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -318,6 +318,14 @@ class ProjectController extends \PHPCI\Controller $field->setRows(6); $form->addField($field); + $field = new Form\Element\TextArea('build_config'); + $field->setRequired(false); + $field->setLabel('PHPCI build config for this project (instead phpci.yml in the project repository)'); + $field->setClass('form-control'); + $field->setContainerClass('form-group'); + $field->setRows(6); + $form->addField($field); + $field = new Form\Element\Submit(); $field->setValue('Save Project'); $field->setContainerClass('form-group'); diff --git a/PHPCI/Model/Base/ProjectBase.php b/PHPCI/Model/Base/ProjectBase.php index df1c0a34..adb9ac5a 100644 --- a/PHPCI/Model/Base/ProjectBase.php +++ b/PHPCI/Model/Base/ProjectBase.php @@ -37,6 +37,7 @@ class ProjectBase extends Model 'title' => null, 'reference' => null, 'git_key' => null, + 'build_config' => null, 'type' => null, 'token' => null, 'access_information' => null, @@ -52,6 +53,7 @@ class ProjectBase extends Model 'title' => 'getTitle', 'reference' => 'getReference', 'git_key' => 'getGitKey', + 'build_config' => 'getBuildConfig', 'type' => 'getType', 'token' => 'getToken', 'access_information' => 'getAccessInformation', @@ -69,6 +71,7 @@ class ProjectBase extends Model 'title' => 'setTitle', 'reference' => 'setReference', 'git_key' => 'setGitKey', + 'build_config' => 'setBuildConfig', 'type' => 'setType', 'token' => 'setToken', 'access_information' => 'setAccessInformation', @@ -103,6 +106,11 @@ class ProjectBase extends Model 'nullable' => true, 'default' => null, ), + 'build_config' => array( + 'type' => 'text', + 'nullable' => true, + 'default' => null, + ), 'type' => array( 'type' => 'varchar', 'length' => 50, @@ -132,8 +140,8 @@ class ProjectBase extends Model * @var array */ public $indexes = array( - 'PRIMARY' => array('unique' => true, 'columns' => 'id'), - 'idx_project_title' => array('columns' => 'title'), + 'PRIMARY' => array('unique' => true, 'columns' => 'id'), + 'idx_project_title' => array('columns' => 'title'), ); /** @@ -149,7 +157,7 @@ class ProjectBase extends Model */ public function getId() { - $rtn = $this->data['id']; + $rtn = $this->data['id']; return $rtn; } @@ -161,7 +169,7 @@ class ProjectBase extends Model */ public function getTitle() { - $rtn = $this->data['title']; + $rtn = $this->data['title']; return $rtn; } @@ -173,7 +181,7 @@ class ProjectBase extends Model */ public function getReference() { - $rtn = $this->data['reference']; + $rtn = $this->data['reference']; return $rtn; } @@ -185,7 +193,19 @@ class ProjectBase extends Model */ public function getGitKey() { - $rtn = $this->data['git_key']; + $rtn = $this->data['git_key']; + + return $rtn; + } + + /** + * Get the value of BuildConfig / build_config. + * + * @return string + */ + public function getBuildConfig() + { + $rtn = $this->data['build_config']; return $rtn; } @@ -197,7 +217,7 @@ class ProjectBase extends Model */ public function getType() { - $rtn = $this->data['type']; + $rtn = $this->data['type']; return $rtn; } @@ -209,7 +229,7 @@ class ProjectBase extends Model */ public function getToken() { - $rtn = $this->data['token']; + $rtn = $this->data['token']; return $rtn; } @@ -221,7 +241,7 @@ class ProjectBase extends Model */ public function getAccessInformation() { - $rtn = $this->data['access_information']; + $rtn = $this->data['access_information']; return $rtn; } @@ -233,7 +253,7 @@ class ProjectBase extends Model */ public function getLastCommit() { - $rtn = $this->data['last_commit']; + $rtn = $this->data['last_commit']; return $rtn; } @@ -316,6 +336,24 @@ class ProjectBase extends Model $this->_setModified('git_key'); } + /** + * Set the value of BuildConfig / build_config. + * + * @param $value string + */ + public function setBuildConfig($value) + { + $this->_validateString('BuildConfig', $value); + + if ($this->data['build_config'] === $value) { + return; + } + + $this->data['build_config'] = $value; + + $this->_setModified('build_config'); + } + /** * Set the value of Type / type. * diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 485376ad..3feae1b1 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -86,15 +86,18 @@ class LocalBuild extends Build protected function handleConfig(Builder $builder, $reference) { - /** @todo Add support for database-based yml definition */ - if (!is_file($reference . '/phpci.yml')) { - $builder->logFailure('Project does not contain a phpci.yml file.'); - return false; - } + $build_config = $this->getProject()->getBuildConfig(); + if (!$build_config) + { + if (!is_file($reference . '/phpci.yml')) { + $builder->logFailure('Project does not contain a phpci.yml file.'); + return false; + } + $build_config = file_get_contents($reference . '/phpci.yml'); + } $yamlParser = new YamlParser(); - $yamlFile = file_get_contents($reference . '/phpci.yml'); - $builder->setConfigArray($yamlParser->parse($yamlFile)); + $builder->setConfigArray($yamlParser->parse($build_config)); return $builder->getConfig('build_settings'); } } diff --git a/PHPCI/Model/Build/MercurialBuild.php b/PHPCI/Model/Build/MercurialBuild.php index dbfcf4e2..412c2ad3 100644 --- a/PHPCI/Model/Build/MercurialBuild.php +++ b/PHPCI/Model/Build/MercurialBuild.php @@ -34,17 +34,20 @@ class MercurialBuild extends Build */ public function createWorkingCopy(Builder $builder, $buildPath) { - $yamlParser = new YamlParser(); - $this->cloneByHttp($builder, $buildPath); - if (!is_file($buildPath . 'phpci.yml')) { - $builder->logFailure('Project does not contain a phpci.yml file.'); - return false; - } + $build_config = $this->getProject()->getBuildConfig(); + if (!$build_config) + { + if (!is_file($buildPath . '/phpci.yml')) { + $builder->logFailure('Project does not contain a phpci.yml file.'); + return false; + } + $build_config = file_get_contents($buildPath . '/phpci.yml'); + } - $yamlFile = file_get_contents($buildPath . 'phpci.yml'); - $builder->setConfigArray($yamlParser->parse($yamlFile)); + $yamlParser = new YamlParser(); + $builder->setConfigArray($yamlParser->parse($build_config)); return true; } diff --git a/PHPCI/Model/Build/RemoteGitBuild.php b/PHPCI/Model/Build/RemoteGitBuild.php index 4faf2557..3c84b06d 100644 --- a/PHPCI/Model/Build/RemoteGitBuild.php +++ b/PHPCI/Model/Build/RemoteGitBuild.php @@ -34,7 +34,6 @@ class RemoteGitBuild extends Build */ public function createWorkingCopy(Builder $builder, $buildPath) { - $yamlParser = new YamlParser(); $key = trim($this->getProject()->getGitKey()); if (!empty($key)) { @@ -48,13 +47,18 @@ class RemoteGitBuild extends Build return false; } - if (!is_file($buildPath . 'phpci.yml')) { - $builder->logFailure('Project does not contain a phpci.yml file.'); - return false; - } + $build_config = $this->getProject()->getBuildConfig(); + if (!$build_config) + { + if (!is_file($buildPath . '/phpci.yml')) { + $builder->logFailure('Project does not contain a phpci.yml file.'); + return false; + } + $build_config = file_get_contents($buildPath . '/phpci.yml'); + } - $yamlFile = file_get_contents($buildPath . 'phpci.yml'); - $builder->setConfigArray($yamlParser->parse($yamlFile)); + $yamlParser = new YamlParser(); + $builder->setConfigArray($yamlParser->parse($build_config)); return true; } From f4df607a162d264855d171b39304636d2be2b80a Mon Sep 17 00:00:00 2001 From: Corpsee Date: Sat, 15 Mar 2014 12:22:59 +0700 Subject: [PATCH 013/119] Moved handleConfig functionality into general Build method. --- PHPCI/Model/Build.php | 24 ++++++++++++++++++++++++ PHPCI/Model/Build/LocalBuild.php | 18 ------------------ PHPCI/Model/Build/MercurialBuild.php | 16 +--------------- PHPCI/Model/Build/RemoteGitBuild.php | 16 +--------------- 4 files changed, 26 insertions(+), 48 deletions(-) diff --git a/PHPCI/Model/Build.php b/PHPCI/Model/Build.php index ff0a0b23..27cf4055 100644 --- a/PHPCI/Model/Build.php +++ b/PHPCI/Model/Build.php @@ -11,6 +11,8 @@ namespace PHPCI\Model; use b8\Store\Factory; use PHPCI\Model\Base\BuildBase; +use PHPCI\Builder; +use Symfony\Component\Yaml\Parser as YamlParser; /** * Build Model @@ -77,4 +79,26 @@ class Build extends BuildBase { return ($this->getStatus() === self::STATUS_SUCCESS); } + + /** + * @param Builder $builder + * @param string $buildPath + * + * @return bool + */ + protected function handleConfig(Builder $builder, $buildPath) + { + $build_config = $this->getProject()->getBuildConfig(); + if (!$build_config) { + if (!is_file($buildPath . '/phpci.yml')) { + $builder->logFailure('Project does not contain a phpci.yml file.'); + return false; + } + $build_config = file_get_contents($buildPath . '/phpci.yml'); + } + + $yamlParser = new YamlParser(); + $builder->setConfigArray($yamlParser->parse($build_config)); + return $builder->getConfig('build_settings'); + } } diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 3feae1b1..1148b72e 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -11,7 +11,6 @@ namespace PHPCI\Model\Build; use PHPCI\Model\Build; use PHPCI\Builder; -use Symfony\Component\Yaml\Parser as YamlParser; /** * Local Build Model @@ -83,21 +82,4 @@ class LocalBuild extends Build return true; } - - protected function handleConfig(Builder $builder, $reference) - { - $build_config = $this->getProject()->getBuildConfig(); - if (!$build_config) - { - if (!is_file($reference . '/phpci.yml')) { - $builder->logFailure('Project does not contain a phpci.yml file.'); - return false; - } - $build_config = file_get_contents($reference . '/phpci.yml'); - } - - $yamlParser = new YamlParser(); - $builder->setConfigArray($yamlParser->parse($build_config)); - return $builder->getConfig('build_settings'); - } } diff --git a/PHPCI/Model/Build/MercurialBuild.php b/PHPCI/Model/Build/MercurialBuild.php index 412c2ad3..22ba9fb8 100644 --- a/PHPCI/Model/Build/MercurialBuild.php +++ b/PHPCI/Model/Build/MercurialBuild.php @@ -11,7 +11,6 @@ namespace PHPCI\Model\Build; use PHPCI\Model\Build; use PHPCI\Builder; -use Symfony\Component\Yaml\Parser as YamlParser; /** * Mercurial Build Model @@ -36,20 +35,7 @@ class MercurialBuild extends Build { $this->cloneByHttp($builder, $buildPath); - $build_config = $this->getProject()->getBuildConfig(); - if (!$build_config) - { - if (!is_file($buildPath . '/phpci.yml')) { - $builder->logFailure('Project does not contain a phpci.yml file.'); - return false; - } - $build_config = file_get_contents($buildPath . '/phpci.yml'); - } - - $yamlParser = new YamlParser(); - $builder->setConfigArray($yamlParser->parse($build_config)); - - return true; + return $this->handleConfig($builder, $buildPath); } /** diff --git a/PHPCI/Model/Build/RemoteGitBuild.php b/PHPCI/Model/Build/RemoteGitBuild.php index 3c84b06d..5be3000c 100644 --- a/PHPCI/Model/Build/RemoteGitBuild.php +++ b/PHPCI/Model/Build/RemoteGitBuild.php @@ -11,7 +11,6 @@ namespace PHPCI\Model\Build; use PHPCI\Model\Build; use PHPCI\Builder; -use Symfony\Component\Yaml\Parser as YamlParser; /** * Remote Git Build Model @@ -47,20 +46,7 @@ class RemoteGitBuild extends Build return false; } - $build_config = $this->getProject()->getBuildConfig(); - if (!$build_config) - { - if (!is_file($buildPath . '/phpci.yml')) { - $builder->logFailure('Project does not contain a phpci.yml file.'); - return false; - } - $build_config = file_get_contents($buildPath . '/phpci.yml'); - } - - $yamlParser = new YamlParser(); - $builder->setConfigArray($yamlParser->parse($build_config)); - - return true; + return $this->handleConfig($builder, $buildPath); } /** From 20bab0d47ab111abcbccaa7c1ada61ccfe3e6dd5 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Sat, 15 Mar 2014 12:57:06 +0700 Subject: [PATCH 014/119] Windows fixes --- PHPCI/Helper/CommandExecutor.php | 2 +- PHPCI/Model/Build/LocalBuild.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PHPCI/Helper/CommandExecutor.php b/PHPCI/Helper/CommandExecutor.php index 70bfcff5..2e88b938 100644 --- a/PHPCI/Helper/CommandExecutor.php +++ b/PHPCI/Helper/CommandExecutor.php @@ -127,7 +127,7 @@ class CommandExecutor } // Use "where" for windows and "which" for other OS - $findCmd = IS_WIN ? 'which' : 'where'; + $findCmd = IS_WIN ? 'where' : 'which'; $findCmdResult = trim(shell_exec($findCmd . ' ' . $bin)); if (!empty($findCmdResult)) { diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 1148b72e..e5837595 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -46,7 +46,7 @@ class LocalBuild extends Build } else { $cmd = 'cp -Rf "%s" "%s/"'; if (IS_WIN) { - $cmd = 'copy /Y "%s" "%s/"'; + $cmd = 'xcopy /E /Y "%s" "%s/*"'; } $builder->executeCommand($cmd, $reference, $buildPath); } From 3aa4806e250c5ac197179625654941fa180147e3 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Sat, 15 Mar 2014 12:57:06 +0700 Subject: [PATCH 015/119] Windows fixes --- PHPCI/Helper/CommandExecutor.php | 2 +- PHPCI/Model/Build/LocalBuild.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PHPCI/Helper/CommandExecutor.php b/PHPCI/Helper/CommandExecutor.php index 70bfcff5..2e88b938 100644 --- a/PHPCI/Helper/CommandExecutor.php +++ b/PHPCI/Helper/CommandExecutor.php @@ -127,7 +127,7 @@ class CommandExecutor } // Use "where" for windows and "which" for other OS - $findCmd = IS_WIN ? 'which' : 'where'; + $findCmd = IS_WIN ? 'where' : 'which'; $findCmdResult = trim(shell_exec($findCmd . ' ' . $bin)); if (!empty($findCmdResult)) { diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index 485376ad..8cf3844b 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -47,7 +47,7 @@ class LocalBuild extends Build } else { $cmd = 'cp -Rf "%s" "%s/"'; if (IS_WIN) { - $cmd = 'copy /Y "%s" "%s/"'; + $cmd = 'xcopy /E /Y "%s" "%s/*"'; } $builder->executeCommand($cmd, $reference, $buildPath); } From 92647c6bf9aa0b678e6da4108bd29fa5c5acf34f Mon Sep 17 00:00:00 2001 From: Corpsee Date: Tue, 18 Mar 2014 01:10:47 +0700 Subject: [PATCH 016/119] Added simple error/exception handler and logging --- PHPCI/Logging/Handler.php | 100 +++++++++++++++++++++++++++++++++ PHPCI/Logging/LoggerConfig.php | 4 +- bootstrap.php | 7 ++- console | 4 +- 4 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 PHPCI/Logging/Handler.php diff --git a/PHPCI/Logging/Handler.php b/PHPCI/Logging/Handler.php new file mode 100644 index 00000000..3ae5e93f --- /dev/null +++ b/PHPCI/Logging/Handler.php @@ -0,0 +1,100 @@ + 'Warning', + E_NOTICE => 'Notice', + E_USER_ERROR => 'User Error', + E_USER_WARNING => 'User Warning', + E_USER_NOTICE => 'User Notice', + E_STRICT => 'Runtime Notice', + E_RECOVERABLE_ERROR => 'Catchable Fatal Error', + E_DEPRECATED => 'Deprecated', + E_USER_DEPRECATED => 'User Deprecated', + ); + + /** + * @var LoggerInterface + */ + protected $logger; + + public function __construct(LoggerInterface $logger = NULL) + { + $this->logger = $logger; + } + + public static function register(LoggerInterface $logger = NULL) + { + $handler = new static($logger); + + set_error_handler(array($handler, 'handleError')); + register_shutdown_function(array($handler, 'handleFatalError')); + + set_exception_handler(array($handler, 'handleException')); + } + + /** + * @param integer $level + * @param string $message + * @param string $file + * @param integer $line + * + * @throws \ErrorException + */ + public function handleError($level, $message, $file, $line) + { + if (error_reporting() & $level) { + + $exception_level = isset($this->levels[$level]) ? $this->levels[$level] : $level; + + throw new \ErrorException( + sprintf('%s: %s in %s line %d', $exception_level, $message, $file, $line), + 0, $level, $file, $line + ); + } + } + + /** + * @throws \ErrorException + */ + public function handleFatalError() + { + $fatal_error = error_get_last(); + + if ($fatal_error['type'] === E_ERROR) { + + $e = new \ErrorException( + sprintf('%s: %s in %s line %d', $fatal_error['type'], $fatal_error['message'], $fatal_error['file'], $fatal_error['line']), + 0, $fatal_error['type'], $fatal_error['file'], $fatal_error['line'] + ); + $this->log($e); + } + } + + /** + * @param \Exception $exception + */ + public function handleException(\Exception $exception) + { + $this->log($exception); + } + + protected function log(\Exception $exception) + { + if (null !== $this->logger) { + + $message = sprintf( + '%s: %s (uncaught exception) at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine() + ); + $this->logger->error($message); + } + } +} \ No newline at end of file diff --git a/PHPCI/Logging/LoggerConfig.php b/PHPCI/Logging/LoggerConfig.php index 5c579f6e..3eb0a5b2 100644 --- a/PHPCI/Logging/LoggerConfig.php +++ b/PHPCI/Logging/LoggerConfig.php @@ -22,7 +22,7 @@ class LoggerConfig { public static function newFromFile($filePath) { if (file_exists($filePath)) { - $configArray = require($filePath); + $configArray = require_once($filePath); } else { $configArray = array(); @@ -48,7 +48,7 @@ class LoggerConfig { */ public function getFor($name) { $handlers = $this->getHandlers(self::KEY_AlwaysLoaded); - $handlers = array_merge($handlers, $this->getHandlers($name)); + //$handlers = array_merge($handlers, $this->getHandlers($name)); return new Logger($name, $handlers); } diff --git a/bootstrap.php b/bootstrap.php index 01301dbb..a8ececf3 100755 --- a/bootstrap.php +++ b/bootstrap.php @@ -8,6 +8,9 @@ */ // Let PHP take a guess as to the default timezone, if the user hasn't set one: +use PHPCI\Logging\Handler; +use PHPCI\Logging\LoggerConfig; + date_default_timezone_set(@date_default_timezone_get()); // Set up a basic autoloader for PHPCI: @@ -37,10 +40,12 @@ if (!file_exists(dirname(__FILE__) . '/vendor/autoload.php') && defined('PHPCI_I exit(1); } - // Load Composer autoloader: require_once(dirname(__FILE__) . '/vendor/autoload.php'); +$loggerConfig = LoggerConfig::newFromFile(__DIR__ . "/loggerconfig.php"); +Handler::register($loggerConfig->getFor('Exceptions')); + // Load configuration if present: $conf = array(); $conf['b8']['app']['namespace'] = 'PHPCI'; diff --git a/console b/console index 8a65f1c5..43fc2b8f 100755 --- a/console +++ b/console @@ -21,8 +21,6 @@ use PHPCI\Command\PollCommand; use PHPCI\Command\CreateAdminCommand; use Symfony\Component\Console\Application; -$loggerConfig = \PHPCI\Logging\LoggerConfig::newFromFile(__DIR__ . "/loggerconfig.php"); - $application = new Application(); $application->add(new RunCommand($loggerConfig->getFor('RunCommand'))); @@ -33,4 +31,4 @@ $application->add(new DaemonCommand($loggerConfig->getFor('DaemonCommand'))); $application->add(new PollCommand($loggerConfig->getFor('PollCommand'))); $application->add(new CreateAdminCommand); -$application->run(); +$application->run(); \ No newline at end of file From e7e685e9bd1203eb3a4a0ade32430784c45e4494 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Tue, 18 Mar 2014 22:57:05 +0700 Subject: [PATCH 017/119] ProjectController::view 404 fix --- PHPCI/Controller/ProjectController.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 19fb3149..03c8c1ac 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -17,6 +17,7 @@ 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. @@ -47,7 +48,11 @@ class ProjectController extends \PHPCI\Controller */ public function view($projectId) { - $project = $this->projectStore->getById($projectId); + $project = $this->projectStore->getById($projectId); + if (!$project) { + throw new NotFoundException('Project with id: ' . $projectId . ' not found'); + } + $page = $this->getParam('p', 1); $builds = $this->getLatestBuildsHtml($projectId, (($page - 1) * 10)); From b2240104b45a09a940d980d987b5c4688b415c19 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Tue, 18 Mar 2014 23:58:23 +0700 Subject: [PATCH 018/119] Fixed rm for windows --- PHPCI/Builder.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index ba6d2e3a..6f04c9d8 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -216,7 +216,12 @@ class Builder implements LoggerAwareInterface // Clean up: $this->buildLogger->log('Removing build.'); - shell_exec(sprintf('rm -Rf "%s"', $this->buildPath)); + + $cmd = 'rm -Rf "%s"'; + if (IS_WIN) { + $cmd = 'deltree /Y "%s"'; + } + $this->executeCommand($cmd, $this->buildPath); // Update the build in the database, ping any external services, etc. $this->build->sendStatusPostback(); From b28b5a575f28f5a4b947228a7546ade18fa09712 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Wed, 19 Mar 2014 00:04:29 +0700 Subject: [PATCH 019/119] Fixed rm for windows --- PHPCI/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index 6f04c9d8..34373ba8 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -219,7 +219,7 @@ class Builder implements LoggerAwareInterface $cmd = 'rm -Rf "%s"'; if (IS_WIN) { - $cmd = 'deltree /Y "%s"'; + $cmd = 'rmdir /S /Q "%s"'; } $this->executeCommand($cmd, $this->buildPath); From 15d5c022c57e612c6d04c1a1a95c3846ab71185c Mon Sep 17 00:00:00 2001 From: Corpsee Date: Thu, 20 Mar 2014 22:17:54 +0700 Subject: [PATCH 020/119] Improved error/exception handler and logging --- PHPCI/Logging/Handler.php | 13 +++++++++++-- PHPCI/Logging/LoggerConfig.php | 2 +- bootstrap.php | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/PHPCI/Logging/Handler.php b/PHPCI/Logging/Handler.php index 3ae5e93f..36e80844 100644 --- a/PHPCI/Logging/Handler.php +++ b/PHPCI/Logging/Handler.php @@ -69,8 +69,17 @@ class Handler { $fatal_error = error_get_last(); - if ($fatal_error['type'] === E_ERROR) { - + try { + if (($e = error_get_last()) !== null) { + $e = new \ErrorException( + sprintf('%s: %s in %s line %d', $fatal_error['type'], $fatal_error['message'], $fatal_error['file'], $fatal_error['line']), + 0, $fatal_error['type'], $fatal_error['file'], $fatal_error['line'] + ); + $this->log($e); + } + } + catch (\Exception $e) + { $e = new \ErrorException( sprintf('%s: %s in %s line %d', $fatal_error['type'], $fatal_error['message'], $fatal_error['file'], $fatal_error['line']), 0, $fatal_error['type'], $fatal_error['file'], $fatal_error['line'] diff --git a/PHPCI/Logging/LoggerConfig.php b/PHPCI/Logging/LoggerConfig.php index 3eb0a5b2..b0ebeeec 100644 --- a/PHPCI/Logging/LoggerConfig.php +++ b/PHPCI/Logging/LoggerConfig.php @@ -48,7 +48,7 @@ class LoggerConfig { */ public function getFor($name) { $handlers = $this->getHandlers(self::KEY_AlwaysLoaded); - //$handlers = array_merge($handlers, $this->getHandlers($name)); + $handlers = array_merge($handlers, $this->getHandlers($name)); return new Logger($name, $handlers); } diff --git a/bootstrap.php b/bootstrap.php index a8ececf3..3cfcf038 100755 --- a/bootstrap.php +++ b/bootstrap.php @@ -44,7 +44,7 @@ if (!file_exists(dirname(__FILE__) . '/vendor/autoload.php') && defined('PHPCI_I require_once(dirname(__FILE__) . '/vendor/autoload.php'); $loggerConfig = LoggerConfig::newFromFile(__DIR__ . "/loggerconfig.php"); -Handler::register($loggerConfig->getFor('Exceptions')); +Handler::register($loggerConfig->getFor('_')); // Load configuration if present: $conf = array(); From 2730b47e0b07e88ea3a37cd49e20a7c607a8a9c0 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Thu, 20 Mar 2014 22:32:57 +0700 Subject: [PATCH 021/119] Fixed log pathes --- loggerconfig.php.example | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loggerconfig.php.example b/loggerconfig.php.example index dad42f17..c306673b 100644 --- a/loggerconfig.php.example +++ b/loggerconfig.php.example @@ -1,16 +1,16 @@ function() { return array( - new \Monolog\Handler\StreamHandler('c:\temp\errors.log', \Monolog\Logger::ERROR), + new \Monolog\Handler\StreamHandler(__DIR__ . DIRECTORY_SEPARATOR . 'errors.log', \Monolog\Logger::ERROR), ); }, - /** Loggers for the RunCommand */ 'RunCommand' => function() { return array( - new \Monolog\Handler\RotatingFileHandler('c:\temp\everything',3, \Monolog\Logger::INFO), + new \Monolog\Handler\RotatingFileHandler(__DIR__ . DIRECTORY_SEPARATOR . 'everything',3, \Monolog\Logger::DEBUG), ); - } + }, ); \ No newline at end of file From 1cdb29840e31e37abc8e20c59f424ac2807d6633 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Thu, 20 Mar 2014 22:33:25 +0700 Subject: [PATCH 022/119] Fixed log pathes --- loggerconfig.php.example | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loggerconfig.php.example b/loggerconfig.php.example index dad42f17..c306673b 100644 --- a/loggerconfig.php.example +++ b/loggerconfig.php.example @@ -1,16 +1,16 @@ function() { return array( - new \Monolog\Handler\StreamHandler('c:\temp\errors.log', \Monolog\Logger::ERROR), + new \Monolog\Handler\StreamHandler(__DIR__ . DIRECTORY_SEPARATOR . 'errors.log', \Monolog\Logger::ERROR), ); }, - /** Loggers for the RunCommand */ 'RunCommand' => function() { return array( - new \Monolog\Handler\RotatingFileHandler('c:\temp\everything',3, \Monolog\Logger::INFO), + new \Monolog\Handler\RotatingFileHandler(__DIR__ . DIRECTORY_SEPARATOR . 'everything',3, \Monolog\Logger::DEBUG), ); - } + }, ); \ No newline at end of file From 04dae16157f2ee099bd6d5a3392a064722292366 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Thu, 20 Mar 2014 22:51:30 +0700 Subject: [PATCH 023/119] Fixed require() in LoggerConfig --- PHPCI/Logging/LoggerConfig.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Logging/LoggerConfig.php b/PHPCI/Logging/LoggerConfig.php index b0ebeeec..5c579f6e 100644 --- a/PHPCI/Logging/LoggerConfig.php +++ b/PHPCI/Logging/LoggerConfig.php @@ -22,7 +22,7 @@ class LoggerConfig { public static function newFromFile($filePath) { if (file_exists($filePath)) { - $configArray = require_once($filePath); + $configArray = require($filePath); } else { $configArray = array(); From 08a15d872429bb625b0ef69213a2dfcef52cddd0 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Mon, 24 Mar 2014 23:43:20 +0700 Subject: [PATCH 024/119] Added exception context for errror/exception handler logging --- PHPCI/Logging/Handler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Logging/Handler.php b/PHPCI/Logging/Handler.php index 36e80844..55e0e4a3 100644 --- a/PHPCI/Logging/Handler.php +++ b/PHPCI/Logging/Handler.php @@ -103,7 +103,7 @@ class Handler $message = sprintf( '%s: %s (uncaught exception) at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine() ); - $this->logger->error($message); + $this->logger->error($message, array('exception' => $exception)); } } } \ No newline at end of file From 7e669ada4797fcce9e7e5c1d21e1bbcd3ad11db2 Mon Sep 17 00:00:00 2001 From: "steve.brazier" Date: Tue, 25 Mar 2014 14:17:03 +0000 Subject: [PATCH 025/119] Merge remote-tracking branch 'origin/master' into feature/pluginfactoryconfig Conflicts: PHPCI/Builder.php PHPCI/Plugin/Util/Factory.php --- PHPCI/Plugin/Util/Factory.php | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/PHPCI/Plugin/Util/Factory.php b/PHPCI/Plugin/Util/Factory.php index 9740516f..097f8bf5 100644 --- a/PHPCI/Plugin/Util/Factory.php +++ b/PHPCI/Plugin/Util/Factory.php @@ -36,7 +36,28 @@ class Factory { 'array' ); } - + + /** + * Trys to get a function from the file path specified. If the + * file returns a function then $this will be passed to it. + * This enables the config file to call any public methods. + * + * @param $configPath + * @return bool - true if the function exists else false. + */ + public function addConfigFromFile($configPath) + { + // The file is expected to return a function which can + // act on the pluginFactory to register any resources needed. + if (file_exists($configPath)) { + $configFunction = require($configPath); + if (is_callable($configFunction)) { + $configFunction($this); + return true; + } + } + return false; + } public function getLastOptions() { From 326113ebbcc40fd83b00e61a44061f469f140e98 Mon Sep 17 00:00:00 2001 From: "steve.brazier" Date: Tue, 25 Mar 2014 14:18:50 +0000 Subject: [PATCH 026/119] psr tidy up of util/Factory.php --- PHPCI/Plugin/Util/Factory.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/PHPCI/Plugin/Util/Factory.php b/PHPCI/Plugin/Util/Factory.php index 097f8bf5..971b3e23 100644 --- a/PHPCI/Plugin/Util/Factory.php +++ b/PHPCI/Plugin/Util/Factory.php @@ -4,7 +4,8 @@ namespace PHPCI\Plugin\Util; -class Factory { +class Factory +{ const TYPE_ARRAY = "array"; const TYPE_CALLABLE = "callable"; @@ -18,18 +19,17 @@ class Factory { */ private $container; - function __construct(\Pimple $container = null) + public function __construct(\Pimple $container = null) { if ($container) { $this->container = $container; - } - else { + } else { $this->container = new \Pimple(); } $self = $this; $this->registerResource( - function() use ($self) { + function () use ($self) { return $self->getLastOptions(); }, 'options', @@ -89,7 +89,7 @@ class Factory { if ($constructor) { $argsToUse = array(); - foreach($constructor->getParameters() as $param) { + foreach ($constructor->getParameters() as $param) { $argsToUse = $this->addArgFromParam($argsToUse, $param); } $plugin = $reflectedPlugin->newInstanceArgs($argsToUse); @@ -107,11 +107,11 @@ class Factory { * @throws \InvalidArgumentException * @internal param mixed $resource */ - public function registerResource($loader, - $name = null, - $type = null - ) - { + public function registerResource( + $loader, + $name = null, + $type = null + ) { if ($name === null && $type === null) { throw new \InvalidArgumentException( "Type or Name must be specified" @@ -161,9 +161,9 @@ class Factory { $class = $param->getClass(); if ($class) { return $class->getName(); - } elseif($param->isArray()) { + } elseif ($param->isArray()) { return self::TYPE_ARRAY; - } elseif($param->isCallable()) { + } elseif ($param->isCallable()) { return self::TYPE_CALLABLE; } else { return null; @@ -188,4 +188,4 @@ class Factory { return $existingArgs; } -} \ No newline at end of file +} From 5892fcb26ebec5ad541b41b52fedea81883614f5 Mon Sep 17 00:00:00 2001 From: Remo Laubacher Date: Wed, 26 Mar 2014 08:22:27 +0100 Subject: [PATCH 027/119] fix BuildLogger instantiation --- PHPCI/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index 9b88e597..b7b8c77e 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -121,7 +121,7 @@ class Builder implements LoggerAwareInterface $pluginFactory = $this->buildPluginFactory($build); $pluginFactory->addConfigFromFile(PHPCI_DIR . "/pluginconfig.php"); - $this->pluginExecutor = new Plugin\Util\Executor($pluginFactory, $this); + $this->pluginExecutor = new Plugin\Util\Executor($pluginFactory, $this->buildLogger); $this->commandExecutor = new CommandExecutor( $this->buildLogger, From 9f5b05aa2ae4b8bb58d267bf03fe3582fd624108 Mon Sep 17 00:00:00 2001 From: zigster Date: Sun, 30 Mar 2014 11:59:56 +0200 Subject: [PATCH 028/119] Bugfix Errors with PHPCI GitHub hook #296 > fixed access to undefined class member _buildStore to buildStore --- PHPCI/Controller/WebhookController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Controller/WebhookController.php b/PHPCI/Controller/WebhookController.php index 1b118440..9a9d143b 100644 --- a/PHPCI/Controller/WebhookController.php +++ b/PHPCI/Controller/WebhookController.php @@ -97,7 +97,7 @@ class WebhookController extends \PHPCI\Controller } try { - $this->_buildStore->save($build); + $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()); From 72b7a3d9126e314e2183fffe0ef6867ed66c7f1d Mon Sep 17 00:00:00 2001 From: Witold Wasiczko Date: Mon, 24 Mar 2014 16:55:42 +0100 Subject: [PATCH 029/119] Use args in Codeception plugin --- PHPCI/Plugin/Codeception.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/PHPCI/Plugin/Codeception.php b/PHPCI/Plugin/Codeception.php index 802d3540..bac0e7be 100644 --- a/PHPCI/Plugin/Codeception.php +++ b/PHPCI/Plugin/Codeception.php @@ -20,7 +20,14 @@ use PHPCI\Model\Build; */ class Codeception implements \PHPCI\Plugin { - protected $args; + /** + * @var string + */ + protected $args = ''; + + /** + * @var Builder + */ protected $phpci; /** @@ -30,14 +37,13 @@ class Codeception implements \PHPCI\Plugin public function __construct(Builder $phpci, Build $build, array $options = array()) { - $this->phpci = $phpci; + $this->phpci = $phpci; if (isset($options['config'])) { $this->xmlConfigFile = $options['config']; } - if (isset($options['args'])) { - $this->args = $options['args']; + $this->args = (string) $options['args']; } } @@ -69,9 +75,9 @@ class Codeception implements \PHPCI\Plugin return false; } - $cmd = 'cd "%s" && ' . $codecept . ' run -c "%s"'; + $cmd = 'cd "%s" && ' . $codecept . ' run -c "%s" '. $this->args; if (IS_WIN) { - $cmd = 'cd /d "%s" && ' . $codecept . ' run -c "%s"'; + $cmd = 'cd /d "%s" && ' . $codecept . ' run -c "%s" '. $this->args; } $success = $this->phpci->executeCommand($cmd, $this->phpci->buildPath, $this->phpci->buildPath . $configPath); From 3f8e76789326d752ce04c0060929649d42743157 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 10 Apr 2014 15:37:28 +0100 Subject: [PATCH 030/119] Removing web based installer, as it is more trouble than it is worth. --- public/install.php | 408 --------------------------------------------- 1 file changed, 408 deletions(-) delete mode 100644 public/install.php diff --git a/public/install.php b/public/install.php deleted file mode 100644 index f1e61a23..00000000 --- a/public/install.php +++ /dev/null @@ -1,408 +0,0 @@ -dump($config, 5); - - file_put_contents(PHPCI_DIR . 'PHPCI/config.yml', $yaml); - - /** - * Create database: - */ - $dbhost = $config['b8']['database']['servers']['write'][0]; - $dbname = $config['b8']['database']['name'] ?: 'phpci'; - $dbuser = $config['b8']['database']['username'] ?: 'phpci'; - $dbpass = $config['b8']['database']['password']; - - $pdo = new PDO('mysql:host=' . $dbhost, $dbuser, $dbpass); - - $pdo->query('CREATE DATABASE IF NOT EXISTS `' . $dbname . '`'); - - /** - * Bootstrap PHPCI and populate database: - */ - require(PHPCI_DIR . 'bootstrap.php'); - - ob_start(); - $gen = new \b8\Database\Generator(\b8\Database::getConnection(), 'PHPCI', PHPCI_DIR . 'PHPCI/Model/Base/'); - $gen->generate(); - ob_end_clean(); - - /** - * Create our admin user: - */ - $store = \b8\Store\Factory::getStore('User'); - - try { - $user = $store->getByEmail($adminUser); - } catch (Exception $ex) { - } - - if (empty($user)) { - $user = new \PHPCI\Model\User(); - $user->setEmail($adminUser); - $user->setName($adminUser); - $user->setIsAdmin(1); - $user->setHash(password_hash($adminPass, PASSWORD_DEFAULT)); - - $store->save($user); - } - - $formAction = rtrim( $phpciUrl, '/' ) . '/session/login'; - } -} - - -switch ($installStage) { - case 'start': - $nextStage = 'database'; - break; - - case 'database': - $nextStage = 'github'; - break; - - case 'github': - $nextStage = 'email'; - break; - - case 'email': - $nextStage = 'complete'; - break; -} - -?> - - - - Install PHPCI - - - - - - - - -
-
- -
-
- - - - - -

Welcome to PHPCI!

- -

Your server has passed all of PHPCI's pre-installation checks, please press continue below to - begin installation.

- -

Please correct the problems below, then refresh this page to continue.

- - - -

- Important! - You need to run composer to install dependencies before running the installer. -

- - - - -

- Important! - ./PHPCI/config.yml needs to be writeable to continue. -

- - - -

Important! PHPCI requires PHP 5.3.3 or above.

- - - - -

Database Details

-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- -

PHPCI Details

-
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- - - -

Github App Settings (Optional)

-
- -
- -
-
- -
- -
- -
-
- - - -

SMTP Settings (Optional)

-
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -

The address system emails should come from.

-
-
- -
- -
- -

The address to which notifications should go by default.

-
-
- - - -

Thank you for installing PHPCI. Click continue below to log in for the first time!

- - - - - - -
-
- -
-
- -
-
- - -
-
- - From efe8529d3f0a46d570a4f1a5f3c3724dca12be71 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 10 Apr 2014 15:37:54 +0100 Subject: [PATCH 031/119] Removing warning about install.php being present. --- PHPCI/View/layout.phtml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/PHPCI/View/layout.phtml b/PHPCI/View/layout.phtml index bc731848..c455334c 100644 --- a/PHPCI/View/layout.phtml +++ b/PHPCI/View/layout.phtml @@ -64,14 +64,6 @@
- - -
- - Warning! install.php detected, for security purposes please delete it immediately. -
- -
From 9f182aad9141c43e93cb4622d411a19778e169a0 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 10 Apr 2014 15:38:16 +0100 Subject: [PATCH 032/119] Updating console installer to be more reliable, easier to use, and use Symfony console properly. --- PHPCI/Command/InstallCommand.php | 334 +++++++++++++++++++++---------- 1 file changed, 223 insertions(+), 111 deletions(-) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index 7f9daf6d..4cfc818e 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -1,28 +1,34 @@ -* @package PHPCI -* @subpackage Console -*/ + * Install console command - Installs PHPCI. + * @author Dan Cryer + * @package PHPCI + * @subpackage Console + */ class InstallCommand extends Command { protected function configure() @@ -33,22 +39,70 @@ class InstallCommand extends Command } /** - * Installs PHPCI - Can be run more than once as long as you ^C instead of entering an email address. - */ + * Installs PHPCI - Can be run more than once as long as you ^C instead of entering an email address. + */ protected function execute(InputInterface $input, OutputInterface $output) { - // Gather initial data from the user: - $conf = array(); - $conf['b8']['database']['servers']['read'] = $this->ask('Enter your MySQL host: '); - $conf['b8']['database']['servers']['write'] = $conf['b8']['database']['servers']['read']; - $conf['b8']['database']['name'] = $this->ask('Enter the database name PHPCI should use: '); - $conf['b8']['database']['username'] = $this->ask('Enter your MySQL username: '); - $conf['b8']['database']['password'] = $this->ask('Enter your MySQL password: ', true); - $ask = 'Your PHPCI URL (without trailing slash): '; - $conf['phpci']['url'] = $this->ask($ask, false, array(FILTER_VALIDATE_URL,"/[^\/]$/i")); - $conf['phpci']['github']['id'] = $this->ask('(Optional) Github Application ID: ', true); - $conf['phpci']['github']['secret'] = $this->ask('(Optional) Github Application Secret: ', true); + $output->writeln(''); + $output->writeln('******************'); + $output->writeln(' Welcome to PHPCI'); + $output->writeln('******************'); + $output->writeln(''); + $this->checkRequirements($output); + + $output->writeln('Please answer the following questions:'); + $output->writeln('-------------------------------------'); + $output->writeln(''); + + + /** + * @var \Symfony\Component\Console\Helper\DialogHelper + */ + $dialog = $this->getHelperSet()->get('dialog'); + + // ---- + // Get MySQL connection information and verify that it works: + // ---- + $connectionVerified = false; + + while (!$connectionVerified) { + $db = array(); + $db['servers']['read'] = $dialog->ask($output, 'Please enter your MySQL host [localhost]: ', 'localhost'); + $db['servers']['write'] = $db['servers']['read']; + $db['name'] = $dialog->ask($output, 'Please enter your database name [phpci]: ', 'phpci'); + $db['username'] = $dialog->ask($output, 'Please enter your database username [phpci]: ', 'phpci'); + $db['password'] = $dialog->askHiddenResponse($output, 'Please enter your database password: '); + + $connectionVerified = $this->verifyDatabaseDetails($db, $output); + } + + $output->writeln(''); + + // ---- + // Get basic installation details (URL, etc) + // ---- + + $conf = array(); + $conf['b8']['database'] = $db; + $conf['phpci']['url'] = $dialog->askAndValidate( + $output, + 'Your PHPCI URL (without trailing slash): ', + function ($answer) { + if (!filter_var($answer, FILTER_VALIDATE_URL)) { + throw new Exception('Must be a valid URL'); + } + + return $answer; + }, + false + ); + + $this->writeConfigFile($conf); + $this->setupDatabase($output); + $this->createAdminUser($output, $dialog); + + /* $conf['phpci']['email_settings']['smtp_address'] = $this->ask('(Optional) Smtp server address: ', true); $conf['phpci']['email_settings']['smtp_port'] = $this->ask('(Optional) Smtp port: ', true); $conf['phpci']['email_settings']['smtp_encryption'] = $this->ask('(Optional) Smtp encryption: ', true); @@ -58,112 +112,170 @@ class InstallCommand extends Command $ask = '(Optional) Default address to email notifications to: '; $conf['phpci']['email_settings']['default_mailto_address'] = $this->ask($ask, true); + */ + } - $dbUser = $conf['b8']['database']['username']; - $dbPass = $conf['b8']['database']['password']; - $dbHost = $conf['b8']['database']['servers']['write']; - $dbName = $conf['b8']['database']['name']; + /** + * Check PHP version, required modules and for disabled functions. + * @param OutputInterface $output + */ + protected function checkRequirements(OutputInterface $output) + { + $output->write('Checking requirements...'); + $errors = false; - // Create the database if it doesn't exist: - $cmd = 'mysql -u' . $dbUser . (!empty($dbPass) ? ' -p' . $dbPass : '') . ' -h' . $dbHost . - ' -e "CREATE DATABASE IF NOT EXISTS ' . $dbName . '"'; + // Check PHP version: + if (!(version_compare(PHP_VERSION, '5.3.3') >= 0)) { + $output->writeln(''); + $output->writeln('PHPCI requires at least PHP 5.3.3 to function.'); + $errors = true; + } - shell_exec($cmd); + // Check for required extensions: + if (!extension_loaded('PDO')) { + $output->writeln(''); + $output->writeln('PDO extension must be installed.'); + $errors = true; + } + if (!extension_loaded('pdo_mysql')) { + $output->writeln(''); + $output->writeln('PDO MySQL extension must be installed.'); + $errors = true; + } + + if (!extension_loaded('mcrypt')) { + $output->writeln(''); + $output->writeln('Mcrypt extension must be installed.'); + $errors = true; + } + + // Check we can use the exec() and shell_exec() functions: + if (!function_exists('exec')) { + $output->writeln(''); + $output->writeln('PHPCI needs to be able to call the exec() function. Is it disabled in php.ini?'); + $errors = true; + } + + if (!function_exists('shell_exec')) { + $output->writeln(''); + $output->writeln('PHPCI needs to be able to call the shell_exec() function. Is it disabled in php.ini?'); + $errors = true; + } + + if (!function_exists('password_hash')) { + $output->writeln(''); + $output->writeln('PHPCI requires the password_hash() function available in PHP 5.4, or the password_compat library by ircmaxell.'); + $errors = true; + } + + if ($errors) { + $output->writeln(''); + die; + } + + $output->writeln(' OK'); + $output->writeln(''); + } + + /** + * Try and connect to MySQL using the details provided. + * @param array $db + * @param OutputInterface $output + * @return bool + */ + protected function verifyDatabaseDetails(array $db, OutputInterface $output) + { + try { + $pdo = new PDO( + 'mysql:host='.$db['servers']['write'].';dbname='.$db['name'], + $db['username'], + $db['password'], + array( + \PDO::ATTR_PERSISTENT => false, + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_TIMEOUT => 2, + \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'', + ) + ); + + return true; + + } catch (Exception $ex) { + $output->writeln('PHPCI could not connect to MySQL with the details provided. Please try again.'); + $output->writeln('' . $ex->getMessage() . ''); + } + + return false; + } + + /** + * Write the PHPCI config.yml file. + * @param array $config + */ + protected function writeConfigFile(array $config) + { $dumper = new \Symfony\Component\Yaml\Dumper(); - $yaml = $dumper->dump($conf); + $yaml = $dumper->dump($config); file_put_contents(PHPCI_DIR . 'PHPCI/config.yml', $yaml); + } + protected function setupDatabase(OutputInterface $output) + { + $output->write('Setting up your database... '); + + // Load PHPCI's bootstrap file: require(PHPCI_DIR . 'bootstrap.php'); - // Update the database: - $gen = new \b8\Database\Generator(\b8\Database::getConnection(), 'PHPCI', './PHPCI/Model/Base/'); - $gen->generate(); - - // Try to create a user account: - $adminEmail = $this->ask('Enter your email address (leave blank if updating): ', true, FILTER_VALIDATE_EMAIL); - - if (empty($adminEmail)) { - return; + 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('PHPCI failed to set up the database.'); + $output->writeln('' . $ex->getMessage() . ''); + die; } - $adminPass = $this->ask('Enter your desired admin password: '); - $adminName = $this->ask('Enter your name: '); + + $output->writeln('OK'); + } + + protected function createAdminUser(OutputInterface $output, DialogHelper $dialog) + { + // Try to create a user account: + $adminEmail = $dialog->askAndValidate( + $output, + 'Your email address: ', + function ($answer) { + if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) { + throw new Exception('Must be a valid email address.'); + } + + return $answer; + }, + false + ); + + $adminPass = $dialog->askHiddenResponse($output, 'Enter your desired admin password: '); + $adminName = $dialog->ask($output, 'Enter your name: '); try { - $user = new \PHPCI\Model\User(); + $user = new User(); $user->setEmail($adminEmail); $user->setName($adminName); $user->setIsAdmin(1); $user->setHash(password_hash($adminPass, PASSWORD_DEFAULT)); - $store = \b8\Store\Factory::getStore('User'); + $store = Factory::getStore('User'); $store->save($user); - print 'User account created!' . PHP_EOL; + $output->writeln('User account created!'); } catch (\Exception $ex) { - print 'There was a problem creating your account. :(' . PHP_EOL; - print $ex->getMessage(); + $output->writeln('PHPCI failed to create your admin account.'); + $output->writeln('' . $ex->getMessage() . ''); + die; } } - - protected function ask($question, $emptyOk = false, $validationFilter = null) - { - print $question . ' '; - - $rtn = ''; - $stdin = fopen('php://stdin', 'r'); - $rtn = fgets($stdin); - fclose($stdin); - - $rtn = trim($rtn); - - if (!$emptyOk && empty($rtn)) { - $rtn = $this->ask($question, $emptyOk, $validationFilter); - } elseif ($validationFilter != null && ! empty($rtn)) { - if (! $this -> controlFormat($rtn, $validationFilter, $statusMessage)) { - print $statusMessage; - $rtn = $this->ask($question, $emptyOk, $validationFilter); - } - } - - return $rtn; - } - protected function controlFormat($valueToInspect, $filter, &$statusMessage) - { - $filters = !(is_array($filter))? array($filter) : $filter; - $statusMessage = ''; - $status = true; - $options = array(); - - foreach ($filters as $filter) { - if (! is_int($filter)) { - $regexp = $filter; - $filter = FILTER_VALIDATE_REGEXP; - $options = array( - 'options' => array( - 'regexp' => $regexp, - ) - ); - } - if (! filter_var($valueToInspect, $filter, $options)) { - $status = false; - - switch ($filter) - { - case FILTER_VALIDATE_URL: - $statusMessage = 'Incorrect url format.' . PHP_EOL; - break; - case FILTER_VALIDATE_EMAIL: - $statusMessage = 'Incorrect e-mail format.' . PHP_EOL; - break; - case FILTER_VALIDATE_REGEXP: - $statusMessage = 'Incorrect format.' . PHP_EOL; - break; - } - } - } - - return $status; - } } From 65f51cff4a3283e777b3cff5485d2246eeb5a440 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 10 Apr 2014 14:58:26 +0000 Subject: [PATCH 033/119] Adding verification to the install and update commands to check whether PHPCI is installed. --- PHPCI/Command/InstallCommand.php | 15 +++++++++++++++ PHPCI/Command/UpdateCommand.php | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index 4cfc818e..6e846ab6 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -43,6 +43,8 @@ class InstallCommand extends Command */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->verifyNotInstalled($output); + $output->writeln(''); $output->writeln('******************'); $output->writeln(' Welcome to PHPCI'); @@ -278,4 +280,17 @@ class InstallCommand extends Command die; } } + + protected function verifyNotInstalled(OutputInterface $output) + { + if (file_exists(PHPCI_DIR . 'PHPCI/config.yml')) { + $content = file_get_contents(PHPCI_DIR . 'PHPCI/config.yml'); + + if (!empty($content)) { + $output->writeln('PHPCI/config.yml exists and is not empty.'); + $output->writeln('If you were trying to update PHPCI, please use phpci:update instead.'); + die; + } + } + } } diff --git a/PHPCI/Command/UpdateCommand.php b/PHPCI/Command/UpdateCommand.php index 855ca893..127b272e 100644 --- a/PHPCI/Command/UpdateCommand.php +++ b/PHPCI/Command/UpdateCommand.php @@ -48,8 +48,30 @@ class UpdateCommand extends Command */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->verifyInstalled($output); + + $output->writeln('Updating PHPCI database.'); + // Update the database: $gen = new \b8\Database\Generator(\b8\Database::getConnection(), 'PHPCI', './PHPCI/Model/Base/'); $gen->generate(); + + $output->writeln('Done!'); + } + + protected function verifyInstalled(OutputInterface $output) + { + if (!file_exists(PHPCI_DIR . 'PHPCI/config.yml')) { + $output->writeln('PHPCI does not appear to be installed.'); + $output->writeln('Please install PHPCI via phpci:install instead.'); + die; + } + + $content = file_get_contents(PHPCI_DIR . 'PHPCI/config.yml'); + if (empty($content)) { + $output->writeln('PHPCI does not appear to be installed.'); + $output->writeln('Please install PHPCI via phpci:install instead.'); + die; + } } } From 9849d31a0eb2a910f92dca176ced9b582ef000f0 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 10 Apr 2014 14:59:24 +0000 Subject: [PATCH 034/119] Using UTC timezone if one is not set. --- bootstrap.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bootstrap.php b/bootstrap.php index 3cfcf038..4f3e8a67 100755 --- a/bootstrap.php +++ b/bootstrap.php @@ -11,7 +11,10 @@ use PHPCI\Logging\Handler; use PHPCI\Logging\LoggerConfig; -date_default_timezone_set(@date_default_timezone_get()); +$timezone = ini_get('date.timezone'); +if (empty($timezone)) { + date_default_timezone_set('UTC'); +} // Set up a basic autoloader for PHPCI: $autoload = function ($class) { From 2b791b1f3b6a9132d161958526f97864679bf0f8 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 10 Apr 2014 16:31:10 +0100 Subject: [PATCH 035/119] Removing commented code from the installer --- PHPCI/Command/InstallCommand.php | 12 --- PHPCI/Controller/SettingsController.php | 110 ++++++++++++++++++++++-- PHPCI/View/Settings/index.phtml | 31 ++++++- 3 files changed, 132 insertions(+), 21 deletions(-) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index 6e846ab6..3b8ca701 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -103,18 +103,6 @@ class InstallCommand extends Command $this->writeConfigFile($conf); $this->setupDatabase($output); $this->createAdminUser($output, $dialog); - - /* - $conf['phpci']['email_settings']['smtp_address'] = $this->ask('(Optional) Smtp server address: ', true); - $conf['phpci']['email_settings']['smtp_port'] = $this->ask('(Optional) Smtp port: ', true); - $conf['phpci']['email_settings']['smtp_encryption'] = $this->ask('(Optional) Smtp encryption: ', true); - $conf['phpci']['email_settings']['smtp_username'] = $this->ask('(Optional) Smtp Username: ', true); - $conf['phpci']['email_settings']['smtp_password'] = $this->ask('(Optional) Smtp Password: ', true); - $conf['phpci']['email_settings']['from_address'] = $this->ask('(Optional) Email address to send from: ', true); - - $ask = '(Optional) Default address to email notifications to: '; - $conf['phpci']['email_settings']['default_mailto_address'] = $this->ask($ask, true); - */ } /** diff --git a/PHPCI/Controller/SettingsController.php b/PHPCI/Controller/SettingsController.php index 6f8f544c..c2ea099b 100644 --- a/PHPCI/Controller/SettingsController.php +++ b/PHPCI/Controller/SettingsController.php @@ -39,7 +39,15 @@ class SettingsController extends Controller public function index() { $this->view->settings = $this->settings; + + $emailSettings = array(); + + if (isset($this->settings['phpci']['email_settings'])) { + $emailSettings = $this->settings['phpci']['email_settings']; + } + $this->view->github = $this->getGithubForm(); + $this->view->emailSettings = $this->getEmailForm($emailSettings); if (!empty($this->settings['phpci']['github']['token'])) { $this->view->githubUser = $this->getGithubUser($this->settings['phpci']['github']['token']); @@ -52,17 +60,28 @@ class SettingsController extends Controller { $this->settings['phpci']['github']['id'] = $this->getParam('githubid', ''); $this->settings['phpci']['github']['secret'] = $this->getParam('githubsecret', ''); - $error = $this->storeSettings(); - if($error) - { + if($error) { header('Location: ' . PHPCI_URL . 'settings?saved=2'); - } - else - { + } else { header('Location: ' . PHPCI_URL . 'settings?saved=1'); } + + die; + } + + public function email() + { + $this->settings['phpci']['email_settings'] = $this->getParams(); + $error = $this->storeSettings(); + + if ($error) { + header('Location: ' . PHPCI_URL . 'settings?saved=2'); + } else { + header('Location: ' . PHPCI_URL . 'settings?saved=1'); + } + die; } @@ -120,18 +139,23 @@ class SettingsController extends Controller $field->setLabel('Application ID'); $field->setClass('form-control'); $field->setContainerClass('form-group'); - $field->setValue($this->settings['phpci']['github']['id']); $form->addField($field); + if (isset($this->settings['phpci']['github']['id'])) { + $field->setValue($this->settings['phpci']['github']['id']); + } + $field = new Form\Element\Text('githubsecret'); $field->setRequired(true); $field->setPattern('[a-zA-Z0-9]+'); $field->setLabel('Application Secret'); $field->setClass('form-control'); $field->setContainerClass('form-group'); - $field->setValue($this->settings['phpci']['github']['secret']); $form->addField($field); + if (isset($this->settings['phpci']['github']['secret'])) { + $field->setValue($this->settings['phpci']['github']['secret']); + } $field = new Form\Element\Submit(); $field->setValue('Save »'); @@ -141,6 +165,76 @@ class SettingsController extends Controller return $form; } + protected function getEmailForm($values = array()) + { + $form = new Form(); + $form->setMethod('POST'); + $form->setAction(PHPCI_URL . 'settings/email'); + $form->addField(new Form\Element\Csrf('csrf')); + + $field = new Form\Element\Text('smtp_address'); + $field->setRequired(false); + $field->setLabel('SMTP Server'); + $field->setClass('form-control'); + $field->setContainerClass('form-group'); + $field->setValue('localhost'); + $form->addField($field); + + $field = new Form\Element\Text('smtp_port'); + $field->setRequired(false); + $field->setPattern('[0-9]+'); + $field->setLabel('SMTP Port'); + $field->setClass('form-control'); + $field->setContainerClass('form-group'); + $field->setValue(25); + $form->addField($field); + + $field = new Form\Element\Text('smtp_username'); + $field->setRequired(false); + $field->setLabel('SMTP Username'); + $field->setClass('form-control'); + $field->setContainerClass('form-group'); + $form->addField($field); + + $field = new Form\Element\Text('smtp_password'); + $field->setRequired(false); + $field->setLabel('SMTP Password'); + $field->setClass('form-control'); + $field->setContainerClass('form-group'); + $form->addField($field); + + $field = new Form\Element\Email('from_address'); + $field->setRequired(false); + $field->setLabel('From Email Address'); + $field->setClass('form-control'); + $field->setContainerClass('form-group'); + $form->addField($field); + + $field = new Form\Element\Email('default_mailto_address'); + $field->setRequired(false); + $field->setLabel('Default Notification Address'); + $field->setClass('form-control'); + $field->setContainerClass('form-group'); + $form->addField($field); + + $field = new Form\Element\Checkbox('smtp_encryption'); + $field->setCheckedValue(1); + $field->setRequired(false); + $field->setLabel('Use SMTP encryption?'); + $field->setContainerClass('form-group'); + $field->setValue(1); + $form->addField($field); + + $field = new Form\Element\Submit(); + $field->setValue('Save »'); + $field->setClass('btn btn-success pull-right'); + $form->addField($field); + + $form->setValues($values); + + return $form; + } + protected function getGithubUser($token) { $http = new HttpClient('https://api.github.com'); diff --git a/PHPCI/View/Settings/index.phtml b/PHPCI/View/Settings/index.phtml index be0c88b2..3f0eb5ec 100644 --- a/PHPCI/View/Settings/index.phtml +++ b/PHPCI/View/Settings/index.phtml @@ -28,7 +28,12 @@

Github Application

@@ -66,3 +71,27 @@ + +
+
+
+

Email Settings

+ + + +

+ Before PHPCI can send build status emails, you need to configure your SMTP settings below. +

+ + +
+ +
+ +
+ +
+ +
+
+
\ No newline at end of file From 1a92779f25fbcb113bad10f76946102f00fbe74d Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 10 Apr 2014 16:31:48 +0100 Subject: [PATCH 036/119] Adding blank lane at end of index.php --- public/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/public/index.php b/public/index.php index 134e9a7b..e1754b62 100644 --- a/public/index.php +++ b/public/index.php @@ -16,3 +16,4 @@ require_once('../bootstrap.php'); $fc = new PHPCI\Application($config, new b8\Http\Request()); print $fc->handleRequest(); + From ccb3d91ae13b6aa2e9b8467e6a0285efe23ece96 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Thu, 10 Apr 2014 23:41:02 +0700 Subject: [PATCH 037/119] Inverted priority of configs: phpci.yml is primary now --- PHPCI/Model/Build.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/PHPCI/Model/Build.php b/PHPCI/Model/Build.php index 27cf4055..20ff6a34 100644 --- a/PHPCI/Model/Build.php +++ b/PHPCI/Model/Build.php @@ -88,13 +88,16 @@ class Build extends BuildBase */ protected function handleConfig(Builder $builder, $buildPath) { - $build_config = $this->getProject()->getBuildConfig(); - if (!$build_config) { - if (!is_file($buildPath . '/phpci.yml')) { + if (is_file($buildPath . '/phpci.yml')) { + $build_config = file_get_contents($buildPath . '/phpci.yml'); + } + + if (!is_file($buildPath . '/phpci.yml') || !$build_config) { + $build_config = $this->getProject()->getBuildConfig(); + if (!$build_config) { $builder->logFailure('Project does not contain a phpci.yml file.'); return false; } - $build_config = file_get_contents($buildPath . '/phpci.yml'); } $yamlParser = new YamlParser(); From 7ac671424edbe05087f8685e3bb33aeda3b20a7c Mon Sep 17 00:00:00 2001 From: Corpsee Date: Thu, 10 Apr 2014 23:52:21 +0700 Subject: [PATCH 038/119] Genereted models by console phpci:generate command --- PHPCI/Model/Base/BuildBase.php | 512 +++++++++++------------- PHPCI/Model/Base/BuildMetaBase.php | 254 ++++++------ PHPCI/Model/Base/ProjectBase.php | 346 ++++++++-------- PHPCI/Model/Base/UserBase.php | 231 +++++------ PHPCI/Store/Base/BuildMetaStoreBase.php | 15 +- PHPCI/Store/Base/BuildStoreBase.php | 19 +- PHPCI/Store/Base/ProjectStoreBase.php | 15 +- PHPCI/Store/Base/UserStoreBase.php | 14 +- 8 files changed, 643 insertions(+), 763 deletions(-) diff --git a/PHPCI/Model/Base/BuildBase.php b/PHPCI/Model/Base/BuildBase.php index 59e4c21e..02dd6280 100644 --- a/PHPCI/Model/Base/BuildBase.php +++ b/PHPCI/Model/Base/BuildBase.php @@ -3,7 +3,6 @@ /** * Build base model for table: build */ - namespace PHPCI\Model\Base; use PHPCI\Model; @@ -15,336 +14,323 @@ use b8\Store\Factory; class BuildBase extends Model { /** - * @var array - */ + * @var array + */ public static $sleepable = array(); /** - * @var string - */ + * @var string + */ protected $tableName = 'build'; /** - * @var string - */ + * @var string + */ protected $modelName = 'Build'; /** - * @var array - */ + * @var array + */ protected $data = array( - 'id' => null, - 'project_id' => null, - 'commit_id' => null, - 'status' => null, - 'log' => null, - 'branch' => null, - 'created' => null, - 'started' => null, - 'finished' => null, - 'plugins' => null, + 'id' => null, + 'project_id' => null, + 'commit_id' => null, + 'status' => null, + 'log' => null, + 'branch' => null, + 'created' => null, + 'started' => null, + 'finished' => null, + 'plugins' => null, 'committer_email' => null, - 'commit_message' => null, + 'commit_message' => null, ); /** - * @var array - */ + * @var array + */ protected $getters = array( // Direct property getters: - 'id' => 'getId', - 'project_id' => 'getProjectId', - 'commit_id' => 'getCommitId', - 'status' => 'getStatus', - 'log' => 'getLog', - 'branch' => 'getBranch', - 'created' => 'getCreated', - 'started' => 'getStarted', - 'finished' => 'getFinished', - 'plugins' => 'getPlugins', + 'id' => 'getId', + 'project_id' => 'getProjectId', + 'commit_id' => 'getCommitId', + 'status' => 'getStatus', + 'log' => 'getLog', + 'branch' => 'getBranch', + 'created' => 'getCreated', + 'started' => 'getStarted', + 'finished' => 'getFinished', + 'plugins' => 'getPlugins', 'committer_email' => 'getCommitterEmail', - 'commit_message' => 'getCommitMessage', - + 'commit_message' => 'getCommitMessage', // Foreign key getters: - 'Project' => 'getProject', + 'Project' => 'getProject', ); /** - * @var array - */ + * @var array + */ protected $setters = array( // Direct property setters: - 'id' => 'setId', - 'project_id' => 'setProjectId', - 'commit_id' => 'setCommitId', - 'status' => 'setStatus', - 'log' => 'setLog', - 'branch' => 'setBranch', - 'created' => 'setCreated', - 'started' => 'setStarted', - 'finished' => 'setFinished', - 'plugins' => 'setPlugins', + 'id' => 'setId', + 'project_id' => 'setProjectId', + 'commit_id' => 'setCommitId', + 'status' => 'setStatus', + 'log' => 'setLog', + 'branch' => 'setBranch', + 'created' => 'setCreated', + 'started' => 'setStarted', + 'finished' => 'setFinished', + 'plugins' => 'setPlugins', 'committer_email' => 'setCommitterEmail', - 'commit_message' => 'setCommitMessage', - + 'commit_message' => 'setCommitMessage', // Foreign key setters: - 'Project' => 'setProject', + 'Project' => 'setProject', ); /** - * @var array - */ + * @var array + */ public $columns = array( - 'id' => array( - 'type' => 'int', - 'length' => 11, - 'primary_key' => true, + 'id' => array( + 'type' => 'int', + 'length' => 11, + 'primary_key' => true, 'auto_increment' => true, + 'default' => null, + ), + 'project_id' => array( + 'type' => 'int', + 'length' => 11, 'default' => null, ), - 'project_id' => array( - 'type' => 'int', - 'length' => 11, - 'default' => null, - ), - 'commit_id' => array( - 'type' => 'varchar', - 'length' => 50, + 'commit_id' => array( + 'type' => 'varchar', + 'length' => 50, 'nullable' => true, + 'default' => null, + ), + 'status' => array( + 'type' => 'tinyint', + 'length' => 4, 'default' => null, ), - 'status' => array( - 'type' => 'tinyint', - 'length' => 4, - 'default' => null, - ), - 'log' => array( - 'type' => 'longtext', + 'log' => array( + 'type' => 'longtext', 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'branch' => array( - 'type' => 'varchar', - 'length' => 50, + 'branch' => array( + 'type' => 'varchar', + 'length' => 50, 'default' => 'master', ), - 'created' => array( - 'type' => 'datetime', + 'created' => array( + 'type' => 'datetime', 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'started' => array( - 'type' => 'datetime', + 'started' => array( + 'type' => 'datetime', 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'finished' => array( - 'type' => 'datetime', + 'finished' => array( + 'type' => 'datetime', 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'plugins' => array( - 'type' => 'text', + 'plugins' => array( + 'type' => 'text', 'nullable' => true, - 'default' => null, + 'default' => null, ), 'committer_email' => array( - 'type' => 'varchar', - 'length' => 512, + 'type' => 'varchar', + 'length' => 512, 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'commit_message' => array( - 'type' => 'text', + 'commit_message' => array( + 'type' => 'text', 'nullable' => true, - 'default' => null, + 'default' => null, ), ); /** - * @var array - */ + * @var array + */ public $indexes = array( - 'PRIMARY' => array('unique' => true, 'columns' => 'id'), - 'project_id' => array('columns' => 'project_id'), - 'idx_status' => array('columns' => 'status'), + 'PRIMARY' => array('unique' => true, 'columns' => 'id'), + 'project_id' => array('columns' => 'project_id'), + 'idx_status' => array('columns' => 'status'), ); /** - * @var array - */ + * @var array + */ public $foreignKeys = array( - 'build_ibfk_1' => array( - 'local_col' => 'project_id', - 'update' => 'CASCADE', - 'delete' => 'CASCADE', - 'table' => 'project', - 'col' => 'id' - ), + 'build_ibfk_1' => array( + 'local_col' => 'project_id', + 'update' => 'CASCADE', + 'delete' => 'CASCADE', + 'table' => 'project', + 'col' => 'id' + ), ); /** - * Get the value of Id / id. - * - * @return int - */ + * Get the value of Id / id. + * + * @return int + */ public function getId() { - $rtn = $this->data['id']; - + $rtn = $this->data['id']; return $rtn; } /** - * Get the value of ProjectId / project_id. - * - * @return int - */ + * Get the value of ProjectId / project_id. + * + * @return int + */ public function getProjectId() { - $rtn = $this->data['project_id']; - + $rtn = $this->data['project_id']; return $rtn; } /** - * Get the value of CommitId / commit_id. - * - * @return string - */ + * Get the value of CommitId / commit_id. + * + * @return string + */ public function getCommitId() { - $rtn = $this->data['commit_id']; - + $rtn = $this->data['commit_id']; return $rtn; } /** - * Get the value of Status / status. - * - * @return int - */ + * Get the value of Status / status. + * + * @return int + */ public function getStatus() { - $rtn = $this->data['status']; - + $rtn = $this->data['status']; return $rtn; } /** - * Get the value of Log / log. - * - * @return string - */ + * Get the value of Log / log. + * + * @return string + */ public function getLog() { - $rtn = $this->data['log']; - + $rtn = $this->data['log']; return $rtn; } /** - * Get the value of Branch / branch. - * - * @return string - */ + * Get the value of Branch / branch. + * + * @return string + */ public function getBranch() { - $rtn = $this->data['branch']; - + $rtn = $this->data['branch']; return $rtn; } /** - * Get the value of Created / created. - * - * @return \DateTime - */ + * Get the value of Created / created. + * + * @return \DateTime + */ public function getCreated() { - $rtn = $this->data['created']; + $rtn = $this->data['created']; if (!empty($rtn)) { - $rtn = new \DateTime($rtn); + $rtn = new \DateTime($rtn); } - return $rtn; } /** - * Get the value of Started / started. - * - * @return \DateTime - */ + * Get the value of Started / started. + * + * @return \DateTime + */ public function getStarted() { - $rtn = $this->data['started']; + $rtn = $this->data['started']; if (!empty($rtn)) { - $rtn = new \DateTime($rtn); + $rtn = new \DateTime($rtn); } - return $rtn; } /** - * Get the value of Finished / finished. - * - * @return \DateTime - */ + * Get the value of Finished / finished. + * + * @return \DateTime + */ public function getFinished() { - $rtn = $this->data['finished']; + $rtn = $this->data['finished']; if (!empty($rtn)) { - $rtn = new \DateTime($rtn); + $rtn = new \DateTime($rtn); } - return $rtn; } /** - * Get the value of Plugins / plugins. - * - * @return string - */ + * Get the value of Plugins / plugins. + * + * @return string + */ public function getPlugins() { - $rtn = $this->data['plugins']; - + $rtn = $this->data['plugins']; return $rtn; } /** - * Get the value of CommitterEmail / committer_email. - * - * @return string - */ + * Get the value of CommitterEmail / committer_email. + * + * @return string + */ public function getCommitterEmail() { - $rtn = $this->data['committer_email']; - + $rtn = $this->data['committer_email']; return $rtn; } /** - * Get the value of CommitMessage / commit_message. - * - * @return string - */ + * Get the value of CommitMessage / commit_message. + * + * @return string + */ public function getCommitMessage() { - $rtn = $this->data['commit_message']; - + $rtn = $this->data['commit_message']; return $rtn; } /** - * Set the value of Id / id. - * - * Must not be null. - * @param $value int - */ + * Set the value of Id / id. + * + * Must not be null. + * + * @param $value int + */ public function setId($value) { $this->_validateNotNull('Id', $value); @@ -353,18 +339,17 @@ class BuildBase extends Model if ($this->data['id'] === $value) { return; } - $this->data['id'] = $value; - $this->_setModified('id'); } /** - * Set the value of ProjectId / project_id. - * - * Must not be null. - * @param $value int - */ + * Set the value of ProjectId / project_id. + * + * Must not be null. + * + * @param $value int + */ public function setProjectId($value) { $this->_validateNotNull('ProjectId', $value); @@ -373,17 +358,15 @@ class BuildBase extends Model if ($this->data['project_id'] === $value) { return; } - $this->data['project_id'] = $value; - $this->_setModified('project_id'); } /** - * Set the value of CommitId / commit_id. - * - * @param $value string - */ + * Set the value of CommitId / commit_id. + * + * @param $value string + */ public function setCommitId($value) { $this->_validateString('CommitId', $value); @@ -391,18 +374,17 @@ class BuildBase extends Model if ($this->data['commit_id'] === $value) { return; } - $this->data['commit_id'] = $value; - $this->_setModified('commit_id'); } /** - * Set the value of Status / status. - * - * Must not be null. - * @param $value int - */ + * Set the value of Status / status. + * + * Must not be null. + * + * @param $value int + */ public function setStatus($value) { $this->_validateNotNull('Status', $value); @@ -411,17 +393,15 @@ class BuildBase extends Model if ($this->data['status'] === $value) { return; } - $this->data['status'] = $value; - $this->_setModified('status'); } /** - * Set the value of Log / log. - * - * @param $value string - */ + * Set the value of Log / log. + * + * @param $value string + */ public function setLog($value) { $this->_validateString('Log', $value); @@ -429,18 +409,17 @@ class BuildBase extends Model if ($this->data['log'] === $value) { return; } - $this->data['log'] = $value; - $this->_setModified('log'); } /** - * Set the value of Branch / branch. - * - * Must not be null. - * @param $value string - */ + * Set the value of Branch / branch. + * + * Must not be null. + * + * @param $value string + */ public function setBranch($value) { $this->_validateNotNull('Branch', $value); @@ -449,17 +428,15 @@ class BuildBase extends Model if ($this->data['branch'] === $value) { return; } - $this->data['branch'] = $value; - $this->_setModified('branch'); } /** - * Set the value of Created / created. - * - * @param $value \DateTime - */ + * Set the value of Created / created. + * + * @param $value \DateTime + */ public function setCreated($value) { $this->_validateDate('Created', $value); @@ -467,17 +444,15 @@ class BuildBase extends Model if ($this->data['created'] === $value) { return; } - $this->data['created'] = $value; - $this->_setModified('created'); } /** - * Set the value of Started / started. - * - * @param $value \DateTime - */ + * Set the value of Started / started. + * + * @param $value \DateTime + */ public function setStarted($value) { $this->_validateDate('Started', $value); @@ -485,17 +460,15 @@ class BuildBase extends Model if ($this->data['started'] === $value) { return; } - $this->data['started'] = $value; - $this->_setModified('started'); } /** - * Set the value of Finished / finished. - * - * @param $value \DateTime - */ + * Set the value of Finished / finished. + * + * @param $value \DateTime + */ public function setFinished($value) { $this->_validateDate('Finished', $value); @@ -503,17 +476,15 @@ class BuildBase extends Model if ($this->data['finished'] === $value) { return; } - $this->data['finished'] = $value; - $this->_setModified('finished'); } /** - * Set the value of Plugins / plugins. - * - * @param $value string - */ + * Set the value of Plugins / plugins. + * + * @param $value string + */ public function setPlugins($value) { $this->_validateString('Plugins', $value); @@ -521,17 +492,15 @@ class BuildBase extends Model if ($this->data['plugins'] === $value) { return; } - $this->data['plugins'] = $value; - $this->_setModified('plugins'); } /** - * Set the value of CommitterEmail / committer_email. - * - * @param $value string - */ + * Set the value of CommitterEmail / committer_email. + * + * @param $value string + */ public function setCommitterEmail($value) { $this->_validateString('CommitterEmail', $value); @@ -539,17 +508,15 @@ class BuildBase extends Model if ($this->data['committer_email'] === $value) { return; } - $this->data['committer_email'] = $value; - $this->_setModified('committer_email'); } /** - * Set the value of CommitMessage / commit_message. - * - * @param $value string - */ + * Set the value of CommitMessage / commit_message. + * + * @param $value string + */ public function setCommitMessage($value) { $this->_validateString('CommitMessage', $value); @@ -557,9 +524,7 @@ class BuildBase extends Model if ($this->data['commit_message'] === $value) { return; } - $this->data['commit_message'] = $value; - $this->_setModified('commit_message'); } @@ -578,22 +543,21 @@ class BuildBase extends Model return null; } - $cacheKey = 'Cache.Project.' . $key; - $rtn = $this->cache->get($cacheKey, null); + $cacheKey = 'Cache.Project.' . $key; + $rtn = $this->cache->get($cacheKey, null); if (empty($rtn)) { - $rtn = Factory::getStore('Project', 'PHPCI')->getById($key); + $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 - */ + * 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? @@ -611,15 +575,16 @@ class BuildBase extends Model } /** - * Set Project - Accepts a Project model. - * - * @param $value \PHPCI\Model\Project - */ + * Set Project - Accepts a Project model. + * + * @param $value \PHPCI\Model\Project + */ public function setProjectObject(\PHPCI\Model\Project $value) { return $this->setProjectId($value->getId()); } + /** * Get BuildMeta models by BuildId for this Build. * @@ -632,15 +597,11 @@ class BuildBase extends Model return Factory::getStore('BuildMeta', 'PHPCI')->getByBuildId($this->getId()); } - - - public static function getByPrimaryKey($value, $useConnection = 'read') { return Factory::getStore('Build', 'PHPCI')->getByPrimaryKey($value, $useConnection); } - public static function getById($value, $useConnection = 'read') { return Factory::getStore('Build', 'PHPCI')->getById($value, $useConnection); @@ -655,7 +616,4 @@ class BuildBase extends Model { return Factory::getStore('Build', 'PHPCI')->getByStatus($value, $limit, $useConnection); } - - - } diff --git a/PHPCI/Model/Base/BuildMetaBase.php b/PHPCI/Model/Base/BuildMetaBase.php index 83333102..7c360075 100644 --- a/PHPCI/Model/Base/BuildMetaBase.php +++ b/PHPCI/Model/Base/BuildMetaBase.php @@ -15,182 +15,176 @@ use b8\Store\Factory; class BuildMetaBase extends Model { /** - * @var array - */ + * @var array + */ public static $sleepable = array(); /** - * @var string - */ + * @var string + */ protected $tableName = 'build_meta'; /** - * @var string - */ + * @var string + */ protected $modelName = 'BuildMeta'; /** - * @var array - */ + * @var array + */ protected $data = array( - 'id' => null, + 'id' => null, 'project_id' => null, - 'build_id' => null, - 'meta_key' => null, + 'build_id' => null, + 'meta_key' => null, 'meta_value' => null, ); /** - * @var array - */ + * @var array + */ protected $getters = array( // Direct property getters: - 'id' => 'getId', + 'id' => 'getId', 'project_id' => 'getProjectId', - 'build_id' => 'getBuildId', - 'meta_key' => 'getMetaKey', + 'build_id' => 'getBuildId', + 'meta_key' => 'getMetaKey', 'meta_value' => 'getMetaValue', - // Foreign key getters: - 'Build' => 'getBuild', + 'Build' => 'getBuild', ); /** - * @var array - */ + * @var array + */ protected $setters = array( // Direct property setters: - 'id' => 'setId', + 'id' => 'setId', 'project_id' => 'setProjectId', - 'build_id' => 'setBuildId', - 'meta_key' => 'setMetaKey', + 'build_id' => 'setBuildId', + 'meta_key' => 'setMetaKey', 'meta_value' => 'setMetaValue', - // Foreign key setters: - 'Build' => 'setBuild', + 'Build' => 'setBuild', ); /** - * @var array - */ + * @var array + */ public $columns = array( - 'id' => array( - 'type' => 'int', - 'length' => 10, - 'primary_key' => true, + 'id' => array( + 'type' => 'int', + 'length' => 10, + 'primary_key' => true, 'auto_increment' => true, - 'default' => null, + 'default' => null, ), 'project_id' => array( - 'type' => 'int', - 'length' => 11, + 'type' => 'int', + 'length' => 11, 'default' => null, ), - 'build_id' => array( - 'type' => 'int', - 'length' => 11, + 'build_id' => array( + 'type' => 'int', + 'length' => 11, 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'meta_key' => array( - 'type' => 'varchar', - 'length' => 255, + 'meta_key' => array( + 'type' => 'varchar', + 'length' => 255, 'default' => null, ), 'meta_value' => array( - 'type' => 'text', + 'type' => 'text', 'nullable' => true, - 'default' => null, + 'default' => null, ), ); /** - * @var array - */ + * @var array + */ public $indexes = array( - 'PRIMARY' => array('unique' => true, 'columns' => 'id'), - 'idx_meta_id' => array('unique' => true, 'columns' => 'build_id, meta_key'), + 'PRIMARY' => array('unique' => true, 'columns' => 'id'), + 'idx_meta_id' => array('unique' => true, 'columns' => 'build_id, meta_key'), ); /** - * @var array - */ + * @var array + */ public $foreignKeys = array( - 'fk_meta_build_id' => array( - 'local_col' => 'build_id', - 'update' => 'CASCADE', - 'delete' => 'CASCADE', - 'table' => 'build', - 'col' => 'id' - ), + 'fk_meta_build_id' => array( + 'local_col' => 'build_id', + 'update' => 'CASCADE', + 'delete' => 'CASCADE', + 'table' => 'build', + 'col' => 'id' + ), ); /** - * Get the value of Id / id. - * - * @return int - */ + * Get the value of Id / id. + * + * @return int + */ public function getId() { - $rtn = $this->data['id']; - + $rtn = $this->data['id']; return $rtn; } /** - * Get the value of ProjectId / project_id. - * - * @return int - */ + * Get the value of ProjectId / project_id. + * + * @return int + */ public function getProjectId() { - $rtn = $this->data['project_id']; - + $rtn = $this->data['project_id']; return $rtn; } /** - * Get the value of BuildId / build_id. - * - * @return int - */ + * Get the value of BuildId / build_id. + * + * @return int + */ public function getBuildId() { - $rtn = $this->data['build_id']; - + $rtn = $this->data['build_id']; return $rtn; } /** - * Get the value of MetaKey / meta_key. - * - * @return string - */ + * Get the value of MetaKey / meta_key. + * + * @return string + */ public function getMetaKey() { - $rtn = $this->data['meta_key']; - + $rtn = $this->data['meta_key']; return $rtn; } /** - * Get the value of MetaValue / meta_value. - * - * @return string - */ + * Get the value of MetaValue / meta_value. + * + * @return string + */ public function getMetaValue() { - $rtn = $this->data['meta_value']; - + $rtn = $this->data['meta_value']; return $rtn; } /** - * Set the value of Id / id. - * - * Must not be null. - * @param $value int - */ + * Set the value of Id / id. + * + * Must not be null. + * + * @param $value int + */ public function setId($value) { $this->_validateNotNull('Id', $value); @@ -199,18 +193,17 @@ class BuildMetaBase extends Model if ($this->data['id'] === $value) { return; } - $this->data['id'] = $value; - $this->_setModified('id'); } /** - * Set the value of ProjectId / project_id. - * - * Must not be null. - * @param $value int - */ + * Set the value of ProjectId / project_id. + * + * Must not be null. + * + * @param $value int + */ public function setProjectId($value) { $this->_validateNotNull('ProjectId', $value); @@ -219,17 +212,15 @@ class BuildMetaBase extends Model if ($this->data['project_id'] === $value) { return; } - $this->data['project_id'] = $value; - $this->_setModified('project_id'); } /** - * Set the value of BuildId / build_id. - * - * @param $value int - */ + * Set the value of BuildId / build_id. + * + * @param $value int + */ public function setBuildId($value) { $this->_validateInt('BuildId', $value); @@ -237,18 +228,17 @@ class BuildMetaBase extends Model if ($this->data['build_id'] === $value) { return; } - $this->data['build_id'] = $value; - $this->_setModified('build_id'); } /** - * Set the value of MetaKey / meta_key. - * - * Must not be null. - * @param $value string - */ + * Set the value of MetaKey / meta_key. + * + * Must not be null. + * + * @param $value string + */ public function setMetaKey($value) { $this->_validateNotNull('MetaKey', $value); @@ -257,17 +247,15 @@ class BuildMetaBase extends Model if ($this->data['meta_key'] === $value) { return; } - $this->data['meta_key'] = $value; - $this->_setModified('meta_key'); } /** - * Set the value of MetaValue / meta_value. - * - * @param $value string - */ + * Set the value of MetaValue / meta_value. + * + * @param $value string + */ public function setMetaValue($value) { $this->_validateString('MetaValue', $value); @@ -275,9 +263,7 @@ class BuildMetaBase extends Model if ($this->data['meta_value'] === $value) { return; } - $this->data['meta_value'] = $value; - $this->_setModified('meta_value'); } @@ -296,22 +282,21 @@ class BuildMetaBase extends Model return null; } - $cacheKey = 'Cache.Build.' . $key; - $rtn = $this->cache->get($cacheKey, null); + $cacheKey = 'Cache.Build.' . $key; + $rtn = $this->cache->get($cacheKey, null); if (empty($rtn)) { - $rtn = Factory::getStore('Build', 'PHPCI')->getById($key); + $rtn = Factory::getStore('Build', 'PHPCI')->getById($key); $this->cache->set($cacheKey, $rtn); } - return $rtn; } /** - * Set Build - Accepts an ID, an array representing a Build or a Build model. - * - * @param $value mixed - */ + * Set Build - Accepts an ID, an array representing a Build or a Build model. + * + * @param $value mixed + */ public function setBuild($value) { // Is this an instance of Build? @@ -329,24 +314,20 @@ class BuildMetaBase extends Model } /** - * Set Build - Accepts a Build model. - * - * @param $value \PHPCI\Model\Build - */ + * Set Build - Accepts a Build model. + * + * @param $value \PHPCI\Model\Build + */ public function setBuildObject(\PHPCI\Model\Build $value) { return $this->setBuildId($value->getId()); } - - - public static function getByPrimaryKey($value, $useConnection = 'read') { return Factory::getStore('BuildMeta', 'PHPCI')->getByPrimaryKey($value, $useConnection); } - public static function getById($value, $useConnection = 'read') { return Factory::getStore('BuildMeta', 'PHPCI')->getById($value, $useConnection); @@ -356,7 +337,4 @@ class BuildMetaBase extends Model { return Factory::getStore('BuildMeta', 'PHPCI')->getByBuildId($value, $limit, $useConnection); } - - - } diff --git a/PHPCI/Model/Base/ProjectBase.php b/PHPCI/Model/Base/ProjectBase.php index adb9ac5a..b208bfff 100644 --- a/PHPCI/Model/Base/ProjectBase.php +++ b/PHPCI/Model/Base/ProjectBase.php @@ -15,255 +15,244 @@ use b8\Store\Factory; class ProjectBase extends Model { /** - * @var array - */ + * @var array + */ public static $sleepable = array(); /** - * @var string - */ + * @var string + */ protected $tableName = 'project'; /** - * @var string - */ + * @var string + */ protected $modelName = 'Project'; /** - * @var array - */ + * @var array + */ protected $data = array( - 'id' => null, - 'title' => null, - 'reference' => null, - 'git_key' => null, - 'build_config' => null, - 'type' => null, - 'token' => null, + 'id' => null, + 'title' => null, + 'reference' => null, + 'git_key' => null, + 'build_config' => null, + 'type' => null, + 'token' => null, 'access_information' => null, - 'last_commit' => null, + 'last_commit' => null, ); /** - * @var array - */ + * @var array + */ protected $getters = array( // Direct property getters: - 'id' => 'getId', - 'title' => 'getTitle', - 'reference' => 'getReference', - 'git_key' => 'getGitKey', - 'build_config' => 'getBuildConfig', - 'type' => 'getType', - 'token' => 'getToken', + 'id' => 'getId', + 'title' => 'getTitle', + 'reference' => 'getReference', + 'git_key' => 'getGitKey', + 'build_config' => 'getBuildConfig', + 'type' => 'getType', + 'token' => 'getToken', 'access_information' => 'getAccessInformation', - 'last_commit' => 'getLastCommit', - + 'last_commit' => 'getLastCommit', // Foreign key getters: ); /** - * @var array - */ + * @var array + */ protected $setters = array( // Direct property setters: - 'id' => 'setId', - 'title' => 'setTitle', - 'reference' => 'setReference', - 'git_key' => 'setGitKey', - 'build_config' => 'setBuildConfig', - 'type' => 'setType', - 'token' => 'setToken', + 'id' => 'setId', + 'title' => 'setTitle', + 'reference' => 'setReference', + 'git_key' => 'setGitKey', + 'build_config' => 'setBuildConfig', + 'type' => 'setType', + 'token' => 'setToken', 'access_information' => 'setAccessInformation', - 'last_commit' => 'setLastCommit', - + 'last_commit' => 'setLastCommit', // Foreign key setters: ); /** - * @var array - */ + * @var array + */ public $columns = array( - 'id' => array( - 'type' => 'int', - 'length' => 11, - 'primary_key' => true, + 'id' => array( + 'type' => 'int', + 'length' => 11, + 'primary_key' => true, 'auto_increment' => true, + 'default' => null, + ), + 'title' => array( + 'type' => 'varchar', + 'length' => 250, 'default' => null, ), - 'title' => array( - 'type' => 'varchar', - 'length' => 250, + 'reference' => array( + 'type' => 'varchar', + 'length' => 250, 'default' => null, ), - 'reference' => array( - 'type' => 'varchar', - 'length' => 250, - 'default' => null, - ), - 'git_key' => array( - 'type' => 'text', + 'git_key' => array( + 'type' => 'text', 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'build_config' => array( - 'type' => 'text', + 'build_config' => array( + 'type' => 'text', 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'type' => array( - 'type' => 'varchar', - 'length' => 50, + 'type' => array( + 'type' => 'varchar', + 'length' => 50, 'default' => 1, ), - 'token' => array( - 'type' => 'varchar', - 'length' => 50, + 'token' => array( + 'type' => 'varchar', + 'length' => 50, 'nullable' => true, - 'default' => null, + 'default' => null, ), 'access_information' => array( - 'type' => 'varchar', - 'length' => 250, + 'type' => 'varchar', + 'length' => 250, 'nullable' => true, - 'default' => null, + 'default' => null, ), - 'last_commit' => array( - 'type' => 'varchar', - 'length' => 250, + 'last_commit' => array( + 'type' => 'varchar', + 'length' => 250, 'nullable' => true, - 'default' => null, + 'default' => null, ), ); /** - * @var array - */ + * @var array + */ public $indexes = array( - 'PRIMARY' => array('unique' => true, 'columns' => 'id'), + 'PRIMARY' => array('unique' => true, 'columns' => 'id'), 'idx_project_title' => array('columns' => 'title'), ); /** - * @var array - */ - public $foreignKeys = array( - ); + * @var array + */ + public $foreignKeys = array(); /** - * Get the value of Id / id. - * - * @return int - */ + * Get the value of Id / id. + * + * @return int + */ public function getId() { $rtn = $this->data['id']; - return $rtn; } /** - * Get the value of Title / title. - * - * @return string - */ + * Get the value of Title / title. + * + * @return string + */ public function getTitle() { $rtn = $this->data['title']; - return $rtn; } /** - * Get the value of Reference / reference. - * - * @return string - */ + * Get the value of Reference / reference. + * + * @return string + */ public function getReference() { $rtn = $this->data['reference']; - return $rtn; } /** - * Get the value of GitKey / git_key. - * - * @return string - */ + * Get the value of GitKey / git_key. + * + * @return string + */ public function getGitKey() { $rtn = $this->data['git_key']; - return $rtn; } /** - * Get the value of BuildConfig / build_config. - * - * @return string - */ + * Get the value of BuildConfig / build_config. + * + * @return string + */ public function getBuildConfig() { $rtn = $this->data['build_config']; - return $rtn; } /** - * Get the value of Type / type. - * - * @return string - */ + * Get the value of Type / type. + * + * @return string + */ public function getType() { $rtn = $this->data['type']; - return $rtn; } /** - * Get the value of Token / token. - * - * @return string - */ + * Get the value of Token / token. + * + * @return string + */ public function getToken() { $rtn = $this->data['token']; - return $rtn; } /** - * Get the value of AccessInformation / access_information. - * - * @return string - */ + * Get the value of AccessInformation / access_information. + * + * @return string + */ public function getAccessInformation() { $rtn = $this->data['access_information']; - return $rtn; } /** - * Get the value of LastCommit / last_commit. - * - * @return string - */ + * Get the value of LastCommit / last_commit. + * + * @return string + */ public function getLastCommit() { $rtn = $this->data['last_commit']; - return $rtn; } /** - * Set the value of Id / id. - * - * Must not be null. - * @param $value int - */ + * Set the value of Id / id. + * + * Must not be null. + * + * @param $value int + */ public function setId($value) { $this->_validateNotNull('Id', $value); @@ -272,18 +261,17 @@ class ProjectBase extends Model if ($this->data['id'] === $value) { return; } - $this->data['id'] = $value; - $this->_setModified('id'); } /** - * Set the value of Title / title. - * - * Must not be null. - * @param $value string - */ + * Set the value of Title / title. + * + * Must not be null. + * + * @param $value string + */ public function setTitle($value) { $this->_validateNotNull('Title', $value); @@ -292,18 +280,17 @@ class ProjectBase extends Model if ($this->data['title'] === $value) { return; } - $this->data['title'] = $value; - $this->_setModified('title'); } /** - * Set the value of Reference / reference. - * - * Must not be null. - * @param $value string - */ + * Set the value of Reference / reference. + * + * Must not be null. + * + * @param $value string + */ public function setReference($value) { $this->_validateNotNull('Reference', $value); @@ -312,17 +299,15 @@ class ProjectBase extends Model if ($this->data['reference'] === $value) { return; } - $this->data['reference'] = $value; - $this->_setModified('reference'); } /** - * Set the value of GitKey / git_key. - * - * @param $value string - */ + * Set the value of GitKey / git_key. + * + * @param $value string + */ public function setGitKey($value) { $this->_validateString('GitKey', $value); @@ -330,17 +315,15 @@ class ProjectBase extends Model if ($this->data['git_key'] === $value) { return; } - $this->data['git_key'] = $value; - $this->_setModified('git_key'); } /** - * Set the value of BuildConfig / build_config. - * - * @param $value string - */ + * Set the value of BuildConfig / build_config. + * + * @param $value string + */ public function setBuildConfig($value) { $this->_validateString('BuildConfig', $value); @@ -348,18 +331,17 @@ class ProjectBase extends Model if ($this->data['build_config'] === $value) { return; } - $this->data['build_config'] = $value; - $this->_setModified('build_config'); } /** - * Set the value of Type / type. - * - * Must not be null. - * @param $value string - */ + * Set the value of Type / type. + * + * Must not be null. + * + * @param $value string + */ public function setType($value) { $this->_validateNotNull('Type', $value); @@ -368,17 +350,16 @@ class ProjectBase extends Model if ($this->data['type'] === $value) { return; } - $this->data['type'] = $value; - $this->_setModified('type'); } + /** - * Set the value of Token / token. - * - * @param $value string - */ + * Set the value of Token / token. + * + * @param $value string + */ public function setToken($value) { $this->_validateString('Token', $value); @@ -386,17 +367,15 @@ class ProjectBase extends Model if ($this->data['token'] === $value) { return; } - $this->data['token'] = $value; - $this->_setModified('token'); } /** - * Set the value of AccessInformation / access_information. - * - * @param $value string - */ + * Set the value of AccessInformation / access_information. + * + * @param $value string + */ public function setAccessInformation($value) { $this->_validateString('AccessInformation', $value); @@ -404,17 +383,15 @@ class ProjectBase extends Model if ($this->data['access_information'] === $value) { return; } - $this->data['access_information'] = $value; - $this->_setModified('access_information'); } /** - * Set the value of LastCommit / last_commit. - * - * @param $value string - */ + * Set the value of LastCommit / last_commit. + * + * @param $value string + */ public function setLastCommit($value) { $this->_validateString('LastCommit', $value); @@ -422,9 +399,7 @@ class ProjectBase extends Model if ($this->data['last_commit'] === $value) { return; } - $this->data['last_commit'] = $value; - $this->_setModified('last_commit'); } @@ -440,15 +415,11 @@ class ProjectBase extends Model return Factory::getStore('Build', 'PHPCI')->getByProjectId($this->getId()); } - - - public static function getByPrimaryKey($value, $useConnection = 'read') { return Factory::getStore('Project', 'PHPCI')->getByPrimaryKey($value, $useConnection); } - public static function getById($value, $useConnection = 'read') { return Factory::getStore('Project', 'PHPCI')->getById($value, $useConnection); @@ -458,7 +429,4 @@ class ProjectBase extends Model { return Factory::getStore('Project', 'PHPCI')->getByTitle($value, $limit, $useConnection); } - - - } diff --git a/PHPCI/Model/Base/UserBase.php b/PHPCI/Model/Base/UserBase.php index f0b0e393..055eacce 100644 --- a/PHPCI/Model/Base/UserBase.php +++ b/PHPCI/Model/Base/UserBase.php @@ -15,173 +15,168 @@ use b8\Store\Factory; class UserBase extends Model { /** - * @var array - */ + * @var array + */ public static $sleepable = array(); /** - * @var string - */ + * @var string + */ protected $tableName = 'user'; /** - * @var string - */ + * @var string + */ protected $modelName = 'User'; /** - * @var array - */ + * @var array + */ protected $data = array( - 'id' => null, - 'email' => null, - 'hash' => null, + + 'id' => null, + 'email' => null, + 'hash' => null, 'is_admin' => null, - 'name' => null, + 'name' => null, + ); /** - * @var array - */ + * @var array + */ protected $getters = array( // Direct property getters: - 'id' => 'getId', - 'email' => 'getEmail', - 'hash' => 'getHash', + 'id' => 'getId', + 'email' => 'getEmail', + 'hash' => 'getHash', 'is_admin' => 'getIsAdmin', - 'name' => 'getName', - + 'name' => 'getName', // Foreign key getters: ); /** - * @var array - */ + * @var array + */ protected $setters = array( // Direct property setters: - 'id' => 'setId', - 'email' => 'setEmail', - 'hash' => 'setHash', + 'id' => 'setId', + 'email' => 'setEmail', + 'hash' => 'setHash', 'is_admin' => 'setIsAdmin', - 'name' => 'setName', - + 'name' => 'setName', // Foreign key setters: ); /** - * @var array - */ + * @var array + */ public $columns = array( - 'id' => array( - 'type' => 'int', - 'length' => 11, - 'primary_key' => true, + 'id' => array( + 'type' => 'int', + 'length' => 11, + 'primary_key' => true, 'auto_increment' => true, + 'default' => null, + ), + 'email' => array( + 'type' => 'varchar', + 'length' => 250, 'default' => null, ), - 'email' => array( - 'type' => 'varchar', - 'length' => 250, - 'default' => null, - ), - 'hash' => array( - 'type' => 'varchar', - 'length' => 250, + 'hash' => array( + 'type' => 'varchar', + 'length' => 250, 'default' => null, ), 'is_admin' => array( - 'type' => 'tinyint', - 'length' => 1, + 'type' => 'tinyint', + 'length' => 1, 'default' => null, ), - 'name' => array( - 'type' => 'varchar', - 'length' => 250, + 'name' => array( + 'type' => 'varchar', + 'length' => 250, 'nullable' => true, - 'default' => null, + 'default' => null, ), ); /** - * @var array - */ + * @var array + */ public $indexes = array( - 'PRIMARY' => array('unique' => true, 'columns' => 'id'), - 'idx_email' => array('unique' => true, 'columns' => 'email'), + 'PRIMARY' => array('unique' => true, 'columns' => 'id'), + 'idx_email' => array('unique' => true, 'columns' => 'email'), ); /** - * @var array - */ - public $foreignKeys = array( - ); + * @var array + */ + public $foreignKeys = array(); /** - * Get the value of Id / id. - * - * @return int - */ + * Get the value of Id / id. + * + * @return int + */ public function getId() { - $rtn = $this->data['id']; - + $rtn = $this->data['id']; return $rtn; } /** - * Get the value of Email / email. - * - * @return string - */ + * Get the value of Email / email. + * + * @return string + */ public function getEmail() { - $rtn = $this->data['email']; - + $rtn = $this->data['email']; return $rtn; } /** - * Get the value of Hash / hash. - * - * @return string - */ + * Get the value of Hash / hash. + * + * @return string + */ public function getHash() { - $rtn = $this->data['hash']; - + $rtn = $this->data['hash']; return $rtn; } /** - * Get the value of IsAdmin / is_admin. - * - * @return int - */ + * Get the value of IsAdmin / is_admin. + * + * @return int + */ public function getIsAdmin() { - $rtn = $this->data['is_admin']; - + $rtn = $this->data['is_admin']; return $rtn; } /** - * Get the value of Name / name. - * - * @return string - */ + * Get the value of Name / name. + * + * @return string + */ public function getName() { - $rtn = $this->data['name']; - + $rtn = $this->data['name']; return $rtn; } /** - * Set the value of Id / id. - * - * Must not be null. - * @param $value int - */ + * Set the value of Id / id. + * + * Must not be null. + * + * @param $value int + */ public function setId($value) { $this->_validateNotNull('Id', $value); @@ -190,18 +185,17 @@ class UserBase extends Model if ($this->data['id'] === $value) { return; } - $this->data['id'] = $value; - $this->_setModified('id'); } /** - * Set the value of Email / email. - * - * Must not be null. - * @param $value string - */ + * Set the value of Email / email. + * + * Must not be null. + * + * @param $value string + */ public function setEmail($value) { $this->_validateNotNull('Email', $value); @@ -210,18 +204,17 @@ class UserBase extends Model if ($this->data['email'] === $value) { return; } - $this->data['email'] = $value; - $this->_setModified('email'); } /** - * Set the value of Hash / hash. - * - * Must not be null. - * @param $value string - */ + * Set the value of Hash / hash. + * + * Must not be null. + * + * @param $value string + */ public function setHash($value) { $this->_validateNotNull('Hash', $value); @@ -230,18 +223,17 @@ class UserBase extends Model if ($this->data['hash'] === $value) { return; } - $this->data['hash'] = $value; - $this->_setModified('hash'); } /** - * Set the value of IsAdmin / is_admin. - * - * Must not be null. - * @param $value int - */ + * Set the value of IsAdmin / is_admin. + * + * Must not be null. + * + * @param $value int + */ public function setIsAdmin($value) { $this->_validateNotNull('IsAdmin', $value); @@ -250,17 +242,15 @@ class UserBase extends Model if ($this->data['is_admin'] === $value) { return; } - $this->data['is_admin'] = $value; - $this->_setModified('is_admin'); } /** - * Set the value of Name / name. - * - * @param $value string - */ + * Set the value of Name / name. + * + * @param $value string + */ public function setName($value) { $this->_validateString('Name', $value); @@ -268,21 +258,15 @@ class UserBase extends Model if ($this->data['name'] === $value) { return; } - $this->data['name'] = $value; - $this->_setModified('name'); } - - - public static function getByPrimaryKey($value, $useConnection = 'read') { return Factory::getStore('User', 'PHPCI')->getByPrimaryKey($value, $useConnection); } - public static function getById($value, $useConnection = 'read') { return Factory::getStore('User', 'PHPCI')->getById($value, $useConnection); @@ -292,7 +276,4 @@ class UserBase extends Model { return Factory::getStore('User', 'PHPCI')->getByEmail($value, $useConnection); } - - - } diff --git a/PHPCI/Store/Base/BuildMetaStoreBase.php b/PHPCI/Store/Base/BuildMetaStoreBase.php index 4abd97a3..1be8292a 100644 --- a/PHPCI/Store/Base/BuildMetaStoreBase.php +++ b/PHPCI/Store/Base/BuildMetaStoreBase.php @@ -16,9 +16,11 @@ use PHPCI\Model\BuildMeta; */ class BuildMetaStoreBase extends Store { - protected $tableName = 'build_meta'; - protected $modelName = '\PHPCI\Model\BuildMeta'; - protected $primaryKey = 'id'; + protected $tableName = 'build_meta'; + + protected $modelName = '\PHPCI\Model\BuildMeta'; + + protected $primaryKey = 'id'; public function getByPrimaryKey($value, $useConnection = 'read') { @@ -32,7 +34,7 @@ class BuildMetaStoreBase extends Store } $query = 'SELECT * FROM `build_meta` WHERE `id` = :id LIMIT 1'; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':id', $value); if ($stmt->execute()) { @@ -40,7 +42,6 @@ class BuildMetaStoreBase extends Store return new BuildMeta($data); } } - return null; } @@ -51,15 +52,13 @@ class BuildMetaStoreBase extends Store } $add = ''; - if ($limit) { $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `build_meta` WHERE `build_id` = :build_id' . $add; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':build_id', $value); if ($stmt->execute()) { diff --git a/PHPCI/Store/Base/BuildStoreBase.php b/PHPCI/Store/Base/BuildStoreBase.php index b67d5f73..4b797375 100644 --- a/PHPCI/Store/Base/BuildStoreBase.php +++ b/PHPCI/Store/Base/BuildStoreBase.php @@ -16,9 +16,11 @@ use PHPCI\Model\Build; */ class BuildStoreBase extends Store { - protected $tableName = 'build'; - protected $modelName = '\PHPCI\Model\Build'; - protected $primaryKey = 'id'; + protected $tableName = 'build'; + + protected $modelName = '\PHPCI\Model\Build'; + + protected $primaryKey = 'id'; public function getByPrimaryKey($value, $useConnection = 'read') { @@ -32,7 +34,7 @@ class BuildStoreBase extends Store } $query = 'SELECT * FROM `build` WHERE `id` = :id LIMIT 1'; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':id', $value); if ($stmt->execute()) { @@ -40,7 +42,6 @@ class BuildStoreBase extends Store return new Build($data); } } - return null; } @@ -51,15 +52,13 @@ class BuildStoreBase extends Store } $add = ''; - if ($limit) { $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `build` WHERE `project_id` = :project_id' . $add; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':project_id', $value); if ($stmt->execute()) { @@ -83,15 +82,13 @@ class BuildStoreBase extends Store } $add = ''; - if ($limit) { $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `build` WHERE `status` = :status' . $add; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':status', $value); if ($stmt->execute()) { diff --git a/PHPCI/Store/Base/ProjectStoreBase.php b/PHPCI/Store/Base/ProjectStoreBase.php index 410a305e..808f83c9 100644 --- a/PHPCI/Store/Base/ProjectStoreBase.php +++ b/PHPCI/Store/Base/ProjectStoreBase.php @@ -16,9 +16,11 @@ use PHPCI\Model\Project; */ class ProjectStoreBase extends Store { - protected $tableName = 'project'; - protected $modelName = '\PHPCI\Model\Project'; - protected $primaryKey = 'id'; + protected $tableName = 'project'; + + protected $modelName = '\PHPCI\Model\Project'; + + protected $primaryKey = 'id'; public function getByPrimaryKey($value, $useConnection = 'read') { @@ -32,7 +34,7 @@ class ProjectStoreBase extends Store } $query = 'SELECT * FROM `project` WHERE `id` = :id LIMIT 1'; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':id', $value); if ($stmt->execute()) { @@ -40,7 +42,6 @@ class ProjectStoreBase extends Store return new Project($data); } } - return null; } @@ -51,15 +52,13 @@ class ProjectStoreBase extends Store } $add = ''; - if ($limit) { $add .= ' LIMIT ' . $limit; } - $count = null; $query = 'SELECT * FROM `project` WHERE `title` = :title' . $add; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':title', $value); if ($stmt->execute()) { diff --git a/PHPCI/Store/Base/UserStoreBase.php b/PHPCI/Store/Base/UserStoreBase.php index fd903d8e..cafebea3 100644 --- a/PHPCI/Store/Base/UserStoreBase.php +++ b/PHPCI/Store/Base/UserStoreBase.php @@ -16,9 +16,11 @@ use PHPCI\Model\User; */ class UserStoreBase extends Store { - protected $tableName = 'user'; - protected $modelName = '\PHPCI\Model\User'; - protected $primaryKey = 'id'; + protected $tableName = 'user'; + + protected $modelName = '\PHPCI\Model\User'; + + protected $primaryKey = 'id'; public function getByPrimaryKey($value, $useConnection = 'read') { @@ -32,7 +34,7 @@ class UserStoreBase extends Store } $query = 'SELECT * FROM `user` WHERE `id` = :id LIMIT 1'; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':id', $value); if ($stmt->execute()) { @@ -40,7 +42,6 @@ class UserStoreBase extends Store return new User($data); } } - return null; } @@ -51,7 +52,7 @@ class UserStoreBase extends Store } $query = 'SELECT * FROM `user` WHERE `email` = :email LIMIT 1'; - $stmt = Database::getConnection($useConnection)->prepare($query); + $stmt = Database::getConnection($useConnection)->prepare($query); $stmt->bindValue(':email', $value); if ($stmt->execute()) { @@ -59,7 +60,6 @@ class UserStoreBase extends Store return new User($data); } } - return null; } } From 7e2aef058fcfbc16f269f814a6906144589a5aef Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Sat, 12 Apr 2014 00:11:46 +0200 Subject: [PATCH 039/119] fix #334: fix flickering of quality trend graph; fix hidden data points for single errors / warnings --- public/assets/js/build-plugins/loc.js | 15 +++--- public/assets/js/build-plugins/warnings.js | 61 ++++++++++------------ 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/public/assets/js/build-plugins/loc.js b/public/assets/js/build-plugins/loc.js index aa75c073..df0b4ce6 100644 --- a/public/assets/js/build-plugins/loc.js +++ b/public/assets/js/build-plugins/loc.js @@ -36,25 +36,26 @@ var locPlugin = PHPCI.UiPlugin.extend({ }, displayChart: function() { - var build = this.lastData; + var builds = this.lastData; - if (!build || !build.length) { + if (!builds || !builds.length) { return; } $('#phploc-lines').empty().animate({height: '275px'}); - var data = [["Build", "Lines", "Comment Lines", "Non-Comment Lines", "Logical Lines"]]; - for (var idx in build) { - data.push(['Build ' + build[idx].build_id, parseInt(build[idx].meta_value.LOC), parseInt(build[idx].meta_value.CLOC), parseInt(build[idx].meta_value.NCLOC), parseInt(build[idx].meta_value.LLOC)]); + var titles = ['Build', 'Lines', 'Comment Lines', 'Non-Comment Lines', 'Logical Lines']; + var data = [titles]; + for (var i in builds) { + data.push(['Build ' + builds[i].build_id, parseInt(builds[i].meta_value.LOC), parseInt(builds[i].meta_value.CLOC), parseInt(builds[i].meta_value.NCLOC), parseInt(builds[i].meta_value.LLOC)]); } var data = google.visualization.arrayToDataTable(data); - var options = { hAxis: {title: 'Builds'}, vAxis: {title: 'Lines'}, - backgroundColor: { fill: 'transparent' } + backgroundColor: { fill: 'transparent' }, + height: 275 }; var chart = new google.visualization.LineChart(document.getElementById('phploc-lines')); diff --git a/public/assets/js/build-plugins/warnings.js b/public/assets/js/build-plugins/warnings.js index c485dd4e..6bd371a1 100644 --- a/public/assets/js/build-plugins/warnings.js +++ b/public/assets/js/build-plugins/warnings.js @@ -1,17 +1,23 @@ -var plugin = PHPCI.UiPlugin.extend({ +var warningsPlugin = PHPCI.UiPlugin.extend({ id: 'build-warnings-chart', css: 'col-lg-6 col-md-6 col-sm-12 col-xs-12', title: 'Quality Trend', + keys: { + 'phpmd-warnings': 'PHPMD Warnings', + 'phpcs-warnings': 'PHPCS Warnings', + 'phpcs-errors': 'PHPCS Errors', + 'phplint-errors': 'PHPLint Errors' + }, data: {}, - keys: null, displayOnUpdate: false, register: function() { var self = this; - var query1 = PHPCI.registerQuery('phpmd-warnings', -1, {num_builds: 10, key: 'phpmd-warnings'}) - var query2 = PHPCI.registerQuery('phpcs-warnings', -1, {num_builds: 10, key: 'phpcs-warnings'}) - var query3 = PHPCI.registerQuery('phpcs-errors', -1, {num_builds: 10, key: 'phpcs-errors'}) - var query4 = PHPCI.registerQuery('phplint-errors', -1, {num_builds: 10, key: 'phplint-errors'}) + + var queries = []; + for (var key in self.keys) { + queries.push(PHPCI.registerQuery(key, -1, {num_builds: 10, key: key})); + } $(window).on('phpmd-warnings phpcs-warnings phpcs-errors phplint-errors', function(data) { self.onUpdate(data); @@ -20,10 +26,9 @@ var plugin = PHPCI.UiPlugin.extend({ $(window).on('build-updated', function(data) { if (data.queryData.status > 1) { self.displayOnUpdate = true; - query1(); - query2(); - query3(); - query4(); + for (var query in queries) { + queries[query](); + } } }); @@ -36,23 +41,22 @@ var plugin = PHPCI.UiPlugin.extend({ onUpdate: function(e) { var self = this; - var build = e.queryData; + var builds = e.queryData; - if (!build || !build.length) { + if (!builds || !builds.length) { return; } - for (var i in build) { - var buildId = build[i]['build_id']; - var metaKey = build[i]['meta_key']; - var metaVal = build[i]['meta_value']; + for (var i in builds) { + var buildId = builds[i]['build_id']; + var metaKey = builds[i]['meta_key']; + var metaVal = builds[i]['meta_value']; if (!self.data[buildId]) { self.data[buildId] = {}; } self.data[buildId][metaKey] = metaVal; - self.keys = Object.keys(self.data[buildId]); } if (self.displayOnUpdate) { @@ -66,25 +70,16 @@ var plugin = PHPCI.UiPlugin.extend({ $('#build-warnings').empty().animate({height: '275px'}); var titles = ['Build']; - var keys = self.keys; - - for (var i in keys) { - var t = { - 'phpmd-warnings': 'PHPMD Warnings', - 'phpcs-warnings': 'PHPCS Warnings', - 'phpcs-errors': 'PHPCS Errors', - 'phplint-errors': 'PHPLint Errors' - }; - titles.push(t[keys[i]]); + for (var key in self.keys) { + titles.push(self.keys[key]); } var data = [titles]; - for (var build in self.data) { var thisBuild = ['#' + build]; - for (var i in keys) { - thisBuild.push(parseInt(self.data[build][keys[i]])); + for (var key in self.keys) { + thisBuild.push(parseInt(self.data[build][key])); } data.push(thisBuild); @@ -94,7 +89,9 @@ var plugin = PHPCI.UiPlugin.extend({ var options = { hAxis: {title: 'Build'}, vAxis: {title: 'Warnings'}, - backgroundColor: { fill: 'transparent' } + backgroundColor: { fill: 'transparent' }, + height: 275, + pointSize: 3 }; var chart = new google.visualization.LineChart(document.getElementById('build-warnings')); @@ -102,4 +99,4 @@ var plugin = PHPCI.UiPlugin.extend({ } }); -PHPCI.registerPlugin(new plugin()); \ No newline at end of file +PHPCI.registerPlugin(new warningsPlugin()); From 187d6898088a26c78ea27f2da9c6d6bf430dabed Mon Sep 17 00:00:00 2001 From: Claus Due Date: Sat, 12 Apr 2014 02:44:27 +0200 Subject: [PATCH 040/119] Bad copy/pasted method comment in CopyBuild plugin --- PHPCI/Plugin/CopyBuild.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Plugin/CopyBuild.php b/PHPCI/Plugin/CopyBuild.php index 494a0d3f..4449d16c 100644 --- a/PHPCI/Plugin/CopyBuild.php +++ b/PHPCI/Plugin/CopyBuild.php @@ -32,7 +32,7 @@ class CopyBuild implements \PHPCI\Plugin } /** - * Executes Composer and runs a specified command (e.g. install / update) + * Copies files from the root of the build directory into the target folder */ public function execute() { From 402e576cadf1b258a77169a0796d9ac61749ec7b Mon Sep 17 00:00:00 2001 From: Claus Due Date: Sat, 12 Apr 2014 13:50:10 +0200 Subject: [PATCH 041/119] Missing property declaration for `ignore` on Plugin.CopyBuild --- PHPCI/Plugin/CopyBuild.php | 1 + 1 file changed, 1 insertion(+) diff --git a/PHPCI/Plugin/CopyBuild.php b/PHPCI/Plugin/CopyBuild.php index 494a0d3f..f9151004 100644 --- a/PHPCI/Plugin/CopyBuild.php +++ b/PHPCI/Plugin/CopyBuild.php @@ -21,6 +21,7 @@ use PHPCI\Model\Build; class CopyBuild implements \PHPCI\Plugin { protected $directory; + protected $ignore; protected $phpci; public function __construct(Builder $phpci, Build $build, array $options = array()) From 9cb63dbe0651600f796a0965b7a1c62f62a78e73 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Sat, 12 Apr 2014 14:31:31 +0200 Subject: [PATCH 042/119] Wipe Plugin - wipes a folder --- PHPCI/Plugin/Wipe.php | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 PHPCI/Plugin/Wipe.php diff --git a/PHPCI/Plugin/Wipe.php b/PHPCI/Plugin/Wipe.php new file mode 100644 index 00000000..3efd8a44 --- /dev/null +++ b/PHPCI/Plugin/Wipe.php @@ -0,0 +1,49 @@ + +* @package PHPCI +* @subpackage Plugins +*/ +class Wipe implements \PHPCI\Plugin +{ + protected $directory; + protected $phpci; + + public function __construct(Builder $phpci, Build $build, array $options = array()) + { + $path = $phpci->buildPath; + $this->phpci = $phpci; + $this->directory = isset($options['directory']) ? $options['directory'] : $path; + } + + /** + * Wipes a directory's contents + */ + public function execute() + { + $build = $this->phpci->buildPath; + + if ($this->directory == $build || empty($this->directory)) { + return true; + } + if (is_dir($this->directory)) { + $cmd = 'rm -rf %s*'; + $success = $this->phpci->executeCommand($cmd, $this->directory); + } + return $success; + } +} From 34ea46e1395ccfa73e273aa971440594adcf7a36 Mon Sep 17 00:00:00 2001 From: Claus Due Date: Sat, 12 Apr 2014 17:28:52 +0200 Subject: [PATCH 043/119] Preserve absolute paths in Plugin.PhpMessDetector Before: all paths, including absolute paths, were treated relative to build directory. After: any absolute path is not prefixed with the build directory path; it gets used as-is. --- PHPCI/Plugin/PhpMessDetector.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/PHPCI/Plugin/PhpMessDetector.php b/PHPCI/Plugin/PhpMessDetector.php index 89c22f66..c634c238 100755 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -32,7 +32,8 @@ class PhpMessDetector implements \PHPCI\Plugin /** * @var string, based on the assumption the root may not hold the code to be - * tested, exteds the base path + * tested, exteds the base path only if the provided path is relative. Absolute + * paths are used verbatim */ protected $path; @@ -97,11 +98,16 @@ class PhpMessDetector implements \PHPCI\Plugin $this->phpci->logFailure('Could not find phpmd.'); return false; } + + $path = $this->phpci->buildPath . $this->path; + if ($this->path{0} == '/') { + $path = $this->path; + } $cmd = $phpmd . ' "%s" text %s %s %s'; $success = $this->phpci->executeCommand( $cmd, - $this->phpci->buildPath . $this->path, + $path, implode(',', $this->rules), $ignore, $suffixes From 0bf7698cac0cd9fb9ced6069e6417a4ab0c77afd Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 08:57:17 +0100 Subject: [PATCH 044/119] Check $this->path is set before use, fixes #355 --- PHPCI/Plugin/PhpMessDetector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Plugin/PhpMessDetector.php b/PHPCI/Plugin/PhpMessDetector.php index c634c238..c5e56e4e 100755 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -100,7 +100,7 @@ class PhpMessDetector implements \PHPCI\Plugin } $path = $this->phpci->buildPath . $this->path; - if ($this->path{0} == '/') { + if (!empty($this->path) && $this->path{0} == '/') { $path = $this->path; } From 6513454265720b5a911271c70cfc7c36000abeca Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 09:05:46 +0100 Subject: [PATCH 045/119] Adding global try/catch in Builder, in hope of fixing forever-hanging. Closes #354, Closes #304 --- PHPCI/Builder.php | 66 ++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index b7b8c77e..04c5c48e 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -188,41 +188,47 @@ class Builder implements LoggerAwareInterface $this->build->sendStatusPostback(); $this->success = true; - // Set up the build: - $this->setupBuild(); + try { + // Set up the build: + $this->setupBuild(); - // Run the core plugin stages: - foreach (array('setup', 'test') as $stage) { - $this->success &= $this->pluginExecutor->executePlugins($this->config, $stage); - } + // Run the core plugin stages: + foreach (array('setup', 'test') as $stage) { + $this->success &= $this->pluginExecutor->executePlugins($this->config, $stage); + } - // Set the status so this can be used by complete, success and failure - // stages. - if ($this->success) { - $this->build->setStatus(Build::STATUS_SUCCESS); - } else { + // Set the status so this can be used by complete, success and failure + // stages. + if ($this->success) { + $this->build->setStatus(Build::STATUS_SUCCESS); + } else { + $this->build->setStatus(Build::STATUS_FAILED); + } + + // Complete stage plugins are always run + $this->pluginExecutor->executePlugins($this->config, 'complete'); + + if ($this->success) { + $this->pluginExecutor->executePlugins($this->config, 'success'); + $this->buildLogger->logSuccess('BUILD SUCCESSFUL!'); + } else { + $this->pluginExecutor->executePlugins($this->config, 'failure'); + $this->buildLogger->logFailure("BUILD FAILURE"); + } + + // Clean up: + $this->buildLogger->log('Removing build.'); + + $cmd = 'rm -Rf "%s"'; + if (IS_WIN) { + $cmd = 'rmdir /S /Q "%s"'; + } + $this->executeCommand($cmd, $this->buildPath); + } catch (\Exception $ex) { $this->build->setStatus(Build::STATUS_FAILED); + $this->buildLogger->logFailure('Exception: ' . $ex->getMessage()); } - // Complete stage plugins are always run - $this->pluginExecutor->executePlugins($this->config, 'complete'); - - if ($this->success) { - $this->pluginExecutor->executePlugins($this->config, 'success'); - $this->buildLogger->logSuccess('BUILD SUCCESSFUL!'); - } else { - $this->pluginExecutor->executePlugins($this->config, 'failure'); - $this->buildLogger->logFailure("BUILD FAILURE"); - } - - // Clean up: - $this->buildLogger->log('Removing build.'); - - $cmd = 'rm -Rf "%s"'; - if (IS_WIN) { - $cmd = 'rmdir /S /Q "%s"'; - } - $this->executeCommand($cmd, $this->buildPath); // Update the build in the database, ping any external services, etc. $this->build->sendStatusPostback(); From 6917e88f9b3f31c4f4448dd92df34928f0bdd034 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 09:05:48 +0100 Subject: [PATCH 046/119] Adding global try/catch in Builder, in hope of fixing forever-hanging. Closes #354, Closes #304 --- PHPCI/Builder.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index 04c5c48e..92b43e9d 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -136,16 +136,22 @@ class Builder implements LoggerAwareInterface /** * Set the config array, as read from phpci.yml - * @param array + * @param array|null $config + * @throws \Exception */ - public function setConfigArray(array $config) + public function setConfigArray($config) { + if (is_null($config) || !is_array($config)) { + throw new \Exception('This project does not contain a phpci.yml file, or it is empty.'); + } + $this->config = $config; } /** * Access a variable from the phpci.yml file. * @param string + * @return mixed */ public function getConfig($key) { From 1bc5f9048cde20a2ae6f3560de6dfe27b62245df Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 09:29:01 +0100 Subject: [PATCH 047/119] Fixes for feedback in #341. --- PHPCI/Command/InstallCommand.php | 47 ++++++++++++-------------------- composer.json | 4 +++ 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index 3b8ca701..e6432103 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -121,36 +121,26 @@ class InstallCommand extends Command $errors = true; } - // Check for required extensions: - if (!extension_loaded('PDO')) { - $output->writeln(''); - $output->writeln('PDO extension must be installed.'); - $errors = true; + // Check required extensions are present: + $requiredExtensions = array('PDO', 'pdo_mysql', 'mcrypt'); + + foreach ($requiredExtensions as $extension) { + if (!extension_loaded($extension)) { + $output->writeln(''); + $output->writeln(''.$extension.' extension must be installed.'); + $errors = true; + } } - if (!extension_loaded('pdo_mysql')) { - $output->writeln(''); - $output->writeln('PDO MySQL extension must be installed.'); - $errors = true; - } + // Check required functions are callable: + $requiredFunctions = array('exec', 'shell_exec'); - if (!extension_loaded('mcrypt')) { - $output->writeln(''); - $output->writeln('Mcrypt extension must be installed.'); - $errors = true; - } - - // Check we can use the exec() and shell_exec() functions: - if (!function_exists('exec')) { - $output->writeln(''); - $output->writeln('PHPCI needs to be able to call the exec() function. Is it disabled in php.ini?'); - $errors = true; - } - - if (!function_exists('shell_exec')) { - $output->writeln(''); - $output->writeln('PHPCI needs to be able to call the shell_exec() function. Is it disabled in php.ini?'); - $errors = true; + foreach ($requiredFunctions as $function) { + if (!function_exists($function)) { + $output->writeln(''); + $output->writeln('PHPCI needs to be able to call the '.$function.'() function. Is it disabled in php.ini?'); + $errors = true; + } } if (!function_exists('password_hash')) { @@ -160,8 +150,7 @@ class InstallCommand extends Command } if ($errors) { - $output->writeln(''); - die; + throw new Exception('PHPCI cannot be installed, as not all requirements are met. Please review the errors above before continuing.'); } $output->writeln(' OK'); diff --git a/composer.json b/composer.json index 7ccbc600..8de9e9eb 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,10 @@ }, "require": { + "php": ">=5.3.3", + "ext-mcrypt": "*", + "ext-pdo": "*", + "ext-pdo_mysql": "*", "block8/b8framework" : "1.*", "ircmaxell/password-compat": "1.*", "swiftmailer/swiftmailer" : "5.0.*", From 1ba1087b5aedf440e0ac79ca42c837c440983299 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 09:48:39 +0100 Subject: [PATCH 048/119] Updating dependencies - Fixes #320, thanks @GrahamCampbell --- composer.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 8de9e9eb..40aada7d 100644 --- a/composer.json +++ b/composer.json @@ -27,19 +27,19 @@ "ext-mcrypt": "*", "ext-pdo": "*", "ext-pdo_mysql": "*", - "block8/b8framework" : "1.*", - "ircmaxell/password-compat": "1.*", - "swiftmailer/swiftmailer" : "5.0.*", - "symfony/yaml" : "2.*", - "symfony/console" : "2.*", - "psr/log": "1.0.0", - "monolog/monolog": "1.6.0", - "pimple/pimple": "1.1.*" + "block8/b8framework" : "~1.1", + "ircmaxell/password-compat": "~1.0", + "swiftmailer/swiftmailer" : "~5.0", + "symfony/yaml" : "~2.1", + "symfony/console" : "~2.1", + "psr/log": "~1.0", + "monolog/monolog": "~1.6", + "pimple/pimple": "~1.1" }, "require-dev": { - "phpunit/phpunit": "3.7.*", - "phpspec/prophecy-phpunit": "1.*" + "phpunit/phpunit": "~3.7", + "phpspec/prophecy-phpunit": "~1.0" }, "suggest": { From 97fd9bea666cfcc81439037661e39568d54377b1 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 09:54:09 +0100 Subject: [PATCH 049/119] Updating composer.lock to reflect new dependency versions --- composer.lock | 195 +++++++++++++------------------------------------- 1 file changed, 50 insertions(+), 145 deletions(-) diff --git a/composer.lock b/composer.lock index f2c730ae..62788338 100644 --- a/composer.lock +++ b/composer.lock @@ -3,20 +3,20 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "07f37de4c8bacd8a1a7b6e14269178d1", + "hash": "0ac85acececb32f472d8aa807ed054e7", "packages": [ { "name": "block8/b8framework", - "version": "1.1.0", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/Block8/b8framework.git", - "reference": "f643e0d3497599016cb62611ceb9288710423121" + "reference": "63a18f2fdc1dc31b657ea39ef841339d89f24ce8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Block8/b8framework/zipball/f643e0d3497599016cb62611ceb9288710423121", - "reference": "f643e0d3497599016cb62611ceb9288710423121", + "url": "https://api.github.com/repos/Block8/b8framework/zipball/63a18f2fdc1dc31b657ea39ef841339d89f24ce8", + "reference": "63a18f2fdc1dc31b657ea39ef841339d89f24ce8", "shasum": "" }, "require": { @@ -50,7 +50,7 @@ "mvc", "php" ], - "time": "2014-02-24 11:25:23" + "time": "2014-04-01 15:30:13" }, { "name": "ircmaxell/password-compat", @@ -93,16 +93,16 @@ }, { "name": "monolog/monolog", - "version": "1.6.0", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd" + "reference": "392ef35fd470638e08d0160d6b1cbab63cb23174" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f72392d0e6eb855118f5a84e89ac2d257c704abd", - "reference": "f72392d0e6eb855118f5a84e89ac2d257c704abd", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/392ef35fd470638e08d0160d6b1cbab63cb23174", + "reference": "392ef35fd470638e08d0160d6b1cbab63cb23174", "shasum": "" }, "require": { @@ -110,26 +110,32 @@ "psr/log": "~1.0" }, "require-dev": { - "doctrine/couchdb": "dev-master", - "mlehner/gelf-php": "1.0.*", - "raven/raven": "0.5.*" + "aws/aws-sdk-php": "~2.4, >2.4.8", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "phpunit/phpunit": "~3.7.0", + "raven/raven": "~0.5", + "ruflin/elastica": "0.90.*" }, "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", "ext-mongo": "Allow sending log messages to a MongoDB server", - "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server", - "raven/raven": "Allow sending log messages to a Sentry server" + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { - "psr-0": { - "Monolog": "src/" + "psr-4": { + "Monolog\\": "src/Monolog" } }, "notification-url": "https://packagist.org/downloads/", @@ -151,7 +157,7 @@ "logging", "psr-3" ], - "time": "2013-07-28 22:38:30" + "time": "2014-03-23 19:50:26" }, { "name": "pimple/pimple", @@ -241,16 +247,16 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v5.0.3", + "version": "v5.1.0", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "32edc3b0de0fdc1b10f5c4912e8677b3f411a230" + "reference": "748c01c1144713ac0118396935d10b6ceec91b68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/32edc3b0de0fdc1b10f5c4912e8677b3f411a230", - "reference": "32edc3b0de0fdc1b10f5c4912e8677b3f411a230", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/748c01c1144713ac0118396935d10b6ceec91b68", + "reference": "748c01c1144713ac0118396935d10b6ceec91b68", "shasum": "" }, "require": { @@ -274,7 +280,9 @@ "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { "name": "Chris Corbyn" @@ -286,21 +294,21 @@ "mail", "mailer" ], - "time": "2013-12-03 13:33:24" + "time": "2014-03-18 09:03:27" }, { "name": "symfony/console", - "version": "v2.4.2", + "version": "v2.4.3", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "940f217cbc3c8a33e5403e7c595495c4884400fe" + "reference": "ef20f1f58d7f693ee888353962bd2db336e3bbcb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/940f217cbc3c8a33e5403e7c595495c4884400fe", - "reference": "940f217cbc3c8a33e5403e7c595495c4884400fe", + "url": "https://api.github.com/repos/symfony/Console/zipball/ef20f1f58d7f693ee888353962bd2db336e3bbcb", + "reference": "ef20f1f58d7f693ee888353962bd2db336e3bbcb", "shasum": "" }, "require": { @@ -341,21 +349,21 @@ ], "description": "Symfony Console Component", "homepage": "http://symfony.com", - "time": "2014-02-11 13:52:09" + "time": "2014-03-01 17:35:04" }, { "name": "symfony/yaml", - "version": "v2.4.2", + "version": "v2.4.3", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "bb6ddaf8956139d1b8c360b4b713ed0138e876b3" + "reference": "77a41c2835ab7cfe8bf6d15e25d3af8f3eb3bacd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/bb6ddaf8956139d1b8c360b4b713ed0138e876b3", - "reference": "bb6ddaf8956139d1b8c360b4b713ed0138e876b3", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/77a41c2835ab7cfe8bf6d15e25d3af8f3eb3bacd", + "reference": "77a41c2835ab7cfe8bf6d15e25d3af8f3eb3bacd", "shasum": "" }, "require": { @@ -390,116 +398,10 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2014-01-07 13:28:54" - } - ], - "packages-dev": [ - { - "name": "phpspec/prophecy", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "976a65af02a2a0e17ce6c949f7b43437205628bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/976a65af02a2a0e17ce6c949f7b43437205628bb", - "reference": "976a65af02a2a0e17ce6c949f7b43437205628bb", - "shasum": "" - }, - "require-dev": { - "phpspec/phpspec": "2.0.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "http://phpspec.org", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2014-01-24 11:03:43" - }, - { - "name": "phpspec/prophecy-phpunit", - "version": "v1.0.0", - "target-dir": "Prophecy/PhpUnit", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy-phpunit.git", - "reference": "ebc983be95b026fcea18afb7870e7b9041dc9d11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/ebc983be95b026fcea18afb7870e7b9041dc9d11", - "reference": "ebc983be95b026fcea18afb7870e7b9041dc9d11", - "shasum": "" - }, - "require": { - "phpspec/prophecy": "~1.0" - }, - "suggest": { - "phpunit/phpunit": "if it is not installed globally" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\PhpUnit\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christophe Coevoet", - "email": "stof@notk.org" - } - ], - "description": "PhpUnit test case integrating the Prophecy mocking library", - "homepage": "http://phpspec.org", - "keywords": [ - "phpunit", - "prophecy" - ], - "time": "2013-07-04 21:27:53" + "time": "2014-03-12 18:29:58" } ], + "packages-dev": null, "aliases": [ ], @@ -507,9 +409,12 @@ "stability-flags": [ ], - "platform": [ - - ], + "platform": { + "php": ">=5.3.3", + "ext-mcrypt": "*", + "ext-pdo": "*", + "ext-pdo_mysql": "*" + }, "platform-dev": [ ] From 257249fadde1885cdbbb631da2cc6284bbd5b630 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 09:15:39 +0000 Subject: [PATCH 050/119] Adding guard around ssh-keygen in project controller, hopefully fixes #340 --- PHPCI/Controller/ProjectController.php | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index cf41aee3..7c336eca 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -160,12 +160,17 @@ class ProjectController extends \PHPCI\Controller mkdir($tempPath); } - shell_exec('ssh-keygen -q -t rsa -b 2048 -f '.$keyFile.' -N "" -C "deploy@phpci"'); + if ($this->canGenerateKeys()) { + shell_exec('ssh-keygen -q -t rsa -b 2048 -f '.$keyFile.' -N "" -C "deploy@phpci"'); - $pub = file_get_contents($keyFile . '.pub'); - $prv = file_get_contents($keyFile); + $pub = file_get_contents($keyFile . '.pub'); + $prv = file_get_contents($keyFile); - $values = array('key' => $prv, 'pubkey' => $pub); + $values = array('key' => $prv, 'pubkey' => $pub); + } else { + $pub = null; + $values = array(); + } } $form = $this->projectForm($values); @@ -325,7 +330,7 @@ class ProjectController extends \PHPCI\Controller $field = new Form\Element\TextArea('build_config'); $field->setRequired(false); - $field->setLabel('PHPCI build config for this project (instead phpci.yml in the project repository)'); + $field->setLabel('PHPCI build config for this project (if you cannot add a phpci.yml file in the project repository)'); $field->setClass('form-control'); $field->setContainerClass('form-group'); $field->setRows(6); @@ -425,4 +430,10 @@ class ProjectController extends \PHPCI\Controller return true; }; } + + protected function canGenerateKeys() + { + $result = @shell_exec('ssh-keygen'); + return !empty($result); + } } From ad38db47bd1efd42f8664105dd460af5d14da00c Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 10:23:04 +0100 Subject: [PATCH 051/119] Updating PHPSpec plugin to work with v2. Fixes #339 --- PHPCI/Plugin/PhpSpec.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/PHPCI/Plugin/PhpSpec.php b/PHPCI/Plugin/PhpSpec.php index afd36699..02aebba7 100644 --- a/PHPCI/Plugin/PhpSpec.php +++ b/PHPCI/Plugin/PhpSpec.php @@ -21,15 +21,10 @@ use PHPCI\Model\Build; class PhpSpec implements \PHPCI\Plugin { protected $phpci; - protected $bootstrap; public function __construct(Builder $phpci, Build $build, array $options = array()) { $this->phpci = $phpci; - - if (!empty($options['bootstrap'])) { - $this->bootstrap = $this->buildPath . $options['bootstrap']; - } } /** @@ -47,11 +42,7 @@ class PhpSpec implements \PHPCI\Plugin return false; } - if ($this->bootstrap) { - $success = $this->phpci->executeCommand($phpspec . ' -f d'); - } else { - $success = $this->phpci->executeCommand($phpspec . ' -f d --bootstrap "%s"', $this->bootstrap); - } + $success = $this->phpci->executeCommand($phpspec . ' --format=pretty --no-code-generation'); chdir($curdir); From 886d79946d4438ffb736a445d084119c8a61008a Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 10:14:06 +0000 Subject: [PATCH 052/119] Fixing issues when adding a gitlab project --- PHPCI/Controller/ProjectController.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 7c336eca..95f8c2cd 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -189,11 +189,21 @@ class ProjectController extends \PHPCI\Controller if ($values['type'] == "gitlab") { preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches); + $info = array(); - $info["user"] = $matches[1]; - $info["domain"] = $matches[2]; + if (isset($matches[1])) { + $info["user"] = $matches[1]; + } + + if (isset($matches[2])) { + $info["domain"] = $matches[2]; + } + $values['access_information'] = serialize($info); - $values['reference'] = $matches[3]."/".$matches[4]; + + if (isset($matches[3]) && isset($matches[4])) { + $values['reference'] = $matches[3]."/".$matches[4]; + } } $values['git_key'] = $values['key']; From 0e6523e2cd9c9e41a9229d326ade7b15a6c717a6 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 10:14:19 +0000 Subject: [PATCH 053/119] Adding basic git plugin --- PHPCI/Plugin/Git.php | 125 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 PHPCI/Plugin/Git.php diff --git a/PHPCI/Plugin/Git.php b/PHPCI/Plugin/Git.php new file mode 100644 index 00000000..54f1f160 --- /dev/null +++ b/PHPCI/Plugin/Git.php @@ -0,0 +1,125 @@ + + * @package PHPCI + * @subpackage Plugins + */ +class Git implements \PHPCI\Plugin +{ + protected $phpci; + protected $build; + protected $actions = array(); + + public function __construct(Builder $phpci, Build $build, array $options = array()) + { + $this->phpci = $phpci; + $this->build = $build; + $this->actions = $options; + } + + + public function execute() + { + $buildPath = $this->phpci->buildPath; + + // Check if there are any actions to be run for the branch we're running on: + if (!array_key_exists($this->build->getBranch(), $this->actions)) { + return true; + } + + // If there are, run them: + $curdir = getcwd(); + chdir($buildPath); + + $success = true; + foreach ($this->actions[$this->build->getBranch()] as $action => $options) { + if (!$this->runAction($action, $options)) { + $success = false; + break; + } + } + + chdir($curdir); + + return $success; + } + + protected function runAction($action, $options = array()) + { + // If options isn't an array, it should be. + if (!is_array($options)) { + $options = array(); + } + + // Handle git merges. + if ($action == 'merge' && array_key_exists('branch', $options)) { + $cmd = 'git checkout %s && git merge ' . $this->build->getBranch(); + return $this->phpci->executeCommand($cmd, $this->directory, $options['branch']); + } + + // Handle tagging: + if ($action == 'tag') { + $tagName = date('Ymd-His'); + $message = 'Tag created by PHPCI: ' . date('Y-m-d H:i:s'); + + if (array_key_exists('name', $options)) { + $tagName = $this->phpci->interpolate($options['name']); + } + + if (array_key_exists('message', $options)) { + $message = $this->phpci->interpolate($options['message']); + } + + $cmd = 'git tag %s -m "%s"'; + return $this->phpci->executeCommand($cmd, $tagName, $message); + } + + // Handle pull: + if ($action == 'pull') { + $branch = $this->build->getBranch(); + $remote = 'origin'; + + if (array_key_exists('branch', $options)) { + $branch = $this->phpci->interpolate($options['branch']); + } + + if (array_key_exists('remote', $options)) { + $remote = $this->phpci->interpolate($options['remote']); + } + + return $this->phpci->executeCommand('git pull %s %s', $remote, $branch); + } + + // Handle push: + if ($action == 'push') { + $branch = $this->build->getBranch(); + $remote = 'origin'; + + if (array_key_exists('branch', $options)) { + $branch = $this->phpci->interpolate($options['branch']); + } + + if (array_key_exists('remote', $options)) { + $remote = $this->phpci->interpolate($options['remote']); + } + + return $this->phpci->executeCommand('git push %s %s', $remote, $branch); + } + + return false; + } +} From b7e0a545bc84c8104c78d3537ccbb725e03709d1 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 11:03:40 +0000 Subject: [PATCH 054/119] Adding post install script --- composer.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/composer.json b/composer.json index 40aada7d..2f7b45b7 100644 --- a/composer.json +++ b/composer.json @@ -52,5 +52,11 @@ "atoum/atoum": "Atoum", "jakub-onderka/php-parallel-lint": "Parallel Linting Tool", "behat/behat": "Behat BDD Testing" + }, + + "scripts": { + "post-root-package-install": [ + "./console phpci:install" + ] } } From 6c01406935c721e30de82258afc1b50b49f5851e Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 12:05:00 +0100 Subject: [PATCH 055/119] Fixing previous commit >_> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2f7b45b7..b3b9213b 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ }, "scripts": { - "post-root-package-install": [ + "post-create-project-cmd": [ "./console phpci:install" ] } From 959864c5827769220664e970abf8eb1e50df84a0 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 12:05:45 +0100 Subject: [PATCH 056/119] Fixing previous commit >_> --- composer.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/composer.json b/composer.json index b3b9213b..40aada7d 100644 --- a/composer.json +++ b/composer.json @@ -52,11 +52,5 @@ "atoum/atoum": "Atoum", "jakub-onderka/php-parallel-lint": "Parallel Linting Tool", "behat/behat": "Behat BDD Testing" - }, - - "scripts": { - "post-create-project-cmd": [ - "./console phpci:install" - ] } } From acf4d093bbd1715b1e3aa020089502e27a9d6594 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 12:30:03 +0100 Subject: [PATCH 057/119] Updating PHPMD to enforce rules being an array. Fixes #319 --- PHPCI/Plugin/PhpMessDetector.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PHPCI/Plugin/PhpMessDetector.php b/PHPCI/Plugin/PhpMessDetector.php index c5e56e4e..06bc72e8 100755 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -86,6 +86,11 @@ class PhpMessDetector implements \PHPCI\Plugin $suffixes = ' --suffixes ' . implode(',', $this->suffixes); } + 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; From 3bf9e1ab254e9353bc4a2223aaed65feb00053fc Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 12:37:32 +0100 Subject: [PATCH 058/119] Inlining the validateSession functionality in Application, fixes #312 --- PHPCI/Application.php | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/PHPCI/Application.php b/PHPCI/Application.php index 3d889967..5c9647d2 100644 --- a/PHPCI/Application.php +++ b/PHPCI/Application.php @@ -26,11 +26,27 @@ class Application extends b8\Application $route = '/:controller/:action'; $opts = array('controller' => 'Home', 'action' => 'index'); - $this->router->clearRoutes(); - $this->router->register($route, $opts, function (&$route, Response &$response) use (&$request) { + // Inlined as a closure to fix "using $this when not in object context" on 5.3 + $validateSession = function () { + if (!empty($_SESSION['user_id'])) { + $user = b8\Store\Factory::getStore('User')->getByPrimaryKey($_SESSION['user_id']); + + if ($user) { + $_SESSION['user'] = $user; + return true; + } + + unset($_SESSION['user_id']); + } + + return false; + }; + + // Handler for the route we're about to register, checks for a valid session where necessary: + $routeHandler = function (&$route, Response &$response) use (&$request, $validateSession) { $skipValidation = in_array($route['controller'], array('session', 'webhook', 'build-status')); - if (!$skipValidation && !$this->validateSession()) { + if (!$skipValidation && !$validateSession()) { if ($request->isAjax()) { $response->setResponseCode(401); $response->setContent(''); @@ -43,7 +59,10 @@ class Application extends b8\Application } return true; - }); + }; + + $this->router->clearRoutes(); + $this->router->register($route, $opts, $routeHandler); } /** * Handle an incoming web request. @@ -60,23 +79,4 @@ class Application extends b8\Application return $this->response; } - - /** - * Validate whether or not the remote user has a valid session: - */ - protected function validateSession() - { - if (!empty($_SESSION['user_id'])) { - $user = b8\Store\Factory::getStore('User')->getByPrimaryKey($_SESSION['user_id']); - - if ($user) { - $_SESSION['user'] = $user; - return true; - } - - unset($_SESSION['user_id']); - } - - return false; - } } From c888b445411a20e4b3dd81b0d803864998a18ef3 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 14:46:15 +0100 Subject: [PATCH 059/119] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 6f5a14af..defd1998 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,7 @@ _**Please be aware that PHPCI is a beta-release project, so whilst it is very st We've got documentation on our wiki on [installing PHPCI](https://github.com/Block8/PHPCI/wiki/Installing-PHPCI) and [adding support for PHPCI to your projects](https://github.com/Block8/PHPCI/wiki/Adding-PHPCI-Support-to-Your-Projects). ##Contributing -Contributions from others would be very much appreciated! If you just want to make a simple change, simply fork the repository, and send us a pull request when you're ready. - -If you'd like to get more involved in developing PHPCI or to become a maintainer / committer on the main PHPCI repository, join the [mailing list](https://groups.google.com/forum/#!forum/php-ci). +Contributions from others would be very much appreciated! Please read our [guide to contributing](https://github.com/Block8/PHPCI/wiki/Contributing-to-PHPCI) for more information on how to get involved. ##Questions? Your best place to go is the [mailing list](https://groups.google.com/forum/#!forum/php-ci), if you're already a member of the mailing list, you can simply email php-ci@googlegroups.com. From 03141f41c4c7ccadbb52966945bbd740bbaed9a3 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 16:45:14 +0100 Subject: [PATCH 060/119] Fixing redirect to install.php --- bootstrap.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 4f3e8a67..ee819c49 100755 --- a/bootstrap.php +++ b/bootstrap.php @@ -33,9 +33,8 @@ $autoload = function ($class) { spl_autoload_register($autoload, true, true); -if (!file_exists(dirname(__FILE__) . '/PHPCI/config.yml') && (!defined('PHPCI_IS_CONSOLE') || !PHPCI_IS_CONSOLE) && substr($_SERVER['PHP_SELF'], -12) != '/install.php') { - header('Location: install.php'); - die; +if (!file_exists(dirname(__FILE__) . '/PHPCI/config.yml') && (!defined('PHPCI_IS_CONSOLE') || !PHPCI_IS_CONSOLE)) { + die('PHPCI has not yet been installed - Please use the command ./console phpci:install to install it.'); } if (!file_exists(dirname(__FILE__) . '/vendor/autoload.php') && defined('PHPCI_IS_CONSOLE') && PHPCI_IS_CONSOLE) { From 78e4b9d1041dfc61f592e3137ebf0007af9d2357 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 16 Apr 2014 16:38:19 +0000 Subject: [PATCH 061/119] Updating RemoteGitBuild to support a Git SSH wrapper. See #114 --- PHPCI/Model/Build/RemoteGitBuild.php | 67 +++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/PHPCI/Model/Build/RemoteGitBuild.php b/PHPCI/Model/Build/RemoteGitBuild.php index 5be3000c..bc4192b1 100644 --- a/PHPCI/Model/Build/RemoteGitBuild.php +++ b/PHPCI/Model/Build/RemoteGitBuild.php @@ -72,22 +72,24 @@ class RemoteGitBuild extends Build */ protected function cloneBySsh(Builder $builder, $cloneTo) { - // Copy the project's keyfile to disk: - $keyPath = realpath($cloneTo); + $keyFile = $this->writeSshKey($cloneTo); - if ($keyPath === false) { - $keyPath = dirname($cloneTo); + if (!IS_WIN) { + $gitSshWrapper = $this->writeSshWrapper($cloneTo, $keyFile); } - $keyFile = $keyPath . '.key'; + // Do the git clone: + $cmd = 'git clone -b %s %s "%s"'; - file_put_contents($keyFile, $this->getProject()->getGitKey()); - chmod($keyFile, 0600); + if (!IS_WIN) { + $cmd = 'export GIT_SSH="'.$gitSshWrapper.'" && ' . $cmd; + } - // Use the key file to do an SSH clone: - $cmd = 'eval `ssh-agent -s` && ssh-add "%s" && git clone -b %s %s "%s" && ssh-agent -k'; - $success = $builder->executeCommand($cmd, $keyFile, $this->getBranch(), $this->getCloneUrl(), $cloneTo); + var_dump($cmd); + $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') { @@ -98,9 +100,52 @@ class RemoteGitBuild extends Build $builder->executeCommand($cmd, $cloneTo, $this->getCommitId()); } - // Remove the key file: + // Remove the key file and git wrapper: unlink($keyFile); + unlink($gitSshWrapper); return $success; } + + /** + * Create an SSH key file on disk for this build. + * @param $cloneTo + * @return string + */ + protected function writeSshKey($cloneTo) + { + $keyPath = dirname($cloneTo . '/temp'); + $keyFile = $keyPath . '.key'; + + // Write the contents of this project's git key to the file: + file_put_contents($keyFile, $this->getProject()->getGitKey()); + chmod($keyFile, 0600); + + // Return the filename: + return $keyFile; + } + + /** + * Create an SSH wrapper script for Git to use, to disable host key checking, etc. + * @param $cloneTo + * @param $keyFile + * @return string + */ + protected function writeSshWrapper($cloneTo, $keyFile) + { + $path = dirname($cloneTo . '/temp'); + $wrapperFile = $path . '.sh'; + + // Write out the wrapper script for this build: + $script = << Date: Wed, 16 Apr 2014 16:38:40 +0000 Subject: [PATCH 062/119] Removing top level build directory, as it is not used. --- build/.gitignore | 2 -- 1 file changed, 2 deletions(-) delete mode 100755 build/.gitignore diff --git a/build/.gitignore b/build/.gitignore deleted file mode 100755 index c96a04f0..00000000 --- a/build/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file From ef5ba4693d86414c6053a8543b0e45bd5e58de75 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Fri, 11 Apr 2014 21:55:01 +0200 Subject: [PATCH 063/119] fix #335: unify (loc / quality trend) graph labels --- public/assets/js/build-plugins/loc.js | 4 ++-- public/assets/js/build-plugins/warnings.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/assets/js/build-plugins/loc.js b/public/assets/js/build-plugins/loc.js index df0b4ce6..d71a42ad 100644 --- a/public/assets/js/build-plugins/loc.js +++ b/public/assets/js/build-plugins/loc.js @@ -47,7 +47,7 @@ var locPlugin = PHPCI.UiPlugin.extend({ var titles = ['Build', 'Lines', 'Comment Lines', 'Non-Comment Lines', 'Logical Lines']; var data = [titles]; for (var i in builds) { - data.push(['Build ' + builds[i].build_id, parseInt(builds[i].meta_value.LOC), parseInt(builds[i].meta_value.CLOC), parseInt(builds[i].meta_value.NCLOC), parseInt(builds[i].meta_value.LLOC)]); + data.push(['#' + builds[i].build_id, parseInt(builds[i].meta_value.LOC), parseInt(builds[i].meta_value.CLOC), parseInt(builds[i].meta_value.NCLOC), parseInt(builds[i].meta_value.LLOC)]); } var data = google.visualization.arrayToDataTable(data); @@ -63,4 +63,4 @@ var locPlugin = PHPCI.UiPlugin.extend({ } }); -PHPCI.registerPlugin(new locPlugin()); \ No newline at end of file +PHPCI.registerPlugin(new locPlugin()); diff --git a/public/assets/js/build-plugins/warnings.js b/public/assets/js/build-plugins/warnings.js index 6bd371a1..8b86a1e7 100644 --- a/public/assets/js/build-plugins/warnings.js +++ b/public/assets/js/build-plugins/warnings.js @@ -87,8 +87,8 @@ var warningsPlugin = PHPCI.UiPlugin.extend({ var data = google.visualization.arrayToDataTable(data); var options = { - hAxis: {title: 'Build'}, - vAxis: {title: 'Warnings'}, + hAxis: {title: 'Builds'}, + vAxis: {title: 'Warnings / Errors'}, backgroundColor: { fill: 'transparent' }, height: 275, pointSize: 3 From 1f8a18d11346a53c0eb5e562f9c30f5485f2b98b Mon Sep 17 00:00:00 2001 From: Claus Due Date: Sat, 12 Apr 2014 13:52:26 +0200 Subject: [PATCH 064/119] Cross-platform safe copy in Plugin.CopyBuild Rather than using `xargs` which behaves differently on BSD and Linux, it's safer to use the straight `cp`. We lose the output of which files were copied - but I'd be more than happy to add this as a separate command to list which files were copied and which were ignored. --- PHPCI/Plugin/CopyBuild.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Plugin/CopyBuild.php b/PHPCI/Plugin/CopyBuild.php index c06408b8..39d41e3f 100644 --- a/PHPCI/Plugin/CopyBuild.php +++ b/PHPCI/Plugin/CopyBuild.php @@ -43,7 +43,7 @@ class CopyBuild implements \PHPCI\Plugin return false; } - $cmd = 'mkdir -p "%s" && ls -1a "%s"* | xargs -r -t "%s/"'; + $cmd = 'mkdir -p "%s" && cp -R "%s" "%s"'; $success = $this->phpci->executeCommand($cmd, $this->directory, $build, $this->directory); if ($this->ignore) { From 08afe7b10467738d97c574e19a12f361f520e6ed Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Thu, 24 Apr 2014 16:25:24 +0100 Subject: [PATCH 065/119] Adding per-page titles throughout PHPCI, fixes #371 --- PHPCI/Application.php | 6 ++++++ PHPCI/Controller/BuildController.php | 3 +++ PHPCI/Controller/HomeController.php | 2 ++ PHPCI/Controller/PluginController.php | 2 ++ PHPCI/Controller/ProjectController.php | 7 +++++++ PHPCI/Controller/UserController.php | 8 ++++++++ PHPCI/View/layout.phtml | 2 +- 7 files changed, 29 insertions(+), 1 deletion(-) diff --git a/PHPCI/Application.php b/PHPCI/Application.php index 5c9647d2..ecc71ad5 100644 --- a/PHPCI/Application.php +++ b/PHPCI/Application.php @@ -73,6 +73,12 @@ class Application extends b8\Application if (View::exists('layout') && $this->response->hasLayout()) { $view = new View('layout'); + $pageTitle = $this->config->get('page_title', null); + + if (!is_null($pageTitle)) { + $view->title = $pageTitle; + } + $view->content = $this->response->getContent(); $this->response->setContent($view->render()); } diff --git a/PHPCI/Controller/BuildController.php b/PHPCI/Controller/BuildController.php index 032ce118..3ebb8432 100644 --- a/PHPCI/Controller/BuildController.php +++ b/PHPCI/Controller/BuildController.php @@ -40,6 +40,9 @@ class BuildController extends \PHPCI\Controller $this->view->plugins = $this->getUiPlugins(); $this->view->build = $build; $this->view->data = $this->getBuildData($build); + + $title = 'Build #' . $build->getId() . ' - ' . $build->getProjectTitle(); + $this->config->set('page_title', $title); } protected function getUiPlugins() diff --git a/PHPCI/Controller/HomeController.php b/PHPCI/Controller/HomeController.php index 95676efc..b2d4bd6b 100644 --- a/PHPCI/Controller/HomeController.php +++ b/PHPCI/Controller/HomeController.php @@ -56,6 +56,8 @@ class HomeController extends \PHPCI\Controller $this->view->projects = $projects['items']; $this->view->summary = $summaryView->render(); + $this->config->set('page_title', 'Dashboard'); + return $this->view->render(); } diff --git a/PHPCI/Controller/PluginController.php b/PHPCI/Controller/PluginController.php index b7e32ddb..4f51e6c9 100644 --- a/PHPCI/Controller/PluginController.php +++ b/PHPCI/Controller/PluginController.php @@ -75,6 +75,8 @@ class PluginController extends \PHPCI\Controller $this->view->plugins = $pluginInfo->getInstalledPlugins(); + $this->config->set('page_title', 'Plugins'); + return $this->view->render(); } diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 95f8c2cd..42c74a10 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -61,6 +61,8 @@ class ProjectController extends \PHPCI\Controller $this->view->project = $project; $this->view->page = $page; + $this->config->set('page_title', $project->getTitle()); + return $this->view->render(); } @@ -134,6 +136,8 @@ class ProjectController extends \PHPCI\Controller */ public function add() { + $this->config->set('page_title', 'Add Project'); + if (!$_SESSION['user']->getIsAdmin()) { throw new \Exception('You do not have permission to do that.'); } @@ -229,6 +233,9 @@ class ProjectController extends \PHPCI\Controller $method = $this->request->getMethod(); $project = $this->projectStore->getById($projectId); + $this->config->set('page_title', 'Edit: ' . $project->getTitle()); + + if ($method == 'POST') { $values = $this->getParams(); } else { diff --git a/PHPCI/Controller/UserController.php b/PHPCI/Controller/UserController.php index ad41aff6..c8fade0c 100644 --- a/PHPCI/Controller/UserController.php +++ b/PHPCI/Controller/UserController.php @@ -40,6 +40,8 @@ class UserController extends Controller $users = $this->userStore->getWhere(array(), 1000, 0, array(), array('email' => 'ASC')); $this->view->users = $users; + $this->config->set('page_title', 'Users'); + return $this->view->render(); } @@ -52,6 +54,9 @@ class UserController extends Controller throw new \Exception('You do not have permission to do that.'); } + $this->config->set('page_title', 'Add User'); + + $method = $this->request->getMethod(); if ($method == 'POST') { @@ -96,6 +101,9 @@ class UserController extends Controller $method = $this->request->getMethod(); $user = $this->userStore->getById($userId); + $this->config->set('page_title', 'Edit: ' . $user->getName()); + + if ($method == 'POST') { $values = $this->getParams(); } else { diff --git a/PHPCI/View/layout.phtml b/PHPCI/View/layout.phtml index c455334c..73c97d75 100644 --- a/PHPCI/View/layout.phtml +++ b/PHPCI/View/layout.phtml @@ -1,7 +1,7 @@ - PHPCI + <?php if (!empty($title)) { print $title . ' - '; } ?>PHPCI From 2e4e3129b77c4f798aeb08424a376af16730c5c6 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Fri, 25 Apr 2014 10:17:39 +0100 Subject: [PATCH 066/119] Adding the ability to run projects with no build configuration. Runs what plugins it can automatically. Closes #235 --- PHPCI/Model/Build.php | 67 +++++++++++++++++++++++++++---- PHPCI/Plugin/Composer.php | 14 ++++++- PHPCI/Plugin/Lint.php | 3 +- PHPCI/Plugin/PhpCodeSniffer.php | 68 ++++++++++++++++++++++++++------ PHPCI/Plugin/PhpLoc.php | 12 +++++- PHPCI/Plugin/PhpMessDetector.php | 24 ++++++++++- PHPCI/Plugin/PhpSpec.php | 3 +- PHPCI/Plugin/PhpUnit.php | 40 ++++++++++++++++++- PHPCI/ZeroConfigPlugin.php | 21 ++++++++++ 9 files changed, 224 insertions(+), 28 deletions(-) create mode 100644 PHPCI/ZeroConfigPlugin.php diff --git a/PHPCI/Model/Build.php b/PHPCI/Model/Build.php index 20ff6a34..c5b0dc1a 100644 --- a/PHPCI/Model/Build.php +++ b/PHPCI/Model/Build.php @@ -88,20 +88,73 @@ class Build extends BuildBase */ protected function handleConfig(Builder $builder, $buildPath) { + $build_config = null; + + // Try phpci.yml first: if (is_file($buildPath . '/phpci.yml')) { $build_config = file_get_contents($buildPath . '/phpci.yml'); } - if (!is_file($buildPath . '/phpci.yml') || !$build_config) { + // Try getting the project build config from the database: + if (empty($build_config)) { $build_config = $this->getProject()->getBuildConfig(); - if (!$build_config) { - $builder->logFailure('Project does not contain a phpci.yml file.'); - return false; + } + + // Fall back to zero config plugins: + if (empty($build_config)) { + $build_config = $this->getZeroConfigPlugins($builder); + } + + if (is_string($build_config)) { + $yamlParser = new YamlParser(); + $build_config = $yamlParser->parse($build_config); + } + + $builder->setConfigArray($build_config); + return true; + } + + protected function getZeroConfigPlugins(Builder $builder) + { + $pluginDir = PHPCI_DIR . 'PHPCI/Plugin/'; + $dir = new \DirectoryIterator($pluginDir); + + $config = array( + 'build_settings' => array( + 'ignore' => array( + 'vendor/', + ) + ) + ); + + foreach ($dir as $item) { + if ($item->isDot()) { + continue; + } + + if (!$item->isFile()) { + continue; + } + + if ($item->getExtension() != 'php') { + continue; + } + + $className = '\PHPCI\Plugin\\'.$item->getBasename('.php'); + + $reflectedPlugin = new \ReflectionClass($className); + + if (!$reflectedPlugin->implementsInterface('\PHPCI\ZeroConfigPlugin')) { + continue; + } + + foreach (array('setup', 'test', 'complete', 'success', 'failure') as $stage) { + if ($className::canExecute($stage, $builder, $this)) { + $config[$stage][$className] = array(); + } } } - $yamlParser = new YamlParser(); - $builder->setConfigArray($yamlParser->parse($build_config)); - return $builder->getConfig('build_settings'); + return $config; } } diff --git a/PHPCI/Plugin/Composer.php b/PHPCI/Plugin/Composer.php index d40ac100..70462eba 100644 --- a/PHPCI/Plugin/Composer.php +++ b/PHPCI/Plugin/Composer.php @@ -9,6 +9,7 @@ namespace PHPCI\Plugin; +use PHPCI; use PHPCI\Builder; use PHPCI\Model\Build; @@ -18,13 +19,24 @@ use PHPCI\Model\Build; * @package PHPCI * @subpackage Plugins */ -class Composer implements \PHPCI\Plugin +class Composer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin { protected $directory; protected $action; protected $preferDist; protected $phpci; + public static function canExecute($stage, Builder $builder, Build $build) + { + $path = $builder->buildPath . '/composer.json'; + + if (file_exists($path) && $stage == 'setup') { + return true; + } + + return false; + } + public function __construct(Builder $phpci, Build $build, array $options = array()) { $path = $phpci->buildPath; diff --git a/PHPCI/Plugin/Lint.php b/PHPCI/Plugin/Lint.php index ebab146e..73b4beaf 100644 --- a/PHPCI/Plugin/Lint.php +++ b/PHPCI/Plugin/Lint.php @@ -9,6 +9,7 @@ namespace PHPCI\Plugin; +use PHPCI; use PHPCI\Builder; use PHPCI\Model\Build; @@ -18,7 +19,7 @@ use PHPCI\Model\Build; * @package PHPCI * @subpackage Plugins */ -class Lint implements \PHPCI\Plugin +class Lint implements PHPCI\Plugin { protected $directories; protected $recursive = true; diff --git a/PHPCI/Plugin/PhpCodeSniffer.php b/PHPCI/Plugin/PhpCodeSniffer.php index 2f0d7592..b942e44b 100755 --- a/PHPCI/Plugin/PhpCodeSniffer.php +++ b/PHPCI/Plugin/PhpCodeSniffer.php @@ -9,6 +9,7 @@ namespace PHPCI\Plugin; +use PHPCI; use PHPCI\Builder; use PHPCI\Model\Build; @@ -18,7 +19,7 @@ use PHPCI\Model\Build; * @package PHPCI * @subpackage Plugins */ -class PhpCodeSniffer implements \PHPCI\Plugin +class PhpCodeSniffer implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin { /** * @var \PHPCI\Builder @@ -50,6 +51,16 @@ class PhpCodeSniffer implements \PHPCI\Plugin */ protected $encoding; + /** + * @var int + */ + protected $allowed_errors; + + /** + * @var int + */ + protected $allowed_warnings; + /** * @var string, based on the assumption the root may not hold the code to be * tested, exteds the base path @@ -61,21 +72,33 @@ class PhpCodeSniffer implements \PHPCI\Plugin */ protected $ignore; + public static function canExecute($stage, Builder $builder, Build $build) + { + if ($stage == 'test') { + return true; + } + + return false; + } + /** * @param \PHPCI\Builder $phpci + * @param \PHPCI\Model\Build $build * @param array $options */ public function __construct(Builder $phpci, Build $build, array $options = array()) { - $this->phpci = $phpci; - $this->build = $build; - $this->suffixes = array('php'); - $this->directory = $phpci->buildPath; - $this->standard = 'PSR2'; - $this->tab_width = ''; - $this->encoding = ''; - $this->path = ''; - $this->ignore = $this->phpci->ignore; + $this->phpci = $phpci; + $this->build = $build; + $this->suffixes = array('php'); + $this->directory = $phpci->buildPath; + $this->standard = 'PSR2'; + $this->tab_width = ''; + $this->encoding = ''; + $this->path = ''; + $this->ignore = $this->phpci->ignore; + $this->allowed_warnings = -1; + $this->allowed_errors = -1; if (isset($options['suffixes'])) { $this->suffixes = (array)$options['suffixes']; @@ -104,6 +127,14 @@ class PhpCodeSniffer implements \PHPCI\Plugin 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']; + } } /** @@ -121,7 +152,7 @@ class PhpCodeSniffer implements \PHPCI\Plugin } $cmd = $phpcs . ' --report=emacs %s %s %s %s %s "%s"'; - $success = $this->phpci->executeCommand( + $this->phpci->executeCommand( $cmd, $standard, $suffixes, @@ -133,14 +164,25 @@ class PhpCodeSniffer implements \PHPCI\Plugin $output = $this->phpci->getLastOutput(); + $success = true; $matches = array(); if (preg_match_all('/\: warning \-/', $output, $matches)) { - $this->build->storeMeta('phpcs-warnings', count($matches[0])); + $warnings = count($matches[0]); + $this->build->storeMeta('phpcs-warnings', $warnings); + + if ($this->allowed_warnings != -1 && $warnings > $this->allowed_warnings) { + $success = false; + } } $matches = array(); if (preg_match_all('/\: error \-/', $output, $matches)) { - $this->build->storeMeta('phpcs-errors', count($matches[0])); + $errors = count($matches[0]); + $this->build->storeMeta('phpcs-errors', $errors); + + if ($this->allowed_errors != -1 && $errors > $this->allowed_errors) { + $success = false; + } } return $success; diff --git a/PHPCI/Plugin/PhpLoc.php b/PHPCI/Plugin/PhpLoc.php index 809b6409..000b82cc 100644 --- a/PHPCI/Plugin/PhpLoc.php +++ b/PHPCI/Plugin/PhpLoc.php @@ -9,6 +9,7 @@ namespace PHPCI\Plugin; +use PHPCI; use PHPCI\Builder; use PHPCI\Model\Build; @@ -18,7 +19,7 @@ use PHPCI\Model\Build; * @package PHPCI * @subpackage Plugins */ -class PhpLoc implements \PHPCI\Plugin +class PhpLoc implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin { /** * @var string @@ -29,6 +30,15 @@ class PhpLoc implements \PHPCI\Plugin */ protected $phpci; + 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; diff --git a/PHPCI/Plugin/PhpMessDetector.php b/PHPCI/Plugin/PhpMessDetector.php index 06bc72e8..f68d7aec 100755 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -9,6 +9,7 @@ namespace PHPCI\Plugin; +use PHPCI; use PHPCI\Builder; use PHPCI\Model\Build; @@ -18,7 +19,7 @@ use PHPCI\Model\Build; * @package PHPCI * @subpackage Plugins */ -class PhpMessDetector implements \PHPCI\Plugin +class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin { /** * @var \PHPCI\Builder @@ -49,6 +50,15 @@ class PhpMessDetector implements \PHPCI\Plugin */ protected $rules; + public static function canExecute($stage, Builder $builder, Build $build) + { + if ($stage == 'test') { + return true; + } + + return false; + } + /** * @param \PHPCI\Builder $phpci * @param array $options @@ -61,11 +71,16 @@ class PhpMessDetector implements \PHPCI\Plugin $this->ignore = $phpci->ignore; $this->path = ''; $this->rules = array('codesize', 'unusedcode', 'naming'); + $this->allowed_warnings = -1; if (!empty($options['path'])) { $this->path = $options['path']; } + if (array_key_exists('allowed_warnings', $options)) { + $this->allowed_warnings = (int)$options['allowed_warnings']; + } + foreach (array('rules', 'ignore', 'suffixes') as $key) { $this->overrideSetting($options, $key); } @@ -110,7 +125,7 @@ class PhpMessDetector implements \PHPCI\Plugin } $cmd = $phpmd . ' "%s" text %s %s %s'; - $success = $this->phpci->executeCommand( + $this->phpci->executeCommand( $cmd, $path, implode(',', $this->rules), @@ -118,9 +133,14 @@ class PhpMessDetector implements \PHPCI\Plugin $suffixes ); + $success = true; $errors = count(array_filter(explode(PHP_EOL, trim($this->phpci->getLastOutput())))); $this->build->storeMeta('phpmd-warnings', $errors); + if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) { + $success = false; + } + return $success; } diff --git a/PHPCI/Plugin/PhpSpec.php b/PHPCI/Plugin/PhpSpec.php index 02aebba7..843017b9 100644 --- a/PHPCI/Plugin/PhpSpec.php +++ b/PHPCI/Plugin/PhpSpec.php @@ -9,6 +9,7 @@ namespace PHPCI\Plugin; +use PHPCI; use PHPCI\Builder; use PHPCI\Model\Build; @@ -18,7 +19,7 @@ use PHPCI\Model\Build; * @package PHPCI * @subpackage Plugins */ -class PhpSpec implements \PHPCI\Plugin +class PhpSpec implements PHPCI\Plugin { protected $phpci; diff --git a/PHPCI/Plugin/PhpUnit.php b/PHPCI/Plugin/PhpUnit.php index fde1b2fa..ab0cfc58 100755 --- a/PHPCI/Plugin/PhpUnit.php +++ b/PHPCI/Plugin/PhpUnit.php @@ -9,6 +9,7 @@ namespace PHPCI\Plugin; +use PHPCI; use PHPCI\Builder; use PHPCI\Model\Build; @@ -18,7 +19,7 @@ use PHPCI\Model\Build; * @package PHPCI * @subpackage Plugins */ -class PhpUnit implements \PHPCI\Plugin +class PhpUnit implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin { protected $args; protected $phpci; @@ -46,9 +47,44 @@ class PhpUnit implements \PHPCI\Plugin */ protected $xmlConfigFile; + public static function canExecute($stage, Builder $builder, Build $build) + { + if ($stage == 'test' && !is_null(self::findConfigFile($builder->buildPath))) { + return true; + } + + return false; + } + + public static function findConfigFile($buildPath) + { + if (file_exists($buildPath . '/phpunit.xml')) { + return $buildPath . '/phpunit.xml'; + } + + if (file_exists($buildPath . '/tests/phpunit.xml')) { + return $buildPath . '/tests/phpunit.xml'; + } + + if (file_exists($buildPath . '/phpunit.xml.dist')) { + return $buildPath . '/phpunit.xml.dist'; + } + + if (file_exists($buildPath . '/tests/phpunit.xml.dist')) { + return $buildPath . '/tests/phpunit.xml.dist'; + } + + return null; + } + public function __construct(Builder $phpci, Build $build, array $options = array()) { - $this->phpci = $phpci; + $this->phpci = $phpci; + + if (!count($options)) { + $this->runFrom = $phpci->buildPath; + $this->xmlConfigFile = self::findConfigFile($phpci->buildPath); + } if (isset($options['directory'])) { $this->directory = $options['directory']; diff --git a/PHPCI/ZeroConfigPlugin.php b/PHPCI/ZeroConfigPlugin.php new file mode 100644 index 00000000..b779cf5e --- /dev/null +++ b/PHPCI/ZeroConfigPlugin.php @@ -0,0 +1,21 @@ + + */ +interface ZeroConfigPlugin +{ + public static function canExecute($stage, Builder $builder, Build $build); +} From ab848b9ebfd61056629a7bf93dc993d99763475d Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Fri, 25 Apr 2014 11:25:46 +0000 Subject: [PATCH 067/119] UI improvements for the Build view screen --- PHPCI/View/Build/view.phtml | 98 +++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 16 deletions(-) diff --git a/PHPCI/View/Build/view.phtml b/PHPCI/View/Build/view.phtml index 0c6817c9..52d4db80 100644 --- a/PHPCI/View/Build/view.phtml +++ b/PHPCI/View/Build/view.phtml @@ -1,38 +1,60 @@ -
-

getProject()->getTitle(); ?> - Build #getId(); ?>

+
+ + +
+

+ getProject()->getTitle(); ?> + #getId(); ?> + + +

+
+
+ getCommitMessage()): ?> +
+ getCommitMessage(); ?> +
+ + Branch: getBranch(); ?>
- Committer: getCommitterEmail(); ?>
- Commit ID: getCommitId() == 'Manual' ? 'HEAD' : $build->getCommitId(); ?>
- Commit Message: getCommitMessage(); ?> + Committer: getCommitterEmail(); ?> + + getCommitId() != 'Manual'): ?> +
Commit ID: getCommitId(); ?>
+
- -
Options
-
-
+
getStatus(); ?>); }); + + function updateBuildStatus(status) { + var statusClass = null; + var statusText = null; + + switch (status) { + case 0: + statusClass = 'info'; + statusText = 'Pending'; + break; + case 1: + statusClass = 'warning'; + statusText = 'Running'; + break; + case 2: + statusClass = 'success'; + statusText = 'Success'; + break; + case 3: + statusClass = 'danger'; + statusText = 'Failed'; + break; + } + + $('#title') + .removeClass('panel-info') + .removeClass('panel-warning') + .removeClass('panel-success') + .removeClass('panel-danger') + .addClass('panel-' + statusClass); + + $('#title .label') + .removeClass('label-info') + .removeClass('label-warning') + .removeClass('label-success') + .removeClass('label-danger') + .addClass('label-' + statusClass) + .text(statusText); + } From 96eee9c9b75d75121445ed87ff282f080e3ccf2f Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Fri, 25 Apr 2014 11:26:33 +0000 Subject: [PATCH 068/119] Making new manual builds use the active user's email as the committer address --- PHPCI/Controller/ProjectController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 42c74a10..2ecc177b 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -80,6 +80,7 @@ class ProjectController extends \PHPCI\Controller $build->setStatus(Build::STATUS_NEW); $build->setBranch($project->getType() === 'hg' ? 'default' : 'master'); $build->setCreated(new \DateTime()); + $build->setCommitterEmail($_SESSION['user']->getEmail()); $build = $this->buildStore->save($build); From 985c51c5e435e2272d686ff66ced8d677989498c Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Fri, 25 Apr 2014 11:28:27 +0000 Subject: [PATCH 069/119] Migrating PHPMD to use XML report format and add a UI plugin to display warning information. See #305 --- PHPCI/Builder.php | 5 ++ PHPCI/Helper/CommandExecutor.php | 5 +- PHPCI/Model/Build.php | 5 ++ PHPCI/Model/Build/GithubBuild.php | 20 +++++++ PHPCI/Plugin/PhpMessDetector.php | 48 ++++++++++++++++- public/assets/css/phpci.css | 35 +++++++++++-- public/assets/js/build-plugins/phpmd.js | 69 +++++++++++++++++++++++++ public/assets/js/phpci.js | 11 ++-- 8 files changed, 184 insertions(+), 14 deletions(-) create mode 100644 public/assets/js/build-plugins/phpmd.js diff --git a/PHPCI/Builder.php b/PHPCI/Builder.php index 92b43e9d..4547564a 100644 --- a/PHPCI/Builder.php +++ b/PHPCI/Builder.php @@ -258,6 +258,11 @@ class Builder implements LoggerAwareInterface return $this->commandExecutor->getLastOutput(); } + public function logExecOutput($enableLog = true) + { + $this->commandExecutor->logExecOutput = $enableLog; + } + /** * Find a binary required by a plugin. * @param $binary diff --git a/PHPCI/Helper/CommandExecutor.php b/PHPCI/Helper/CommandExecutor.php index 2e88b938..dc284b6a 100644 --- a/PHPCI/Helper/CommandExecutor.php +++ b/PHPCI/Helper/CommandExecutor.php @@ -25,6 +25,9 @@ class CommandExecutor protected $lastOutput; + public $logExecOutput = true; + + /** * The path which findBinary will look in. * @var string @@ -80,7 +83,7 @@ class CommandExecutor $lastOutput = trim($lastOutput, '"'); } - if (!empty($this->lastOutput) && ($this->verbose|| $status != 0)) { + if ($this->logExecOutput && !empty($this->lastOutput) && ($this->verbose|| $status != 0)) { $this->logger->log($this->lastOutput); } diff --git a/PHPCI/Model/Build.php b/PHPCI/Model/Build.php index c5b0dc1a..edd8fd2c 100644 --- a/PHPCI/Model/Build.php +++ b/PHPCI/Model/Build.php @@ -157,4 +157,9 @@ class Build extends BuildBase return $config; } + + public function getFileLink($file, $line = null) + { + return null; + } } diff --git a/PHPCI/Model/Build/GithubBuild.php b/PHPCI/Model/Build/GithubBuild.php index 98d7a8eb..02118c60 100644 --- a/PHPCI/Model/Build/GithubBuild.php +++ b/PHPCI/Model/Build/GithubBuild.php @@ -93,4 +93,24 @@ class GithubBuild extends RemoteGitBuild return 'https://github.com/' . $this->getProject()->getReference() . '.git'; } } + + public function getCommitMessage() + { + $rtn = $this->data['commit_message']; + + $rtn = preg_replace('/\#([0-9]+)/', '#$1', $rtn); + $rtn = preg_replace('/\@([a-zA-Z0-9_]+)/', '@$1', $rtn); + + return $rtn; + } + + public function getFileLinkTemplate() + { + $link = 'https://github.com/' . $this->getProject()->getReference() . '/'; + $link .= 'blob/' . $this->getBranch() . '/'; + $link .= '{FILE}'; + $link .= '#L{LINE}'; + + return $link; + } } diff --git a/PHPCI/Plugin/PhpMessDetector.php b/PHPCI/Plugin/PhpMessDetector.php index f68d7aec..7745c363 100755 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -124,7 +124,12 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin $path = $this->path; } - $cmd = $phpmd . ' "%s" text %s %s %s'; + $cmd = $phpmd . ' "%s" xml %s %s %s'; + + // 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, @@ -133,9 +138,14 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin $suffixes ); + // Re-enable exec output logging: + $this->phpci->logExecOutput(true); + $success = true; - $errors = count(array_filter(explode(PHP_EOL, trim($this->phpci->getLastOutput())))); + + list($errors, $data) = $this->processReport(trim($this->phpci->getLastOutput())); $this->build->storeMeta('phpmd-warnings', $errors); + $this->build->storeMeta('phpmd-data', $data); if ($this->allowed_warnings != -1 && $errors > $this->allowed_warnings) { $success = false; @@ -150,4 +160,38 @@ class PhpMessDetector implements PHPCI\Plugin, PHPCI\ZeroConfigPlugin $this->{$key} = $options[$key]; } } + + protected function processReport($xml) + { + $xml = simplexml_load_string($xml); + + if ($xml === false) { + throw new \Exception('Could not process PHPMD report XML.'); + } + + $warnings = 0; + $data = array(); + + foreach ($xml->file as $file) { + $fileName = (string)$file['name']; + $fileName = str_replace($this->phpci->buildPath, '', $fileName); + + foreach ($file->violation as $violation) { + $warnings++; + $warning = array( + 'file' => $fileName, + 'line_start' => (int)$violation['beginline'], + 'line_end' => (int)$violation['endline'], + 'rule' => (string)$violation['rule'], + 'ruleset' => (string)$violation['ruleset'], + 'priority' => (int)$violation['priority'], + 'message' => (string)$violation, + ); + + $data[] = $warning; + } + } + + return array($warnings, $data); + } } diff --git a/public/assets/css/phpci.css b/public/assets/css/phpci.css index ce34fe82..6b09a8e7 100644 --- a/public/assets/css/phpci.css +++ b/public/assets/css/phpci.css @@ -57,11 +57,16 @@ td .label { #title { - border-bottom: 1px solid #ccc; - margin: -10px -10px 15px -10px; - padding: 10px; } + #title img { + border: 1px solid #fff; + border-radius: 50%; + box-shadow: 2px 2px 2px rgba(0,0,0,0.1); + margin-bottom: 15px; + margin-right: 15px; + } + #title h1 { font-size: 2em; @@ -69,6 +74,23 @@ td .label { padding: 0; } + #title h1 span { + font-weight: lighter; + margin-left: 15px; + } + + #title h1 label { + margin-top: -6px; + } + + #build-info { + margin-left: 100px; + } + .commit-message { + font-size: 1.2em; + margin-bottom: 10px; + } + h2 { color: #246; font-size: 1.8em; @@ -135,8 +157,13 @@ td .label { .ui-sortable-placeholder * { visibility: hidden; } -.ui-plugin { padding-top: 15px; } +.ui-plugin .panel-title { + cursor: move; +} +.panel-body table { + margin-bottom: 0; +} #loading { font-family: Roboto, Arial, Sans-Serif; diff --git a/public/assets/js/build-plugins/phpmd.js b/public/assets/js/build-plugins/phpmd.js new file mode 100644 index 00000000..56e8e995 --- /dev/null +++ b/public/assets/js/build-plugins/phpmd.js @@ -0,0 +1,69 @@ +var phpmdPlugin = PHPCI.UiPlugin.extend({ + id: 'build-phpmd-warnings', + css: 'col-lg-12 col-md-12 col-sm-12 col-xs-12', + title: 'PHP Mess Detector', + lastData: null, + displayOnUpdate: false, + + register: function() { + var self = this; + var query = PHPCI.registerQuery('phpmd-data', -1, {key: 'phpmd-data'}) + + $(window).on('phpmd-data', function(data) { + self.onUpdate(data); + }); + + $(window).on('build-updated', function(data) { + if (data.queryData.status > 1) { + self.displayOnUpdate = true; + query(); + } + }); + }, + + render: function() { + + return $('' + + '' + + '' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + + '
FileStartEndMessage
'); + }, + + onUpdate: function(e) { + if (this.lastData && this.lastData[0]) { + return; + } + + this.lastData = e.queryData; + + var errors = this.lastData[0].meta_value; + var tbody = $('#phpmd-data tbody'); + tbody.empty(); + + for (var i in errors) { + var file = errors[i].file; + + if (PHPCI.fileLinkTemplate) { + var fileLink = PHPCI.fileLinkTemplate.replace('{FILE}', file); + fileLink = fileLink.replace('{LINE}', errors[i].line_start); + + file = '' + file + ''; + } + + var row = $('' + + ''+file+'' + + ''+errors[i].line_start+'' + + ''+errors[i].line_end+'' + + ''+errors[i].message+''); + + tbody.append(row); + } + } +}); + +PHPCI.registerPlugin(new phpmdPlugin()); diff --git a/public/assets/js/phpci.js b/public/assets/js/phpci.js index 7cf07458..e4c29791 100644 --- a/public/assets/js/phpci.js +++ b/public/assets/js/phpci.js @@ -382,7 +382,7 @@ var PHPCIObject = Class.extend({ } $('#plugins').sortable({ - handle: '.title', + handle: '.panel-title', connectWith: '#plugins', update: self.storePluginOrder }); @@ -391,16 +391,13 @@ var PHPCIObject = Class.extend({ }, renderPlugin: function(plugin) { - var output = $('
').addClass('box-content').append(plugin.render()); + var output = $('
').addClass('panel-body').append(plugin.render()); var container = $('
').addClass('ui-plugin ' + plugin.css); var content = $('
').attr('id', plugin.id).append(output); - - if (plugin.box) { - content.addClass('box'); - } + content.addClass('panel'); if (plugin.title) { - content.prepend('

'+plugin.title+'

'); + content.prepend('

'+plugin.title+'

'); } content.append(output); From 77ce6b3c1d6a0e736c2c7a15530224adb4e81fe2 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Fri, 25 Apr 2014 11:29:00 +0000 Subject: [PATCH 070/119] Updating phpci.yml to allow the current level of PHPMD errors, but no more than that. --- phpci.yml | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/phpci.yml b/phpci.yml index ec5b056a..7cad819a 100644 --- a/phpci.yml +++ b/phpci.yml @@ -1,18 +1,19 @@ build_settings: - verbose: false - ignore: - - "vendor" - - "Tests" - - "PHPCI/Command" # PHPMD complains about un-used parameters, but they are required. - - "public/install.php" # PHPCS really doesn't like PHP mixed with HTML (and so it shouldn't) + verbose: false + ignore: + - "vendor" + - "Tests" + - "PHPCI/Command" # PHPMD complains about un-used parameters, but they are required. + - "public/install.php" # PHPCS really doesn't like PHP mixed with HTML (and so it shouldn't) test: - php_mess_detector: - php_code_sniffer: - standard: "PSR2" - php_loc: + php_mess_detector: + allowed_warnings: 31 # Set max warnings at the current level - Disallow any further errors creeping in. + php_code_sniffer: + standard: "PSR2" + php_loc: failure: - email: - committer: true - cc: ["php-ci@googlegroups.com"] + email: + committer: true + cc: ["php-ci@googlegroups.com"] From ad4692685488b8de34cbc2b4b68c5ea8af9fba02 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Fri, 25 Apr 2014 12:35:36 +0100 Subject: [PATCH 071/119] Updating allowed PHPMD warning limit --- phpci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpci.yml b/phpci.yml index 7cad819a..52330436 100644 --- a/phpci.yml +++ b/phpci.yml @@ -8,7 +8,7 @@ build_settings: test: php_mess_detector: - allowed_warnings: 31 # Set max warnings at the current level - Disallow any further errors creeping in. + allowed_warnings: 35 # Set max warnings at the current level - Disallow any further errors creeping in. php_code_sniffer: standard: "PSR2" php_loc: From a789f7cb266828bb7846d9ed057bc58ace048b1c Mon Sep 17 00:00:00 2001 From: Joseph Pugh Date: Mon, 28 Apr 2014 14:26:37 -0500 Subject: [PATCH 072/119] implement RemoteGitBuild::getFileLinkTemplate required by PHPCI/View/Build/view.phtml --- PHPCI/Model/Build/GitlabBuild.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/PHPCI/Model/Build/GitlabBuild.php b/PHPCI/Model/Build/GitlabBuild.php index 98be17c8..8c1e038b 100644 --- a/PHPCI/Model/Build/GitlabBuild.php +++ b/PHPCI/Model/Build/GitlabBuild.php @@ -38,6 +38,18 @@ class GitlabBuild extends RemoteGitBuild return 'http://' . $domain . '/' . $this->getProject()->getReference() . '/tree/' . $this->getBranch(); } + /** + * Get link to specific file (and line) in a the repo's branch + */ + public function getFileLinkTemplate() + { + return sprintf('http://%s/%s/blob/%s/{FILE}#L{LINE}', + $this->getProject()->getAccessInformation("domain"), + $this->getProject()->getReference(), + $this->getBranch() + ); + } + /** * Get the URL to be used to clone this remote repository. */ From a38adb5d783732d4a9c8ed0e499f93dbf79d4197 Mon Sep 17 00:00:00 2001 From: Corpsee Date: Tue, 29 Apr 2014 23:22:04 +0700 Subject: [PATCH 073/119] Humanised yaml application config --- PHPCI/Command/InstallCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PHPCI/Command/InstallCommand.php b/PHPCI/Command/InstallCommand.php index e6432103..aac34dca 100644 --- a/PHPCI/Command/InstallCommand.php +++ b/PHPCI/Command/InstallCommand.php @@ -195,7 +195,7 @@ class InstallCommand extends Command protected function writeConfigFile(array $config) { $dumper = new \Symfony\Component\Yaml\Dumper(); - $yaml = $dumper->dump($config); + $yaml = $dumper->dump($config, 2); file_put_contents(PHPCI_DIR . 'PHPCI/config.yml', $yaml); } From a474a5d179a1cba16291db1e6819c43e3090248f Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Wed, 30 Apr 2014 14:13:07 +0100 Subject: [PATCH 074/119] UI updates --- PHPCI/View/Build/view.phtml | 59 +++-- PHPCI/View/BuildsTable.phtml | 4 +- PHPCI/View/Home/index.phtml | 68 +++--- PHPCI/View/Project/view.phtml | 83 ++++--- PHPCI/View/ProjectForm.phtml | 32 ++- PHPCI/View/SummaryTable.phtml | 2 +- PHPCI/View/User/index.phtml | 18 +- PHPCI/View/layout.phtml | 4 +- public/assets/css/bootstrap-theme.min.css | 7 + public/assets/css/bootstrap.min.css | 14 +- public/assets/css/phpci.css | 200 ++++----------- .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20335 bytes .../fonts/glyphicons-halflings-regular.svg | 229 ++++++++++++++++++ .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 41280 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23320 bytes public/assets/js/bootstrap.min.js | 13 +- public/assets/js/build-plugins/phpcs.js | 72 ++++++ public/assets/js/build-plugins/phpmd.js | 1 + public/assets/js/phpci.js | 12 +- 19 files changed, 537 insertions(+), 281 deletions(-) create mode 100755 public/assets/css/bootstrap-theme.min.css mode change 100644 => 100755 public/assets/css/bootstrap.min.css create mode 100755 public/assets/fonts/glyphicons-halflings-regular.eot create mode 100755 public/assets/fonts/glyphicons-halflings-regular.svg create mode 100755 public/assets/fonts/glyphicons-halflings-regular.ttf create mode 100755 public/assets/fonts/glyphicons-halflings-regular.woff mode change 100644 => 100755 public/assets/js/bootstrap.min.js create mode 100644 public/assets/js/build-plugins/phpcs.js diff --git a/PHPCI/View/Build/view.phtml b/PHPCI/View/Build/view.phtml index 52d4db80..567df543 100644 --- a/PHPCI/View/Build/view.phtml +++ b/PHPCI/View/Build/view.phtml @@ -1,48 +1,47 @@ -
+

- getProject()->getTitle(); ?> + + getProject()->getTitle(); ?> #getId(); ?>

+
+
+ getCommitMessage()): ?> +
+ getCommitMessage(); ?> +
+ -
- getCommitMessage()): ?> -
- getCommitMessage(); ?> + Branch: getBranch(); ?>
+ Committer: getCommitterEmail(); ?> + + getCommitId() != 'Manual'): ?> +
Commit ID: getCommitId(); ?>
+
- - - Branch: getBranch(); ?>
- Committer: getCommitterEmail(); ?> - - getCommitId() != 'Manual'): ?> -
Commit ID: getCommitId(); ?>
-
- - - -
Options
- - +
+
+

Options

+
+ +
@@ -104,14 +103,14 @@ foreach ($plugins as $plugin) { break; } - $('#title') + $('.build-info-panel') .removeClass('panel-info') .removeClass('panel-warning') .removeClass('panel-success') .removeClass('panel-danger') .addClass('panel-' + statusClass); - $('#title .label') + $('.build-info-panel .label') .removeClass('label-info') .removeClass('label-warning') .removeClass('label-success') diff --git a/PHPCI/View/BuildsTable.phtml b/PHPCI/View/BuildsTable.phtml index 9c1b3aea..da67e087 100644 --- a/PHPCI/View/BuildsTable.phtml +++ b/PHPCI/View/BuildsTable.phtml @@ -79,9 +79,9 @@ switch($build->getStatus())
- View + View User()->getIsAdmin()): ?> -