diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e9897fb..dc1b566b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,7 +109,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### Fixed - Install command return code. -- [PHPUnit] Xdebug settings for coverage option. Pull request [#427](https://github.com/php-censor/php-censor/pull/427). Thanks to [@KieranFYI](https://github.com/KieranFYI). +- **[PHPUnit]** Xdebug settings for coverage option. Pull request [#427](https://github.com/php-censor/php-censor/pull/427). Thanks to [@KieranFYI](https://github.com/KieranFYI). ## Other versions diff --git a/Makefile b/Makefile index 84eb1c67..ebbb9b0b 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,14 @@ code-style-fix: php-info install ## Fix code style psalm: php-info install ## Run Psalm check $(PHP) vendor/bin/psalm --config=psalm.xml.dist --threads=4 --show-snippet=true --show-info=true +rector: php-info install ## Run Rector check + $(PHP) vendor/bin/rector --dry-run --clear-cache + +rector-fix: php-info install ## Run Rector fix + $(PHP) vendor/bin/rector --clear-cache + run-worker: php-info install ## Run PHP Censor worker $(PHP) bin/console php-censor:worker -v -.PHONY: php-info list install install-force update test test-coverage mutation-test code-style-fix psalm run-worker +.PHONY: php-info list install install-force update test test-coverage mutation-test code-style-fix psalm rector rector-fix run-worker .DEFAULT_GOAL := list diff --git a/README.md b/README.md index c8c13c76..89079768 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,19 @@

