diff --git a/.editorconfig b/.editorconfig index b26a9a9..dd9a2b5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,15 +1,15 @@ -; This file is for unifying the coding style for different editors and IDEs. -; More information at https://editorconfig.org - root = true [*] charset = utf-8 +end_of_line = lf indent_size = 4 indent_style = space -end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 48a95b6..c09f81e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,15 +2,19 @@ # https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html # Ignore all test and documentation with "export-ignore". -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.scrutinizer.yml export-ignore -/.styleci.yml export-ignore -/.travis.yml export-ignore -/PULL_REQUEST_TEMPLATE.md export-ignore -/ISSUE_TEMPLATE.md export-ignore -/phpcs.xml.dist export-ignore -/phpunit.xml.dist export-ignore -/tests export-ignore -/docs export-ignore +/.github export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/phpunit.xml.dist export-ignore +/art export-ignore +/docs export-ignore +/tests export-ignore +/workbench export-ignore +/.editorconfig export-ignore +/.php_cs.dist.php export-ignore +/psalm.xml export-ignore +/psalm.xml.dist export-ignore +/testbench.yaml export-ignore +/UPGRADING.md export-ignore +/phpstan.neon.dist export-ignore +/phpstan-baseline.neon export-ignore diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..fe4cfe6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,66 @@ +name: Bug Report +description: Report an Issue or Bug with the Package +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + We're sorry to hear you have a problem. Can you help us solve it by providing the following details. + - type: textarea + id: what-happened + attributes: + label: What happened? + description: What did you expect to happen? + placeholder: I cannot currently do X thing because when I do, it breaks X thing. + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce the bug + description: How did this occur, please add any config values used and provide a set of reliable steps if possible. + placeholder: When I do X I see Y. + validations: + required: true + - type: input + id: package-version + attributes: + label: Package Version + description: What version of our Package are you running? Please be as specific as possible + placeholder: 2.0.0 + validations: + required: true + - type: input + id: php-version + attributes: + label: PHP Version + description: What version of PHP are you running? Please be as specific as possible + placeholder: 8.2.0 + validations: + required: true + - type: input + id: laravel-version + attributes: + label: Laravel Version + description: What version of Laravel are you running? Please be as specific as possible + placeholder: 9.0.0 + validations: + required: true + - type: dropdown + id: operating-systems + attributes: + label: Which operating systems does with happen with? + description: You may select more than one. + multiple: true + options: + - macOS + - Windows + - Linux + - type: textarea + id: notes + attributes: + label: Notes + description: Use this field to provide any other notes that you feel might be relevant to the issue. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..33c2cdd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Ask a question + url: https://github.com/swisnl/laravel-psr-http-client-bridge/discussions/new?category=q-a + about: Ask the community for help + - name: Request a feature + url: https://github.com/swisnl/laravel-psr-http-client-bridge/discussions/new?category=ideas + about: Share ideas for new features + - name: Report a security issue + url: https://github.com/swisnl/laravel-psr-http-client-bridge/security/policy + about: Learn how to notify us for sensitive bugs diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..39b1580 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" + + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..70d8e7b --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,33 @@ +name: dependabot-auto-merge +on: pull_request_target + +permissions: + pull-requests: write + contents: write + +jobs: + dependabot: + runs-on: ubuntu-latest + timeout-minutes: 5 + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v1.6.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Auto-merge Dependabot PRs for semver-minor updates + if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Auto-merge Dependabot PRs for semver-patch updates + if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/fix-php-code-style-issues.yml b/.github/workflows/fix-php-code-style-issues.yml new file mode 100644 index 0000000..cd4239c --- /dev/null +++ b/.github/workflows/fix-php-code-style-issues.yml @@ -0,0 +1,28 @@ +name: Fix PHP code style issues + +on: + push: + paths: + - '**.php' + +permissions: + contents: write + +jobs: + php-code-styling: + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + + - name: Fix PHP code style issues + uses: aglipanci/laravel-pint-action@2.3.1 + + - name: Commit changes + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Fix styling diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000..af21e45 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,28 @@ +name: PHPStan + +on: + push: + paths: + - '**.php' + - 'phpstan.neon.dist' + - '.github/workflows/phpstan.yml' + +jobs: + phpstan: + name: phpstan + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: none + + - name: Install composer dependencies + uses: ramsey/composer-install@v2 + + - name: Run PHPStan + run: ./vendor/bin/phpstan --error-format=github diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..758c4ed --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,54 @@ +name: run-tests + +on: + push: + paths: + - '**.php' + - '.github/workflows/run-tests.yml' + - 'phpunit.xml.dist' + - 'composer.json' + - 'composer.lock' + +jobs: + test: + runs-on: ${{ matrix.os }} + timeout-minutes: 5 + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest, windows-latest] + php: [8.3, 8.2, 8.1] + laravel: [10.*] + stability: [prefer-lowest, prefer-stable] + include: + - laravel: 10.* + testbench: 8.* + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo + coverage: none + + - name: Setup problem matchers + run: | + echo "::add-matcher::${{ runner.tool_cache }}/php.json" + echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Install dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.stability }} --prefer-dist --no-interaction + + - name: List Installed Dependencies + run: composer show -D + + - name: Execute tests + run: vendor/bin/pest --ci diff --git a/.gitignore b/.gitignore index 2acd464..a7f372d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ .idea +.phpunit.cache build composer.lock -vendor +coverage +docs phpunit.xml -.phpunit.result.cache +phpstan.neon +testbench.yaml +vendor +node_modules diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 629ac3c..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,31 +0,0 @@ -build: - nodes: - analysis: - project_setup: - override: true - tests: - override: [php-scrutinizer-run] - -filter: - excluded_paths: [tests/*] - -checks: - php: - remove_extra_empty_lines: true - remove_php_closing_tag: true - remove_trailing_whitespace: true - fix_use_statements: - remove_unused: true - preserve_multiple: false - preserve_blanklines: true - order_alphabetically: true - fix_php_opening_tag: true - fix_linefeed: true - fix_line_ending: true - fix_identation_4spaces: true - fix_doc_comments: true - -tools: - external_code_coverage: - timeout: 600 - runs: 4 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 24e20fa..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: php - -php: - - 7.4 - - 8.0 - - 8.1 - -## Cache composer -cache: - directories: - - $HOME/.composer/cache - -matrix: - include: - - php: 7.4 - env: 'COMPOSER_FLAGS="--prefer-stable --prefer-lowest"' - -before_script: - - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist - -script: - - vendor/bin/php-cs-fixer fix -v --dry-run --using-cache=no - - XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover - -after_script: - - | - composer global require --no-interaction --prefer-dist scrutinizer/ocular - ~/.config/composer/vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 5b48c57..0000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,27 +0,0 @@ - - -## Detailed description - -Provide a detailed description of the change or addition you are proposing. - -Make it clear if the issue is a bug, an enhancement or just a question. - -## Context - -Why is this change important to you? How would you use it? - -How can it benefit other users? - -## Possible implementation - -Not obligatory, but suggest an idea for implementing addition or change. - -## Your environment - -Include as many relevant details about the environment you experienced the bug in and how to reproduce it. - -* Version used (e.g. PHP 5.6, HHVM 3): -* Operating system and version (e.g. Ubuntu 16.04, Windows 7): -* Link to your project: -* ... -* ... diff --git a/README.md b/README.md index aeda05d..76f5644 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,23 @@ [![Latest Version on Packagist][ico-version]][link-packagist] [![Software License][ico-license]](LICENSE.md) [![Buy us a tree][ico-treeware]][link-treeware] -[![Build Status][ico-travis]][link-travis] -[![Coverage Status][ico-scrutinizer]][link-scrutinizer] -[![Quality Score][ico-code-quality]][link-code-quality] +[![Build Status][ico-github-actions]][link-github-actions] [![Total Downloads][ico-downloads]][link-downloads] [![Made by SWIS][ico-swis]][link-swis] -Provides a bridge to use the Laravel HTTP Client as PSR-18 HTTP Client. Created as an experiment to use the HTTP response fakes and assertions in tests, for libraries that require a PSR-18 HTTP Client. +Provides a bridge to use the Laravel HTTP Client as PSR-18 HTTP Client, for usage with libraries that require such a Client. This allows you to: + + * 🤖 Use request fakes and assertions in your tests + * 🔍 Debug requests in tools like Telescope or Pulse + * 🐛 See requests in error trackers such as Flare or Sentry + * 🚀 Etc. ## Install Via Composer ``` bash -$ composer require swisnl/laravel-psr-http-client-bridge +composer require swisnl/laravel-psr-http-client-bridge ``` ## Usage @@ -30,7 +33,9 @@ $response = $client->sendRequest($request); If you want to configure some request options, you can provide a callable that returns a `PendingRequest`. ``` php -$client = new Swis\Laravel\Bridge\PsrHttpClient\Client(fn () => Http::withOptions(['proxy' => 'http://localhost:8125'])); +$client = new Swis\Laravel\Bridge\PsrHttpClient\Client( + fn () => Http::withOptions(['proxy' => 'http://localhost:8125']) +); ``` ## Change log @@ -40,7 +45,7 @@ Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed re ## Testing ``` bash -$ composer test +composer test ``` ## Contributing @@ -49,7 +54,7 @@ Please see [CONTRIBUTING](CONTRIBUTING.md) and [CODE_OF_CONDUCT](CODE_OF_CONDUCT ## Security -If you discover any security related issues, please email security@swis.nl instead of using the issue tracker. +Please review [our security policy](../../security/policy) on how to report security vulnerabilities. ## Credits @@ -69,16 +74,12 @@ This package is [Treeware](https://treeware.earth). If you use it in production, [ico-version]: https://img.shields.io/packagist/v/swisnl/laravel-psr-http-client-bridge.svg?style=flat-square [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square [ico-treeware]: https://img.shields.io/badge/Treeware-%F0%9F%8C%B3-lightgreen.svg?style=flat-square -[ico-travis]: https://img.shields.io/travis/swisnl/laravel-psr-http-client-bridge/master.svg?style=flat-square -[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/swisnl/laravel-psr-http-client-bridge.svg?style=flat-square -[ico-code-quality]: https://img.shields.io/scrutinizer/g/swisnl/laravel-psr-http-client-bridge.svg?style=flat-square +[ico-github-actions]: https://img.shields.io/github/actions/workflow/status/swisnl/laravel-psr-http-client-bridge/run-tests.yml?label=tests&branch=master&style=flat-square [ico-downloads]: https://img.shields.io/packagist/dt/swisnl/laravel-psr-http-client-bridge.svg?style=flat-square [ico-swis]: https://img.shields.io/badge/%F0%9F%9A%80-made%20by%20SWIS-%230737A9.svg?style=flat-square [link-packagist]: https://packagist.org/packages/swisnl/laravel-psr-http-client-bridge -[link-travis]: https://travis-ci.com/github/swisnl/laravel-psr-http-client-bridge -[link-scrutinizer]: https://scrutinizer-ci.com/g/swisnl/laravel-psr-http-client-bridge/code-structure -[link-code-quality]: https://scrutinizer-ci.com/g/swisnl/laravel-psr-http-client-bridge +[link-github-actions]: https://github.com/swisnl/laravel-psr-http-client-bridge/actions/workflows/run-tests.yml [link-downloads]: https://packagist.org/packages/swisnl/laravel-psr-http-client-bridge [link-treeware]: https://plant.treeware.earth/swisnl/laravel-psr-http-client-bridge [link-author]: https://github.com/swisnl diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..602c615 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,12 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|---------| ------------------ | +| 1.x | :white_check_mark: | +| 0.x | :x: | + +## Reporting a Vulnerability + +If you discover any security related issues, please email security@swis.nl instead of using the issue tracker. diff --git a/composer.json b/composer.json index 17927b0..2d756eb 100644 --- a/composer.json +++ b/composer.json @@ -23,15 +23,22 @@ } ], "require": { - "php": "^7.4|^8.0", - "laravel/framework": "^10.0", + "php": "^8.1", + "illuminate/contracts": "^10.0", "psr/http-client": "^1.0" }, "require-dev": { "guzzlehttp/guzzle": "^7.4", "laravel/pint": "^1.0", - "orchestra/testbench": "^8.21", - "phpunit/phpunit": "^9.5" + "nunomaduro/collision": "^7.8", + "larastan/larastan": "^2.0.1", + "orchestra/testbench": "^8.8", + "pestphp/pest": "^2.20", + "pestphp/pest-plugin-arch": "^2.5", + "pestphp/pest-plugin-laravel": "^2.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0" }, "autoload": { "psr-4": { @@ -44,15 +51,18 @@ } }, "scripts": { - "test": "vendor/bin/phpunit", + "analyse": "vendor/bin/phpstan analyse", + "test": "vendor/bin/pest", + "test-coverage": "vendor/bin/pest --coverage", "format": "vendor/bin/pint" }, - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" + "config": { + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true, + "phpstan/extension-installer": true } }, - "config": { - "sort-packages": true - } + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..e69de29 diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..2093489 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,9 @@ +includes: + - phpstan-baseline.neon + +parameters: + level: 6 + paths: + - src + tmpDir: build/phpstan + checkMissingIterableValueType: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a8222c6..289ebac 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,28 +1,38 @@ - + - + tests - - - src/ - - + + + + + + + - - - - + + + + ./src + + diff --git a/tests/ArchTest.php b/tests/ArchTest.php new file mode 100644 index 0000000..87fb64c --- /dev/null +++ b/tests/ArchTest.php @@ -0,0 +1,5 @@ +expect(['dd', 'dump', 'ray']) + ->each->not->toBeUsed(); diff --git a/tests/ClientTest.php b/tests/ClientTest.php index bac85f6..d77b883 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -1,53 +1,37 @@ Http::response('foo=baz', 404, ['X-Foo' => 'Baz'])]); - - $client = new Client(); - $response = $client->sendRequest(new PsrRequest('POST', 'https://example.com', ['X-Foo' => 'Bar'], 'foo=bar')); - - Http::assertSent(function (Request $request) { - return $request->method() === 'POST' - && $request->url() === 'https://example.com' - && $request->hasHeader('X-Foo', 'Bar') - && $request->body() === 'foo=bar'; - }); - - $this->assertEquals('foo=baz', (string) $response->getBody()); - $this->assertEquals(404, $response->getStatusCode()); - $this->assertEquals(['Baz'], $response->getHeader('X-Foo')); - } - - /** - * @test - */ - public function itUsesTheProvidedRequestFactory(): void - { - Http::fake(['*' => Http::response()]); - - $client = new Client(fn () => Http::withHeaders(['X-Foo' => 'Bar'])); - $client->sendRequest(new PsrRequest('GET', 'https://example.com')); - - Http::assertSent(function (Request $request) { - return $request->method() === 'GET' - && $request->url() === 'https://example.com' - && $request->hasHeader('X-Foo', 'Bar'); - }); - } -} +it('can send a request', function () { + Http::fake(['*' => Http::response('foo=baz', 404, ['X-Foo' => 'Baz'])]); + + $client = new Client(); + $response = $client->sendRequest(new PsrRequest('POST', 'https://example.com', ['X-Foo' => 'Bar'], 'foo=bar')); + + Http::assertSent(function (Request $request) { + return $request->method() === 'POST' + && $request->url() === 'https://example.com' + && $request->hasHeader('X-Foo', 'Bar') + && $request->body() === 'foo=bar'; + }); + + expect((string)$response->getBody())->toBe('foo=baz') + ->and($response->getStatusCode())->toBe(404) + ->and($response->getHeader('X-Foo'))->toBe(['Baz']); +}); + +it('uses the provided request factory', function () { + Http::fake(['*' => Http::response()]); + + $client = new Client(fn () => Http::withHeaders(['X-Foo' => 'Bar'])); + $client->sendRequest(new PsrRequest('GET', 'https://example.com')); + + Http::assertSent(function (Request $request) { + return $request->method() === 'GET' + && $request->url() === 'https://example.com' + && $request->hasHeader('X-Foo', 'Bar'); + }); +}); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..d45cfd7 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,5 @@ +in(__DIR__);