From 76c682dd5df0e5125d15222d535b9c93b100743f Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Mon, 15 Mar 2021 17:40:02 +0100 Subject: [PATCH] Bump everything --- .gitattributes | 10 +++ .github/workflows/coding-standards.yml | 34 +++++++++ .github/workflows/continuous-integration.yml | 74 ++++++++++++++++++++ .github/workflows/static-analysis.yml | 59 ++++++++++++++++ .gitignore | 3 +- .scrutinizer.yml | 32 --------- .travis.yml | 56 --------------- LICENCE | 30 ++++++++ README.md | 42 +++++++++-- composer.json | 17 +++-- phpcs.xml.dist | 6 +- phpstan.neon.dist | 2 - phpunit.xml.dist | 8 +-- psalm.xml.dist | 25 +++++++ src/Extractor/Extractor.php | 10 +-- src/Extractor/RequestExtractor.php | 8 +-- src/Extractor/ResponseExtractor.php | 24 +++---- src/HttpJsonRpcRequestFactory.php | 16 ++--- src/JsonRpcRequestFactory.php | 2 +- 19 files changed, 316 insertions(+), 142 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/workflows/coding-standards.yml create mode 100644 .github/workflows/continuous-integration.yml create mode 100644 .github/workflows/static-analysis.yml delete mode 100644 .scrutinizer.yml delete mode 100644 .travis.yml create mode 100644 LICENCE create mode 100644 psalm.xml.dist diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..4eed74e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text eol=lf +/.gitattributes export-ignore +/.gitignore export-ignore +/.github export-ignore +/phpcs.xml.dist export-ignore +/phpstan.neon.dist export-ignore +/phpunit.xml.dist export-ignore +/psalm.xml.dist export-ignore +/tests export-ignore diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml new file mode 100644 index 0000000..2582648 --- /dev/null +++ b/.github/workflows/coding-standards.yml @@ -0,0 +1,34 @@ +name: "Coding Standards" + +on: + pull_request: + push: + branches: + - "master" + +jobs: + coding-standards: + name: "Coding Standards" + runs-on: "ubuntu-20.04" + + strategy: + matrix: + php-version: + - "7.4" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + tools: "cs2pr" + + - name: "Install dependencies with Composer" + uses: "ramsey/composer-install@v1" + + - name: "Run PHP_CodeSniffer" + run: "vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr" diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..7131de5 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,74 @@ +name: "CI" + +on: + pull_request: + push: + branches: + - "master" + schedule: + - cron: "42 3 * * *" + +jobs: + phpunit: + name: "PHPUnit" + runs-on: "ubuntu-20.04" + + strategy: + matrix: + php-version: + - "7.4" + - "8.0" + dependencies: + - "highest" + include: + - dependencies: "lowest" + php-version: "7.4" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + with: + fetch-depth: 2 + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + coverage: "pcov" + ini-values: "zend.assertions=1" + + - name: "Install dependencies with Composer" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "${{ matrix.dependencies }}" + + - name: "Run PHPUnit" + run: "vendor/bin/phpunit --coverage-clover=coverage.xml" + + - name: "Upload coverage file" + uses: "actions/upload-artifact@v2" + with: + name: "phpunit-${{ matrix.deps }}-${{ matrix.php-version }}.coverage" + path: "coverage.xml" + + upload_coverage: + name: "Upload coverage to Codecov" + runs-on: "ubuntu-20.04" + needs: + - "phpunit" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + with: + fetch-depth: 2 + + - name: "Download coverage files" + uses: "actions/download-artifact@v2" + with: + path: "reports" + + - name: "Upload to Codecov" + uses: "codecov/codecov-action@v1" + with: + directory: reports diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..62fd758 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,59 @@ +name: "Static Analysis" + +on: + pull_request: + push: + branches: + - "master" + +jobs: + static-analysis-phpstan: + name: "Static Analysis with PHPStan" + runs-on: "ubuntu-20.04" + + strategy: + matrix: + php-version: + - "7.4" + + steps: + - name: "Checkout code" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + tools: "cs2pr" + + - name: "Install dependencies with Composer" + uses: "ramsey/composer-install@v1" + + - name: "Run a static analysis with phpstan/phpstan" + run: "vendor/bin/phpstan --error-format=checkstyle | cs2pr" + + static-analysis-psalm: + name: "Static Analysis with Psalm" + runs-on: "ubuntu-20.04" + + strategy: + matrix: + php-version: + - "7.4" + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Psalm + uses: docker://vimeo/psalm-github-actions:4.3.2 + with: + args: --shepherd + composer_require_dev: true + security_analysis: true + report_file: results.sarif + - name: Upload Security Analysis results to GitHub + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index 202d7c9..56ed85a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ -/vendor/ /.phpcs-cache /.phpunit.result.cache /composer.lock /phpcs.xml /phpstan.neon +/psalm.xml /phpunit.xml +/vendor/ diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 96b33ae..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,32 +0,0 @@ -build: - nodes: - analysis: - environment: - php: - version: 7.2 - cache: - disabled: false - directories: - - ~/.composer/cache - project_setup: - override: true - tests: - override: - - php-scrutinizer-run - - phpcs-run - dependencies: - override: - - COMPOSER_ARGS="--prefer-stable" make - -checks: - php: - code_rating: true - -tools: - external_code_coverage: - timeout: 3600 - -build_failure_conditions: - - 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed - - 'issues.severity(>= MAJOR).new.exists' # New issues of major or higher severity - - 'project.metric_change("scrutinizer.test_coverage", < 0)' # Code Coverage decreased from previous inspection diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ed38a5f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,56 +0,0 @@ -dist: xenial -language: php - -php: - - "7.2" - - "7.3" - - 7.4snapshot - - nightly - -env: - - DEPENDENCIES= - - DEPENDENCIES=--prefer-lowest - -before_install: - - mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available" - -install: COMPOSER_ARGS="--prefer-stable $DEPENDENCIES" make - -script: make test - -stages: - - Code Quality - - Test - -jobs: - allow_failures: - - php: 7.4snapshot - - php: nightly - - include: - - stage: Code Quality - name: Lint - php: "7.2" - script: make lint - - name: Coding Standard - php: "7.2" - script: make cs - - name: Static Analysis - php: "7.2" - script: make static-analysis - - - stage: Test - name: COVERAGE - php: "7.2" - before_script: - - mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{.disabled,} - - if [[ ! $(php -m | grep -si xdebug) ]]; then echo "xdebug required for coverage"; exit 1; fi - script: - - ./vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml - after_script: - - wget https://github.com/scrutinizer-ci/ocular/releases/download/1.6.0/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml - -cache: - directories: - - $HOME/.composer/cache diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..6d861d3 --- /dev/null +++ b/LICENCE @@ -0,0 +1,30 @@ +License +======= + +This work is published under the MIT license (see full statement below). +If you want to deal (as described below) only with a part of this work, +you have to include this license in the part itself. + +The MIT License (MIT) +--------------------- + +Copyright (c) 2014-2015 VaĊĦek Purchart + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/README.md b/README.md index 6e391e5..cfebd40 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,38 @@ # JSON RPC 2.0 PSR-7 Message Factory -[![Build Status](https://travis-ci.com/simpod/json-rpc.svg?branch=master)](https://travis-ci.com/simpod/json-rpc) -[![Downloads](https://poser.pugx.org/simpod/json-rpc/d/total.svg)](https://packagist.org/packages/simpod/json-rpc) -[![Packagist](https://poser.pugx.org/simpod/json-rpc/v/stable.svg)](https://packagist.org/packages/simpod/json-rpc) -[![Licence](https://poser.pugx.org/simpod/json-rpc/license.svg)](https://packagist.org/packages/simpod/json-rpc) -[![Quality Score](https://scrutinizer-ci.com/g/simpod/json-rpc/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/simpod/json-rpc) -[![Code Coverage](https://scrutinizer-ci.com/g/simpod/json-rpc/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/simpod/json-rpc) +[![GitHub Actions][GA Image]][GA Link] +[![Shepherd Type][Shepherd Image]][Shepherd Link] +[![Code Coverage][Coverage Image]][CodeCov Link] +[![Downloads][Downloads Image]][Packagist Link] +[![Packagist][Packagist Image]][Packagist Link] +[![Infection MSI][Infection Image]][Infection Link] + +## Installation + +Add as [Composer](https://getcomposer.org/) dependency: + +```sh +composer require simpod/json-rpc +``` + +[GA Image]: https://github.com/simPod/PhpJsonRpc/workflows/CI/badge.svg + +[GA Link]: https://github.com/simPod/PhpJsonRpc/actions?query=workflow%3A%22CI%22+branch%3Amaster + +[Shepherd Image]: https://shepherd.dev/github/simPod/PhpJsonRpc/coverage.svg + +[Shepherd Link]: https://shepherd.dev/github/simPod/PhpJsonRpc + +[Coverage Image]: https://codecov.io/gh/simPod/PhpJsonRpc/branch/master/graph/badge.svg + +[CodeCov Link]: https://codecov.io/gh/simPod/PhpJsonRpc/branch/master + +[Downloads Image]: https://poser.pugx.org/simpod/json-rpc/d/total.svg + +[Packagist Image]: https://poser.pugx.org/simpod/json-rpc/v/stable.svg + +[Packagist Link]: https://packagist.org/packages/simpod/json-rpc + +[Infection Image]: https://badge.stryker-mutator.io/github.com/simPod/PhpJsonRpc/master + +[Infection Link]: https://infection.github.io diff --git a/composer.json b/composer.json index fdd0691..d7084b4 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } }, "require": { - "php": "^7.2", + "php": "^7.4 || ^8.0", "ext-json": "*", "nyholm/psr7": "^1.2", "php-http/httplug": "^2.0", @@ -25,14 +25,17 @@ "thecodingmachine/safe": "^1.0.2" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "cdn77/coding-standard": "^4.0", + "hectorj/safe-php-psalm-plugin": "dev-master#b60ed45a06d5246e2efd193ce9c8940b244d5c7d", "jakub-onderka/php-parallel-lint": "^1.0", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.11.16", - "phpstan/phpstan-phpunit": "^0.11.2", - "phpstan/phpstan-strict-rules": "^0.11.1", - "phpunit/phpunit": "^8.4", - "thecodingmachine/phpstan-safe-rule": "^1.0" + "phpstan/phpstan": "0.12.81", + "phpstan/phpstan-phpunit": "0.12.18", + "phpstan/phpstan-strict-rules": "^0.12.7", + "phpunit/phpunit": "^9.5", + "psalm/plugin-phpunit": "0.15.1", + "thecodingmachine/phpstan-safe-rule": "^1.0", + "vimeo/psalm": "4.6.3" }, "config": { "sort-packages": true diff --git a/phpcs.xml.dist b/phpcs.xml.dist index e6d6f46..e8ad2a2 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -3,9 +3,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd" > - + - + + + src/ tests/ diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9e70cb2..8ea502f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,4 @@ parameters: - bootstrap: %currentWorkingDirectory%/tests/bootstrap.php - memory-limit: -1 level: max paths: - %currentWorkingDirectory%/src diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9e0190f..9247927 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,9 +13,9 @@ tests - - + + src - - + + diff --git a/psalm.xml.dist b/psalm.xml.dist new file mode 100644 index 0000000..fe880b6 --- /dev/null +++ b/psalm.xml.dist @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/src/Extractor/Extractor.php b/src/Extractor/Extractor.php index adccf46..846ccc9 100644 --- a/src/Extractor/Extractor.php +++ b/src/Extractor/Extractor.php @@ -5,16 +5,18 @@ namespace SimPod\JsonRpc\Extractor; use Psr\Http\Message\MessageInterface; + use function Safe\json_decode; abstract class Extractor { - /** @var mixed[] */ - protected $messageContents; + /** @var array{id: string, jsonrpc: string, error?: array{code: int, message: string, data?: mixed}, method: string, params?: array} */ + protected array $messageContents; public function __construct(MessageInterface $message) { - $body = $message->getBody(); - $this->messageContents = json_decode((string) $body, true); + /** @var array{id: string, jsonrpc: string, error?: array{code: int, message: string, data?: mixed}, method: string, params?: array} $contents */ + $contents = json_decode((string) $message->getBody(), true); + $this->messageContents = $contents; } } diff --git a/src/Extractor/RequestExtractor.php b/src/Extractor/RequestExtractor.php index c15d244..c3fa34c 100644 --- a/src/Extractor/RequestExtractor.php +++ b/src/Extractor/RequestExtractor.php @@ -6,9 +6,7 @@ final class RequestExtractor extends Extractor { - /** - * @return string|int|null - */ + /** @return string|int|null */ public function getId() { return $this->messageContents['id'] ?? null; @@ -19,9 +17,7 @@ public function getMethod() : string return $this->messageContents['method']; } - /** - * @return mixed[]|null - */ + /** @return mixed[]|null */ public function getParams() : ?array { return $this->messageContents['params'] ?? null; diff --git a/src/Extractor/ResponseExtractor.php b/src/Extractor/ResponseExtractor.php index 4eb97ba..9752f73 100644 --- a/src/Extractor/ResponseExtractor.php +++ b/src/Extractor/ResponseExtractor.php @@ -8,33 +8,33 @@ final class ResponseExtractor extends Extractor { public function getErrorCode() : ?int { - return $this->messageContents['error']['code'] ?? null; + $error = $this->messageContents['error'] ?? null; + + return $error === null ? null : $error['code']; } public function getErrorMessage() : ?string { - return $this->messageContents['error']['message'] ?? null; + $error = $this->messageContents['error'] ?? null; + + return $error === null ? null : $error['message']; } - /** - * @return mixed - */ + /** @return mixed */ public function getErrorData() { - return $this->messageContents['error']['data'] ?? null; + $error = $this->messageContents['error'] ?? null; + + return $error === null ? null : ($error['data'] ?? null); } - /** - * @return string|int|null - */ + /** @return string|int|null */ public function getId() { return $this->messageContents['id'] ?? null; } - /** - * @return mixed - */ + /** @return mixed */ public function getResult() { return $this->messageContents['result'] ?? null; diff --git a/src/HttpJsonRpcRequestFactory.php b/src/HttpJsonRpcRequestFactory.php index 53cb555..a265703 100644 --- a/src/HttpJsonRpcRequestFactory.php +++ b/src/HttpJsonRpcRequestFactory.php @@ -7,14 +7,14 @@ use Nyholm\Psr7\Stream; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\RequestInterface; + use function Safe\json_encode; final class HttpJsonRpcRequestFactory implements JsonRpcRequestFactory { private const V2_0 = '2.0'; - /** @var RequestFactoryInterface */ - private $messageFactory; + private RequestFactoryInterface $messageFactory; public function __construct(RequestFactoryInterface $messageFactory) { @@ -29,8 +29,8 @@ public function notification(string $method, ?array $params = null) : RequestInt return $this->createRequest( [ 'jsonrpc' => self::V2_0, - 'method' => $method, - 'params' => $params, + 'method' => $method, + 'params' => $params, ] ); } @@ -42,8 +42,8 @@ public function request($id, string $method, ?array $params = null) : RequestInt { $body = [ 'jsonrpc' => self::V2_0, - 'method' => $method, - 'id' => $id, + 'method' => $method, + 'id' => $id, ]; if ($params !== null) { @@ -53,9 +53,7 @@ public function request($id, string $method, ?array $params = null) : RequestInt return $this->createRequest($body); } - /** - * @param mixed[] $body - */ + /** @param mixed[] $body */ private function createRequest(array $body = []) : RequestInterface { return $this->messageFactory->createRequest('POST', '') diff --git a/src/JsonRpcRequestFactory.php b/src/JsonRpcRequestFactory.php index b6a5d35..50647ca 100644 --- a/src/JsonRpcRequestFactory.php +++ b/src/JsonRpcRequestFactory.php @@ -8,7 +8,7 @@ interface JsonRpcRequestFactory { - public const METHOD_REQUEST = 'REQUEST'; + public const METHOD_REQUEST = 'REQUEST'; public const METHOD_NOTIFICATION = 'NOTIFICATION'; /**