**PHP Censor** is an open source, self-hosted, continuous integration server for PHP projects -([PHPCI](https://www.phptesting.org) fork). [Official twitter @php_censor](https://twitter.com/php_censor). +([PHPCI](https://github.com/dancryer/PHPCI) fork). [Official twitter @php_censor](https://twitter.com/php_censor). 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.7` | `release-1.3` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | -| `2.0` (Rick Sanchez) | `2.0.10` | `release-2.0` | Current stable version ([Upgrade from v1 to v2](docs/UPGRADE_2.0.md)) | `>=7.4` | -| `2.1` | WIP | `master` | Feature minor 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.7` | `release-1.3` | Old version (**UNSUPPORTED**) | `>=5.6, <8.0` | +| `2.0` (Rick Sanchez) | `2.0.14` | `release-2.0` | Last stable version ([Upgrade from v1 to v2](docs/UPGRADE_2.0.md)) | `>=7.4` | +| `2.1` (Mr. Meeseeks) | `2.1.6` | `release-2.1` | Current stable version | `>=7.4` | +| `2.2` | WIP | `master` | Feature minor version (WIP) | `>=7.4` | [![Dashboard](docs/screenshots/dashboard.png)](docs/screenshots/dashboard.png) @@ -72,7 +73,7 @@ PHPMessDetector, PHPTalLint and TechnicalDebt; * Run through any combination of the other [supported plugins](docs/en/README.md#plugins), including Campfire, CleanBuild, CopyBuild, Deployer, Env, Git, Grunt, Gulp, PackageBuild, Phar, Phing, Shell and Wipe; -* Send notifications to Email, XMPP, Slack, IRC, Flowdock, HipChat and +* Send notifications to Email, XMPP, Slack, IRC, Flowdock and [Telegram](docs/en/plugins/telegram_notify.md); * Use your LDAP-server for authentication; @@ -160,11 +161,28 @@ cd /path/to/php-censor ./vendor/bin/phpunit --configuration ./phpunit.xml.dist --coverage-html ./tests/runtime/coverage -vvv --colors=always ``` -For Phar plugin tests set 'phar.readonly' setting to Off (0) in `php.ini` config. Otherwise the tests will be skipped. +For Phar plugin tests set `phar.readonly` setting to Off (`0`) in `php.ini` config. Otherwise the tests will be skipped. -For database tests create an empty 'test_db' database on 'localhost' with user/password: `root/` -for MySQL and with user/password: `postgres/` for PostgreSQL (You can change default test user, password and -database name in `phpunit.xml[.dist]` config constants). If connection failed the tests will be skipped. +For database tests create an empty databases on 'localhost' with user/password for MySQL/PostgreSQL and set env +variables from `phpunit.xml.dist` config. For example: + +```shell +#!/usr/bin/env bash + +psql --username="test" --host="127.0.0.1" --echo-all --command="DROP DATABASE IF EXISTS \"php-censor-test\";" +psql --username="test" --host="127.0.0.1" --echo-all --command="CREATE DATABASE \"php-censor-test\";" + +mysql --user="test" --password="test" --host="127.0.0.1" --verbose --execute="CREATE DATABASE IF NOT EXISTS \`php-censor-test\`;" + +export SKIP_DB_TESTS=0;\ +export POSTGRESQL_DBNAME=php-censor-test;\ +export POSTGRESQL_USER=test;\ +export POSTGRESQL_PASSWORD=test;\ +export MYSQL_DBNAME=php-censor-test;\ +export MYSQL_USER=test;\ +export MYSQL_PASSWORD=test;\ +vendor/bin/phpunit --configuration=phpunit.xml.dist --verbose +``` ## Documentation diff --git a/VERSION.md b/VERSION.md index 399088bf..a74d18b8 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -2.1.6 +2.2.0-alpha diff --git a/composer.json b/composer.json index b260263b..fee2d97b 100644 --- a/composer.json +++ b/composer.json @@ -82,7 +82,6 @@ "sebastian/diff": "^4.0", "maknz/slack": "^1.7", - "hipchat/hipchat-php": "^1.4", "php-censor/flowdock-client": "^2.0" }, "require-dev": { @@ -97,7 +96,8 @@ "php-censor/phpdoc-checker": "^3.0", "friendsofphp/php-cs-fixer": "^3.3", "symfony/var-dumper": "^4.4", - "vimeo/psalm": "^4.23" + "vimeo/psalm": "^4.23", + "rector/rector": "^0.14" }, "extra": { "platform": { diff --git a/composer.lock b/composer.lock index d757b279..09fe3ffd 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": "20b1f00489615f4ab268d26b842fdd1d", + "content-hash": "b021933c25e0840d8c885e184593250d", "packages": [ { "name": "cakephp/core", @@ -728,52 +728,6 @@ ], "time": "2023-04-17T16:00:37+00:00" }, - { - "name": "hipchat/hipchat-php", - "version": "v1.4", - "source": { - "type": "git", - "url": "https://github.com/hipchat/hipchat-php.git", - "reference": "5936c0a48d2d514d94bfc1d774b04c42cd3bc39e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hipchat/hipchat-php/zipball/5936c0a48d2d514d94bfc1d774b04c42cd3bc39e", - "reference": "5936c0a48d2d514d94bfc1d774b04c42cd3bc39e", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "HipChat": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "HipChat", - "email": "support@hipchat.com", - "homepage": "https://www.hipchat.com", - "role": "Company" - } - ], - "description": "PHP library for HipChat", - "homepage": "http://github.com/hipchat/hipchat-php", - "keywords": [ - "hipchat" - ], - "support": { - "issues": "https://github.com/hipchat/hipchat-php/issues", - "source": "https://github.com/hipchat/hipchat-php/tree/master" - }, - "time": "2015-04-28T22:48:40+00:00" - }, { "name": "jasongrimes/paginator", "version": "1.0.3", @@ -6861,6 +6815,64 @@ }, "time": "2025-02-19T13:28:12+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.12.21", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "14276fdef70575106a3392a4ed553c06a984df28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/14276fdef70575106a3392a4ed553c06a984df28", + "reference": "14276fdef70575106a3392a4ed553c06a984df28", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-03-09T09:24:50+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.32", @@ -7283,6 +7295,63 @@ ], "time": "2024-12-05T13:48:26+00:00" }, + { + "name": "rector/rector", + "version": "0.14.8", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "46ee9a173a2b2645ca92a75ffc17460139fa226e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/46ee9a173a2b2645ca92a75ffc17460139fa226e", + "reference": "46ee9a173a2b2645ca92a75ffc17460139fa226e", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "phpstan/phpstan": "^1.9.0" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-php-parser": "*", + "rector/rector-phpoffice": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.14-dev" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/0.14.8" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2022-11-14T14:09:49+00:00" + }, { "name": "sanmai/later", "version": "0.1.4", diff --git a/docs/CHANGELOG_0.x.md b/docs/CHANGELOG_0.x.md index f9ce08cc..5b57c35a 100644 --- a/docs/CHANGELOG_0.x.md +++ b/docs/CHANGELOG_0.x.md @@ -941,7 +941,7 @@ requests as comments on Github (`php-censor.github.comments.commit` and `php-cen ## [0.1.0](https://github.com/php-censor/php-censor/tree/0.1.0) (2017-01-04) -Initial release. Changes from [PHPCI](https://www.phptesting.org/) v1.7.1: +Initial release. Changes from [PHPCI](https://github.com/dancryer/PHPCI) v1.7.1: ### Added diff --git a/docs/en/README.md b/docs/en/README.md index 6a937707..eb00f0a7 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -85,7 +85,6 @@ Plugins * [Campfire](plugins/campfire_notify.md) - `campfire_notify` * [Email](plugins/email_notify.md) - `email_notify` * [FlowDock](plugins/flowdock_notify.md) - `flowdock_notify` -* [HipChat](plugins/hipchat_notify.md) - `hipchat_notify` * [IRC](plugins/irc_notify.md) - `irc_notify` * [Slack](plugins/slack_notify.md) - `slack_notify` * [Telegram](plugins/telegram_notify.md) - `telegram_notify` diff --git a/docs/en/installing.md b/docs/en/installing.md index 1785f71f..fd9aa498 100644 --- a/docs/en/installing.md +++ b/docs/en/installing.md @@ -65,10 +65,10 @@ cd ./php-censor.local --admin-email='admin@php-censor.local' ``` -* [Add a virtual host to your web server](docs/en/virtual_host.md), pointing to the `public` directory within your new +* [Add a virtual host to your web server](virtual_host.md), pointing to the `public` directory within your new PHP Censor directory. You'll need to set up rewrite rules to point all non-existent requests to PHP Censor; -* [Set up the PHP Censor Worker](docs/en/workers/worker.md); +* [Set up the PHP Censor Worker](workers/worker.md); ## Installing via Docker diff --git a/docs/en/plugins/hipchat_notify.md b/docs/en/plugins/hipchat_notify.md deleted file mode 100644 index 6dfa9a10..00000000 --- a/docs/en/plugins/hipchat_notify.md +++ /dev/null @@ -1,36 +0,0 @@ -Plugin Hipchat Notify -===================== - -This plugin joins a [HipChat](https://www.hipchat.com/) room and sends a user-defined message, for example a -"Build Succeeded" message. - -Configuration -------------- - -### Options - -| Field | Required? | Description | -|-------|-----------|-------------| -| `auth_token` | Yes | Your HipChat API authentication token (v1) | -| `room` | Yes | Your Hipchat room name or ID number. This can also be an array of room names or numbers, and the message will be sent to all rooms. | -| `message` | No | The message to send to the room. Default - `%PROJECT_TITLE% built at %BUILD_LINK%` | -| `color` | No | Message color. Valid values: yellow, green, red, purple, gray, random. Default - `yellow`| -| `notify` | No | Whether or not this message should trigger a notification for people in the room (change the tab color, play a sound, etc). Default - `false`. | - -Message can be formatted via HTML. Example: -```html -%PROJECT_TITLE% - build %BUILD_ID% failed! -``` - -### Examples - -```yml -success: - hipchat_notify_step: - plugin: hipchat_notify - auth_token: 123 - room: 456 - message: '%PROJECT_TITLE% - build %BUILD_ID% failed!' - color: red - notify: true -``` diff --git a/docs/en/plugins/telegram_notify.md b/docs/en/plugins/telegram_notify.md index 105ec471..a8932773 100644 --- a/docs/en/plugins/telegram_notify.md +++ b/docs/en/plugins/telegram_notify.md @@ -24,6 +24,7 @@ complete: recipients: - "" - "-" + - "-/" - "@" send_log: true ``` diff --git a/psalm.xml.dist b/psalm.xml.dist index 4e9226bd..9664617d 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -1,10 +1,11 @@ diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..a5d4ab02 --- /dev/null +++ b/rector.php @@ -0,0 +1,23 @@ +paths([ + __DIR__ . '/src' + ]); + + // register a single rule + $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); + + $rectorConfig->sets([ + SetList::PHP_74, + //SetList::CODE_QUALITY, + //SetList::TYPE_DECLARATION_STRICT, + //SetList::DEAD_CODE, + ]); +}; diff --git a/src/Command/AddSecretCommand.php b/src/Command/AddSecretCommand.php new file mode 100644 index 00000000..754b3fa7 --- /dev/null +++ b/src/Command/AddSecretCommand.php @@ -0,0 +1,95 @@ + + */ +class AddSecretCommand extends Command +{ + private SecretStore $secretStore; + + public function __construct( + ConfigurationInterface $configuration, + DatabaseManager $databaseManager, + StoreRegistry $storeRegistry, + LoggerInterface $logger, + SecretStore $secretStore, + ?string $name = null + ) { + parent::__construct($configuration, $databaseManager, $storeRegistry, $logger, $name); + + $this->secretStore = $secretStore; + } + + /** + * Configure. + */ + protected function configure(): void + { + $this + ->setName('php-censor:add-secret') + + ->addArgument('secret-name', InputArgument::REQUIRED, 'Secret name') + ->addArgument('secret-value', InputArgument::REQUIRED, 'Secret value') + + ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force to update existing values') + + ->setDescription('Update secret'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $secretName = (string)$input->getArgument('secret-name'); + $secretValue = (string)$input->getArgument('secret-value'); + $force = (bool)$input->getOption('force'); + + $secrets = $this->secretStore->getByNames([$secretName]); + if ($secrets && !$force) { + $output->writeln( + \sprintf('Secret with name "%s" already exists! Use flag "-f|--force" if you want update secret.', $secretName) + ); + + return 1; + } + + if (!\preg_match(\sprintf('#%s#', Secret::SECRET_NAME_PATTERN), $secretName)) { + $output->writeln( + \sprintf('Secret name "%s" is invalid! Use only letters, numbers and "-" or "_".', $secretName) + ); + + return 2; + } + + $secret = new Secret($this->storeRegistry); + $secret->setCreateDate(new \DateTime()); + $secret->setUserId(null); + $secret->setName($secretName); + + if ($secrets && $force) { + $secret = $secrets[$secretName]; + } + + $secret->setValue($secretValue); + + $this->secretStore->save($secret); + + return 0; + } +} diff --git a/src/Command/CheckLocalizationCommand.php b/src/Command/CheckLocalizationsCommand.php similarity index 82% rename from src/Command/CheckLocalizationCommand.php rename to src/Command/CheckLocalizationsCommand.php index 10f81be1..e655fa2e 100644 --- a/src/Command/CheckLocalizationCommand.php +++ b/src/Command/CheckLocalizationsCommand.php @@ -14,7 +14,7 @@ * * @author Dmitry Khomutov */ -class CheckLocalizationCommand extends Command +class CheckLocalizationsCommand extends Command { protected string $basePath = __DIR__ . '/../Languages'; @@ -25,27 +25,25 @@ protected function configure(): void $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', 's', InputOption::VALUE_NONE, 'Same than English version') + ->addOption('languages', 'l', InputOption::VALUE_OPTIONAL, 'List of languages separated by commas. By default, all languages', '') - ->setDescription('Check localizations.'); + ->setDescription('Check localizations'); } protected function execute(InputInterface $input, OutputInterface $output): int { $output->writeln("\nCheck localizations!"); - $sameThanEnglish = (null !== $input->getOption('same')) - ? $input->getOption('same') - : false; + $sameThanEnglish = (bool)$input->getOption('same'); - $languagesList = (null !== $input->getOption('langs')) - ? \explode(',', $input->getOption('langs')) + $languages = $input->getOption('languages') + ? \explode(',', $input->getOption('languages')) : []; // Get English version - $english = $this->getTranslations($this->basePath.'/lang.en.php'); - $othersLanguages = $this->getLanguages($languagesList); + $english = $this->getTranslations($this->basePath . '/lang.en.php'); + $othersLanguages = $this->getLanguages($languages); $diffs = $this->compareTranslations($english, $othersLanguages); foreach ($diffs as $language => $value) { diff --git a/src/Command/CreateBuildCommand.php b/src/Command/CreateBuildCommand.php index fcebb607..b7422cf0 100644 --- a/src/Command/CreateBuildCommand.php +++ b/src/Command/CreateBuildCommand.php @@ -54,11 +54,12 @@ protected function configure(): void $this ->setName('php-censor:create-build') - ->addArgument('projectId', InputArgument::REQUIRED, 'A project ID') + ->addArgument('project-id', InputArgument::REQUIRED, 'A project ID') ->addOption('commit', null, InputOption::VALUE_OPTIONAL, 'Commit ID to build') ->addOption('branch', null, InputOption::VALUE_OPTIONAL, 'Branch to build') ->addOption('email', null, InputOption::VALUE_OPTIONAL, 'Committer email') ->addOption('message', null, InputOption::VALUE_OPTIONAL, 'Commit message') + ->addOption('environment', null, InputOption::VALUE_OPTIONAL, 'Build environment') ->setDescription('Create a build for a project'); } @@ -70,10 +71,10 @@ protected function configure(): void */ public function execute(InputInterface $input, OutputInterface $output): int { - $projectId = (int)$input->getArgument('projectId'); + $projectId = (int)$input->getArgument('project-id'); $commitId = $input->getOption('commit'); $branch = $input->getOption('branch'); - $environment = $input->hasOption('environment') ? $input->getOption('environment') : null; + $environment = $input->getOption('environment'); $ciEmail = $input->getOption('email'); $ciMessage = $input->getOption('message'); diff --git a/src/Command/InstallCommand.php b/src/Command/InstallCommand.php index 051420e6..f6bc9b36 100644 --- a/src/Command/InstallCommand.php +++ b/src/Command/InstallCommand.php @@ -89,9 +89,8 @@ protected function configure(): void ->addOption( 'config-from-file', null, - InputOption::VALUE_OPTIONAL, - 'Take config from file and ignore options', - false + InputOption::VALUE_NONE, + 'Take config from file and ignore options' ) ->setDescription('Install PHP Censor'); @@ -228,12 +227,12 @@ private function getConfigInformation(InputInterface $input, OutputInterface $ou /** @var $helper QuestionHelper */ $helper = $this->getHelperSet()->get('question'); - $urlValidator = function ($answer) { - if (!\filter_var($answer, FILTER_VALIDATE_URL)) { - throw new InvalidArgumentException('Must be a valid URL.'); + $urlValidator = function ($domain) { + if (!\filter_var($domain, FILTER_VALIDATE_URL)) { + throw new InvalidArgumentException("${domain} is not a valid URL!"); } - return \rtrim($answer, '/'); + return \rtrim($domain, '/'); }; if ($url = $input->getOption('url')) { diff --git a/src/Command/WorkerCommand.php b/src/Command/WorkerCommand.php index f98be5d1..7d70be3b 100644 --- a/src/Command/WorkerCommand.php +++ b/src/Command/WorkerCommand.php @@ -5,7 +5,6 @@ namespace PHPCensor\Command; use Exception; -use Monolog\Logger; use Pheanstalk\Contract\PheanstalkInterface; use PHPCensor\BuildFactory; use PHPCensor\Common\Application\ConfigurationInterface; @@ -53,7 +52,6 @@ public function __construct( protected function configure(): void { - $whenHints = 'soon=when next job done (default), done=when current jobs done, idle=when waiting for jobs'; $this ->setName('php-censor:worker') ->addOption( @@ -66,7 +64,8 @@ protected function configure(): void 'stop-worker', 's', InputOption::VALUE_OPTIONAL, - "Gracefully stop one worker ($whenHints)" + "Gracefully stop one worker ('soon' = when next job done, 'done' = when current jobs done, 'idle' = when waiting for jobs)", + '' ) ->setDescription('Runs the PHP Censor build worker.'); } @@ -126,7 +125,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } - $canPeriodicalWork = $input->hasOption('periodical-work') && $input->getOption('periodical-work'); + $periodicalWork = (bool)$input->getOption('periodical-work'); $worker = new BuildWorker( $this->configuration, $this->databaseManager, @@ -137,7 +136,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $config['host'], (int)$this->configuration->get('php-censor.queue.port', PheanstalkInterface::DEFAULT_PORT), $config['name'], - $canPeriodicalWork + $periodicalWork ); $worker->startWorker(); diff --git a/src/Console/Application.php b/src/Console/Application.php index ee1dbf32..d4d6098a 100644 --- a/src/Console/Application.php +++ b/src/Console/Application.php @@ -15,7 +15,8 @@ use Phinx\Console\Command\Rollback; use Phinx\Console\Command\Status; use PHPCensor\BuildFactory; -use PHPCensor\Command\CheckLocalizationCommand; +use PHPCensor\Command\AddSecretCommand; +use PHPCensor\Command\CheckLocalizationsCommand; use PHPCensor\Command\CreateAdminCommand; use PHPCensor\Command\CreateBuildCommand; use PHPCensor\Command\InstallCommand; @@ -30,6 +31,7 @@ use PHPCensor\Service\BuildService; use PHPCensor\Store\BuildStore; use PHPCensor\Store\ProjectStore; +use PHPCensor\Store\SecretStore; use PHPCensor\Store\UserStore; use PHPCensor\StoreRegistry; use Symfony\Component\Console\Application as BaseApplication; @@ -179,6 +181,9 @@ public function __construct( /** @var BuildStore $buildStore */ $buildStore = $this->storeRegistry->get('Build'); + /** @var SecretStore $secretStore */ + $secretStore = $this->storeRegistry->get('Secret'); + $buildFactory = new BuildFactory( $this->configuration, $this->storeRegistry @@ -200,7 +205,8 @@ public function __construct( $this->add(new RemoveOldBuildsCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $projectStore, $buildService)); $this->add(new WorkerCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $buildService, $buildFactory)); $this->add(new RebuildQueueCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger)); - $this->add(new CheckLocalizationCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger)); + $this->add(new CheckLocalizationsCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger)); + $this->add(new AddSecretCommand($this->configuration, $this->databaseManager, $this->storeRegistry, $logger, $secretStore)); } public function getHelp(): string diff --git a/src/Controller/SecretController.php b/src/Controller/SecretController.php index 0f3b42d9..3ed942c6 100644 --- a/src/Controller/SecretController.php +++ b/src/Controller/SecretController.php @@ -100,7 +100,7 @@ public function edit(?int $secretId = null) $field ->setClass('form-control') ->setContainerClass('form-group') - ->setPattern('^[-_\w\d]+$') + ->setPattern(Secret::SECRET_NAME_PATTERN) ->setValue($secret->getName()); $form->addField($field); diff --git a/src/Helper/CommandExecutor.php b/src/Helper/CommandExecutor.php index 1a0765a0..b240a27e 100644 --- a/src/Helper/CommandExecutor.php +++ b/src/Helper/CommandExecutor.php @@ -29,7 +29,7 @@ class CommandExecutor implements CommandExecutorInterface /** * @var array */ - protected $lastOutput; + protected $lastOutput = []; /** * @var string @@ -57,19 +57,15 @@ class CommandExecutor implements CommandExecutorInterface /** * Commands with no proper exit mechanism - * - * @var array */ - private static $noExitCommands = [ + private static array $noExitCommands = [ 'codecept', ]; /** * Environment variables that should not be inherited - * - * @var array */ - private static $blacklistEnvVars = [ + private static array $blacklistEnvVars = [ 'PHP_SELF', 'SCRIPT_NAME', 'SCRIPT_FILENAME', @@ -86,7 +82,6 @@ public function __construct(BuildLogger $logger, $rootDir, $verbose = false) { $this->logger = $logger; $this->verbose = $verbose; - $this->lastOutput = []; $this->rootDir = $rootDir; } @@ -136,9 +131,7 @@ public function executeCommand($args = []) \exec("ps auxww | grep '{$withNoExit}' | grep -v grep", $response); $response = \array_filter( $response, - function ($a) { - return \strpos($a, $this->buildPath) !== false; - } + fn ($a) => \strpos($a, $this->buildPath) !== false ); } while (!empty($response)); $process->stop(); diff --git a/src/Languages/lang.en.php b/src/Languages/lang.en.php index 210fd8f3..dd767785 100644 --- a/src/Languages/lang.en.php +++ b/src/Languages/lang.en.php @@ -431,7 +431,6 @@ 'deployer' => 'Deployer', 'env' => 'Env', 'grunt' => 'Grunt', - 'hipchat_notify' => 'Hipchat Notify', 'irc_notify' => 'IRC Notify', 'lint' => 'Lint', 'mysql' => 'MySQL', diff --git a/src/Languages/lang.es.php b/src/Languages/lang.es.php index abba6e06..e982c42c 100644 --- a/src/Languages/lang.es.php +++ b/src/Languages/lang.es.php @@ -415,7 +415,6 @@ 'deployer' => 'Deployer', 'env' => 'Env', 'grunt' => 'Grunt', - 'hipchat_notify' => 'Hipchat Notify', 'irc' => 'IRC', 'lint' => 'Lint', 'mysql' => 'MySQL', diff --git a/src/Languages/lang.fr.php b/src/Languages/lang.fr.php index dd1fedb6..d0e23ee7 100644 --- a/src/Languages/lang.fr.php +++ b/src/Languages/lang.fr.php @@ -405,7 +405,6 @@ 'deployer' => 'Deployer', 'env' => 'Env', 'grunt' => 'Grunt', - 'hipchat_notify' => 'Hipchat Notify', 'irc_notify' => 'IRC Notify', 'lint' => 'Lint', 'mysql' => 'MySQL', diff --git a/src/Languages/lang.id.php b/src/Languages/lang.id.php index 7da0b339..e871d51c 100644 --- a/src/Languages/lang.id.php +++ b/src/Languages/lang.id.php @@ -412,7 +412,6 @@ 'deployer' => 'Deployer', 'env' => 'Env', 'grunt' => 'Grunt', - 'hipchat_notify' => 'Hipchat Notify', 'irc' => 'IRC', 'lint' => 'Lint', 'mysql' => 'MySQL', diff --git a/src/Languages/lang.my.php b/src/Languages/lang.my.php index d8db7cdf..29099f2d 100644 --- a/src/Languages/lang.my.php +++ b/src/Languages/lang.my.php @@ -413,7 +413,6 @@ 'deployer' => 'Deployer', 'env' => 'Env', 'grunt' => 'Grunt', - 'hipchat_notify' => 'Hipchat Notify', 'irc' => 'IRC', 'lint' => 'Lint', 'mysql' => 'MySQL', diff --git a/src/Languages/lang.pt-br.php b/src/Languages/lang.pt-br.php index 6f20fad5..b482ff23 100644 --- a/src/Languages/lang.pt-br.php +++ b/src/Languages/lang.pt-br.php @@ -423,7 +423,6 @@ 'deployer' => 'Deployer', 'env' => 'Env', 'grunt' => 'Grunt', - 'hipchat_notify' => 'Hipchat Notify', 'irc' => 'IRC', 'lint' => 'Lint', 'mysql' => 'MySQL', diff --git a/src/Languages/lang.ru.php b/src/Languages/lang.ru.php index d2e56821..80a90a52 100644 --- a/src/Languages/lang.ru.php +++ b/src/Languages/lang.ru.php @@ -419,7 +419,6 @@ 'deployer' => 'Deployer', 'env' => 'Env', 'grunt' => 'Grunt', - 'hipchat_notify' => 'Hipchat Notify', 'irc_notify' => 'IRC Notify', 'lint' => 'Lint', 'mysql' => 'MySQL', diff --git a/src/Logging/BuildDBLogHandler.php b/src/Logging/BuildDBLogHandler.php index 4b33ab3c..a0cfbd9a 100644 --- a/src/Logging/BuildDBLogHandler.php +++ b/src/Logging/BuildDBLogHandler.php @@ -79,7 +79,7 @@ private function sanitize(string $message): string ROOT_DIR, ], [ '/', - '/', + '//', '/', '/', ], $message); diff --git a/src/Model/Build/GitBuild.php b/src/Model/Build/GitBuild.php index 77c388ab..65528935 100644 --- a/src/Model/Build/GitBuild.php +++ b/src/Model/Build/GitBuild.php @@ -102,8 +102,8 @@ protected function cloneByHttp(Builder $builder, $cloneTo) $cmd .= ' --depth ' . \intval($buildSettings['clone_depth']) . ' '; } - $cmd .= ' -b "%s" "%s" "%s"'; - $success = $builder->executeCommand($cmd, $this->getBranch(), $this->getCloneUrl(), $cloneTo); + $cmd .= ' -b %s "%s" "%s"'; + $success = $builder->executeCommand($cmd, \escapeshellarg($this->getBranch()), $this->getCloneUrl(), $cloneTo); if ($success) { $success = $this->postCloneSetup($builder, $cloneTo); @@ -132,10 +132,10 @@ protected function cloneBySsh(Builder $builder, $cloneTo) $cmd .= ' --depth ' . \intval($buildSettings['clone_depth']) . ' '; } - $cmd .= ' -b "%s" "%s" "%s"'; + $cmd .= ' -b %s "%s" "%s"'; $cmd = 'export GIT_SSH="' . $gitSshWrapper . '" && ' . $cmd; - $success = $builder->executeCommand($cmd, $this->getBranch(), $this->getCloneUrl(), $cloneTo); + $success = $builder->executeCommand($cmd, \escapeshellarg($this->getBranch()), $this->getCloneUrl(), $cloneTo); if ($success) { $extra = [ @@ -167,7 +167,7 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul if (empty($this->getEnvironmentId()) && !empty($commitId)) { $cmd = $chdir . ' && git checkout %s --quiet'; - $success = $builder->executeCommand($cmd, $cloneTo, $commitId); + $success = $builder->executeCommand($cmd, $cloneTo, \escapeshellarg($commitId)); } // Always update the commit hash with the actual HEAD hash @@ -176,11 +176,11 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul $this->setCommitId($commitId); - if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%s %s', $cloneTo, $commitId)) { + if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%s %s', $cloneTo, \escapeshellarg($commitId))) { $this->setCommitMessage(\trim($builder->getLastOutput())); } - if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%ae %s', $cloneTo, $commitId)) { + if ($builder->executeCommand($chdir . ' && git log -1 --pretty=format:%%ae %s', $cloneTo, \escapeshellarg($commitId))) { $this->setCommitterEmail(\trim($builder->getLastOutput())); } } diff --git a/src/Model/Build/HgBuild.php b/src/Model/Build/HgBuild.php index 6ac11e84..046dc824 100644 --- a/src/Model/Build/HgBuild.php +++ b/src/Model/Build/HgBuild.php @@ -78,7 +78,7 @@ public function createWorkingCopy(Builder $builder, $buildPath) */ protected function cloneByHttp(Builder $builder, $cloneTo) { - return $builder->executeCommand('hg clone %s "%s" -r %s', $this->getCloneUrl(), $cloneTo, $this->getBranch()); + return $builder->executeCommand('hg clone %s "%s" -r %s', $this->getCloneUrl(), $cloneTo, \escapeshellarg($this->getBranch())); } /** @@ -94,7 +94,7 @@ protected function cloneBySsh(Builder $builder, $cloneTo) // Do the hg clone: $cmd = 'hg clone --ssh "ssh -i ' . $keyFile . '" %s "%s" -r %s'; - $success = $builder->executeCommand($cmd, $this->getCloneUrl(), $cloneTo, $this->getBranch()); + $success = $builder->executeCommand($cmd, $this->getCloneUrl(), $cloneTo, \escapeshellarg($this->getBranch())); if ($success) { $success = $this->postCloneSetup($builder, $cloneTo); @@ -121,7 +121,7 @@ protected function postCloneSetup(Builder $builder, $cloneTo, array $extra = nul // Allow switching to a specific branch: if (!empty($commitId)) { $cmd = 'cd "%s" && hg checkout %s'; - $success = $builder->executeCommand($cmd, $cloneTo, $this->getBranch()); + $success = $builder->executeCommand($cmd, $cloneTo, \escapeshellarg($this->getBranch())); } return $success; diff --git a/src/Model/Build/SvnBuild.php b/src/Model/Build/SvnBuild.php index 97869dcb..a1ab3498 100644 --- a/src/Model/Build/SvnBuild.php +++ b/src/Model/Build/SvnBuild.php @@ -111,7 +111,7 @@ protected function cloneByHttp(Builder $builder, $cloneTo) if (!empty($this->getCommitId())) { $cmd .= ' -r %s %s "%s"'; - $success = $builder->executeCommand($cmd, $this->getCommitId(), $this->getCloneUrl(), $cloneTo); + $success = $builder->executeCommand($cmd, \escapeshellarg($this->getCommitId()), $this->getCloneUrl(), $cloneTo); } else { $cmd .= ' %s "%s"'; $success = $builder->executeCommand($cmd, $this->getCloneUrl(), $cloneTo); diff --git a/src/Model/Secret.php b/src/Model/Secret.php index 211626a4..e0e241d4 100644 --- a/src/Model/Secret.php +++ b/src/Model/Secret.php @@ -14,4 +14,5 @@ */ class Secret extends BaseSecret { + public const SECRET_NAME_PATTERN = '^[-_\w\d]+$'; } diff --git a/src/Plugin/Behat.php b/src/Plugin/Behat.php index 710a2802..bfff90a4 100644 --- a/src/Plugin/Behat.php +++ b/src/Plugin/Behat.php @@ -21,7 +21,7 @@ class Behat extends Plugin /** * @var string */ - protected $features; + protected $features = ''; /** * @return string @@ -40,8 +40,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) $this->executable = $this->findBinary(['behat', 'behat.phar']); - $this->features = ''; - if (!empty($options['features'])) { $this->features = $options['features']; } diff --git a/src/Plugin/BitbucketNotify.php b/src/Plugin/BitbucketNotify.php index ccb22f25..862d53c6 100644 --- a/src/Plugin/BitbucketNotify.php +++ b/src/Plugin/BitbucketNotify.php @@ -269,7 +269,7 @@ protected function prepareResult($targetBranch) return []; } - $plugins = \array_unique(\array_merge(\array_keys($targetBranchBuildStats), \array_keys($currentBranchBuildStats))); + $plugins = \array_unique([...\array_keys($targetBranchBuildStats), ...\array_keys($currentBranchBuildStats)]); \sort($plugins); $result = []; diff --git a/src/Plugin/CampfireNotify.php b/src/Plugin/CampfireNotify.php index 06b58d29..60d5b450 100644 --- a/src/Plugin/CampfireNotify.php +++ b/src/Plugin/CampfireNotify.php @@ -21,7 +21,7 @@ class CampfireNotify extends Plugin protected $url; protected $authToken; protected $userAgent; - protected $cookie; + protected $cookie = 'php-censor-cookie'; protected $verbose = false; protected $room; protected $message; @@ -44,7 +44,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) $this->message = $options['message']; $version = $this->builder->interpolate('%SYSTEM_VERSION%'); $this->userAgent = 'PHP Censor/' . $version; - $this->cookie = "php-censor-cookie"; if (isset($options['verbose']) && $options['verbose']) { $this->verbose = true; diff --git a/src/Plugin/Composer.php b/src/Plugin/Composer.php index 74363ef8..97852ece 100644 --- a/src/Plugin/Composer.php +++ b/src/Plugin/Composer.php @@ -19,11 +19,11 @@ */ class Composer extends Plugin implements ZeroConfigPluginInterface { - protected $action; - protected $preferDist; - protected $noDev; - protected $ignorePlatformReqs; - protected $preferSource; + protected $action = 'install'; + protected $preferDist = false; + protected $noDev = false; + protected $ignorePlatformReqs = false; + protected $preferSource = false; /** * @return string @@ -40,12 +40,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->action = 'install'; - $this->preferDist = false; - $this->preferSource = false; - $this->noDev = false; - $this->ignorePlatformReqs = false; - $this->executable = $this->findBinary(['composer', 'composer.phar']); if (\array_key_exists('action', $options)) { diff --git a/src/Plugin/Deployer.php b/src/Plugin/Deployer.php index 71bcb377..742ad89f 100644 --- a/src/Plugin/Deployer.php +++ b/src/Plugin/Deployer.php @@ -19,7 +19,7 @@ class Deployer extends Plugin { protected $webhookUrl; - protected $reason; + protected $reason = 'PHP Censor Build #%BUILD_ID% - %COMMIT_MESSAGE%'; protected $updateOnly; /** @@ -37,7 +37,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->reason = 'PHP Censor Build #%BUILD_ID% - %COMMIT_MESSAGE%'; if (isset($options['webhook_url'])) { $this->webhookUrl = $options['webhook_url']; } diff --git a/src/Plugin/Grunt.php b/src/Plugin/Grunt.php index 7069c06a..0d49bac7 100644 --- a/src/Plugin/Grunt.php +++ b/src/Plugin/Grunt.php @@ -17,8 +17,8 @@ */ class Grunt extends Plugin { - protected $task; - protected $gruntfile; + protected $task = null; + protected $gruntfile = 'Gruntfile.js'; /** * @return string @@ -35,10 +35,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->task = null; - - $this->gruntfile = 'Gruntfile.js'; - if (isset($options['task'])) { $this->task = $options['task']; } diff --git a/src/Plugin/Gulp.php b/src/Plugin/Gulp.php index 1a33053e..6aff9411 100644 --- a/src/Plugin/Gulp.php +++ b/src/Plugin/Gulp.php @@ -17,8 +17,8 @@ */ class Gulp extends Plugin { - protected $task; - protected $gulpfile; + protected $task = null; + protected $gulpfile = 'gulpfile.js'; /** * @return string @@ -35,12 +35,8 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->task = null; - $this->executable = $this->findBinary('gulp'); - $this->gulpfile = 'gulpfile.js'; - if (isset($options['task'])) { $this->task = $options['task']; } diff --git a/src/Plugin/HipchatNotify.php b/src/Plugin/HipchatNotify.php deleted file mode 100644 index 592593be..00000000 --- a/src/Plugin/HipchatNotify.php +++ /dev/null @@ -1,96 +0,0 @@ - - * @author Dmitry Khomutov - */ -class HipchatNotify extends Plugin -{ - protected $authToken; - protected $color; - protected $notify; - protected $message; - protected $room; - - /** - * @return string - */ - public static function pluginName() - { - return 'hipchat_notify'; - } - - /** - * {@inheritDoc} - */ - public function __construct(Builder $builder, Build $build, array $options = []) - { - parent::__construct($builder, $build, $options); - - if (!\is_array($options) || !isset($options['room']) || !isset($options['auth_token'])) { - throw new InvalidArgumentException('Please define room and authToken for hipchat_notify plugin.'); - } - - if (\array_key_exists('auth_token', $options)) { - $this->authToken = $this->builder->interpolate($options['auth_token'], true); - } - - $this->room = $options['room']; - - if (isset($options['message'])) { - $this->message = $options['message']; - } else { - $this->message = '%PROJECT_TITLE% built at %BUILD_LINK%'; - } - - if (isset($options['color'])) { - $this->color = $options['color']; - } else { - $this->color = 'yellow'; - } - - if (isset($options['notify'])) { - $this->notify = $options['notify']; - } else { - $this->notify = false; - } - } - - /** - * Run the HipChat plugin. - * @return bool - */ - public function execute() - { - $hipChat = new HipChat($this->authToken); - $message = $this->builder->interpolate($this->message); - - $result = true; - if (\is_array($this->room)) { - foreach ($this->room as $room) { - if (!$hipChat->message_room($room, 'PHP Censor', $message, $this->notify, $this->color)) { - $result = false; - } - } - } else { - if (!$hipChat->message_room($this->room, 'PHP Censor', $message, $this->notify, $this->color)) { - $result = false; - } - } - - return $result; - } -} diff --git a/src/Plugin/Mage.php b/src/Plugin/Mage.php index 32668d43..c276703b 100644 --- a/src/Plugin/Mage.php +++ b/src/Plugin/Mage.php @@ -83,9 +83,7 @@ protected function getMageLog() throw new RuntimeException('Log dir read fail'); } - $list = \array_filter($list, function ($name) { - return \preg_match('/^log-\d+-\d+\.log$/', $name); - }); + $list = \array_filter($list, fn ($name) => \preg_match('/^log-\d+-\d+\.log$/', $name)); if (empty($list)) { throw new RuntimeException('Log dir filter fail'); } diff --git a/src/Plugin/Mage3.php b/src/Plugin/Mage3.php index df3f3c72..c60ab9f4 100644 --- a/src/Plugin/Mage3.php +++ b/src/Plugin/Mage3.php @@ -88,9 +88,7 @@ protected function getMageLog() throw new RuntimeException('Log dir read fail'); } - $list = \array_filter($list, function ($name) { - return \preg_match('/^\d+_\d+\.log$/', $name); - }); + $list = \array_filter($list, fn ($name) => \preg_match('/^\d+_\d+\.log$/', $name)); if (empty($list)) { throw new RuntimeException('Log dir filter fail'); } diff --git a/src/Plugin/Pdepend.php b/src/Plugin/Pdepend.php index 941dbe32..74964c0b 100644 --- a/src/Plugin/Pdepend.php +++ b/src/Plugin/Pdepend.php @@ -34,17 +34,17 @@ class Pdepend extends Plugin /** * @var string File where the summary.xml is stored */ - protected $summary; + protected $summary = 'summary.xml'; /** * @var string File where the chart.svg is stored */ - protected $chart; + protected $chart = 'chart.svg'; /** * @var string File where the pyramid.svg is stored */ - protected $pyramid; + protected $pyramid = 'pyramid.svg'; /** * @var string @@ -71,10 +71,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->summary = 'summary.xml'; - $this->pyramid = 'pyramid.svg'; - $this->chart = 'chart.svg'; - $this->executable = $this->findBinary(['pdepend', 'pdepend.phar']); $this->buildDirectory = $build->getBuildDirectory(); diff --git a/src/Plugin/PhpCodeSniffer.php b/src/Plugin/PhpCodeSniffer.php index b67a2fbe..082e221c 100644 --- a/src/Plugin/PhpCodeSniffer.php +++ b/src/Plugin/PhpCodeSniffer.php @@ -25,32 +25,32 @@ class PhpCodeSniffer extends Plugin implements ZeroConfigPluginInterface /** * @var array */ - protected $suffixes; + protected $suffixes = ['php']; /** * @var string */ - protected $standard; + protected $standard = 'PSR2'; /** * @var string */ - protected $tabWidth; + protected $tabWidth = ''; /** * @var string */ - protected $encoding; + protected $encoding = ''; /** * @var int */ - protected $allowedErrors; + protected $allowedErrors = 0; /** * @var int */ - protected $allowedWarnings; + protected $allowedWarnings = 0; /** * @var int @@ -82,13 +82,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->suffixes = ['php']; - $this->standard = 'PSR2'; - $this->tabWidth = ''; - $this->encoding = ''; - $this->allowedWarnings = 0; - $this->allowedErrors = 0; - $this->executable = $this->findBinary(['phpcs', 'phpcs.phar']); if (isset($options['zero_config']) && $options['zero_config']) { diff --git a/src/Plugin/PhpDocblockChecker.php b/src/Plugin/PhpDocblockChecker.php index 24ca38bf..516a75d2 100644 --- a/src/Plugin/PhpDocblockChecker.php +++ b/src/Plugin/PhpDocblockChecker.php @@ -26,7 +26,7 @@ class PhpDocblockChecker extends Plugin implements ZeroConfigPluginInterface /** * @var int */ - protected $allowedWarnings; + protected $allowedWarnings = 0; /** * @return string @@ -43,8 +43,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->allowedWarnings = 0; - if (isset($options['zero_config']) && $options['zero_config']) { $this->allowedWarnings = -1; } diff --git a/src/Plugin/PhpLoc.php b/src/Plugin/PhpLoc.php index 00026008..0529cc3b 100644 --- a/src/Plugin/PhpLoc.php +++ b/src/Plugin/PhpLoc.php @@ -5,6 +5,7 @@ use PHPCensor; use PHPCensor\Builder; use PHPCensor\Model\Build; +use PHPCensor\Model\User; use PHPCensor\Plugin; use PHPCensor\ZeroConfigPluginInterface; @@ -56,9 +57,7 @@ public function execute() { $ignore = ''; if (\is_array($this->ignore)) { - $map = function ($item) { - return \sprintf(' --exclude="%s"', $item); - }; + $map = fn ($item) => \sprintf(' --exclude="%s"', $item); $ignore = \array_map($map, $this->ignore); $ignore = \implode('', $ignore); diff --git a/src/Plugin/PhpMessDetector.php b/src/Plugin/PhpMessDetector.php index 982b45a1..afa99af9 100644 --- a/src/Plugin/PhpMessDetector.php +++ b/src/Plugin/PhpMessDetector.php @@ -24,15 +24,15 @@ class PhpMessDetector extends Plugin implements ZeroConfigPluginInterface /** * @var array */ - protected $suffixes; + protected $suffixes = ['php']; /** * Array of PHPMD rules. Can be one of the builtins (codesize, unusedcode, naming, design, controversial) * or a filename (detected by checking for a / in it), either absolute or relative to the project root. * @var array */ - protected $rules; - protected $allowedWarnings; + protected $rules = ['codesize', 'unusedcode', 'naming']; + protected $allowedWarnings = 0; /** * @return string @@ -49,10 +49,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->suffixes = ['php']; - $this->rules = ['codesize', 'unusedcode', 'naming']; - $this->allowedWarnings = 0; - if (isset($options['zero_config']) && $options['zero_config']) { $this->allowedWarnings = -1; } diff --git a/src/Plugin/PhpParallelLint.php b/src/Plugin/PhpParallelLint.php index 1d39b669..4ec480d7 100644 --- a/src/Plugin/PhpParallelLint.php +++ b/src/Plugin/PhpParallelLint.php @@ -21,12 +21,12 @@ class PhpParallelLint extends Plugin implements ZeroConfigPluginInterface /** * @var string - comma separated list of file extensions */ - protected $extensions; + protected $extensions = 'php'; /** * @var bool - enable short tags */ - protected $shortTag; + protected $shortTag = false; /** * @return string @@ -47,9 +47,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->extensions = 'php'; - $this->shortTag = false; - $this->executable = $this->findBinary(['parallel-lint', 'parallel-lint.phar']); if (isset($options['shorttags'])) { diff --git a/src/Plugin/SecurityChecker.php b/src/Plugin/SecurityChecker.php index 2f7bf71b..53bfeebe 100644 --- a/src/Plugin/SecurityChecker.php +++ b/src/Plugin/SecurityChecker.php @@ -23,7 +23,7 @@ class SecurityChecker extends Plugin implements ZeroConfigPluginInterface /** * @var int */ - protected $allowedWarnings; + protected $allowedWarnings = 0; /** * @var string @@ -53,8 +53,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->allowedWarnings = 0; - if (isset($options['zero_config']) && $options['zero_config']) { $this->allowedWarnings = -1; } diff --git a/src/Plugin/SensiolabsInsight.php b/src/Plugin/SensiolabsInsight.php index 7a8949bc..4bd7790c 100644 --- a/src/Plugin/SensiolabsInsight.php +++ b/src/Plugin/SensiolabsInsight.php @@ -38,7 +38,7 @@ class SensiolabsInsight extends Plugin /** * @var int */ - protected $allowedWarnings; + protected $allowedWarnings = 0; /** * @return string @@ -54,8 +54,6 @@ public static function pluginName() public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - - $this->allowedWarnings = 0; if (\array_key_exists('allowed_warnings', $options)) { $this->allowedWarnings = (int)$options['allowed_warnings']; } diff --git a/src/Plugin/TechnicalDebt.php b/src/Plugin/TechnicalDebt.php index 347e7799..8c19f77e 100644 --- a/src/Plugin/TechnicalDebt.php +++ b/src/Plugin/TechnicalDebt.php @@ -25,17 +25,17 @@ class TechnicalDebt extends Plugin implements ZeroConfigPluginInterface /** * @var array */ - protected $suffixes; + protected $suffixes = ['php']; /** * @var int */ - protected $allowedErrors; + protected $allowedErrors = 0; /** * @var array - terms to search for */ - protected $searches; + protected $searches = ['TODO', 'FIXME', 'TO DO', 'FIX ME']; /** * @var array - lines of . and X to visualize errors @@ -117,10 +117,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->suffixes = ['php']; - $this->allowedErrors = 0; - $this->searches = ['TODO', 'FIXME', 'TO DO', 'FIX ME']; - if (!empty($options['suffixes']) && \is_array($options['suffixes'])) { $this->suffixes = $options['suffixes']; } diff --git a/src/Plugin/TelegramNotify.php b/src/Plugin/TelegramNotify.php index e149bf1e..dbbb0bb5 100644 --- a/src/Plugin/TelegramNotify.php +++ b/src/Plugin/TelegramNotify.php @@ -85,11 +85,19 @@ public function execute() $url = '/bot' . $this->authToken . '/sendMessage'; foreach ($this->recipients as $chatId) { + $chatId = $this->builder->interpolate($chatId, true); + [$chatId, $topicId] = $this->splitChatIdAndTopicId($chatId); + $params = [ - 'chat_id' => $this->builder->interpolate($chatId, true), + 'chat_id' => $chatId, 'text' => $message, 'parse_mode' => 'Markdown', ]; + + if ($topicId !== null) { + $params['message_thread_id'] = $topicId; + } + $client->post(('https://api.telegram.org' . $url), [ 'headers' => [ 'Content-Type' => 'application/json', @@ -103,6 +111,11 @@ public function execute() 'text' => $this->buildMsg, 'parse_mode' => 'Markdown', ]; + + if ($topicId !== null) { + $params['message_thread_id'] = $topicId; + } + $client->post(('https://api.telegram.org' . $url), [ 'headers' => [ 'Content-Type' => 'application/json', @@ -142,4 +155,18 @@ private function buildMessage() return $this->builder->interpolate(\str_replace(['%ICON_BUILD%'], [$buildIcon], $this->message)); } + + /** + * Split chat group id to chat id and topic id + * + * @param int|string $chatId + * @return array{string, string|null} + */ + protected function splitChatIdAndTopicId($chatId) + { + $parts = \explode('/', \trim((string) $chatId) . '/'); + $topicId = $parts[1] !== '' ? $parts[1] : null; + + return [$parts[0], $topicId]; + } } diff --git a/src/Plugin/Util/BitbucketNotifyPluginResult.php b/src/Plugin/Util/BitbucketNotifyPluginResult.php index a7dda97b..8157dcdb 100644 --- a/src/Plugin/Util/BitbucketNotifyPluginResult.php +++ b/src/Plugin/Util/BitbucketNotifyPluginResult.php @@ -22,14 +22,13 @@ class BitbucketNotifyPluginResult protected $right; /** @var string $outputFormat */ - protected $outputFormat; + protected $outputFormat = self::DEFAULT_PLUGIN_OUTPUT_FORMAT; public function __construct($plugin, $left, $right) { $this->plugin = $plugin; $this->left = $left; $this->right = $right; - $this->outputFormat = self::DEFAULT_PLUGIN_OUTPUT_FORMAT; } public function getPlugin() diff --git a/src/Plugin/Util/PhpUnitResult.php b/src/Plugin/Util/PhpUnitResult.php index ac10f74b..e90788cb 100644 --- a/src/Plugin/Util/PhpUnitResult.php +++ b/src/Plugin/Util/PhpUnitResult.php @@ -42,17 +42,17 @@ public function __construct($outputFile, $buildPath = '') */ abstract public function parse(); - abstract protected function getSeverity($testcase); + abstract protected function getSeverity($testCase); - abstract protected function buildMessage($testcase); + abstract protected function buildMessage($testCase); - abstract protected function buildTrace($testcase); + abstract protected function buildTrace($testCase); - abstract protected function getFileAndLine($testcase); + abstract protected function getFileAndLine($testCase); - protected function getOutput($testcase) + protected function getOutput($testCase) { - return $testcase['output']; + return $testCase['output']; } protected function parseTestcase($testcase) diff --git a/src/Plugin/Util/PhpUnitResultJson.php b/src/Plugin/Util/PhpUnitResultJson.php index acd7bc40..da47d408 100644 --- a/src/Plugin/Util/PhpUnitResultJson.php +++ b/src/Plugin/Util/PhpUnitResultJson.php @@ -72,20 +72,21 @@ public function parse() /** * Build the severity of the event * + * @param $testCase * * @return string The severity flags * @throws Exception */ - protected function getSeverity($event) + protected function getSeverity($testCase) { - $status = $event['status']; + $status = $testCase['status']; switch ($status) { case 'fail': $severity = self::SEVERITY_FAIL; break; case 'error': - if (\strpos($event['message'], 'Skipped') === 0 || \strpos($event['message'], 'Incomplete') === 0) { + if (\strpos($testCase['message'], 'Skipped') === 0 || \strpos($testCase['message'], 'Incomplete') === 0) { $severity = self::SEVERITY_SKIPPED; } else { $severity = self::SEVERITY_ERROR; @@ -107,16 +108,16 @@ protected function getSeverity($event) /** * Build the message string for an event * - * @param array $event + * @param array $testCase * * @return string */ - protected function buildMessage($event) + protected function buildMessage($testCase) { - $message = $event['test']; + $message = $testCase['test']; - if ($event['message']) { - $message .= PHP_EOL . $event ['message']; + if ($testCase['message']) { + $message .= PHP_EOL . $testCase ['message']; } return $message; @@ -125,16 +126,16 @@ protected function buildMessage($event) /** * Build a string base trace of the failure * - * @param array $event + * @param array $testCase * * @return string[] */ - protected function buildTrace($event) + protected function buildTrace($testCase) { $formattedTrace = []; - if (!empty($event['trace'])) { - foreach ($event['trace'] as $step) { + if (!empty($testCase['trace'])) { + foreach ($testCase['trace'] as $step) { $line = \str_replace($this->buildPath, '', $step['file']) . ':' . $step['line']; $formattedTrace[] = $line; } @@ -146,20 +147,20 @@ protected function buildTrace($event) /** * Saves additional info for a failing test * - * @param array $event + * @param array $testCase * * @return array */ - protected function getFileAndLine($event) + protected function getFileAndLine($testCase) { - if (empty($event['trace'])) { + if (empty($testCase['trace'])) { return [ 'file' => '', 'line' => '', ]; } - $firstTrace = \end($event['trace']); - \reset($event['trace']); + $firstTrace = \end($testCase['trace']); + \reset($testCase['trace']); return [ 'file' => \str_replace($this->buildPath, '', $firstTrace['file']), diff --git a/src/Plugin/Util/PhpUnitResultJunit.php b/src/Plugin/Util/PhpUnitResultJunit.php index 1cbac12a..003ad587 100644 --- a/src/Plugin/Util/PhpUnitResultJunit.php +++ b/src/Plugin/Util/PhpUnitResultJunit.php @@ -167,9 +167,9 @@ private function internalProblem($description) throw new RuntimeException($description); } - protected function getFileAndLine($testcase) + protected function getFileAndLine($testCase) { - $attributes = $testcase->attributes(); + $attributes = $testCase->attributes(); return [ 'file' => \str_replace($this->buildPath, '', $attributes['file']), diff --git a/src/Plugin/WebhookNotify.php b/src/Plugin/WebhookNotify.php index 3a19d5da..eb0e7a0f 100644 --- a/src/Plugin/WebhookNotify.php +++ b/src/Plugin/WebhookNotify.php @@ -25,7 +25,7 @@ class WebhookNotify extends Plugin /** * @var string The URL to send the webhook to. */ - private $url; + private string $url; /** * @return string diff --git a/src/Plugin/XmppNotify.php b/src/Plugin/XmppNotify.php index a4d51ad4..1601728e 100644 --- a/src/Plugin/XmppNotify.php +++ b/src/Plugin/XmppNotify.php @@ -20,37 +20,37 @@ class XmppNotify extends Plugin /** * @var string, username of sender account xmpp */ - protected $username; + protected $username = ''; /** * @var string, alias server of sender account xmpp */ - protected $server; + protected $server = ''; /** * @var string, password of sender account xmpp */ - protected $password; + protected $password = ''; /** * @var string, alias for sender */ - protected $alias; + protected $alias = ''; /** * @var string, use tls */ - protected $tls; + protected $tls = false; /** * @var array, list of recipients xmpp accounts */ - protected $recipients; + protected $recipients = []; /** * @var string, mask to format date */ - protected $dateFormat; + protected $dateFormat = '%c'; /** * @return string @@ -67,14 +67,6 @@ public function __construct(Builder $builder, Build $build, array $options = []) { parent::__construct($builder, $build, $options); - $this->username = ''; - $this->password = ''; - $this->server = ''; - $this->alias = ''; - $this->recipients = []; - $this->tls = false; - $this->dateFormat = '%c'; - $this->executable = $this->findBinary('sendxmpp'); /* diff --git a/src/Store/BuildErrorStore.php b/src/Store/BuildErrorStore.php index d71f15e2..b40894fa 100644 --- a/src/Store/BuildErrorStore.php +++ b/src/Store/BuildErrorStore.php @@ -8,6 +8,7 @@ use PDO; use PHPCensor\Exception\HttpException; use PHPCensor\Model\BuildError; +use PHPCensor\Model\BuildMeta; use PHPCensor\Store; /** @@ -73,9 +74,7 @@ public function getByBuildId(int $buildId, ?int $limit = null, int $offset = 0, if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new BuildError($this->storeRegistry, $item); - }; + $map = fn ($item) => new BuildError($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); @@ -152,10 +151,7 @@ public function getKnownPlugins(int $buildId, ?int $severity = null, ?string $is if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - - $map = function ($item) { - return $item['plugin']; - }; + $map = fn ($item) => $item['plugin']; return \array_map($map, $res); } else { @@ -185,10 +181,7 @@ public function getKnownSeverities(int $buildId, ?string $plugin = null, ?string if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - - $map = function ($item) { - return (int)$item['severity']; - }; + $map = fn ($item) => (int)$item['severity']; return \array_map($map, $res); } else { diff --git a/src/Store/BuildMetaStore.php b/src/Store/BuildMetaStore.php index 0a240eeb..ff358c70 100644 --- a/src/Store/BuildMetaStore.php +++ b/src/Store/BuildMetaStore.php @@ -6,6 +6,8 @@ use PDO; use PHPCensor\Exception\HttpException; +use PHPCensor\Model\Build; +use PHPCensor\Model\BuildError; use PHPCensor\Model\BuildMeta; use PHPCensor\Store; @@ -68,9 +70,7 @@ public function getByBuildId(int $buildId, int $limit = 1000, string $useConnect if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new BuildMeta($this->storeRegistry, $item); - }; + $map = fn ($item) => new BuildMeta($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); @@ -96,10 +96,7 @@ public function getErrorsForUpgrade(int $limit): array if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - - $map = function ($item) { - return new BuildMeta($this->storeRegistry, $item); - }; + $map = fn ($item) => new BuildMeta($this->storeRegistry, $item); return \array_map($map, $res); } else { diff --git a/src/Store/BuildStore.php b/src/Store/BuildStore.php index 929f39e4..98fd7b81 100644 --- a/src/Store/BuildStore.php +++ b/src/Store/BuildStore.php @@ -44,9 +44,7 @@ public function getByProjectId(int $projectId, int $limit = 1000, string $useCon if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new Build($this->storeRegistry, $item); - }; + $map = fn ($item) => new Build($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); @@ -76,9 +74,7 @@ public function getByStatus(int $status, int $limit = 1000, string $useConnectio if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new Build($this->storeRegistry, $item); - }; + $map = fn ($item) => new Build($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); @@ -99,10 +95,7 @@ public function getBuilds(int $limit = 5, int $offset = 0): array if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - - $map = function ($item) { - return new Build($this->storeRegistry, $item); - }; + $map = fn ($item) => new Build($this->storeRegistry, $item); return \array_map($map, $res); } else { @@ -151,10 +144,7 @@ public function getLatestBuilds(?int $projectId = null, int $limit = 5): array if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - - $map = function ($item) { - return new Build($this->storeRegistry, $item); - }; + $map = fn ($item) => new Build($this->storeRegistry, $item); return \array_map($map, $res); } else { @@ -253,9 +243,7 @@ public function getAllProjectsLatestBuilds(int $limitByProject = 5, int $limitAl } foreach ($projects as $idx => $project) { - $projects[$idx] = \array_filter($project, function ($val) { - return ($val['latest'][0]->getStatus() !== Build::STATUS_SUCCESS); - }); + $projects[$idx] = \array_filter($project, fn ($val) => $val['latest'][0]->getStatus() !== Build::STATUS_SUCCESS); } $projects = \array_filter($projects); @@ -279,10 +267,7 @@ public function getByProjectAndCommit(int $projectId, string $commitId): array if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - - $map = function ($item) { - return new Build($this->storeRegistry, $item); - }; + $map = fn ($item) => new Build($this->storeRegistry, $item); $rtn = \array_map($map, $res); @@ -424,10 +409,7 @@ public function getOldByProject(int $projectId, int $keep = 100): array if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - - $map = function ($item) { - return new Build($this->storeRegistry, $item); - }; + $map = fn ($item) => new Build($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); diff --git a/src/Store/EnvironmentStore.php b/src/Store/EnvironmentStore.php index a0ffe27a..01c6192b 100644 --- a/src/Store/EnvironmentStore.php +++ b/src/Store/EnvironmentStore.php @@ -7,6 +7,7 @@ use Exception; use PDO; use PHPCensor\Exception\HttpException; +use PHPCensor\Model\Build; use PHPCensor\Model\Environment; use PHPCensor\Store; @@ -66,9 +67,7 @@ public function getByProjectId(int $projectId, string $useConnection = 'read'): if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new Environment($this->storeRegistry, $item); - }; + $map = fn ($item) => new Environment($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); diff --git a/src/Store/ProjectStore.php b/src/Store/ProjectStore.php index 84e199bf..f9151207 100644 --- a/src/Store/ProjectStore.php +++ b/src/Store/ProjectStore.php @@ -7,6 +7,7 @@ use Exception; use PDO; use PHPCensor\Exception\HttpException; +use PHPCensor\Model\Environment; use PHPCensor\Model\Project; use PHPCensor\Store; @@ -70,9 +71,7 @@ public function getByTitle(string $title, int $limit = 1000, string $useConnecti if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new Project($this->storeRegistry, $item); - }; + $map = fn ($item) => new Project($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); @@ -97,9 +96,7 @@ public function getKnownBranches(int $projectId): array if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return $item['branch']; - }; + $map = fn ($item) => $item['branch']; return \array_map($map, $res); } else { @@ -122,9 +119,7 @@ public function getAll(string $useConnection = 'read', bool $archived = false): if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new Project($this->storeRegistry, $item); - }; + $map = fn ($item) => new Project($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); @@ -158,9 +153,7 @@ public function getByGroupId(int $groupId, bool $archived = false, int $limit = if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new Project($this->storeRegistry, $item); - }; + $map = fn ($item) => new Project($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); diff --git a/src/Store/UserStore.php b/src/Store/UserStore.php index 74980b6b..fb0ad4a3 100644 --- a/src/Store/UserStore.php +++ b/src/Store/UserStore.php @@ -114,9 +114,7 @@ public function getByName(string $name, int $limit = 1000, string $useConnection if ($stmt->execute()) { $res = $stmt->fetchAll(PDO::FETCH_ASSOC); - $map = function ($item) { - return new User($this->storeRegistry, $item); - }; + $map = fn ($item) => new User($this->storeRegistry, $item); $rtn = \array_map($map, $res); $count = \count($rtn); diff --git a/src/Worker/BuildWorker.php b/src/Worker/BuildWorker.php index 21f22a0e..21c11b91 100644 --- a/src/Worker/BuildWorker.php +++ b/src/Worker/BuildWorker.php @@ -63,7 +63,7 @@ class BuildWorker private Pheanstalk $pheanstalk; - private int $lastPeriodical; + private int $lastPeriodical = 0; public function __construct( ConfigurationInterface $configuration, @@ -87,7 +87,6 @@ public function __construct( $this->queueTube = $queueTube; $this->pheanstalk = Pheanstalk::create($queueHost, $queuePort); - $this->lastPeriodical = 0; $this->canPeriodicalWork = $canPeriodicalWork; } diff --git a/tests/src/Command/CreateBuildCommandTest.php b/tests/src/Command/CreateBuildCommandTest.php index b4dac954..81b2ec72 100644 --- a/tests/src/Command/CreateBuildCommandTest.php +++ b/tests/src/Command/CreateBuildCommandTest.php @@ -85,9 +85,9 @@ public function testExecute(): void { $commandTester = $this->getCommandTester(); - $commandTester->execute(['projectId' => 1]); - $commandTester->execute(['projectId' => 1, '--commit' => '92c8c6e']); - $commandTester->execute(['projectId' => 1, '--branch' => 'master']); + $commandTester->execute(['project-id' => 1]); + $commandTester->execute(['project-id' => 1, '--commit' => '92c8c6e']); + $commandTester->execute(['project-id' => 1, '--branch' => 'master']); self::assertTrue(true); } @@ -97,6 +97,6 @@ public function testExecuteWithUnknownProjectId(): void self::expectException(InvalidArgumentException::class); $commandTester = $this->getCommandTester(); - $commandTester->execute(['projectId' => 2]); + $commandTester->execute(['project-id' => 2]); } } diff --git a/tests/src/Plugin/TelegramNotifyTest.php b/tests/src/Plugin/TelegramNotifyTest.php new file mode 100644 index 00000000..80e66063 --- /dev/null +++ b/tests/src/Plugin/TelegramNotifyTest.php @@ -0,0 +1,42 @@ +getMethod('splitChatIdAndTopicId'); + $method->setAccessible(true); + $instance = $reflection->newInstanceWithoutConstructor(); + + $result = $method->invoke($instance, $chatId); + self::assertSame($expectedThreadId, $result); + } + + public function chatIdProvider(): array + { + return [ + 'without message thread id' => ['-12345', ['-12345', null]], + 'with message thread id' => ['12345/67890', ['12345', '67890']], + 'empty thread id' => ['12345/', ['12345', null]], + 'not group chat' => ['12345', ['12345', null]], + 'empty input' => ['', ['', null]], + 'only slash' => ['/', ['', null]], + 'double slash' => ['//', ['', null]], + 'group id digits only' => [12345, ['12345', null]], + 'group id digits only (negative)' => [-12345, ['-12345', null]], + 'zero topic id' => ['-12345/0', ['-12345', '0']], + 'spaces' => [' -12345/0 ', ['-12345', '0']], + ]; + } +}