From aaf06cd57cdf729ad079abaa8587bcb643a6d946 Mon Sep 17 00:00:00 2001 From: ziming Date: Sun, 23 Aug 2026 17:27:23 +0800 Subject: [PATCH 1/4] Allow Guzzle 8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4626f630..67d76225 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "homepage": "https://github.com/saloonphp/saloon", "require": { "php": "^8.2", - "guzzlehttp/guzzle": "^7.6", + "guzzlehttp/guzzle": "^7.6 || ^8.0", "guzzlehttp/promises": "^1.5 || ^2.0", "guzzlehttp/psr7": "^2.0", "psr/http-factory": "^1.0", From e012fc5b083deeedfcd19cb859ecf4b73e9d4f3f Mon Sep 17 00:00:00 2001 From: ziming Date: Tue, 25 Aug 2026 17:20:39 +0800 Subject: [PATCH 2/4] Allow guzzlehttp/promises & guzzlehttp/psr7 ^3.0 too --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 67d76225..c6c78b1e 100644 --- a/composer.json +++ b/composer.json @@ -21,8 +21,8 @@ "require": { "php": "^8.2", "guzzlehttp/guzzle": "^7.6 || ^8.0", - "guzzlehttp/promises": "^1.5 || ^2.0", - "guzzlehttp/psr7": "^2.0", + "guzzlehttp/promises": "^1.5 || ^2.0 || ^3.0", + "guzzlehttp/psr7": "^2.0 || ^3.0", "psr/http-factory": "^1.0", "psr/http-message": "^1.1 || ^2.0" }, From 30891888fb2d1b9392d81bdf7f3d344b8e6e2fc4 Mon Sep 17 00:00:00 2001 From: Sammyjo20 <29132017+Sammyjo20@users.noreply.github.com> Date: Fri, 4 Sep 2026 21:38:40 +0100 Subject: [PATCH 3/4] Updated tests and matrix --- .github/workflows/tests.yml | 9 ++++++--- src/Http/Senders/GuzzleSender.php | 12 ++++++++++-- tests/Feature/Body/HasMultipartBodyTest.php | 2 -- tests/Feature/GuzzleSenderTest.php | 4 ++-- tests/Feature/RetryConnectorTest.php | 4 ++-- tests/Feature/RetryRequestTest.php | 4 ++-- tests/Feature/SendAndRetryTest.php | 4 ++-- tests/Fixtures/Senders/ArraySender.php | 2 +- 8 files changed, 25 insertions(+), 16 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9a3cf544..23698859 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,9 +26,11 @@ jobs: matrix: os: [ ubuntu-latest, windows-latest ] php: [ 8.2, 8.3, 8.4, 8.5 ] - stability: [ prefer-lowest, prefer-stable ] + guzzle: + - { constraint: '^7.6', stability: prefer-lowest } + - { constraint: '^8.0', stability: prefer-stable } - name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} + name: P${{ matrix.php }} - Guzzle ${{ matrix.guzzle.constraint }} - ${{ matrix.os }} steps: - name: Checkout code @@ -48,6 +50,7 @@ jobs: - name: Install dependencies run: | - composer update --${{ matrix.stability }} --prefer-dist --no-interaction + composer require guzzlehttp/guzzle:${{ matrix.guzzle.constraint }} --no-update + composer update --${{ matrix.guzzle.stability }} --prefer-dist --no-interaction - name: Execute tests run: vendor/bin/pest -p diff --git a/src/Http/Senders/GuzzleSender.php b/src/Http/Senders/GuzzleSender.php index 82c6a47e..b3c6870a 100644 --- a/src/Http/Senders/GuzzleSender.php +++ b/src/Http/Senders/GuzzleSender.php @@ -32,6 +32,8 @@ class GuzzleSender implements Sender /** * Guzzle's Handler Stack. + * + * @var HandlerStack): PromiseInterface> */ protected HandlerStack $handlerStack; @@ -84,6 +86,8 @@ protected function createGuzzleClient(): GuzzleClient /** * The default handler stack used by the underlying Guzzle client + * + * @return HandlerStack): PromiseInterface> */ protected function defaultHandlerStack(): HandlerStack { @@ -118,7 +122,7 @@ public function send(PendingRequest $pendingRequest): Response // Sometimes, Guzzle will throw a RequestException without a response. This // means that it was fatal, so we should still throw a fatal request exception. - $guzzleResponse = $exception->getResponse(); + $guzzleResponse = method_exists($exception, 'getResponse') ? $exception->getResponse() : null; if (is_null($guzzleResponse)) { throw new FatalRequestException($exception, $pendingRequest); @@ -166,7 +170,7 @@ function (TransferException $guzzleException) use ($pendingRequest, $psrRequest) // Sometimes, Guzzle will throw a RequestException without a response. This // means that it was fatal, so we should still throw a fatal request exception. - $guzzleResponse = $guzzleException->getResponse(); + $guzzleResponse = method_exists($guzzleException, 'getResponse') ? $guzzleException->getResponse() : null; if (is_null($guzzleResponse)) { throw new FatalRequestException($guzzleException, $pendingRequest); @@ -211,6 +215,8 @@ public function addMiddleware(callable $callable, string $name = ''): static /** * Overwrite the entire handler stack. * + * @param HandlerStack): PromiseInterface> $handlerStack + * * @return $this */ public function setHandlerStack(HandlerStack $handlerStack): static @@ -222,6 +228,8 @@ public function setHandlerStack(HandlerStack $handlerStack): static /** * Get the handler stack. + * + * @return HandlerStack): PromiseInterface> */ public function getHandlerStack(): HandlerStack { diff --git a/tests/Feature/Body/HasMultipartBodyTest.php b/tests/Feature/Body/HasMultipartBodyTest.php index ba9ea541..74ce4af0 100644 --- a/tests/Feature/Body/HasMultipartBodyTest.php +++ b/tests/Feature/Body/HasMultipartBodyTest.php @@ -74,7 +74,6 @@ expect((string)$guzzleRequest->getBody())->toContain( 'X-Saloon: Yee-haw!', 'Content-Disposition: form-data; name="nickname"; filename="user.txt"', - 'Content-Length: 3', 'Sam', ); @@ -135,7 +134,6 @@ expect($guzzleRequest->getBody()->getContents())->toContain( 'X-Saloon: Yee-haw!', 'Content-Disposition: form-data; name="nickname"; filename="user.txt"', - 'Content-Length: 3', 'Sam', 'Alfie', 'Tom', diff --git a/tests/Feature/GuzzleSenderTest.php b/tests/Feature/GuzzleSenderTest.php index a19c28b9..d6147eec 100644 --- a/tests/Feature/GuzzleSenderTest.php +++ b/tests/Feature/GuzzleSenderTest.php @@ -80,7 +80,7 @@ $saloonStack = invade($handlerStack)->stack; $defaultStack = invade(HandlerStack::create())->stack; - expect($saloonStack)->toHaveSameSize($defaultStack)->toHaveCount(4); + expect($saloonStack)->toHaveSameSize($defaultStack); expect($saloonStack[0][1])->toBe($defaultStack[0][1]); expect($saloonStack[1][1])->toBe($defaultStack[1][1]); @@ -116,7 +116,7 @@ $saloonStack = invade($saloonConfig['handler'])->stack; $defaultStack = invade($defaultConfig['handler'])->stack; - expect($saloonStack)->toHaveSameSize($defaultStack)->toHaveCount(4); + expect($saloonStack)->toHaveSameSize($defaultStack); }); test('you can set a custom handler stack on the guzzle sender', function () { diff --git a/tests/Feature/RetryConnectorTest.php b/tests/Feature/RetryConnectorTest.php index 0f5d4db5..1470b4e2 100644 --- a/tests/Feature/RetryConnectorTest.php +++ b/tests/Feature/RetryConnectorTest.php @@ -210,7 +210,7 @@ $connector = new RetryConnector(5, handleRetry: function (Exception $exception, Request $request) use (&$index) { $index++; - $request->headers()->add('X-Test-Index', $index); + $request->headers()->add('X-Test-Index', (string) $index); return true; }); @@ -230,7 +230,7 @@ $requestCount = 0; $connector = new RetryConnector(6, handleRetry: function (Exception $exception, Request $request) use (&$exceptions, &$index) { - $request->headers()->add('X-Yee-Haw', $index++); + $request->headers()->add('X-Yee-Haw', (string) $index++); return true; }); diff --git a/tests/Feature/RetryRequestTest.php b/tests/Feature/RetryRequestTest.php index 18c428f8..581c39b3 100644 --- a/tests/Feature/RetryRequestTest.php +++ b/tests/Feature/RetryRequestTest.php @@ -214,7 +214,7 @@ $response = $connector->send(new RetryUserRequest(5, handleRetry: function (Exception $exception, Request $request) use (&$index) { $index++; - $request->headers()->add('X-Test-Index', $index); + $request->headers()->add('X-Test-Index', (string) $index); return true; })); @@ -234,7 +234,7 @@ }); $request = new HeaderErrorRetryRequest(6, handleRetry: function (Exception $exception, Request $request) use (&$exceptions, &$index) { - $request->headers()->add('X-Yee-Haw', $index++); + $request->headers()->add('X-Yee-Haw', (string) $index++); return true; }); diff --git a/tests/Feature/SendAndRetryTest.php b/tests/Feature/SendAndRetryTest.php index bd477d96..ba6d8acf 100644 --- a/tests/Feature/SendAndRetryTest.php +++ b/tests/Feature/SendAndRetryTest.php @@ -235,7 +235,7 @@ $response = $connector->sendAndRetry(new UserRequest, 5, 0, function (Exception $exception, Request $request) use (&$index) { $index++; - $request->headers()->add('X-Test-Index', $index); + $request->headers()->add('X-Test-Index', (string) $index); return true; }); @@ -258,7 +258,7 @@ $index = 0; $response = $connector->sendAndRetry($request, 6, 0, function (Exception $exception, Request $request) use (&$exceptions, &$index) { - $request->headers()->add('X-Yee-Haw', $index++); + $request->headers()->add('X-Yee-Haw', (string) $index++); return true; }); diff --git a/tests/Fixtures/Senders/ArraySender.php b/tests/Fixtures/Senders/ArraySender.php index 44ee79f5..0802fa71 100644 --- a/tests/Fixtures/Senders/ArraySender.php +++ b/tests/Fixtures/Senders/ArraySender.php @@ -38,7 +38,7 @@ public function send(PendingRequest $pendingRequest): \Saloon\Http\Response /** @var class-string<\Saloon\Http\Response> $responseClass */ $responseClass = $pendingRequest->getResponseClass(); - return $responseClass::fromPsrResponse(new GuzzleResponse(200, ['X-Fake' => true], 'Default'), $pendingRequest, $pendingRequest->createPsrRequest()); + return $responseClass::fromPsrResponse(new GuzzleResponse(200, ['X-Fake' => 'true'], 'Default'), $pendingRequest, $pendingRequest->createPsrRequest()); } /** From b5d7964705099be900d837142f08f83534d13747 Mon Sep 17 00:00:00 2001 From: Sammyjo20 <29132017+Sammyjo20@users.noreply.github.com> Date: Fri, 4 Sep 2026 21:45:35 +0100 Subject: [PATCH 4/4] Use shell: bash --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 23698859..26a206ee 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -49,6 +49,7 @@ jobs: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Install dependencies + shell: bash run: | composer require guzzlehttp/guzzle:${{ matrix.guzzle.constraint }} --no-update composer update --${{ matrix.guzzle.stability }} --prefer-dist --no-interaction