From d5763b8d78bc5f8c329c0b0fa4fa64c4526d4d86 Mon Sep 17 00:00:00 2001 From: Roy Lindauer Date: Sun, 10 Nov 2013 18:22:05 -0800 Subject: [PATCH 01/12] Fix bug where options could not be overridden in PHPMessdetector plugin --- 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 66944ad6..000f842e 100755 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -115,7 +115,7 @@ class PhpMessDetector implements \PHPCI\Plugin protected function overrideSetting($options, $key) { - if (isset($options[$key]) && is_array($options['key'])) { + if (isset($options[$key]) && is_array($options[$key])) { $this->{$key} = $options[$key]; } } From fb08cdbbe7d1411c40563e057b81cd6de82ec6e7 Mon Sep 17 00:00:00 2001 From: Roy Lindauer Date: Sun, 10 Nov 2013 18:22:54 -0800 Subject: [PATCH 02/12] Fix bug where ruleset file could not be set in PHPMessdetector plugin --- 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 000f842e..89c22f66 100755 --- a/PHPCI/Plugin/PhpMessDetector.php +++ b/PHPCI/Plugin/PhpMessDetector.php @@ -86,7 +86,7 @@ class PhpMessDetector implements \PHPCI\Plugin } foreach ($this->rules as &$rule) { - if ($rule[0] !== '/' && strpos($rule, '/') !== false) { + if (strpos($rule, '/') !== false) { $rule = $this->phpci->buildPath . $rule; } } From 7d306b22954320649e1806c39a73da27157157d3 Mon Sep 17 00:00:00 2001 From: Stian Liknes Date: Tue, 12 Nov 2013 22:18:09 +0100 Subject: [PATCH 03/12] Load configuration and create build directory for bare repositories --- PHPCI/Model/Build/LocalBuild.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PHPCI/Model/Build/LocalBuild.php b/PHPCI/Model/Build/LocalBuild.php index bfb8ac9e..08d997dd 100644 --- a/PHPCI/Model/Build/LocalBuild.php +++ b/PHPCI/Model/Build/LocalBuild.php @@ -33,7 +33,7 @@ class LocalBuild extends Build // If there's a /config file in the reference directory, it is probably a bare repository // which we'll extract into our build path directly. if (is_file($reference.'/config') && $this->handleBareRepository($builder, $reference, $buildPath) === true) { - return true; + return $this->handleConfig($builder, $buildPath) !== false; } $buildSettings = $this->handleConfig($builder, $reference); @@ -57,7 +57,7 @@ class LocalBuild extends Build // If it is indeed a bare repository, then extract it into our build path: if ($gitConfig['core']['bare']) { - $builder->executeCommand('git --git-dir="%s" archive master | tar -x -C "%s"', $reference, $buildPath); + $builder->executeCommand('mkdir %2$s; git --git-dir="%1$s" archive master | tar -x -C "%2$s"', $reference, $buildPath); return true; } From 1008a3db6edc04fd2761bdd39a6502f84eacadb0 Mon Sep 17 00:00:00 2001 From: hek2mgl Date: Wed, 13 Nov 2013 00:48:03 +0100 Subject: [PATCH 04/12] Update install.php "Pretty printing" `config.yml` in order to make it editable by humans. `5` is just value which is looking good for me. It produces a `config.yml` like this: prevstage: - start - database - github - email b8: database: servers: read: - localhost write: - localhost name: phpci username: ***** password: ***** phpci: url: 'http://phpci.my.org' github: id: '' secret: '' email_settings: smtp_address: '' smtp_port: '' smtp_encryption: on smtp_username: '' smtp_password: '' from_address: '' default_mailto_address: '' I guess the `prevstage` node can be replaced before writing? If yes I'll prepare that. --- public/install.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/install.php b/public/install.php index 0b7df4c8..d7ef1973 100644 --- a/public/install.php +++ b/public/install.php @@ -93,7 +93,7 @@ if ($installOK && strtoupper($_SERVER['REQUEST_METHOD']) == 'POST') { unset($config['tmp']); $dumper = new \Symfony\Component\Yaml\Dumper(); - $yaml = $dumper->dump($config); + $yaml = $dumper->dump($config, 5); file_put_contents(PHPCI_DIR . 'PHPCI/config.yml', $yaml); From 2fb162900d717c44bcd95c6eea11b8eae0729906 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Wed, 13 Nov 2013 00:45:38 +0100 Subject: [PATCH 05/12] fixed counting of errors and warnings in Plugin/PhpCodeSniffer; use --report=emacs in Plugin/PhpCodeSniffer to not spam the logs with the full blown report but rather display a small human readable summary report --- PHPCI/Plugin/PhpCodeSniffer.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PHPCI/Plugin/PhpCodeSniffer.php b/PHPCI/Plugin/PhpCodeSniffer.php index 44fa5893..2f0d7592 100755 --- a/PHPCI/Plugin/PhpCodeSniffer.php +++ b/PHPCI/Plugin/PhpCodeSniffer.php @@ -120,7 +120,7 @@ class PhpCodeSniffer implements \PHPCI\Plugin return false; } - $cmd = $phpcs . ' %s %s %s %s %s "%s"'; + $cmd = $phpcs . ' --report=emacs %s %s %s %s %s "%s"'; $success = $this->phpci->executeCommand( $cmd, $standard, @@ -134,12 +134,12 @@ class PhpCodeSniffer implements \PHPCI\Plugin $output = $this->phpci->getLastOutput(); $matches = array(); - if (preg_match_all('/WARNING/', $output, $matches)) { + if (preg_match_all('/\: warning \-/', $output, $matches)) { $this->build->storeMeta('phpcs-warnings', count($matches[0])); } $matches = array(); - if (preg_match_all('/ERROR/', $output, $matches)) { + if (preg_match_all('/\: error \-/', $output, $matches)) { $this->build->storeMeta('phpcs-errors', count($matches[0])); } From a0d5f4b4d87d7754d48c8d2cdfec2dee8afa3638 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Wed, 13 Nov 2013 19:18:24 +0100 Subject: [PATCH 06/12] fix Plugin\PhpParallelLint to reflect latest upstream changes: > executable is now "parallel-lint" instead of "run" > supports --exclude flag (ignore directories) --- PHPCI/Plugin/PhpParallelLint.php | 50 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/PHPCI/Plugin/PhpParallelLint.php b/PHPCI/Plugin/PhpParallelLint.php index b7a8cd24..0aba3100 100644 --- a/PHPCI/Plugin/PhpParallelLint.php +++ b/PHPCI/Plugin/PhpParallelLint.php @@ -20,15 +20,31 @@ use PHPCI\Model\Build; */ class PhpParallelLint implements \PHPCI\Plugin { - protected $directory; - protected $preferDist; + /** + * @var \PHPCI\Builder + */ protected $phpci; + /** + * @var string + */ + protected $directory; + + /** + * @var array - paths to ignore + */ + protected $ignore; + public function __construct(Builder $phpci, Build $build, array $options = array()) { $path = $phpci->buildPath; $this->phpci = $phpci; $this->directory = isset($options['directory']) ? $path . $options['directory'] : $path; + $this->ignore = $this->phpci->ignore; + + if (isset($options['ignore'])) { + $this->ignore = $options['ignore']; + } } /** @@ -36,10 +52,32 @@ class PhpParallelLint implements \PHPCI\Plugin */ public function execute() { - // build the parallel lint command - $cmd = "run %s"; + list($ignore) = $this->getFlags(); - // and execute it - return $this->phpci->executeCommand(PHPCI_BIN_DIR . $cmd, $this->directory); + $phplint = $this->phpci->findBinary('parallel-lint'); + + if (!$phplint) { + $this->phpci->logFailure('Could not find parallel-lint.'); + return false; + } + + $cmd = $phplint . ' %s "%s"'; + $success = $this->phpci->executeCommand( + $cmd, + $ignore, + $this->directory + ); + + return $success; + } + + protected function getFlags() + { + $ignore = ''; + if (count($this->ignore)) { + $ignore = ' --exclude ' . implode(' --exclude ', $this->ignore); + } + + return array($ignore); } } From 801cc8ee5ea9816fceded8406ea20f3eb8de2a62 Mon Sep 17 00:00:00 2001 From: Alexander Wenzel Date: Wed, 13 Nov 2013 19:55:45 +0100 Subject: [PATCH 07/12] store errors from parallel-lint as build_meta (key "phplint-errors"); add them to the "Quality Trend" graph on the build view --- PHPCI/Plugin/PhpParallelLint.php | 20 ++++++++++++++++++-- public/assets/js/build-plugins/warnings.js | 11 +++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/PHPCI/Plugin/PhpParallelLint.php b/PHPCI/Plugin/PhpParallelLint.php index 0aba3100..282098cc 100644 --- a/PHPCI/Plugin/PhpParallelLint.php +++ b/PHPCI/Plugin/PhpParallelLint.php @@ -25,6 +25,11 @@ class PhpParallelLint implements \PHPCI\Plugin */ protected $phpci; + /** + * @var \PHPCI\Model\Build + */ + protected $build; + /** * @var string */ @@ -37,11 +42,15 @@ class PhpParallelLint implements \PHPCI\Plugin public function __construct(Builder $phpci, Build $build, array $options = array()) { - $path = $phpci->buildPath; $this->phpci = $phpci; - $this->directory = isset($options['directory']) ? $path . $options['directory'] : $path; + $this->build = $build; + $this->directory = $phpci->buildPath; $this->ignore = $this->phpci->ignore; + if (isset($options['directory'])) { + $this->directory = $options['directory']; + } + if (isset($options['ignore'])) { $this->ignore = $options['ignore']; } @@ -68,6 +77,13 @@ class PhpParallelLint implements \PHPCI\Plugin $this->directory ); + $output = $this->phpci->getLastOutput(); + + $matches = array(); + if (preg_match_all('/Parse error\:/', $output, $matches)) { + $this->build->storeMeta('phplint-errors', count($matches[0])); + } + return $success; } diff --git a/public/assets/js/build-plugins/warnings.js b/public/assets/js/build-plugins/warnings.js index b77d7bfb..c485dd4e 100644 --- a/public/assets/js/build-plugins/warnings.js +++ b/public/assets/js/build-plugins/warnings.js @@ -11,8 +11,9 @@ var plugin = PHPCI.UiPlugin.extend({ 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'}) - $(window).on('phpmd-warnings phpcs-warnings phpcs-errors', function(data) { + $(window).on('phpmd-warnings phpcs-warnings phpcs-errors phplint-errors', function(data) { self.onUpdate(data); }); @@ -22,6 +23,7 @@ var plugin = PHPCI.UiPlugin.extend({ query1(); query2(); query3(); + query4(); } }); @@ -67,7 +69,12 @@ var plugin = PHPCI.UiPlugin.extend({ var keys = self.keys; for (var i in keys) { - var t = {'phpmd-warnings': 'PHPMD Warnings', 'phpcs-warnings': 'PHPCS Warnings', 'phpcs-errors': 'PHPCS Errors'}; + var t = { + 'phpmd-warnings': 'PHPMD Warnings', + 'phpcs-warnings': 'PHPCS Warnings', + 'phpcs-errors': 'PHPCS Errors', + 'phplint-errors': 'PHPLint Errors' + }; titles.push(t[keys[i]]); } From 8c127d692c825f26d1144f8a78075cd1987d778c Mon Sep 17 00:00:00 2001 From: Jimmy Cleuren Date: Mon, 18 Nov 2013 22:47:44 +0100 Subject: [PATCH 08/12] catching permission error --- PHPCI/Controller/SettingsController.php | 12 ++++++++++-- PHPCI/View/Settings/index.phtml | 8 +++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/PHPCI/Controller/SettingsController.php b/PHPCI/Controller/SettingsController.php index d0582f6a..9fce197d 100644 --- a/PHPCI/Controller/SettingsController.php +++ b/PHPCI/Controller/SettingsController.php @@ -53,9 +53,16 @@ class SettingsController extends Controller $this->settings['phpci']['github']['id'] = $this->getParam('githubid', ''); $this->settings['phpci']['github']['secret'] = $this->getParam('githubsecret', ''); - $this->storeSettings(); + $error = $this->storeSettings(); - header('Location: ' . PHPCI_URL . 'settings?saved=1'); + if($error) + { + header('Location: ' . PHPCI_URL . 'settings?saved=2'); + } + else + { + header('Location: ' . PHPCI_URL . 'settings?saved=1'); + } die; } @@ -94,6 +101,7 @@ class SettingsController extends Controller $dumper = new Dumper(); $yaml = $dumper->dump($this->settings); file_put_contents(APPLICATION_PATH . 'PHPCI/config.yml', $yaml); + if(error_get_last()) return error_get_last()['message']; } protected function getGithubForm() diff --git a/PHPCI/View/Settings/index.phtml b/PHPCI/View/Settings/index.phtml index c8206811..a88b214e 100644 --- a/PHPCI/View/Settings/index.phtml +++ b/PHPCI/View/Settings/index.phtml @@ -1,9 +1,15 @@ - +

Your settings have been saved.

+ +

+ Your settings could not be saved, maybe check the permissions of config.yml? +

+ +

Your Github account has been linked. From 4d3372af88d78d95ea6438c892279bcbe4134e16 Mon Sep 17 00:00:00 2001 From: Jimmy Cleuren Date: Mon, 18 Nov 2013 22:49:18 +0100 Subject: [PATCH 09/12] Command to poll github for new commits --- PHPCI/Command/PollCommand.php | 105 +++++++++++++++++++++++++++++++ PHPCI/Model/Base/ProjectBase.php | 39 ++++++++++++ console | 2 + 3 files changed, 146 insertions(+) create mode 100644 PHPCI/Command/PollCommand.php mode change 100755 => 100644 console diff --git a/PHPCI/Command/PollCommand.php b/PHPCI/Command/PollCommand.php new file mode 100644 index 00000000..e6a1f0de --- /dev/null +++ b/PHPCI/Command/PollCommand.php @@ -0,0 +1,105 @@ + + * @package PHPCI + * @subpackage Console + */ +class PollCommand extends Command +{ + /** + * @var \Monolog\Logger + */ + protected $logger; + + public function __construct(Logger $logger, $name = null) + { + parent::__construct($name); + $this->logger = $logger; + } + + protected function configure() + { + $this + ->setName('phpci:poll-github') + ->setDescription('Poll github to check if we need to start a build.'); + } + + /** + * Pulls all pending builds from the database and runs them. + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $parser = new Parser(); + $yaml = file_get_contents(APPLICATION_PATH . 'PHPCI/config.yml'); + $this->settings = $parser->parse($yaml); + + $token = $this->settings['phpci']['github']['token']; + + if(!$token) + { + $this->logger->error("No github token found"); + exit(); + } + + $buildStore = Factory::getStore('Build'); + + $this->logger->addInfo("Finding projects to poll"); + $projectStore = Factory::getStore('Project'); + $result = $projectStore->getWhere(); + $this->logger->addInfo(sprintf("Found %d projects", count($result['items']))); + + foreach ($result['items'] as $project) { + //$project = ProjectFactory::getProject($project); + + $http = new HttpClient('https://api.github.com'); + $commits = $http->get('/repos/' . $project->getReference() . '/commits', array('access_token' => $token)); + + $last_commit = $commits['body'][0]['sha']; + + $this->logger->info("Last commit to github for " . $project->getTitle() . " is " . $last_commit); + + if($project->getLastCommit() != $last_commit) + { + $this->logger->info("Last commit is different from database, adding new build for " . $project->getTitle()); + + $build = new Build(); + $build->setProjectId($project->getId()); + $build->setCommitId($last_commit); + $build->setStatus(0); + $build->setBranch($project->getType() === 'hg' ? 'default' : 'master'); + $build->setCreated(new \DateTime()); + + $buildStore->save($build); + + $project->setLastCommit($last_commit); + $projectStore->save($project); + } + } + + $this->logger->addInfo("Finished processing builds"); + } +} + diff --git a/PHPCI/Model/Base/ProjectBase.php b/PHPCI/Model/Base/ProjectBase.php index f23e1d7f..e3e12ecc 100644 --- a/PHPCI/Model/Base/ProjectBase.php +++ b/PHPCI/Model/Base/ProjectBase.php @@ -40,6 +40,7 @@ class ProjectBase extends Model 'type' => null, 'token' => null, 'access_information' => null, + 'last_commit' => null, ); /** @@ -54,6 +55,7 @@ class ProjectBase extends Model 'type' => 'getType', 'token' => 'getToken', 'access_information' => 'getAccessInformation', + 'last_commit' => 'getLastCommit', // Foreign key getters: ); @@ -70,6 +72,7 @@ class ProjectBase extends Model 'type' => 'setType', 'token' => 'setToken', 'access_information' => 'setAccessInformation', + 'last_commit' => 'setLastCommit', // Foreign key setters: ); @@ -115,6 +118,12 @@ class ProjectBase extends Model 'nullable' => true, 'default' => null, ), + 'last_commit' => array( + 'type' => 'varchar', + 'length' => 250, + 'nullable' => true, + 'default' => null, + ), ); /** @@ -215,6 +224,18 @@ class ProjectBase extends Model return $rtn; } + /** + * 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. * @@ -349,6 +370,24 @@ class ProjectBase extends Model $this->_setModified('access_information'); } + /** + * Set the value of LastCommit / last_commit. + * + * @param $value string + */ + public function setLastCommit($value) + { + $this->_validateString('LastCommit', $value); + + if ($this->data['last_commit'] === $value) { + return; + } + + $this->data['last_commit'] = $value; + + $this->_setModified('last_commit'); + } + /** * Get Build models by ProjectId for this Project. * diff --git a/console b/console old mode 100755 new mode 100644 index fc639be4..3358dce7 --- a/console +++ b/console @@ -17,6 +17,7 @@ use PHPCI\Command\GenerateCommand; use PHPCI\Command\UpdateCommand; use PHPCI\Command\InstallCommand; use PHPCI\Command\DaemonCommand; +use PHPCI\Command\PollCommand; use Symfony\Component\Console\Application; $loggerConfig = new \PHPCI\Helper\LoggerConfig(__DIR__ . "/loggerconfig.php"); @@ -28,5 +29,6 @@ $application->add(new InstallCommand); $application->add(new UpdateCommand($loggerConfig->GetFor('UpdateCommand'))); $application->add(new GenerateCommand); $application->add(new DaemonCommand($loggerConfig->GetFor('DaemonCommand'))); +$application->add(new PollCommand($loggerConfig->GetFor('PollCommand'))); $application->run(); From 4bc7a6c7679a7981fc8a2e1279e7bdcd98316b09 Mon Sep 17 00:00:00 2001 From: Jimmy Cleuren Date: Mon, 18 Nov 2013 22:54:49 +0100 Subject: [PATCH 10/12] Remove commented line --- PHPCI/Command/PollCommand.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/PHPCI/Command/PollCommand.php b/PHPCI/Command/PollCommand.php index e6a1f0de..511bf602 100644 --- a/PHPCI/Command/PollCommand.php +++ b/PHPCI/Command/PollCommand.php @@ -72,8 +72,6 @@ class PollCommand extends Command $this->logger->addInfo(sprintf("Found %d projects", count($result['items']))); foreach ($result['items'] as $project) { - //$project = ProjectFactory::getProject($project); - $http = new HttpClient('https://api.github.com'); $commits = $http->get('/repos/' . $project->getReference() . '/commits', array('access_token' => $token)); From 8f58902339b429632caeafb409e1cc1a14b15b14 Mon Sep 17 00:00:00 2001 From: Jimmy Cleuren Date: Tue, 19 Nov 2013 22:47:12 +0100 Subject: [PATCH 11/12] catch empty commit id from github --- PHPCI/Command/PollCommand.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/PHPCI/Command/PollCommand.php b/PHPCI/Command/PollCommand.php index 511bf602..af91acec 100644 --- a/PHPCI/Command/PollCommand.php +++ b/PHPCI/Command/PollCommand.php @@ -58,8 +58,7 @@ class PollCommand extends Command $token = $this->settings['phpci']['github']['token']; - if(!$token) - { + if (!$token) { $this->logger->error("No github token found"); exit(); } @@ -79,8 +78,7 @@ class PollCommand extends Command $this->logger->info("Last commit to github for " . $project->getTitle() . " is " . $last_commit); - if($project->getLastCommit() != $last_commit) - { + if ($project->getLastCommit() != $last_commit && $last_commit != "") { $this->logger->info("Last commit is different from database, adding new build for " . $project->getTitle()); $build = new Build(); From db3fcb45d6bafcb1f4bcf25a6876d400c76ce0da Mon Sep 17 00:00:00 2001 From: "steve.brazier" Date: Wed, 27 Nov 2013 08:49:03 +0000 Subject: [PATCH 12/12] remove callable typehint as this is not in php 5.3 --- PHPCI/Plugin/Util/Factory.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/PHPCI/Plugin/Util/Factory.php b/PHPCI/Plugin/Util/Factory.php index 4e6065e6..09cd44cf 100644 --- a/PHPCI/Plugin/Util/Factory.php +++ b/PHPCI/Plugin/Util/Factory.php @@ -75,7 +75,7 @@ class Factory { * @throws \InvalidArgumentException * @internal param mixed $resource */ - public function registerResource(callable $loader, + public function registerResource($loader, $name = null, $type = null ) @@ -86,6 +86,12 @@ class Factory { ); } + if (!($loader instanceof \Closure)) { + throw new \InvalidArgumentException( + '$loader is expected to be a function' + ); + } + $resourceID = $this->getInternalID($type, $name); $this->container[$resourceID] = $loader;