From 33858d801d08fc624dfb89fff4ae6eb64dc020de Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Sun, 10 Jan 2021 12:45:40 +0700 Subject: [PATCH 001/212] Updated releases in README.md. --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7a688dabd..c19e8543b 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,14 @@ PHP Censor versions: -| Version | Latest | Branch | Status | Minimal PHP Version | -| :------------------: | :------: | :-----------: | :-------------------------------------: | :-----------------: | -| `1.0` (Morty Smith) | `1.0.16` | `release-1.0` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | -| `1.1` (Birdperson) | `1.1.6` | `release-1.1` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | -| `1.2` (Summer Smith) | `1.2.4` | `release-1.2` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | -| `1.3` (Jerry Smith) | `1.3.0` | `release-1.3` | Current stable version (**ONLY FIXES**) | `>=5.6, <8.0` | -| `2.0` (Rick Sanchez) | WIP | `master` | Future stable major version (WIP) | `>=7.4` | +| Version | Latest | Branch | Status | Minimal PHP Version | +| :------------------: | :------: | :-----------: | :---------------------------------: | :-----------------: | +| `1.0` (Morty Smith) | `1.0.16` | `release-1.0` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | +| `1.1` (Birdperson) | `1.1.6` | `release-1.1` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | +| `1.2` (Summer Smith) | `1.2.4` | `release-1.2` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | +| `1.3` (Jerry Smith) | `1.3.0` | `release-1.3` | Old stable version (**ONLY FIXES**) | `>=5.6, <8.0` | +| `2.0` (Rick Sanchez) | `2.0.0` | `release-2.0` | Current stable version | `>=7.4` | +| `2.1` | WIP | `master` | Feature minor version (WIP) | `>=7.4` | [![Dashboard](docs/screenshots/dashboard.png)](docs/screenshots/dashboard.png) From 64243fe3ee1f29befdc0820b8c830dfe6b7abca3 Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Sun, 21 Mar 2021 16:42:58 +0700 Subject: [PATCH 002/212] Fixed versions in README.md. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 419df8f58..961b7e3ce 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ PHP Censor versions: | `1.0` (Morty Smith) | `1.0.16` | `release-1.0` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | | `1.1` (Birdperson) | `1.1.6` | `release-1.1` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | | `1.2` (Summer Smith) | `1.2.4` | `release-1.2` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | -| `1.3` (Jerry Smith) | `1.3.0` | `release-1.3` | Old stable version (**ONLY FIXES**) | `>=5.6, <8.0` | -| `2.0` (Rick Sanchez) | `2.0.0` | `release-2.0` | Current stable version | `>=7.4` | +| `1.3` (Jerry Smith) | `1.3.2` | `release-1.3` | Old stable version (**ONLY FIXES**) | `>=5.6, <8.0` | +| `2.0` (Rick Sanchez) | `2.0.2` | `release-2.0` | Current stable version | `>=7.4` | | `2.1` | WIP | `master` | Feature minor version (WIP) | `>=7.4` | [![Dashboard](docs/screenshots/dashboard.png)](docs/screenshots/dashboard.png) From f5368a134d5b9e3a39ec137485b4b18b08e53069 Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Fri, 2 Apr 2021 23:27:51 +0700 Subject: [PATCH 003/212] Small typo fix. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5230daa8a..76c5b0570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,7 +51,7 @@ binary (Symfony CLI) or `fabpot/local-php-security-checker` tool for working. Se [Full Changelog](https://github.com/php-censor/php-censor/compare/1.3.0...2.0.0) -### [How tp upgrade from v1 to v2](/docs/UPGRADE_2.0.md) +### [How to upgrade from v1 to v2](/docs/UPGRADE_2.0.md) ### Changed From 0b52167c21749fd1cbf270eb217dd6b7e97d1be3 Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Sat, 3 Apr 2021 22:46:59 +0700 Subject: [PATCH 004/212] Added "environment" GET parameter for Git webhook. Issue #407. --- src/Controller/WebhookController.php | 127 ++++++++++++++++++++------- 1 file changed, 95 insertions(+), 32 deletions(-) diff --git a/src/Controller/WebhookController.php b/src/Controller/WebhookController.php index 3243bb115..c14baedb6 100644 --- a/src/Controller/WebhookController.php +++ b/src/Controller/WebhookController.php @@ -17,6 +17,7 @@ use PHPCensor\Model\Project; use PHPCensor\Service\BuildService; use PHPCensor\Store\BuildStore; +use PHPCensor\Store\EnvironmentStore; use PHPCensor\Store\Factory; use PHPCensor\Store\ProjectStore; @@ -106,7 +107,8 @@ protected function createBuild( $tag, $committer, $commitMessage, - array $extra = null + array $extra = null, + $environment = null ) { if ($project->getArchived()) { throw new NotFoundException(Lang::get('project_x_not_found', $project->getId())); @@ -135,36 +137,38 @@ protected function createBuild( $environments = $project->getEnvironmentsObjects(); if ($environments['count']) { - $createdBuilds = []; - $environmentIds = $project->getEnvironmentsNamesByBranch($branch); - // use base branch from project - if (!empty($environmentIds)) { - $duplicates = []; - foreach ($environmentIds as $environmentId) { - if (!in_array($environmentId, $ignoreEnvironments) || - ($tag && !in_array($tag, $ignoreTags, true))) { - // If not, create a new build job for it: - $build = $this->buildService->createBuild( - $project, - $environmentId, - $commitId, - $project->getDefaultBranch(), - $tag, - $committer, - $commitMessage, - (int)$source, - null, - $extra - ); - - $createdBuilds[] = [ - 'id' => $build->getID(), - 'environment' => $environmentId, - ]; - } else { - $duplicates[] = \array_search($environmentId, $ignoreEnvironments); - } + $createdBuilds = []; + + /** @var EnvironmentStore $environmentStore */ + $environmentStore = Factory::getStore('Environment'); + $environmentObject = $environmentStore->getByNameAndProjectId($environment, $project->getId()); + if ($environment && $environmentObject) { + if ( + !in_array($environmentObject->getId(), $ignoreEnvironments) || + ($tag && !in_array($tag, $ignoreTags, true)) + ) { + // If not, create a new build job for it: + $build = $this->buildService->createBuild( + $project, + $environmentObject->getId(), + $commitId, + $project->getDefaultBranch(), + $tag, + $committer, + $commitMessage, + (int)$source, + null, + $extra + ); + + $createdBuilds[] = [ + 'id' => $build->getID(), + 'environment' => $environmentObject->getId(), + ]; + } else { + $duplicates[] = \array_search($environmentObject->getId(), $ignoreEnvironments); } + if (!empty($createdBuilds)) { if (empty($duplicates)) { return ['status' => 'ok', 'builds' => $createdBuilds]; @@ -188,7 +192,63 @@ protected function createBuild( ]; } } else { - return ['status' => 'ignored', 'message' => 'Branch not assigned to any environment']; + $environmentIds = $project->getEnvironmentsNamesByBranch($branch); + // use base branch from project + if (!empty($environmentIds)) { + $duplicates = []; + foreach ($environmentIds as $environmentId) { + if ( + !in_array($environmentId, $ignoreEnvironments) || + ($tag && !in_array($tag, $ignoreTags, true)) + ) { + // If not, create a new build job for it: + $build = $this->buildService->createBuild( + $project, + $environmentId, + $commitId, + $project->getDefaultBranch(), + $tag, + $committer, + $commitMessage, + (int)$source, + null, + $extra + ); + + $createdBuilds[] = [ + 'id' => $build->getID(), + 'environment' => $environmentId, + ]; + } else { + $duplicates[] = \array_search($environmentId, $ignoreEnvironments); + } + } + + if (!empty($createdBuilds)) { + if (empty($duplicates)) { + return ['status' => 'ok', 'builds' => $createdBuilds]; + } else { + return [ + 'status' => 'ok', + 'builds' => $createdBuilds, + 'message' => sprintf( + 'For this commit some builds already exists (%s)', + implode(', ', $duplicates) + ) + ]; + } + } else { + return [ + 'status' => 'ignored', + 'message' => sprintf( + 'For this commit already created builds (%s)', + implode(', ', $duplicates) + ) + ]; + } + } else { + return ['status' => 'ignored', 'message' => 'Branch not assigned to any environment']; + } } } else { $environmentId = null; @@ -272,6 +332,7 @@ public function git($projectId) Project::TYPE_GIT, ]); $branch = $this->getParam('branch', $project->getDefaultBranch()); + $environment = $this->getParam('environment'); $commit = $this->getParam('commit'); $commitMessage = $this->getParam('message'); $committer = $this->getParam('committer'); @@ -283,7 +344,9 @@ public function git($projectId) $branch, null, $committer, - $commitMessage + $commitMessage, + null, + $environment ); } From bbd235ae6d239e2c2fdcf48d5138b20124d86e0e Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 19 May 2021 22:12:13 +0700 Subject: [PATCH 005/212] Refactoring: Improved application configuration. --- bin/console | 4 +- bootstrap.php | 52 ++--- composer.json | 2 + composer.lock | 73 +++++- public/index.php | 7 +- src/Application.php | 34 ++- src/BuildFactory.php | 18 +- src/Builder.php | 94 ++------ src/Command/Action/CreateAdmin.php | 105 +++++++++ src/Command/CheckLocalizationCommand.php | 99 +++------ src/Command/Command.php | 81 +++++++ src/Command/CreateAdminCommand.php | 87 +++----- src/Command/CreateBuildCommand.php | 43 ++-- src/Command/InstallCommand.php | 185 ++++++--------- src/Command/LoggingCommand.php | 74 ------ src/Command/RebuildQueueCommand.php | 51 +---- src/Command/RemoveOldBuildsCommand.php | 51 +++-- src/Command/WorkerCommand.php | 36 ++- src/Config.php | 210 ------------------ src/Configuration.php | 37 +++ src/ConfigurationInterface.php | 11 + src/Console/Application.php | 51 +++-- src/Controller.php | 12 +- src/Controller/BuildController.php | 20 +- src/Controller/BuildStatusController.php | 2 +- src/Controller/HomeController.php | 3 +- src/Controller/ProjectController.php | 8 +- src/Controller/SessionController.php | 5 +- src/Controller/UserController.php | 5 +- src/Controller/WebhookController.php | 11 +- src/Controller/WidgetLastBuildsController.php | 4 +- src/Database.php | 10 +- src/DatabaseConnection.php | 107 +++++++++ src/DatabaseManager.php | 103 +++++++++ src/Form/DataTransformer/Yaml.php | 4 +- src/Helper/AnsiConverter.php | 46 ---- src/Helper/Bitbucket.php | 21 +- src/Helper/Email.php | 6 +- src/Helper/Github.php | 13 +- src/Helper/Lang.php | 8 +- src/Helper/SshKey.php | 13 +- src/Http/Router.php | 13 +- src/Logging/AnsiFormatter.php | 4 +- src/Logging/BuildLogger.php | 86 ++----- src/Logging/OutputLogHandler.php | 9 +- src/Model/Build/BitbucketBuild.php | 19 +- src/Model/Build/GitBuild.php | 12 + src/Model/Build/GithubBuild.php | 14 +- src/Model/User.php | 9 +- src/Plugin/EmailNotify.php | 4 +- src/Plugin/Option/PhpUnitOptions.php | 34 ++- src/Plugin/Pdepend.php | 4 +- src/Plugin/PhpUnit.php | 6 +- src/ProcessControl/Factory.php | 54 ----- src/ProcessControl/PosixProcessControl.php | 42 ---- .../ProcessControlInterface.php | 30 --- src/ProcessControl/UnixProcessControl.php | 50 ----- src/Security/Authentication/Service.php | 40 +--- src/Service/BuildService.php | 43 ++-- src/Store/BuildErrorWriter.php | 27 ++- src/View.php | 11 - src/View/Email/long.phtml | 7 +- src/View/layout.phtml | 4 +- src/WebController.php | 7 +- src/Worker/BuildWorker.php | 67 ++---- tests/bootstrap.php | 34 +-- tests/data/configuration.yml | 2 + tests/src/Command/CreateAdminCommandTest.php | 12 +- tests/src/Command/CreateBuildCommandTest.php | 12 +- tests/src/ConfigurationTest.php | 25 +++ tests/src/DatabaseMysqlTest.php | 0 tests/src/DatabasePostgresqlTest.php | 0 tests/src/Helper/AnsiConverterTest.php | 6 +- tests/src/Helper/EmailTest.php | 4 +- tests/src/Logging/AnsiFormatterTest.php | 31 +++ tests/src/Logging/BuildLogger2Test.php | 22 ++ tests/src/Logging/OutputLogHandlerTest.php | 35 +++ tests/src/Model/BuildTest.php | 3 + tests/src/Plugin/EmailTest.php | 4 +- .../src/Plugin/Option/PhpUnitOptionsTest.php | 8 +- tests/src/Plugin/PhpUnitTest.php | 20 +- .../PosixProcessControlTest.php | 18 -- .../src/ProcessControl/ProcessControlTest.php | 130 ----------- .../ProcessControl/UnixProcessControlTest.php | 23 -- .../Security/Authentication/ServiceTest.php | 13 +- tests/src/Service/BuildServiceTest.php | 24 +- tests/src/StoreMysqlTest.php | 0 tests/src/StorePostgresqlTest.php | 0 88 files changed, 1238 insertions(+), 1590 deletions(-) create mode 100644 src/Command/Action/CreateAdmin.php create mode 100644 src/Command/Command.php delete mode 100644 src/Command/LoggingCommand.php delete mode 100644 src/Config.php create mode 100644 src/Configuration.php create mode 100644 src/ConfigurationInterface.php create mode 100644 src/DatabaseConnection.php create mode 100644 src/DatabaseManager.php delete mode 100644 src/Helper/AnsiConverter.php delete mode 100644 src/ProcessControl/Factory.php delete mode 100644 src/ProcessControl/PosixProcessControl.php delete mode 100644 src/ProcessControl/ProcessControlInterface.php delete mode 100644 src/ProcessControl/UnixProcessControl.php create mode 100644 tests/data/configuration.yml create mode 100644 tests/src/ConfigurationTest.php delete mode 100644 tests/src/DatabaseMysqlTest.php delete mode 100644 tests/src/DatabasePostgresqlTest.php create mode 100644 tests/src/Logging/AnsiFormatterTest.php create mode 100644 tests/src/Logging/BuildLogger2Test.php create mode 100644 tests/src/Logging/OutputLogHandlerTest.php delete mode 100644 tests/src/ProcessControl/PosixProcessControlTest.php delete mode 100644 tests/src/ProcessControl/ProcessControlTest.php delete mode 100644 tests/src/ProcessControl/UnixProcessControlTest.php delete mode 100644 tests/src/StoreMysqlTest.php delete mode 100644 tests/src/StorePostgresqlTest.php diff --git a/bin/console b/bin/console index 591f7fd43..32cf66b17 100755 --- a/bin/console +++ b/bin/console @@ -1,11 +1,13 @@ #!/usr/bin/env php run(); +(new Application($configuration))->run(); diff --git a/bootstrap.php b/bootstrap.php index c9bd92bb8..7480aa55a 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -1,48 +1,22 @@ loadYaml($configFile); -} +Database::$configuration = $configuration; -if (!defined('APP_URL') && !empty($config)) { - define('APP_URL', $config->get('php-censor.url', '') . '/'); -} +\define('APP_URL', $configuration->get('php-censor.url', '') . '/'); -Lang::init($config); +Lang::init($configuration); diff --git a/composer.json b/composer.json index 32dfdf526..f299e4ccd 100644 --- a/composer.json +++ b/composer.json @@ -55,6 +55,8 @@ "ext-curl": "*", "ext-bcmath": "*", + "php-censor/common": "dev-master", + "swiftmailer/swiftmailer": "^6.2", "symfony/yaml": "^4.4", "symfony/console": "^4.4", diff --git a/composer.lock b/composer.lock index 8c7f96c0d..5c279927c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3ee10151a1e6af40476ea0e3035893be", + "content-hash": "dd218b940a7209cfbb51dbfe3a08f7c2", "packages": [ { "name": "cakephp/core", @@ -883,6 +883,73 @@ }, "time": "2020-09-22T07:17:48+00:00" }, + { + "name": "php-censor/common", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-censor/common.git", + "reference": "6b36aa2e5e95a18aab130611e209f81f48a3ae28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-censor/common/zipball/6b36aa2e5e95a18aab130611e209f81f48a3ae28", + "reference": "6b36aa2e5e95a18aab130611e209f81f48a3ae28", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.4.0", + "psr/container": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "infection/infection": "^0.12", + "phpunit/phpunit": "^7.5", + "vimeo/psalm": "^3.16" + }, + "default-branch": true, + "type": "library", + "extra": { + "platform": { + "php": "7.4.*" + } + }, + "autoload": { + "psr-4": { + "PHPCensor\\Common\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Dmitry Khomutov", + "email": "poisoncorpsee@gmail.com", + "homepage": "http://corpsee.com", + "role": "PHP Censor developer" + } + ], + "description": "PHP Censor Common Library", + "homepage": "https://php-censor.info", + "keywords": [ + "ci", + "ci-server", + "continuous integration", + "open-source", + "php", + "php-censor", + "self-hosted", + "testing" + ], + "support": { + "issues": "https://github.com/php-censor/common/issues", + "source": "https://github.com/php-censor/common" + }, + "time": "2021-04-25T06:46:27+00:00" + }, { "name": "php-censor/flowdock-client", "version": "1.0.0", @@ -6926,7 +6993,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "php-censor/common": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/public/index.php b/public/index.php index 753adf5e2..e7a5d4410 100644 --- a/public/index.php +++ b/public/index.php @@ -1,8 +1,11 @@ handleRequest(); diff --git a/src/Application.php b/src/Application.php index 5e9be7850..4ce3edbbb 100644 --- a/src/Application.php +++ b/src/Application.php @@ -17,46 +17,45 @@ class Application { /** - * @var array + * @var array|null */ - protected $route; + protected ?array $route; /** * @var Controller|WebController */ - protected $controller; + protected Controller $controller; /** * @var Request */ - protected $request; + protected Request $request; /** - * @var Config + * @var ConfigurationInterface */ - protected $config; + protected ConfigurationInterface $config; /** * @var Router */ - protected $router; + protected Router $router; /** - * @param Config $config + * @param ConfigurationInterface $config * * @param Request|null $request */ - public function __construct(Config $config, Request $request = null) + public function __construct(ConfigurationInterface $config, Request $request = null) { $this->config = $config; + $this->request = new Request(); if (!is_null($request)) { $this->request = $request; - } else { - $this->request = new Request(); } - $this->router = new Router($this, $this->request, $this->config); + $this->router = new Router($this, $this->request); $this->init(); } @@ -149,8 +148,6 @@ public function handleRequest() try { $response = $this->handleRequestInner(); } catch (HttpException $ex) { - $this->config->set('page_title', 'Error'); - $view = new View('exception'); $view->exception = $ex; @@ -159,8 +156,6 @@ public function handleRequest() $response->setResponseCode($ex->getErrorCode()); $response->setContent($view->render()); } catch (Exception $ex) { - $this->config->set('page_title', 'Error'); - $view = new View('exception'); $view->exception = $ex; @@ -195,11 +190,10 @@ protected function loadController($class) * * @return bool */ - protected function shouldSkipAuth() + protected function shouldSkipAuth(): bool { - $config = Config::getInstance(); - $disableAuth = (bool)$config->get('php-censor.security.disable_auth', false); - $defaultUserId = (int)$config->get('php-censor.security.default_user_id', 1); + $disableAuth = (bool)$this->config->get('php-censor.security.disable_auth', false); + $defaultUserId = (int)$this->config->get('php-censor.security.default_user_id', 1); if ($disableAuth && $defaultUserId) { $user = Factory::getStore('User')->getByPrimaryKey($defaultUserId); diff --git a/src/BuildFactory.php b/src/BuildFactory.php index cce0531ae..67051e2a9 100644 --- a/src/BuildFactory.php +++ b/src/BuildFactory.php @@ -14,13 +14,14 @@ class BuildFactory { /** - * @param int $buildId + * @param ConfigurationInterface $configuration + * @param int $buildId * * @return Build|null * * @throws Exception\HttpException */ - public static function getBuildById($buildId) + public static function getBuildById(ConfigurationInterface $configuration, int $buildId): ?Build { $build = Factory::getStore('Build')->getById($buildId); @@ -28,20 +29,23 @@ public static function getBuildById($buildId) return null; } - return self::getBuild($build); + return self::getBuild($configuration, $build); } /** * Takes a generic build and returns a type-specific build model. * - * @param Build $build The build from which to get a more specific build type. + * @param ConfigurationInterface $configuration + * @param Build $build * * @return Build * * @throws Exception\HttpException */ - public static function getBuild(Build $build) - { + public static function getBuild( + ConfigurationInterface $configuration, + Build $build + ): Build { $project = $build->getProject(); if (!empty($project)) { @@ -81,7 +85,7 @@ public static function getBuild(Build $build) } $class = '\\PHPCensor\\Model\\Build\\' . $type; - $build = new $class($build->getDataArray()); + $build = new $class($configuration, $build->getDataArray()); } return $build; diff --git a/src/Builder.php b/src/Builder.php index 1a66a885c..c4a139ef2 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -13,14 +13,13 @@ use PHPCensor\Store\BuildErrorWriter; use PHPCensor\Store\BuildStore; use PHPCensor\Store\Factory; -use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; /** * @author Dan Cryer */ -class Builder implements LoggerAwareInterface +class Builder { /** * @var string @@ -107,16 +106,20 @@ class Builder implements LoggerAwareInterface */ private $buildErrorWriter; + private ConfigurationInterface $configuration; + /** * Set up the builder. * - * @param Build $build + * @param ConfigurationInterface $configuration + * @param Build $build * @param LoggerInterface $logger */ - public function __construct(Build $build, LoggerInterface $logger = null) + public function __construct(ConfigurationInterface $configuration, Build $build, LoggerInterface $logger = null) { - $this->build = $build; - $this->store = Factory::getStore('Build'); + $this->configuration = $configuration; + $this->build = $build; + $this->store = Factory::getStore('Build'); $this->buildLogger = new BuildLogger($logger, $build); $pluginFactory = $this->buildPluginFactory($build); @@ -130,21 +133,20 @@ public function __construct(Build $build, LoggerInterface $logger = null) ); $this->interpolator = new BuildInterpolator(); - $this->buildErrorWriter = new BuildErrorWriter($this->build->getProjectId(), $this->build->getId()); + $this->buildErrorWriter = new BuildErrorWriter($this->configuration, $this->build->getProjectId(), $this->build->getId()); } - /** - * @return BuildLogger - */ - public function getBuildLogger() + public function getBuildLogger(): BuildLogger { return $this->buildLogger; } - /** - * @return null|string - */ - public function getCurrentStage() + public function getConfiguration(): ConfigurationInterface + { + return $this->configuration; + } + + public function getCurrentStage(): ?string { return $this->currentStage; } @@ -189,17 +191,7 @@ public function getConfig($key = null) */ public function getSystemConfig($key) { - return Config::getInstance()->get($key); - } - - /** - * @return string The title of the project being built. - * - * @throws Exception\HttpException - */ - public function getBuildProjectTitle() - { - return $this->build->getProject()->getTitle(); + return $this->configuration->get($key); } /** @@ -292,7 +284,7 @@ public function execute() $this->build->sendStatusPostback(); $this->build->setFinishDate(new DateTime()); - $removeBuilds = (bool)Config::getInstance()->get('php-censor.build.remove_builds', true); + $removeBuilds = (bool)$this->configuration->get('php-censor.build.remove_builds', true); if ($removeBuilds) { // Clean up: $this->buildLogger->log(''); @@ -474,65 +466,27 @@ protected function setupBuild() return true; } - /** - * Sets a logger instance on the object - * - * @param LoggerInterface $logger - */ - public function setLogger(LoggerInterface $logger) - { - $this->buildLogger->setLogger($logger); - } - - /** - * Write to the build log. - * - * @param string $message - * @param string $level - * @param array $context - */ - public function log($message, $level = LogLevel::INFO, $context = []) + public function log(string $message, string $level = LogLevel::INFO, array $context = []): void { $this->buildLogger->log($message, $level, $context); } - /** - * Add a warning-coloured message to the log. - * - * @param string $message - */ - public function logWarning($message) + public function logWarning(string $message): void { $this->buildLogger->logWarning($message); } - /** - * Add a success-coloured message to the log. - * - * @param string $message - */ - public function logSuccess($message) + public function logSuccess(string $message): void { $this->buildLogger->logSuccess($message); } - /** - * Add a failure-coloured message to the log. - * - * @param string $message - * @param Exception $exception The exception that caused the error. - */ - public function logFailure($message, Exception $exception = null) + public function logFailure(string $message, ?\Throwable $exception = null): void { $this->buildLogger->logFailure($message, $exception); } - /** - * Add a debug-coloured message to the log. - * - * @param string $message - */ - public function logDebug($message) + public function logDebug(string $message): void { $this->buildLogger->logDebug($message); } diff --git a/src/Command/Action/CreateAdmin.php b/src/Command/Action/CreateAdmin.php new file mode 100644 index 000000000..17a6e5dc5 --- /dev/null +++ b/src/Command/Action/CreateAdmin.php @@ -0,0 +1,105 @@ + + */ +class CreateAdmin +{ + private QuestionHelper $questionHelper; + + private InputInterface $input; + + private OutputInterface $output; + + private UserStore $userStore; + + public function __construct( + QuestionHelper $questionHelper, + InputInterface $input, + OutputInterface $output, + UserStore $userStore + ) { + $this->questionHelper = $questionHelper; + $this->input = $input; + $this->output = $output; + $this->userStore = $userStore; + } + + public function process(): array + { + $result = []; + $mailValidator = function ($answer) { + if (!\filter_var($answer, FILTER_VALIDATE_EMAIL)) { + throw new InvalidArgumentException('Must be a valid email address.'); + } + + return $answer; + }; + + if ($adminEmail = $this->input->getOption('admin-email')) { + $adminEmail = $mailValidator($adminEmail); + } else { + $questionEmail = new Question('Admin email: '); + $adminEmail = $this->questionHelper->ask($this->input, $this->output, $questionEmail); + } + + if (!$adminName = $this->input->getOption('admin-name')) { + $questionName = new Question('Admin name: '); + $adminName = $this->questionHelper->ask($this->input, $this->output, $questionName); + } + + if (!$adminPassword = $this->input->getOption('admin-password')) { + $questionPassword = new Question('Admin password: '); + $questionPassword->setHidden(true); + $questionPassword->setHiddenFallback(false); + $adminPassword = $this->questionHelper->ask($this->input, $this->output, $questionPassword); + } + + $result['email'] = $adminEmail; + $result['name'] = $adminName; + $result['password'] = $adminPassword; + + return $result; + } + + public function create(array $adminDetails): void + { + try { + $adminUser = $this->userStore->getByEmail($adminDetails['email']); + if ($adminUser) { + throw new \RuntimeException('Admin account already exists!'); + } + + $userService = new UserService($this->userStore); + + $userService->createUser( + $adminDetails['name'], + $adminDetails['email'], + 'internal', + ['type' => 'internal'], + $adminDetails['password'], + true + ); + + $this->output->writeln('User account created!'); + } catch (\Throwable $ex) { + $this->output->writeln('PHP Censor failed to create your admin account!'); + $this->output->writeln('' . $ex->getMessage() . ''); + } + } +} diff --git a/src/Command/CheckLocalizationCommand.php b/src/Command/CheckLocalizationCommand.php index a8ae6ea75..0a5e066a3 100644 --- a/src/Command/CheckLocalizationCommand.php +++ b/src/Command/CheckLocalizationCommand.php @@ -1,65 +1,36 @@ */ class CheckLocalizationCommand extends Command { - /** - * @var string - */ - protected $basePath; - - /** - * @var array - */ - protected $excluded = ['lang.en.php']; - - /** - * Construct. - */ - public function __construct() - { - parent::__construct(); + protected string $basePath = __DIR__ . '/../Languages'; - $this->basePath = __DIR__.'/../Languages'; - } + protected array $excluded = ['lang.en.php']; - /** - * Configure. - */ protected function configure() { $this ->setName('php-censor:check-localizations') - ->addOption( - 'same', - 0, - InputOption::VALUE_OPTIONAL, - 'Same than English version (0 = no, 1 = yes)' - ) - ->addOption( - 'langs', - [], - InputOption::VALUE_OPTIONAL, - 'List of languages separated by commas. By default, all languages' - ) + + ->addOption('same', 0, InputOption::VALUE_OPTIONAL, 'Same than English version (0 = no, 1 = yes)') + ->addOption('langs', [], InputOption::VALUE_OPTIONAL, 'List of languages separated by commas. By default, all languages') + ->setDescription('Check localizations.'); } - /** - * Loops through running. - * - * @param InputInterface $input - * @param OutputInterface $output - */ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("\nCheck localizations!"); @@ -69,7 +40,7 @@ protected function execute(InputInterface $input, OutputInterface $output) : false; $languagesList = (null !== $input->getOption('langs')) - ? explode(',', $input->getOption('langs')) + ? \explode(',', $input->getOption('langs')) : []; // Get English version @@ -78,54 +49,40 @@ protected function execute(InputInterface $input, OutputInterface $output) $diffs = $this->compareTranslations($english, $othersLanguages); foreach ($diffs as $language => $value) { - $output->writeln(sprintf("%s:", $language)); + $output->writeln(\sprintf("%s:", $language)); if (!empty($value['not_present'])) { - $output->writeln("\tNot present:\n\t\t" . implode("\n\t\t", $value['not_present'])); + $output->writeln("\tNot present:\n\t\t" . \implode("\n\t\t", $value['not_present'])); } if ($sameThanEnglish === '1' && !empty($value['same'])) { - $output->writeln("\tSame than English:\n\t\t" . implode("\n\t\t", $value['same'])); + $output->writeln("\tSame than English:\n\t\t" . \implode("\n\t\t", $value['same'])); } } } - /** - * Returns array of translations by language. - * - * @param string $language language code - * - * @return array - */ - private function getTranslations($language) + private function getTranslations(string $language): array { return [ - include($language) + include $language, ]; } - /** - * Returns list of languages. - * - * @param array $languagesList - * - * @return array - */ - private function getLanguages(array $languagesList = []) + private function getLanguages(array $languagesList = []): array { - $files = glob($this->basePath . '/*.php'); + $files = \glob($this->basePath . '/*.php'); - $languages = array_map(function ($dir) use ($languagesList) { - $name = basename($dir); + $languages = \array_map(function ($dir) use ($languagesList) { + $name = \basename($dir); - if (in_array($name, $this->excluded, true)) { + if (\in_array($name, $this->excluded, true)) { return null; } // Check if in list of languages. if (!empty($languagesList)) { - $languageOfName = explode('.', $name); + $languageOfName = \explode('.', $name); - if (null == $languageOfName[1] || !in_array($languageOfName[1], $languagesList)) { + if (null == $languageOfName[1] || !\in_array($languageOfName[1], $languagesList)) { return null; } } @@ -133,7 +90,7 @@ private function getLanguages(array $languagesList = []) return $name; }, $files); - return array_filter($languages); + return \array_filter($languages); } /** @@ -144,7 +101,7 @@ private function getLanguages(array $languagesList = []) * * @return array */ - private function compareTranslations(array $default, array $languages) + private function compareTranslations(array $default, array $languages): array { $diffs = []; @@ -153,7 +110,7 @@ private function compareTranslations(array $default, array $languages) $current = $this->getTranslations($this->basePath.'/'.$language); foreach ($default as $key => $values) { - $keyValues = array_keys($values); + $keyValues = \array_keys($values); foreach ($keyValues as $key2) { if (!isset($current[$key][$key2])) { diff --git a/src/Command/Command.php b/src/Command/Command.php new file mode 100644 index 000000000..78e44ff5b --- /dev/null +++ b/src/Command/Command.php @@ -0,0 +1,81 @@ + + */ +abstract class Command extends BaseCommand +{ + protected ConfigurationInterface $configuration; + + protected LoggerInterface $logger; + + public function __construct( + ConfigurationInterface $configuration, + LoggerInterface $logger, + ?string $name = null + ) { + parent::__construct($name); + + $this->configuration = $configuration; + $this->logger = $logger; + } + + protected function configureLogging(OutputInterface $output) + { + $level = LogLevel::ERROR; + if ($output->isDebug()) { + $level = LogLevel::DEBUG; + } elseif ($output->isVeryVerbose()) { + $level = LogLevel::INFO; + } elseif ($output->isVerbose()) { + $level = LogLevel::NOTICE; + } + + if ($this->logger instanceof Logger) { + $handlers = $this->logger->getHandlers(); + foreach ($handlers as $handler) { + if ($handler instanceof AbstractHandler) { + $handler->setLevel($level); + } + } + + if (!$output->isQuiet()) { + $this->logger->pushHandler( + new OutputLogHandler($output, $level) + ); + } + } + + if ($output->isDebug()) { + $this->logger->notice( + \sprintf('Command "%s" started in debug mode (-vvv).', $this->getName()) + ); + + \define('DEBUG_MODE', true); + } + } + + protected function execute( + InputInterface $input, + OutputInterface $output + ) { + $this->configureLogging($output); + } +} diff --git a/src/Command/CreateAdminCommand.php b/src/Command/CreateAdminCommand.php index c9f660af0..132605bea 100644 --- a/src/Command/CreateAdminCommand.php +++ b/src/Command/CreateAdminCommand.php @@ -1,12 +1,15 @@ * @author Wogan May (@woganmay) */ class CreateAdminCommand extends Command { - /** - * @var UserStore - */ - protected $userStore; + protected UserStore $userStore; - /** - * @param UserStore $userStore - */ - public function __construct(UserStore $userStore) - { - parent::__construct(); + public function __construct( + ConfigurationInterface $configuration, + LoggerInterface $logger, + UserStore $userStore, + ?string $name = null + ) { + parent::__construct($configuration, $logger, $name); $this->userStore = $userStore; } @@ -47,52 +50,20 @@ protected function configure() ->setDescription('Create an admin user'); } - /** - * Creates an admin user in the existing database - * - * {@inheritDoc} - */ protected function execute(InputInterface $input, OutputInterface $output) { - /** @var $helper QuestionHelper */ - $helper = $this->getHelperSet()->get('question'); - - // Function to validate email address. - $mailValidator = function ($answer) { - if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) { - throw new InvalidArgumentException('Must be a valid email address.'); - } - - return $answer; - }; - - if ($adminEmail = $input->getOption('admin-email')) { - $adminEmail = $mailValidator($adminEmail); - } else { - $questionEmail = new Question('Admin email: '); - $adminEmail = $helper->ask($input, $output, $questionEmail); - } - - if (!$adminName = $input->getOption('admin-name')) { - $questionName = new Question('Admin name: '); - $adminName = $helper->ask($input, $output, $questionName); - } - - if (!$adminPassword = $input->getOption('admin-password')) { - $questionPassword = new Question('Admin password: '); - $questionPassword->setHidden(true); - $questionPassword->setHiddenFallback(false); - $adminPassword = $helper->ask($input, $output, $questionPassword); - } - - try { - $userService = new UserService($this->userStore); - $userService->createUser($adminName, $adminEmail, 'internal', ['type' => 'internal'], $adminPassword, true); - - $output->writeln('User account created!'); - } catch (Exception $ex) { - $output->writeln('PHP Censor failed to create your admin account!'); - $output->writeln('' . $ex->getMessage() . ''); - } + /** @var $questionHelper QuestionHelper */ + $questionHelper = $this->getHelperSet()->get('question'); + + $createAdmin = new CreateAdmin( + $questionHelper, + $input, + $output, + $this->userStore + ); + + $createAdmin->create( + $createAdmin->process() + ); } } diff --git a/src/Command/CreateBuildCommand.php b/src/Command/CreateBuildCommand.php index 531547f00..c39266ccc 100644 --- a/src/Command/CreateBuildCommand.php +++ b/src/Command/CreateBuildCommand.php @@ -1,52 +1,48 @@ * @author Jérémy DECOOL (@jdecool) */ class CreateBuildCommand extends Command { - /** - * @var ProjectStore - */ - protected $projectStore; + protected ProjectStore $projectStore; - /** - * @var BuildService - */ - protected $buildService; + protected BuildService $buildService; - /** - * @param ProjectStore $projectStore - * @param BuildService $buildService - */ - public function __construct(ProjectStore $projectStore, BuildService $buildService) - { - parent::__construct(); + public function __construct( + ConfigurationInterface $configuration, + LoggerInterface $logger, + ProjectStore $projectStore, + BuildService $buildService, + ?string $name = null + ) { + parent::__construct($configuration, $logger, $name); $this->projectStore = $projectStore; $this->buildService = $buildService; } - /** - * {@inheritDoc} - */ protected function configure() { $this @@ -61,9 +57,6 @@ protected function configure() ->setDescription('Create a build for a project'); } - /** - * {@inheritDoc} - */ public function execute(InputInterface $input, OutputInterface $output) { $projectId = $input->getArgument('projectId'); @@ -101,7 +94,7 @@ public function execute(InputInterface $input, OutputInterface $output) ); $output->writeln('Build Created'); - } catch (Exception $e) { + } catch (\Throwable $e) { $output->writeln('Failed'); $output->writeln(sprintf('%s', $e->getMessage())); } diff --git a/src/Command/InstallCommand.php b/src/Command/InstallCommand.php index dfb9c1975..c9a80f324 100644 --- a/src/Command/InstallCommand.php +++ b/src/Command/InstallCommand.php @@ -1,39 +1,38 @@ * @author Dan Cryer */ class InstallCommand extends Command { - /** - * @var string - */ - protected $configPath = APP_DIR . 'config.yml'; + protected string $configPath = APP_DIR . 'config.yml'; protected function configure() { @@ -100,9 +99,6 @@ protected function configure() ->setDescription('Install PHP Censor'); } - /** - * Installs PHP Censor - */ protected function execute(InputInterface $input, OutputInterface $output) { $configFromFile = (bool)$input->getOption('config-from-file'); @@ -145,26 +141,22 @@ protected function execute(InputInterface $input, OutputInterface $output) } $admin = $this->getAdminInformation($input, $output); - $this->createAdminUser($admin, $output); + $this->createAdminUser($admin, $input, $output); $this->createDefaultGroup($output); } - /** - * @param OutputInterface $output - * - * @return bool - */ - protected function verifyNotInstalled(OutputInterface $output) + private function verifyNotInstalled(OutputInterface $output): bool { - if (file_exists($this->configPath)) { - $content = file_get_contents($this->configPath); + if (\file_exists($this->configPath)) { + $content = \file_get_contents($this->configPath); if (!empty($content)) { $output->writeln( 'The PHP Censor config file exists and is not empty. ' . 'PHP Censor is already installed!' ); + return false; } } @@ -179,12 +171,12 @@ protected function verifyNotInstalled(OutputInterface $output) * * @throws Exception */ - protected function checkRequirements(OutputInterface $output) + private function checkRequirements(OutputInterface $output) { $output->writeln('Checking requirements...'); $errors = false; - if (!(version_compare(PHP_VERSION, '7.4.0') >= 0)) { + if (!(\version_compare(PHP_VERSION, '7.4.0') >= 0)) { $output->writeln(''); $output->writeln( 'PHP Censor requires at least PHP 7.4.0! Installed PHP ' . PHP_VERSION . ''); @@ -194,7 +186,7 @@ protected function checkRequirements(OutputInterface $output) $requiredExtensions = ['PDO', 'xml', 'json', 'curl', 'openssl']; foreach ($requiredExtensions as $extension) { - if (!extension_loaded($extension)) { + if (!\extension_loaded($extension)) { $output->writeln(''); $output->writeln('Extension required: ' . $extension . ''); $errors = true; @@ -204,7 +196,7 @@ protected function checkRequirements(OutputInterface $output) $requiredFunctions = ['exec', 'shell_exec', 'proc_open']; foreach ($requiredFunctions as $function) { - if (!function_exists($function)) { + if (!\function_exists($function)) { $output->writeln(''); $output->writeln( 'PHP Censor needs to be able to call the ' . $function . @@ -230,48 +222,27 @@ protected function checkRequirements(OutputInterface $output) * * @param InputInterface $input * @param OutputInterface $output + * * @return array + * + * @throws InvalidArgumentException */ - protected function getAdminInformation(InputInterface $input, OutputInterface $output) + private function getAdminInformation(InputInterface $input, OutputInterface $output): array { - $admin = []; - - /** @var $helper QuestionHelper */ - $helper = $this->getHelperSet()->get('question'); + /** @var $questionHelper QuestionHelper */ + $questionHelper = $this->getHelperSet()->get('question'); - // Function to validate email address. - $mailValidator = function ($answer) { - if (!filter_var($answer, FILTER_VALIDATE_EMAIL)) { - throw new InvalidArgumentException('Must be a valid email address.'); - } + /** @var UserStore $userStore */ + $userStore = Factory::getStore('User'); - return $answer; - }; - - if ($adminEmail = $input->getOption('admin-email')) { - $adminEmail = $mailValidator($adminEmail); - } else { - $questionEmail = new Question('Admin email: '); - $adminEmail = $helper->ask($input, $output, $questionEmail); - } - - if (!$adminName = $input->getOption('admin-name')) { - $questionName = new Question('Admin name: '); - $adminName = $helper->ask($input, $output, $questionName); - } - - if (!$adminPassword = $input->getOption('admin-password')) { - $questionPassword = new Question('Admin password: '); - $questionPassword->setHidden(true); - $questionPassword->setHiddenFallback(false); - $adminPassword = $helper->ask($input, $output, $questionPassword); - } - - $admin['email'] = $adminEmail; - $admin['name'] = $adminName; - $admin['password'] = $adminPassword; + $createAdmin = new CreateAdmin( + $questionHelper, + $input, + $output, + $userStore + ); - return $admin; + return $createAdmin->process(); } /** @@ -281,18 +252,20 @@ protected function getAdminInformation(InputInterface $input, OutputInterface $o * @param OutputInterface $output * * @return array + * + * @throws Exception */ - protected function getConfigInformation(InputInterface $input, OutputInterface $output) + private function getConfigInformation(InputInterface $input, OutputInterface $output): array { /** @var $helper QuestionHelper */ $helper = $this->getHelperSet()->get('question'); $urlValidator = function ($answer) { - if (!filter_var($answer, FILTER_VALIDATE_URL)) { + if (!\filter_var($answer, FILTER_VALIDATE_URL)) { throw new Exception('Must be a valid URL.'); } - return rtrim($answer, '/'); + return \rtrim($answer, '/'); }; if ($url = $input->getOption('url')) { @@ -384,7 +357,7 @@ protected function getConfigInformation(InputInterface $input, OutputInterface $ * * @return array */ - protected function getQueueInformation(InputInterface $input, OutputInterface $output) + private function getQueueInformation(InputInterface $input, OutputInterface $output): array { $queueConfig = [ 'host' => null, @@ -433,7 +406,7 @@ protected function getQueueInformation(InputInterface $input, OutputInterface $o * * @return array */ - protected function getDatabaseInformation(InputInterface $input, OutputInterface $output) + private function getDatabaseInformation(InputInterface $input, OutputInterface $output): array { $db = []; @@ -442,7 +415,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface if (!$dbType = $input->getOption('db-type')) { $questionType = new Question('Enter your database type ("mysql" or "pgsql"): '); - $dbType = trim(strtolower($helper->ask($input, $output, $questionType))); + $dbType = \trim(\strtolower($helper->ask($input, $output, $questionType))); } if (!$dbHost = $input->getOption('db-host')) { @@ -450,7 +423,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface 'Enter your database host (default: "localhost"): ', 'localhost' ); - $dbHost = trim($helper->ask($input, $output, $questionHost)); + $dbHost = \trim($helper->ask($input, $output, $questionHost)); } $defaultPort = 3306; @@ -474,10 +447,10 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface if ( $dbType === 'pgsql' - && !$dbPgsqlSslmode = $input->getOption('db-pgsql-sslmode') + && !$dbPgsqlSslMode = $input->getOption('db-pgsql-sslmode') ) { - $questionSslmode = new Question('Enter your database connection\'s SSL mode (default: prefer): ', 'prefer'); - $dbPgsqlSslmode = $helper->ask($input, $output, $questionSslmode); + $questionSslMode = new Question('Enter your database connection\'s SSL mode (default: prefer): ', 'prefer'); + $dbPgsqlSslMode = $helper->ask($input, $output, $questionSslMode); } if (!$dbName = $input->getOption('db-name')) { @@ -485,7 +458,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface 'Enter your database name (default: "php-censor-db"): ', 'php-censor-db' ); - $dbName = trim($helper->ask($input, $output, $questionDb)); + $dbName = \trim($helper->ask($input, $output, $questionDb)); } if (!$dbUser = $input->getOption('db-user')) { @@ -493,7 +466,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface 'Enter your database user (default: "php-censor-user"): ', 'php-censor-user' ); - $dbUser = trim($helper->ask($input, $output, $questionUser)); + $dbUser = \trim($helper->ask($input, $output, $questionUser)); } if (!$dbPass = $input->getOption('db-password')) { @@ -509,8 +482,8 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface ] ]; - if ($dbType === 'pgsql' && !empty($dbPgsqlSslmode)) { - $dbServers[0]['pgsql-sslmode'] = $dbPgsqlSslmode; + if ($dbType === 'pgsql' && !empty($dbPgsqlSslMode)) { + $dbServers[0]['pgsql-sslmode'] = $dbPgsqlSslMode; } $dbServers[0]['port'] = $dbPort; @@ -534,7 +507,7 @@ protected function getDatabaseInformation(InputInterface $input, OutputInterface * * @return bool */ - protected function verifyDatabaseDetails(array $db, OutputInterface $output) + private function verifyDatabaseDetails(array $db, OutputInterface $output): bool { $dns = $db['type'] . ':host=' . $db['servers']['write'][0]['host']; @@ -568,7 +541,7 @@ protected function verifyDatabaseDetails(array $db, OutputInterface $output) unset($pdo); return true; - } catch (Exception $ex) { + } catch (\Throwable $ex) { $output->writeln( 'PHP Censor could not connect to database with the details provided. ' . 'Please try again.' @@ -583,7 +556,7 @@ protected function verifyDatabaseDetails(array $db, OutputInterface $output) * Write the config.yml file. * @param array $config */ - protected function writeConfigFile(array $config) + private function writeConfigFile(array $config): void { $dumper = new Dumper(); $yaml = $dumper->dump($config, 4); @@ -591,18 +564,18 @@ protected function writeConfigFile(array $config) file_put_contents($this->configPath, $yaml); } - protected function setupDatabase(OutputInterface $output) + private function setupDatabase(OutputInterface $output): bool { $output->write('Setting up your database...'); - exec( + \exec( (ROOT_DIR . 'bin/console php-censor-migrations:migrate'), $outputMigration, $status ); $output->writeln(''); - $output->writeln(implode(PHP_EOL, $outputMigration)); + $output->writeln(\implode(PHP_EOL, $outputMigration)); if (0 == $status) { $output->writeln('OK'); @@ -616,41 +589,29 @@ protected function setupDatabase(OutputInterface $output) /** * Create admin user using information loaded before. - * - * @param array $admin - * @param OutputInterface $output */ - protected function createAdminUser($admin, $output) + protected function createAdminUser(array $admin, InputInterface $input, OutputInterface $output): void { - try { - /** @var UserStore $userStore */ - $userStore = Factory::getStore('User'); - $adminUser = $userStore->getByEmail($admin['email']); - if ($adminUser) { - throw new RuntimeException('Admin account already exists!'); - } + /** @var $questionHelper QuestionHelper */ + $questionHelper = $this->getHelperSet()->get('question'); - $userService = new UserService($userStore); - $userService->createUser( - $admin['name'], - $admin['email'], - 'internal', - ['type' => 'internal'], - $admin['password'], - true - ); + /** @var UserStore $userStore */ + $userStore = Factory::getStore('User'); - $output->writeln('User account created!'); - } catch (Exception $ex) { - $output->writeln('PHP Censor failed to create your admin account!'); - $output->writeln('' . $ex->getMessage() . ''); - } + $createAdmin = new CreateAdmin( + $questionHelper, + $input, + $output, + $userStore + ); + + $createAdmin->create($admin); } /** * @param OutputInterface $output */ - protected function createDefaultGroup($output) + protected function createDefaultGroup(OutputInterface $output): void { try { /** @var ProjectGroupStore $projectGroupStore */ @@ -668,18 +629,16 @@ protected function createDefaultGroup($output) Factory::getStore('ProjectGroup')->save($group); $output->writeln('Default project group created!'); - } catch (Exception $ex) { + } catch (\Throwable $ex) { $output->writeln('PHP Censor failed to create default project group!'); $output->writeln('' . $ex->getMessage() . ''); } } - protected function reloadConfig() + protected function reloadConfig(): void { - $config = Config::getInstance(); - - if (file_exists($this->configPath)) { - $config->loadYaml($this->configPath); + if (\file_exists($this->configPath)) { + $config = new Configuration($this->configPath); } } } diff --git a/src/Command/LoggingCommand.php b/src/Command/LoggingCommand.php deleted file mode 100644 index 908fe36b8..000000000 --- a/src/Command/LoggingCommand.php +++ /dev/null @@ -1,74 +0,0 @@ -logger = $logger; - } - - /** - * @param OutputInterface $output - */ - protected function configureLogging(OutputInterface $output) - { - $level = Logger::ERROR; - if ($output->isDebug()) { - $level = Logger::DEBUG; - } elseif ($output->isVeryVerbose()) { - $level = Logger::INFO; - } elseif ($output->isVerbose()) { - $level = Logger::NOTICE; - } - - $handlers = $this->logger->getHandlers(); - foreach ($handlers as $handler) { - if ($handler instanceof AbstractHandler) { - $handler->setLevel($level); - } - } - - if (!$output->isQuiet()) { - $this->logger->pushHandler( - new OutputLogHandler($output, $level) - ); - } - - if ($output->isDebug()) { - $this->logger->notice( - sprintf('Command "%s" started in debug mode (-vvv).', $this->getName()) - ); - - define('DEBUG_MODE', true); - } - } - - /** - * @param InputInterface $input - * @param OutputInterface $output - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $this->configureLogging($output); - } -} diff --git a/src/Command/RebuildQueueCommand.php b/src/Command/RebuildQueueCommand.php index f45dabc9d..9c4caa571 100644 --- a/src/Command/RebuildQueueCommand.php +++ b/src/Command/RebuildQueueCommand.php @@ -1,44 +1,27 @@ * @author Dan Cryer */ class RebuildQueueCommand extends Command { - /** - * @var OutputInterface - */ - protected $output; - - /** - * @var Logger - */ - protected $logger; - - /** - * @param Logger $logger - * @param string $name - */ - public function __construct(Logger $logger, $name = null) - { - parent::__construct($name); - $this->logger = $logger; - } - protected function configure() { $this @@ -48,16 +31,6 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { - $this->output = $output; - - // For verbose mode we want to output all informational and above - // messages to the symphony output interface. - if ($input->hasOption('verbose') && $input->getOption('verbose')) { - $this->logger->pushHandler( - new OutputLogHandler($this->output, Logger::INFO) - ); - } - /** @var BuildStore $buildStore */ $buildStore = Factory::getStore('Build'); @@ -66,16 +39,16 @@ protected function execute(InputInterface $input, OutputInterface $output) $result = $buildStore->getByStatus(0); - $this->logger->addInfo(sprintf('Found %d builds', count($result['items']))); + $this->logger->info(\sprintf('Found %d builds', \count($result['items']))); - $buildService = new BuildService($buildStore, $projectStore); + $buildService = new BuildService($this->configuration, $buildStore, $projectStore); - while (count($result['items'])) { - $build = array_shift($result['items']); - $build = BuildFactory::getBuild($build); + while (\count($result['items'])) { + $build = \array_shift($result['items']); + $build = BuildFactory::getBuild($this->configuration, $build); $project = $build->getProject(); - $this->logger->addInfo('Added build #' . $build->getId() . ' to queue.'); + $this->logger->info('Added build #' . $build->getId() . ' to queue.'); $buildService->addBuildToQueue( $build, (null !== $project) ? $project->getBuildPriority() : Project::DEFAULT_BUILD_PRIORITY diff --git a/src/Command/RemoveOldBuildsCommand.php b/src/Command/RemoveOldBuildsCommand.php index 030b84d5e..6f5150809 100644 --- a/src/Command/RemoveOldBuildsCommand.php +++ b/src/Command/RemoveOldBuildsCommand.php @@ -1,43 +1,40 @@ * @author David Sloan */ class RemoveOldBuildsCommand extends Command { - /** - * @var ProjectStore - */ - protected $projectStore; + protected ProjectStore $projectStore; - /** - * @var BuildService - */ - protected $buildService; + protected BuildService $buildService; - /** - * @param ProjectStore $projectStore - * @param BuildService $buildService - */ - public function __construct(ProjectStore $projectStore, BuildService $buildService) - { - parent::__construct(); + public function __construct( + ConfigurationInterface $configuration, + LoggerInterface $logger, + ProjectStore $projectStore, + BuildService $buildService, + ?string $name = null + ) { + parent::__construct($configuration, $logger, $name); - /** @var ProjectStore $projectStore */ $this->projectStore = $projectStore; - - /** @var BuildStore $buildStore */ $this->buildService = $buildService; } @@ -52,11 +49,13 @@ protected function configure() } /** - * Loops through projects. - * - * @param InputInterface $input - * @param OutputInterface $output - */ + * Loops through projects. + * + * @param InputInterface $input + * @param OutputInterface $output + * + * @throws HttpException + */ protected function execute(InputInterface $input, OutputInterface $output) { $projects = $this->projectStore->getAll(); diff --git a/src/Command/WorkerCommand.php b/src/Command/WorkerCommand.php index 983ab2801..4bbf4be4b 100644 --- a/src/Command/WorkerCommand.php +++ b/src/Command/WorkerCommand.php @@ -1,13 +1,15 @@ * @author Dan Cryer */ -class WorkerCommand extends LoggingCommand +class WorkerCommand extends Command { const MIN_QUEUE_PRIORITY = 24; const MAX_QUEUE_PRIORITY = 2025; - /** - * @var BuildService - */ - protected $buildService; + protected BuildService $buildService; - /** - * @param Logger $logger - * @param BuildService $buildService - * @param string $name - */ public function __construct( - Logger $logger, + ConfigurationInterface $configuration, + LoggerInterface $logger, BuildService $buildService, - $name = null + ?string $name = null ) { - parent::__construct($logger, $name); + parent::__construct($configuration, $logger, $name); $this->buildService = $buildService; } @@ -75,7 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { parent::execute($input, $output); - $config = Config::getInstance()->get('php-censor.queue', []); + $config = $this->configuration->get('php-censor.queue', []); if (empty($config['host']) || empty($config['name'])) { throw new RuntimeException( 'The worker is not configured. You must set a host and queue in your config.yml file.' @@ -90,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } elseif ('idle' === $value) { $priority = self::MAX_QUEUE_PRIORITY; // low priority, stop late } else { - $msg = sprintf('Invalid value "%s" for --stop-worker, valid are soon, done and idle;', $value); + $msg = \sprintf('Invalid value "%s" for --stop-worker, valid are soon, done and idle;', $value); throw new InvalidArgumentException($msg); } $jobData = []; @@ -100,10 +97,11 @@ protected function execute(InputInterface $input, OutputInterface $output) } (new BuildWorker( + $this->configuration, $this->logger, $this->buildService, $config['host'], - Config::getInstance()->get('php-censor.queue.port', Pheanstalk::DEFAULT_PORT), + $this->configuration->get('php-censor.queue.port', Pheanstalk::DEFAULT_PORT), $config['name'], ($input->hasOption('periodical-work') && $input->getOption('periodical-work')) )) diff --git a/src/Config.php b/src/Config.php deleted file mode 100644 index 7423b46e0..000000000 --- a/src/Config.php +++ /dev/null @@ -1,210 +0,0 @@ -setArray($settings); - } elseif (is_string($settings) && file_exists($settings)) { - $this->loadYaml($settings); - } - } - - /** - * @param string $yamlFile - */ - public function loadYaml($yamlFile) - { - // Path to a YAML file. - $parser = new YamlParser(); - $yaml = file_get_contents($yamlFile); - $config = (array)$parser->parse($yaml); - - if (empty($config)) { - return; - } - - $this->setArray($config); - } - - /** - * Get a configuration value by key, returning a default value if not set. - * - * @param string $key - * @param mixed $default - * - * @return mixed - */ - public function get($key, $default = null) - { - $keyParts = explode('.', $key); - $selected = $this->config; - - $i = -1; - $lastPart = count($keyParts) - 1; - while ($part = array_shift($keyParts)) { - $i++; - - if (!array_key_exists($part, $selected)) { - return $default; - } - - if ($i === $lastPart) { - return $selected[$part]; - } else { - $selected = $selected[$part]; - } - } - - return $default; - } - - /** - * Set a value by key. - * - * @param string $key - * @param mixed $value - * - * @return bool - */ - public function set($key, $value = null) - { - $this->config[$key] = $value; - - return true; - } - - /** - * Set an array of values. - * - * @param $array - */ - public function setArray($array) - { - self::deepMerge($this->config, $array); - } - - /** - * Short-hand syntax for get() - * @see Config::get() - * - * @param string $key - * - * @return mixed - */ - public function __get($key) - { - return $this->get($key); - } - - /** - * Short-hand syntax for set() - * @see Config::set() - * - * @param string $key - * @param mixed $value - * - * @return bool - */ - public function __set($key, $value = null) - { - return $this->set($key, $value); - } - - /** - * Is set - * - * @param string $key - * - * @return bool - */ - public function __isset($key) - { - return isset($this->config[$key]); - } - - /** - * Unset - * - * @param string $key - */ - public function __unset($key) - { - unset($this->config[$key]); - } - - /** - * Deeply merge the $target array onto the $source array. The $source array will be modified! - * - * @param array $source - * @param array $target - */ - public static function deepMerge(&$source, $target) - { - if (count($source) === 0) { - $source = $target; - return; - } - - foreach ($target as $targetKey => $targetValue) { - if (isset($source[$targetKey])) { - if (!is_array($source[$targetKey]) && !is_array($targetValue)) { - // Neither value is an array, overwrite - $source[$targetKey] = $targetValue; - } elseif (is_array($source[$targetKey]) && is_array($targetValue)) { - // Both are arrays, deep merge them - self::deepMerge($source[$targetKey], $targetValue); - } elseif (is_array($source[$targetKey])) { - // Source is the array, push target value - $source[$targetKey][] = $targetValue; - } else { - // Target is the array, push source value and copy back - $targetValue[] = $source[$targetKey]; - $source[$targetKey] = $targetValue; - } - } else { - // No merge required, just set the value - $source[$targetKey] = $targetValue; - } - } - } - - /** - * @return array - */ - public function getArray() - { - return $this->config; - } -} diff --git a/src/Configuration.php b/src/Configuration.php new file mode 100644 index 000000000..9cab8a23a --- /dev/null +++ b/src/Configuration.php @@ -0,0 +1,37 @@ +loadYaml($configurationPath); + } + + parent::__construct($parameters); + } + + /** + * @param string $configurationPath + * + * @return array + */ + private function loadYaml(string $configurationPath): array + { + $parser = new YamlParser(); + $yaml = \file_get_contents($configurationPath); + + return (array)$parser->parse($yaml); + } +} diff --git a/src/ConfigurationInterface.php b/src/ConfigurationInterface.php new file mode 100644 index 000000000..bb678f310 --- /dev/null +++ b/src/ConfigurationInterface.php @@ -0,0 +1,11 @@ +get('php-censor.log.rotate', false); $maxFiles = (int)$applicationConfig->get('php-censor.log.max_files', 0); @@ -74,19 +75,22 @@ protected function initLogger(Config $applicationConfig) } /** - * @param string $name - * @param string $version + * @param ConfigurationInterface $applicationConfig + * @param string $name + * @param string $version * * @throws Exception */ - public function __construct($name = 'PHP Censor', $version = 'UNKNOWN') - { - $version = (string)\trim(\file_get_contents(ROOT_DIR . 'VERSION.md')); + public function __construct( + ConfigurationInterface $applicationConfig, + string $name = 'PHP Censor', + string $version = 'UNKNOWN' + ) { + $version = \trim(\file_get_contents(ROOT_DIR . 'VERSION.md')); $version = !empty($version) ? $version : '0.0.0 (UNKNOWN)'; parent::__construct($name, $version); - $applicationConfig = Config::getInstance(); $oldDatabaseSettings = $applicationConfig->get('b8.database', []); $databaseSettings = $applicationConfig->get('php-censor.database', []); if ($oldDatabaseSettings && !$databaseSettings) { @@ -128,7 +132,7 @@ public function __construct($name = 'PHP Censor', $version = 'UNKNOWN') if (!empty($databaseSettings['type']) && $databaseSettings['type'] === 'pgsql' ) { - if (!array_key_exists('pgsql-sslmode', $databaseSettings['servers']['write'][0])) { + if (!\array_key_exists('pgsql-sslmode', $databaseSettings['servers']['write'][0])) { $databaseSettings['servers']['write'][0]['pgsql-sslmode'] = 'prefer'; } @@ -168,24 +172,19 @@ public function __construct($name = 'PHP Censor', $version = 'UNKNOWN') /** @var BuildStore $buildStore */ $buildStore = Factory::getStore('Build'); - $buildService = new BuildService($buildStore, $projectStore); + $buildService = new BuildService($applicationConfig, $buildStore, $projectStore); $logger = $this->initLogger($applicationConfig); - $this->add(new InstallCommand()); - $this->add(new CreateAdminCommand($userStore)); - $this->add(new CreateBuildCommand($projectStore, $buildService)); - $this->add(new RemoveOldBuildsCommand($projectStore, $buildService)); - $this->add(new WorkerCommand($logger, $buildService)); - $this->add(new RebuildQueueCommand($logger)); - $this->add(new CheckLocalizationCommand()); + $this->add(new InstallCommand($applicationConfig, $logger)); + $this->add(new CreateAdminCommand($applicationConfig, $logger, $userStore)); + $this->add(new CreateBuildCommand($applicationConfig, $logger, $projectStore, $buildService)); + $this->add(new RemoveOldBuildsCommand($applicationConfig, $logger, $projectStore, $buildService)); + $this->add(new WorkerCommand($applicationConfig, $logger, $buildService)); + $this->add(new RebuildQueueCommand($applicationConfig, $logger)); + $this->add(new CheckLocalizationCommand($applicationConfig, $logger)); } - /** - * Returns help. - * - * @return string - */ - public function getHelp() + public function getHelp(): string { return self::LOGO . parent::getHelp(); } @@ -195,8 +194,8 @@ public function getHelp() * * @return string The long application version */ - public function getLongVersion() + public function getLongVersion(): string { - return sprintf('%s v%s', $this->getName(), $this->getVersion()); + return \sprintf('%s v%s', $this->getName(), $this->getVersion()); } } diff --git a/src/Controller.php b/src/Controller.php index 1b5efd3f6..a24c37848 100644 --- a/src/Controller.php +++ b/src/Controller.php @@ -10,20 +10,20 @@ abstract class Controller /** * @var Request */ - protected $request; + protected Request $request; /** - * @var Config + * @var ConfigurationInterface */ - protected $config; + protected ConfigurationInterface $configuration; /** - * @param Config $config + * @param ConfigurationInterface $config * @param Request $request */ - public function __construct(Config $config, Request $request) + public function __construct(ConfigurationInterface $config, Request $request) { - $this->config = $config; + $this->configuration = $config; $this->request = $request; } diff --git a/src/Controller/BuildController.php b/src/Controller/BuildController.php index 89ceda792..53c4c8865 100644 --- a/src/Controller/BuildController.php +++ b/src/Controller/BuildController.php @@ -5,7 +5,6 @@ use JasonGrimes\Paginator; use PHPCensor\BuildFactory; use PHPCensor\Exception\HttpException\NotFoundException; -use PHPCensor\Helper\AnsiConverter; use PHPCensor\Helper\Lang; use PHPCensor\Http\Response\JsonResponse; use PHPCensor\Http\Response\RedirectResponse; @@ -18,6 +17,7 @@ use PHPCensor\Store\ProjectStore; use PHPCensor\View; use PHPCensor\WebController; +use SensioLabs\AnsiConverter\AnsiToHtmlConverter; /** * Build Controller - Allows users to run and view builds. @@ -53,7 +53,7 @@ public function init() $this->buildStore = Factory::getStore('Build'); $this->projectStore = Factory::getStore('Project'); - $this->buildService = new BuildService($this->buildStore, $this->projectStore); + $this->buildService = new BuildService($this->configuration, $this->buildStore, $this->projectStore); } /** @@ -76,7 +76,7 @@ public function view($buildId) $severity = null; } - $build = BuildFactory::getBuildById($buildId); + $build = BuildFactory::getBuildById($this->configuration, (int)$buildId); if (!$build) { throw new NotFoundException(Lang::get('build_x_not_found', $buildId)); @@ -84,7 +84,7 @@ public function view($buildId) /** @var User $user */ $user = $this->getUser(); - $perPage = $user->getFinalPerPage(); + $perPage = $user->getFinalPerPage($this->configuration); $data = $this->getBuildData($build, $plugin, $severity, $isNew, (($page - 1) * $perPage), $perPage); $pages = ($data['errors'] === 0) ? 1 @@ -285,7 +285,7 @@ protected function getPaginatorHtml($buildId, $plugin, $severity, $isNew, $total */ public function rebuild($buildId) { - $copy = BuildFactory::getBuildById($buildId); + $copy = BuildFactory::getBuildById($this->configuration, (int)$buildId); $project = Factory::getStore('Project')->getByPrimaryKey($copy->getProjectId()); if (!$copy || $project->getArchived()) { @@ -319,7 +319,7 @@ public function delete($buildId) { $this->requireAdmin(); - $build = BuildFactory::getBuildById($buildId); + $build = BuildFactory::getBuildById($this->configuration, (int)$buildId); if (!$build) { throw new NotFoundException(Lang::get('build_x_not_found', $buildId)); @@ -338,7 +338,9 @@ public function delete($buildId) */ protected function cleanLog($log) { - return AnsiConverter::convert($log); + $converter = new AnsiToHtmlConverter(null, false); + + return $converter->convert($log); } /** @@ -379,7 +381,7 @@ public function ajaxData($buildId) } $response = new JsonResponse(); - $build = BuildFactory::getBuildById($buildId); + $build = BuildFactory::getBuildById($this->configuration, (int)$buildId); if (!$build) { $response->setResponseCode(404); @@ -414,7 +416,7 @@ public function ajaxData($buildId) public function ajaxMeta($buildId) { - $build = BuildFactory::getBuildById($buildId); + $build = BuildFactory::getBuildById($this->configuration, (int)$buildId); $key = $this->getParam('key', null); $numBuilds = $this->getParam('num_builds', 1); $data = null; diff --git a/src/Controller/BuildStatusController.php b/src/Controller/BuildStatusController.php index 298cf0109..6900da021 100644 --- a/src/Controller/BuildStatusController.php +++ b/src/Controller/BuildStatusController.php @@ -142,7 +142,7 @@ protected function getLatestBuilds($projectId, $branch) $builds = $this->buildStore->getWhere($criteria, 10, 0, $order); foreach ($builds['items'] as &$build) { - $build = BuildFactory::getBuild($build); + $build = BuildFactory::getBuild($this->configuration, $build); } return $builds['items']; diff --git a/src/Controller/HomeController.php b/src/Controller/HomeController.php index f58b26452..3b0b8da0c 100644 --- a/src/Controller/HomeController.php +++ b/src/Controller/HomeController.php @@ -2,7 +2,6 @@ namespace PHPCensor\Controller; -use PHPCensor\Config; use PHPCensor\Helper\Lang; use PHPCensor\WebController; @@ -28,7 +27,7 @@ public function index() 'right' => [], ]; - $widgetsConfig = Config::getInstance()->get('php-censor.dashboard_widgets', [ + $widgetsConfig = $this->configuration->get('php-censor.dashboard_widgets', [ 'all_projects' => [ 'side' => 'left', ], diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index c489c63fb..206ad1bbf 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -65,7 +65,7 @@ public function init() $this->buildStore = Factory::getStore('Build'); $this->projectStore = Factory::getStore('Project'); $this->projectService = new ProjectService($this->projectStore); - $this->buildService = new BuildService($this->buildStore, $this->projectStore); + $this->buildService = new BuildService($this->configuration, $this->buildStore, $this->projectStore); } /** @@ -115,7 +115,7 @@ public function view($projectId) /** @var PHPCensor\Model\User $user */ $user = $this->getUser(); - $perPage = $user->getFinalPerPage(); + $perPage = $user->getFinalPerPage($this->configuration); $builds = $this->getLatestBuildsHtml($projectId, $branch, $environment, (($page - 1) * $perPage), $perPage); $pages = ($builds[1] === 0) ? 1 @@ -362,7 +362,7 @@ protected function getLatestBuildsHtml($projectId, $branch = '', $environment = $view = new View('Project/ajax-builds'); foreach ($builds['items'] as &$build) { - $build = BuildFactory::getBuild($build); + $build = BuildFactory::getBuild($this->configuration, $build); } $view->builds = $builds['items']; @@ -386,7 +386,7 @@ public function add() $values['default_branch'] = null; if ($method !== 'POST') { - $sshKey = new SshKey(); + $sshKey = new SshKey($this->configuration); $key = $sshKey->generate(); $values['ssh_private_key'] = $key['ssh_private_key']; diff --git a/src/Controller/SessionController.php b/src/Controller/SessionController.php index d420bd587..89ef4fae3 100644 --- a/src/Controller/SessionController.php +++ b/src/Controller/SessionController.php @@ -2,7 +2,6 @@ namespace PHPCensor\Controller; -use PHPCensor\Config; use PHPCensor\Exception\HttpException; use PHPCensor\Form; use PHPCensor\Form\Element\Checkbox; @@ -48,7 +47,7 @@ public function init() parent::init(); $this->userStore = Factory::getStore('User'); - $this->authentication = Service::getInstance(); + $this->authentication = new Service($this->configuration); } protected function loginForm($values) @@ -225,7 +224,7 @@ public function forgotPassword() $key = md5(date('Y-m-d') . $user->getHash()); $message = Lang::get('reset_email_body', $user->getName(), APP_URL, $user->getId(), $key); - $email = new Email(Config::getInstance()); + $email = new Email($this->configuration); $email->setEmailTo($user->getEmail(), $user->getName()); $email->setSubject(Lang::get('reset_email_title', $user->getName())); $email->setBody($message); diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index a2683f95e..cfdab5ced 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -2,7 +2,6 @@ namespace PHPCensor\Controller; -use PHPCensor\Config; use PHPCensor\Exception\HttpException\ForbiddenException; use PHPCensor\Exception\HttpException\NotFoundException; use PHPCensor\Form; @@ -130,7 +129,7 @@ public function profile() $language->setRequired(true); $language->setOptions( array_merge( - [null => Lang::get('default') . ' (' . Config::getInstance()->get('php-censor.language') . ')'], + [null => Lang::get('default') . ' (' . $this->configuration->get('php-censor.language') . ')'], Lang::getLanguageOptions() ) ); @@ -143,7 +142,7 @@ public function profile() $perPage->setLabel(Lang::get('per_page')); $perPage->setRequired(true); $perPage->setOptions([ - null => Lang::get('default') . ' (' . Config::getInstance()->get('php-censor.per_page') . ')', + null => Lang::get('default') . ' (' . $this->configuration->get('php-censor.per_page') . ')', 10 => 10, 25 => 25, 50 => 50, diff --git a/src/Controller/WebhookController.php b/src/Controller/WebhookController.php index c14baedb6..42d18d675 100644 --- a/src/Controller/WebhookController.php +++ b/src/Controller/WebhookController.php @@ -4,7 +4,6 @@ use Exception; use GuzzleHttp\Client; -use PHPCensor\Config; use PHPCensor\Controller; use PHPCensor\Exception\HttpException\NotFoundException; use PHPCensor\Exception\InvalidArgumentException; @@ -55,7 +54,7 @@ public function init() $this->buildStore = Factory::getStore('Build'); $this->projectStore = Factory::getStore('Project'); - $this->buildService = new BuildService($this->buildStore, $this->projectStore); + $this->buildService = new BuildService($this->configuration, $this->buildStore, $this->projectStore); } /** @@ -526,8 +525,8 @@ protected function bitbucketPullRequest(Project $project, array $payload) ]; } - $username = Config::getInstance()->get('php-censor.bitbucket.username'); - $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password'); + $username = $this->configuration->get('php-censor.bitbucket.username'); + $appPassword = $this->configuration->get('php-censor.bitbucket.app_password'); if (empty($username) || empty($appPassword)) { throw new Exception('Please provide Username and App Password of your Bitbucket account.'); @@ -810,7 +809,7 @@ protected function githubPullRequest(Project $project, array $payload) } $headers = []; - $token = Config::getInstance()->get('php-censor.github.token'); + $token = $this->configuration->get('php-censor.github.token'); if (!empty($token)) { $headers['Authorization'] = 'token ' . $token; @@ -819,7 +818,7 @@ protected function githubPullRequest(Project $project, array $payload) $url = $payload['pull_request']['commits_url']; //for large pull requests, allow grabbing more then the default number of commits - $customPerPage = Config::getInstance()->get('php-censor.github.per_page'); + $customPerPage = $this->configuration->get('php-censor.github.per_page'); $params = []; if ($customPerPage) { $params['per_page'] = $customPerPage; diff --git a/src/Controller/WidgetLastBuildsController.php b/src/Controller/WidgetLastBuildsController.php index 26efe1470..94119b892 100644 --- a/src/Controller/WidgetLastBuildsController.php +++ b/src/Controller/WidgetLastBuildsController.php @@ -37,7 +37,7 @@ public function index() $builds = $this->buildStore->getLatestBuilds(null, 10); foreach ($builds as &$build) { - $build = BuildFactory::getBuild($build); + $build = BuildFactory::getBuild($this->configuration, $build); } $view = new View('WidgetLastBuilds/update'); @@ -59,7 +59,7 @@ public function update() $builds = $this->buildStore->getLatestBuilds(null, 10); foreach ($builds as &$build) { - $build = BuildFactory::getBuild($build); + $build = BuildFactory::getBuild($this->configuration, $build); } $this->view->builds = $builds; diff --git a/src/Database.php b/src/Database.php index 4fbcb1e71..bc5da78d2 100644 --- a/src/Database.php +++ b/src/Database.php @@ -17,10 +17,9 @@ class Database extends PDO */ protected $type = 'read'; - /** - * @var bool - */ - protected static $initialised = false; + protected static bool $initialised = false; + + public static ConfigurationInterface $configuration; /** * @var array @@ -64,8 +63,7 @@ public function lastInsertIdExtended($table = null) protected static function init() { - $config = Config::getInstance(); - $settings = $config->get('php-censor.database', []); + $settings = self::$configuration->get('php-censor.database', []); self::$servers['read'] = $settings['servers']['read']; self::$servers['write'] = $settings['servers']['write']; diff --git a/src/DatabaseConnection.php b/src/DatabaseConnection.php new file mode 100644 index 000000000..aa8dd4b35 --- /dev/null +++ b/src/DatabaseConnection.php @@ -0,0 +1,107 @@ +sequencePattern = $sequencePattern; + $this->pdoConnection = new \PDO($dsn, $username, $password, $options); + } + + public function getPdo(): \PDO + { + return $this->pdoConnection; + } + + public function quoteNames(string $query): string + { + $driver = $this->pdoConnection->getAttribute(\PDO::ATTR_DRIVER_NAME); + $pattern = '\1'; + if (DatabaseManager::MYSQL_TYPE === $driver) { + $pattern = '`\1`'; + } elseif (DatabaseManager::MYSQL_TYPE === $driver) { + $pattern = '"\1"'; + } + + return \preg_replace('#{{(.*?)}}#m', $pattern, $query); + } + + public function lastInsertId(string $tableName): int + { + if (DatabaseManager::POSTGRESQL_TYPE === $this->pdoConnection->getAttribute(\PDO::ATTR_DRIVER_NAME)) { + return (int)$this->pdoConnection->lastInsertId(\sprintf("\"{$this->sequencePattern}\"", $tableName)); + } + + return (int)$this->pdoConnection->lastInsertId(); + } + + /** + * @param string $query + * @param array $options + * + * @return false|\PDOStatement + */ + public function prepare(string $query, array $options = []) + { + return $this->pdoConnection->prepare($this->quoteNames($query), $options); + } + + /** + * @param string $statement + * + * @return int|false + */ + public function exec(string $statement) + { + return $this->pdoConnection->exec($statement); + } + + /** + * @param string $statement + * + * @return false|\PDOStatement + */ + public function query(string $statement) + { + return $this->pdoConnection->query($statement); + } + + public function beginTransaction(): bool + { + return $this->pdoConnection->beginTransaction(); + } + + public function commit(): bool + { + return $this->pdoConnection->commit(); + } + + public function rollBack(): bool + { + return $this->pdoConnection->rollBack(); + } + + public function inTransaction(): bool + { + return $this->pdoConnection->inTransaction(); + } +} diff --git a/src/DatabaseManager.php b/src/DatabaseManager.php new file mode 100644 index 000000000..ef7317451 --- /dev/null +++ b/src/DatabaseManager.php @@ -0,0 +1,103 @@ + null, + 'write' => null + ]; + + public function __construct(ConfigurationInterface $configuration) + { + $this->configuration = $configuration; + } + + /** + * @param string $type + * + * @return \PDO + * + * @throws Exception + */ + public function getConnection(string $type = 'read'): \PDO + { + if (null === $this->connections[$type]) { + $servers = (array)$this->configuration->get("php-censor.database.servers.{$type}", []); + \shuffle($servers); + + $connection = null; + while (\count($servers)) { + $server = \array_shift($servers); + $driver = $this->configuration->get('php-censor.database.type', self::POSTGRESQL_TYPE); + $dsn = $driver . ':host=' . $server['host']; + + if (self::POSTGRESQL_TYPE === $driver) { + if (!\array_key_exists('pgsql-sslmode', $server)) { + $server['pgsql-sslmode'] = 'prefer'; + } + + $dsn .= ';sslmode=' . $server['pgsql-sslmode']; + } + + if (isset($server['port'])) { + $dsn .= ';port=' . (int)$server['port']; + } + + $dsn .= ';dbname=' . $this->configuration->get('php-censor.database.name', ''); + + $pdoOptions = [ + \PDO::ATTR_PERSISTENT => false, + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_TIMEOUT => 2, + ]; + + if (self::MYSQL_TYPE === $driver) { + $pdoOptions[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'"; + } + + try { + $connection = new DatabaseConnection( + $dsn, + $this->configuration->get('php-censor.database.username', ''), + $this->configuration->get('php-censor.database.password', ''), + $pdoOptions + ); + } catch (\PDOException $ex) { + $connection = false; + } + + if ($connection) { + break; + } + } + + // No connection? Oh dear. + if (!$connection && $type === 'read') { + throw new Exception('Could not connect to any ' . $type . ' servers.'); + } + + $this->connections[$type] = $connection; + } + + return $this->connections[$type]; + } + + public function resetConnections(): void + { + $this->connections = [ + 'read' => null, + 'write' => null + ]; + } +} diff --git a/src/Form/DataTransformer/Yaml.php b/src/Form/DataTransformer/Yaml.php index 5e923f8d4..74c2b52c7 100644 --- a/src/Form/DataTransformer/Yaml.php +++ b/src/Form/DataTransformer/Yaml.php @@ -1,9 +1,9 @@ convert($text); - } - - /** - * Do not instantiate this class. - */ - private function __construct() - { - } -} diff --git a/src/Helper/Bitbucket.php b/src/Helper/Bitbucket.php index 135b3bdc4..e80d769cb 100644 --- a/src/Helper/Bitbucket.php +++ b/src/Helper/Bitbucket.php @@ -3,13 +3,20 @@ namespace PHPCensor\Helper; use GuzzleHttp\Client; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; /** * The Bitbucket Helper class provides some Bitbucket API call functionality. */ class Bitbucket { + private ConfigurationInterface $configuration; + + public function __construct(ConfigurationInterface $configuration) + { + $this->configuration = $configuration; + } + /** * Create a comment on a specific file (and commit) in a Bitbucket Pull Request. * @@ -24,8 +31,8 @@ class Bitbucket */ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line, $comment) { - $username = Config::getInstance()->get('php-censor.bitbucket.username'); - $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password'); + $username = $this->configuration->get('php-censor.bitbucket.username'); + $appPassword = $this->configuration->get('php-censor.bitbucket.app_password'); if (empty($username) || empty($appPassword)) { return; @@ -65,8 +72,8 @@ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line */ public function createCommitComment($repo, $commitId, $file, $line, $comment) { - $username = Config::getInstance()->get('php-censor.bitbucket.username'); - $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password'); + $username = $this->configuration->get('php-censor.bitbucket.username'); + $appPassword = $this->configuration->get('php-censor.bitbucket.app_password'); if (empty($username) || empty($appPassword)) { return; @@ -102,8 +109,8 @@ public function createCommitComment($repo, $commitId, $file, $line, $comment) */ public function getPullRequestDiff($repo, $pullRequestId) { - $username = Config::getInstance()->get('php-censor.bitbucket.username'); - $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password'); + $username = $this->configuration->get('php-censor.bitbucket.username'); + $appPassword = $this->configuration->get('php-censor.bitbucket.app_password'); if (empty($username) || empty($appPassword)) { return; diff --git a/src/Helper/Email.php b/src/Helper/Email.php index 769f487e0..0a66a0ede 100644 --- a/src/Helper/Email.php +++ b/src/Helper/Email.php @@ -3,7 +3,7 @@ namespace PHPCensor\Helper; use PHPCensor\Builder; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; use Swift_Message; /** @@ -21,9 +21,9 @@ class Email protected $config; /** - * @param Config $config + * @param ConfigurationInterface $config */ - public function __construct(Config $config) + public function __construct(ConfigurationInterface $config) { $this->config = $config; } diff --git a/src/Helper/Github.php b/src/Helper/Github.php index b89f1e4f7..ad5dd9d2a 100644 --- a/src/Helper/Github.php +++ b/src/Helper/Github.php @@ -3,13 +3,20 @@ namespace PHPCensor\Helper; use GuzzleHttp\Client; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; /** * The Github Helper class provides some Github API call functionality. */ class Github { + private ConfigurationInterface $configuration; + + public function __construct(ConfigurationInterface $configuration) + { + $this->configuration = $configuration; + } + /** * Create a comment on a specific file (and commit) in a Github Pull Request. * @param $repo @@ -22,7 +29,7 @@ class Github */ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line, $comment) { - $token = Config::getInstance()->get('php-censor.github.token'); + $token = $this->configuration->get('php-censor.github.token'); if (!$token) { return null; @@ -58,7 +65,7 @@ public function createPullRequestComment($repo, $pullId, $commitId, $file, $line */ public function createCommitComment($repo, $commitId, $file, $line, $comment) { - $token = Config::getInstance()->get('php-censor.github.token'); + $token = $this->configuration->get('php-censor.github.token'); if (!$token) { return null; diff --git a/src/Helper/Lang.php b/src/Helper/Lang.php index 265d9fa6b..e45d19fd0 100644 --- a/src/Helper/Lang.php +++ b/src/Helper/Lang.php @@ -2,7 +2,7 @@ namespace PHPCensor\Helper; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; use PHPCensor\Store\Factory; use PHPCensor\Store\UserStore; @@ -113,10 +113,10 @@ public static function getStrings() /** * Initialise the Language helper, try load the language file for the user's browser or the configured default. * - * @param Config $config - * @param string $languageForce + * @param ConfigurationInterface $config + * @param string $languageForce */ - public static function init(Config $config, $languageForce = null) + public static function init(ConfigurationInterface $config, $languageForce = null) { self::$defaultStrings = self::loadLanguage(self::DEFAULT_LANGUAGE); self::loadAvailableLanguages(); diff --git a/src/Helper/SshKey.php b/src/Helper/SshKey.php index ef74f9ee5..43ea52e08 100644 --- a/src/Helper/SshKey.php +++ b/src/Helper/SshKey.php @@ -2,13 +2,20 @@ namespace PHPCensor\Helper; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; /** * Helper class for dealing with SSH keys. */ class SshKey { + protected ConfigurationInterface $configuration; + + public function __construct(ConfigurationInterface $configuration) + { + $this->configuration = $configuration; + } + /** * Uses ssh-keygen to generate a public/private key pair. * @@ -28,8 +35,8 @@ public function generate() 'ssh_public_key' => '' ]; - $sshStrength = Config::getInstance()->get('php-censor.ssh.strength', 2048); - $sshComment = Config::getInstance()->get('php-censor.ssh.comment', 'admin@php-censor'); + $sshStrength = $this->configuration->get('php-censor.ssh.strength', 2048); + $sshComment = $this->configuration->get('php-censor.ssh.comment', 'admin@php-censor'); $output = @\shell_exec( \sprintf( diff --git a/src/Http/Router.php b/src/Http/Router.php index da0427f16..c0a6557c9 100644 --- a/src/Http/Router.php +++ b/src/Http/Router.php @@ -3,7 +3,6 @@ namespace PHPCensor\Http; use PHPCensor\Application; -use PHPCensor\Config; use PHPCensor\Exception\InvalidArgumentException; class Router @@ -11,28 +10,22 @@ class Router /** * @var Request; */ - protected $request; - - /** - * @var Config; - */ - protected $config; + protected Request $request; /** * @var Application */ - protected $application; + protected Application $application; /** * @var array */ protected $routes = [['route' => '/:controller/:action', 'callback' => null, 'defaults' => []]]; - public function __construct(Application $application, Request $request, Config $config) + public function __construct(Application $application, Request $request) { $this->application = $application; $this->request = $request; - $this->config = $config; } public function clearRoutes() diff --git a/src/Logging/AnsiFormatter.php b/src/Logging/AnsiFormatter.php index e71967f5d..7ce67f41b 100644 --- a/src/Logging/AnsiFormatter.php +++ b/src/Logging/AnsiFormatter.php @@ -1,5 +1,7 @@ logger = $logger; $this->build = $build; } - /** - * Add an entry to the build log. - * - * @param string|string[] $message - * @param string $level - * @param mixed[] $context - */ - public function log($message, $level = LogLevel::INFO, $context = []) + public function log($message, string $level = LogLevel::INFO, array $context = []): void { - // Skip if no logger has been loaded. - if (!$this->logger) { - return; - } - - if (!is_array($message)) { + if (!\is_array($message)) { $message = [$message]; } - // The build is added to the context so the logger can use - // details from it if required. $context['build'] = $this->build->getId(); foreach ($message as $item) { @@ -60,39 +33,21 @@ public function log($message, $level = LogLevel::INFO, $context = []) } } - /** - * Add a warning-coloured message to the log. - * - * @param string $message - */ - public function logWarning($message) + public function logWarning(string $message): void { $this->log("\033[0;31m" . $message . "\033[0m"); } - /** - * Add a success-coloured message to the log. - * - * @param string $message - */ - public function logSuccess($message) + public function logSuccess(string $message): void { $this->log("\033[0;32m" . $message . "\033[0m"); } - /** - * Add a failure-coloured message to the log. - * - * @param string $message - * @param Exception $exception The exception that caused the error. - */ - public function logFailure($message, Exception $exception = null) + public function logFailure(string $message, ?\Throwable $exception = null): void { $level = LogLevel::INFO; $context = []; - // The psr3 log interface stipulates that exceptions should be passed - // as the exception key in the context array. if ($exception) { $level = LogLevel::ERROR; @@ -103,25 +58,10 @@ public function logFailure($message, Exception $exception = null) $this->log("\033[0;31m" . $message . "\033[0m", $level, $context); } - /** - * Add a debug-coloured message to the log. - * - * @param string $message - */ - public function logDebug($message) + public function logDebug(string $message): void { if ($this->build->isDebug()) { $this->log("\033[0;36m" . $message . "\033[0m", LogLevel::DEBUG); } } - - /** - * Sets a logger instance on the object - * - * @param LoggerInterface $logger - */ - public function setLogger(LoggerInterface $logger) - { - $this->logger = $logger; - } } diff --git a/src/Logging/OutputLogHandler.php b/src/Logging/OutputLogHandler.php index 3a3e61f23..f2dabe98e 100644 --- a/src/Logging/OutputLogHandler.php +++ b/src/Logging/OutputLogHandler.php @@ -1,5 +1,7 @@ get('php-censor.bitbucket.username'); - $appPassword = Config::getInstance()->get('php-censor.bitbucket.app_password'); + $username = $this->configuration->get('php-censor.bitbucket.username'); + $appPassword = $this->configuration->get('php-censor.bitbucket.app_password'); if (empty($username) || empty($appPassword) || empty($this->data['id'])) { return false; } - $allowStatusCommit = (bool)Config::getInstance()->get( + $allowStatusCommit = (bool)$this->configuration->get( 'php-censor.bitbucket.status.commit', false ); @@ -123,7 +122,7 @@ public function sendStatusPostback() break; } - $phpCensorUrl = Config::getInstance()->get('php-censor.url'); + $phpCensorUrl = $this->configuration->get('php-censor.url'); $url = sprintf( '/2.0/repositories/%s/commit/%s/statuses/build', @@ -151,7 +150,7 @@ public function sendStatusPostback() ], ]); - $status = (int)$response->getStatusCode(); + $status = $response->getStatusCode(); return ($status >= 200 && $status < 300); } @@ -203,7 +202,7 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul try { if (in_array($this->getSource(), Build::$pullRequestSources, true)) { - $helper = new Bitbucket(); + $helper = new Bitbucket($this->configuration); $diff = $helper->getPullRequestDiff( $this->getProject()->getReference(), $this->getExtra('pull_request_number') @@ -263,12 +262,12 @@ public function reportError( parent::reportError($builder, $plugin, $message, $severity, $file, $lineStart, $lineEnd); try { - $allowCommentCommit = (bool)Config::getInstance()->get( + $allowCommentCommit = (bool)$this->configuration->get( 'php-censor.bitbucket.comments.commit', false ); - $allowCommentPullRequest = (bool)Config::getInstance()->get( + $allowCommentPullRequest = (bool)$this->configuration->get( 'php-censor.bitbucket.comments.pull_request', false ); @@ -278,7 +277,7 @@ public function reportError( $diffLineNumber = $this->getDiffLineNumber($builder, $file, $lineStart); if (!is_null($diffLineNumber)) { - $helper = new Bitbucket(); + $helper = new Bitbucket($this->configuration); $repo = $this->getProject()->getReference(); $prNumber = $this->getExtra('pull_request_number'); diff --git a/src/Model/Build/GitBuild.php b/src/Model/Build/GitBuild.php index 503cc1e34..10a19c9fb 100644 --- a/src/Model/Build/GitBuild.php +++ b/src/Model/Build/GitBuild.php @@ -4,6 +4,7 @@ use Exception; use PHPCensor\Builder; +use PHPCensor\ConfigurationInterface; use PHPCensor\Model\Build; use Psr\Log\LogLevel; @@ -14,6 +15,17 @@ */ class GitBuild extends Build { + protected ConfigurationInterface $configuration; + + public function __construct( + ConfigurationInterface $configuration, + array $initialData = [] + ) { + parent::__construct($initialData); + + $this->configuration = $configuration; + } + /** * Get the URL to be used to clone this remote repository. * diff --git a/src/Model/Build/GithubBuild.php b/src/Model/Build/GithubBuild.php index 0b23c3124..9fb5192a8 100644 --- a/src/Model/Build/GithubBuild.php +++ b/src/Model/Build/GithubBuild.php @@ -5,7 +5,7 @@ use Exception; use GuzzleHttp\Client; use PHPCensor\Builder; -use PHPCensor\Config; +use PHPCensor\Configuration; use PHPCensor\Helper\Diff; use PHPCensor\Helper\Github; use PHPCensor\Model\Build; @@ -100,12 +100,12 @@ public function sendStatusPostback() return false; } - $token = Config::getInstance()->get('php-censor.github.token'); + $token = $this->configuration->get('php-censor.github.token'); if (empty($token) || empty($this->data['id'])) { return false; } - $allowStatusCommit = (bool)Config::getInstance()->get( + $allowStatusCommit = (bool)$this->configuration->get( 'php-censor.github.status.commit', false ); @@ -134,7 +134,7 @@ public function sendStatusPostback() break; } - $phpCensorUrl = Config::getInstance()->get('php-censor.url'); + $phpCensorUrl = $this->configuration->get('php-censor.url'); $url = '/repos/' . $project->getReference() . '/statuses/' . $this->getCommitId(); $client = new Client([ @@ -274,12 +274,12 @@ public function reportError( parent::reportError($builder, $plugin, $message, $severity, $file, $lineStart, $lineEnd); try { - $allowCommentCommit = (bool)Config::getInstance()->get( + $allowCommentCommit = (bool)$this->configuration->get( 'php-censor.github.comments.commit', false ); - $allowCommentPullRequest = (bool)Config::getInstance()->get( + $allowCommentPullRequest = (bool)$this->configuration->get( 'php-censor.github.comments.pull_request', false ); @@ -289,7 +289,7 @@ public function reportError( $diffLineNumber = $this->getDiffLineNumber($builder, $file, $lineStart); if (!is_null($diffLineNumber)) { - $helper = new Github(); + $helper = new Github($this->configuration); $repo = $this->getProject()->getReference(); $prNumber = $this->getExtra('pull_request_number'); diff --git a/src/Model/User.php b/src/Model/User.php index ddeaef3a7..5e4b8b372 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -2,7 +2,7 @@ namespace PHPCensor\Model; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; use PHPCensor\Model\Base\User as BaseUser; /** @@ -10,16 +10,13 @@ */ class User extends BaseUser { - /** - * @return int - */ - public function getFinalPerPage() + public function getFinalPerPage(ConfigurationInterface $configuration): int { $perPage = $this->getPerPage(); if ($perPage) { return $perPage; } - return (int)Config::getInstance()->get('php-censor.per_page', 10); + return (int)$configuration->get('php-censor.per_page', 10); } } diff --git a/src/Plugin/EmailNotify.php b/src/Plugin/EmailNotify.php index c735367e3..caec69c51 100644 --- a/src/Plugin/EmailNotify.php +++ b/src/Plugin/EmailNotify.php @@ -2,7 +2,7 @@ namespace PHPCensor\Plugin; -use PHPCensor\Config; +use PHPCensor\Configuration; use PHPCensor\Exception\HttpException; use PHPCensor\Helper\Email as EmailHelper; use PHPCensor\Plugin; @@ -87,7 +87,7 @@ public function execute() */ protected function sendEmail($toAddress, $ccList, $subject, $body) { - $email = new EmailHelper(Config::getInstance()); + $email = new EmailHelper($this->builder->getConfiguration()); $email->setEmailTo($toAddress, $toAddress); $email->setSubject($subject); diff --git a/src/Plugin/Option/PhpUnitOptions.php b/src/Plugin/Option/PhpUnitOptions.php index 866065e6a..30babfeb6 100644 --- a/src/Plugin/Option/PhpUnitOptions.php +++ b/src/Plugin/Option/PhpUnitOptions.php @@ -2,8 +2,7 @@ namespace PHPCensor\Plugin\Option; -use PHPCensor\Builder; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; /** * Class PhpUnitOptions validates and parse the option for the PhpUnitV2 plugin @@ -12,29 +11,24 @@ */ class PhpUnitOptions { - /** - * @var array - */ - protected $options; + protected array $options; - /** - * @var string - */ - protected $location; + protected string $location; - /** - * @var array - */ - protected $arguments = []; + protected array $arguments = []; + + protected ConfigurationInterface $configuration; /** - * @param array $options - * @param string $location + * @param ConfigurationInterface $configuration + * @param array $options + * @param string $location */ - public function __construct($options, $location) + public function __construct(ConfigurationInterface $configuration, array $options, string $location) { - $this->options = $options; - $this->location = $location; + $this->configuration = $configuration; + $this->options = $options; + $this->location = $location; } /** @@ -123,7 +117,7 @@ private function parseArguments() * Handles command aliases outside of the args option */ if (isset($this->options['coverage']) && $this->options['coverage']) { - $allowPublicArtifacts = (bool)Config::getInstance()->get( + $allowPublicArtifacts = (bool)$this->configuration->get( 'php-censor.build.allow_public_artifacts', false ); diff --git a/src/Plugin/Pdepend.php b/src/Plugin/Pdepend.php index 2f80ab4ad..6d078be23 100644 --- a/src/Plugin/Pdepend.php +++ b/src/Plugin/Pdepend.php @@ -4,7 +4,7 @@ use Exception; use PHPCensor\Builder; -use PHPCensor\Config; +use PHPCensor\Configuration; use PHPCensor\Model\Build; use PHPCensor\Plugin; use Symfony\Component\Filesystem\Filesystem; @@ -86,7 +86,7 @@ public function __construct(Builder $builder, Build $build, array $options = []) */ public function execute() { - $allowPublicArtifacts = (bool)Config::getInstance()->get( + $allowPublicArtifacts = (bool)$this->builder->getConfiguration()->get( 'php-censor.build.allow_public_artifacts', false ); diff --git a/src/Plugin/PhpUnit.php b/src/Plugin/PhpUnit.php index 0c0c35cbb..ba61e6c49 100644 --- a/src/Plugin/PhpUnit.php +++ b/src/Plugin/PhpUnit.php @@ -5,7 +5,6 @@ use Exception; use PHPCensor; use PHPCensor\Builder; -use PHPCensor\Config; use PHPCensor\Model\Build; use PHPCensor\Model\BuildError; use PHPCensor\Plugin; @@ -14,6 +13,7 @@ use PHPCensor\Plugin\Util\PhpUnitResultJunit; use PHPCensor\ZeroConfigPluginInterface; use Symfony\Component\Filesystem\Filesystem; +use PHPCensor\Configuration; /** * PHP Unit Plugin - A rewrite of the original PHP Unit plugin @@ -81,7 +81,7 @@ public function __construct(Builder $builder, Build $build, array $options = []) $this->buildLocation = PUBLIC_DIR . 'artifacts/phpunit/' . $this->buildDirectory; $this->buildBranchLocation = PUBLIC_DIR . 'artifacts/phpunit/' . $this->buildBranchDirectory; - $this->options = new PhpUnitOptions($options, $this->buildLocation); + $this->options = new PhpUnitOptions($this->builder->getConfiguration(), $options, $this->buildLocation); $this->executable = $this->findBinary(['phpunit', 'phpunit.phar']); } @@ -152,7 +152,7 @@ public function execute() */ protected function runConfig($directory, $configFile, $logFormat) { - $allowPublicArtifacts = (bool)Config::getInstance()->get( + $allowPublicArtifacts = (bool)$this->builder->getConfiguration()->get( 'php-censor.build.allow_public_artifacts', false ); diff --git a/src/ProcessControl/Factory.php b/src/ProcessControl/Factory.php deleted file mode 100644 index 13bf37c6e..000000000 --- a/src/ProcessControl/Factory.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ -class Factory -{ - /** - * ProcessControl singleton. - * - * @var ProcessControlInterface - */ - protected static $instance = null; - - /** - * Returns the ProcessControl singleton. - * - * @return ProcessControlInterface - */ - public static function getInstance() - { - if (static::$instance === null) { - static::$instance = static::createProcessControl(); - } - return static::$instance; - } - - /** - * Create a ProcessControl depending on available extensions and the underlying OS. - * - * Check PosixProcessControl, WindowsProcessControl and UnixProcessControl, in that order. - * - * @return ProcessControlInterface - * - * @throws Exception - */ - public static function createProcessControl() - { - switch (true) { - case PosixProcessControl::isAvailable(): - return new PosixProcessControl(); - case UnixProcessControl::isAvailable(): - return new UnixProcessControl(); - } - - throw new Exception("No ProcessControl implementation available."); - } -} diff --git a/src/ProcessControl/PosixProcessControl.php b/src/ProcessControl/PosixProcessControl.php deleted file mode 100644 index f2c13e755..000000000 --- a/src/ProcessControl/PosixProcessControl.php +++ /dev/null @@ -1,42 +0,0 @@ - - */ -class PosixProcessControl implements ProcessControlInterface -{ - /** - * @param int $pid - * - * @return bool - */ - public function isRunning($pid) - { - // Signal "0" is not sent to the process, but posix_kill checks the process anyway; - return posix_kill($pid, 0); - } - - /** - * {@inheritdoc} - */ - public function kill($pid, $forcefully = false) - { - return posix_kill($pid, $forcefully ? 9 : 15); - } - - /** - * Check whether this posix_kill is available. - * - * @return bool - * - * @internal - */ - public static function isAvailable() - { - return function_exists('posix_kill'); - } -} diff --git a/src/ProcessControl/ProcessControlInterface.php b/src/ProcessControl/ProcessControlInterface.php deleted file mode 100644 index e3fce8c89..000000000 --- a/src/ProcessControl/ProcessControlInterface.php +++ /dev/null @@ -1,30 +0,0 @@ - - */ -interface ProcessControlInterface -{ - /** - * Checks if a process exists. - * - * @param int $pid The process identifier. - * - * @return bool true is the process is running, else false. - */ - public function isRunning($pid); - - /** - * Terminate a running process. - * - * @param int $pid The process identifier. - * @param bool $forcefully Whether to gently (false) or forcefully (true) terminate the process. - * - * @return bool - */ - public function kill($pid, $forcefully = false); -} diff --git a/src/ProcessControl/UnixProcessControl.php b/src/ProcessControl/UnixProcessControl.php deleted file mode 100644 index 6733e9072..000000000 --- a/src/ProcessControl/UnixProcessControl.php +++ /dev/null @@ -1,50 +0,0 @@ - - */ -class UnixProcessControl implements ProcessControlInterface -{ - /** - * Check process using the "ps" command. - * - * @param int $pid - * - * @return bool - */ - public function isRunning($pid) - { - $output = $exitCode = null; - exec(sprintf("ps %d", $pid), $output, $exitCode); - return $exitCode === 0; - } - - /** - * {@inheritdoc} - */ - public function kill($pid, $forcefully = false) - { - $output = []; - $result = 1; - - exec(sprintf("kill -%d %d", $forcefully ? 9 : 15, $pid), $output, $result); - - return !$result; - } - - /** - * Check whether the commands "ps" and "kill" are available. - * - * @return bool - * - * @internal - */ - public static function isAvailable() - { - return DIRECTORY_SEPARATOR === '/' && exec("which ps") && exec("which kill"); - } -} diff --git a/src/Security/Authentication/Service.php b/src/Security/Authentication/Service.php index 1cee22982..cd3cca102 100644 --- a/src/Security/Authentication/Service.php +++ b/src/Security/Authentication/Service.php @@ -2,7 +2,8 @@ namespace PHPCensor\Security\Authentication; -use PHPCensor\Config; +use PHPCensor\Configuration; +use PHPCensor\ConfigurationInterface; /** * Authentication facade. @@ -12,19 +13,16 @@ class Service { /** - * @var Service - */ - private static $instance; - - /** - * Return the service singleton. + * The table of providers. * - * @return Service + * @var array */ - public static function getInstance() + private array $providers; + + public function __construct(ConfigurationInterface $configuration, array $providers = []) { - if (self::$instance === null) { - $config = Config::getInstance()->get( + if (!$providers) { + $config = $configuration->get( 'php-censor.security.auth_providers', [ 'internal' => [ @@ -37,10 +35,9 @@ public static function getInstance() foreach ($config as $key => $providerConfig) { $providers[$key] = self::buildProvider($key, $providerConfig); } - self::$instance = new self($providers); } - return self::$instance; + $this->providers = $providers; } /** @@ -61,23 +58,6 @@ public static function buildProvider($key, $config) return new $class($key, $config); } - /** - * The table of providers. - * - * @var array - */ - private $providers; - - /** - * Initialize the service. - * - * @param array $providers - */ - public function __construct(array $providers) - { - $this->providers = $providers; - } - /** * Return all providers. * diff --git a/src/Service/BuildService.php b/src/Service/BuildService.php index 1fe3d6ce7..1a477f423 100644 --- a/src/Service/BuildService.php +++ b/src/Service/BuildService.php @@ -9,7 +9,7 @@ use Pheanstalk\Pheanstalk; use Pheanstalk\Contract\PheanstalkInterface; use PHPCensor\BuildFactory; -use PHPCensor\Config; +use PHPCensor\ConfigurationInterface; use PHPCensor\Exception\HttpException; use PHPCensor\Model\Build; use PHPCensor\Model\Project; @@ -25,31 +25,22 @@ */ class BuildService { - /** - * @var BuildStore - */ - protected $buildStore; + private BuildStore $buildStore; - /** - * @var ProjectStore - */ - protected $projectStore; + private ProjectStore $projectStore; - /** - * @var bool - */ - public $queueError = false; + private ConfigurationInterface $configuration; + + public bool $queueError = false; - /** - * @param BuildStore $buildStore - * @param ProjectStore $projectStore - */ public function __construct( + ConfigurationInterface $configuration, BuildStore $buildStore, ProjectStore $projectStore ) { - $this->buildStore = $buildStore; - $this->projectStore = $projectStore; + $this->configuration = $configuration; + $this->buildStore = $buildStore; + $this->projectStore = $projectStore; } /** @@ -123,7 +114,7 @@ public function createBuild( if (!empty($buildId)) { $project = $build->getProject(); - $build = BuildFactory::getBuild($build); + $build = BuildFactory::getBuild($this->configuration, $build); $build->sendStatusPostback(); $this->addBuildToQueue( $build, @@ -273,7 +264,7 @@ public function createDuplicateBuild(Build $originalBuild, $source) $buildId = $build->getId(); if (!empty($buildId)) { - $build = BuildFactory::getBuild($build); + $build = BuildFactory::getBuild($this->configuration, $build); $project = $build->getProject(); $build->sendStatusPostback(); $this->addBuildToQueue( @@ -292,7 +283,7 @@ public function createDuplicateBuild(Build $originalBuild, $source) */ public function deleteOldByProject($projectId) { - $keepBuilds = (int)Config::getInstance()->get('php-censor.build.keep_builds', 100); + $keepBuilds = (int)$this->configuration->get('php-censor.build.keep_builds', 100); $builds = $this->buildStore->getOldByProject((int)$projectId, $keepBuilds); /** @var Build $build */ @@ -371,15 +362,13 @@ public function addBuildToQueue(Build $build, $buildPriority = Project::DEFAULT_ */ public function addJobToQueue($jobType, array $jobData, $queuePriority = PheanstalkInterface::DEFAULT_PRIORITY) { - $config = Config::getInstance(); - $settings = $config->get('php-censor.queue', []); - + $settings = $this->configuration->get('php-censor.queue', []); if (!empty($settings['host']) && !empty($settings['name'])) { $jobData['type'] = $jobType; try { $pheanstalk = Pheanstalk::create( $settings['host'], - $config->get('php-censor.queue.port', PheanstalkInterface::DEFAULT_PORT) + $this->configuration->get('php-censor.queue.port', PheanstalkInterface::DEFAULT_PORT) ); $pheanstalk->useTube($settings['name']); @@ -387,7 +376,7 @@ public function addJobToQueue($jobType, array $jobData, $queuePriority = Pheanst json_encode($jobData), $queuePriority, PheanstalkInterface::DEFAULT_DELAY, - $config->get('php-censor.queue.lifetime', 600) + $this->configuration->get('php-censor.queue.lifetime', 600) ); } catch (Exception $ex) { $this->queueError = true; diff --git a/src/Store/BuildErrorWriter.php b/src/Store/BuildErrorWriter.php index 6013ff0d7..c65838348 100644 --- a/src/Store/BuildErrorWriter.php +++ b/src/Store/BuildErrorWriter.php @@ -1,9 +1,11 @@ bufferSize = (int)Config::getInstance()->get('php-censor.build.writer_buffer_size', 500); + public function __construct( + ConfigurationInterface $configuration, + int $projectId, + int $buildId + ) { + $this->bufferSize = (int)$configuration->get('php-censor.build.writer_buffer_size', 500); $this->projectId = $projectId; $this->buildId = $buildId; diff --git a/src/View.php b/src/View.php index 1e0bbe067..be1d257f9 100644 --- a/src/View.php +++ b/src/View.php @@ -112,17 +112,6 @@ public function render() return $html; } - /** - * @return bool - */ - protected function loginIsDisabled() - { - $config = Config::getInstance(); - $disableAuth = (bool)$config->get('php-censor.security.disable_auth', false); - - return $disableAuth; - } - /** * @return User|null * diff --git a/src/View/Email/long.phtml b/src/View/Email/long.phtml index 8b9733d77..1f3480559 100644 --- a/src/View/Email/long.phtml +++ b/src/View/Email/long.phtml @@ -1,12 +1,15 @@

getCommitMessage()); ?>

-    getLog()); ?>
+    convert($build->getLog());
+    ?>
 
diff --git a/src/View/layout.phtml b/src/View/layout.phtml index 15fdf2a31..a382c06f1 100644 --- a/src/View/layout.phtml +++ b/src/View/layout.phtml @@ -105,7 +105,7 @@ $user = $this->getUser(); - loginIsDisabled()): ?> + isLoginDisabled): ?>