diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..d95b72a2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true + +# JSON files +[*.json] +indent_style = space +indent_size = 4 diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 16a20180..c6d09174 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -3,16 +3,15 @@ name: "Continuous Integration" on: push: paths-ignore: - - 'doc/**' - - '.github/**' + - "doc/**" pull_request: paths-ignore: - - 'doc/**' - - '.github/**' + - "doc/**" + jobs: phpunit: - name: PHP ${{ matrix.php-version }} (${{ matrix.dependency-version }}) + name: PHP ${{ matrix.php-version }} (${{ matrix.dependency-versions }}) runs-on: ubuntu-latest continue-on-error: ${{ matrix.experimental }} @@ -21,53 +20,46 @@ jobs: fail-fast: false matrix: php-version: - - '8.1' - - '8.2' - - '8.3' + - "8.1" + - "8.2" + - "8.3" + - "8.4" dependency-versions: [lowest, highest] experimental: [false] - include: - - php-version: '8.4' - dependency-versions: lowest - experimental: true - composer-options: --ignore-platform-reqs - - php-version: '8.4' - dependency-versions: highest - experimental: true - composer-options: --ignore-platform-reqs steps: - - name: Repository checkout - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - name: Repository checkout + uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + + - name: Setup PHP with PECL extension + uses: shivammathur/setup-php@efffd0e4f2504f936fcfe3b69293d31ce0e2fd7a # v2.30.3 + with: + php-version: ${{ matrix.php-version }} + tools: composer:v2 + coverage: pcov - - name: Setup PHP with PECL extension - uses: shivammathur/setup-php@efffd0e4f2504f936fcfe3b69293d31ce0e2fd7a # v2.30.3 - with: - php-version: ${{ matrix.php-version }} - tools: composer:v2 - coverage: pcov + - name: Validate composer.json and composer.lock + run: composer validate --strict - - name: Validate composer.json and composer.lock - run: composer validate --strict + - name: Install dependencies + uses: ramsey/composer-install@57532f8be5bda426838819c5ee9afb8af389d51a # v3.0.0 + with: + dependency-versions: ${{ matrix.dependency-versions }} + composer-options: ${{ matrix.composer-options }} - - name: Install dependencies - uses: ramsey/composer-install@57532f8be5bda426838819c5ee9afb8af389d51a # v3.0.0 - with: - dependency-versions: ${{ matrix.dependency-versions }} - composer-options: ${{ matrix.composer-options }} + - name: Pull the docker image used by the tests. + run: docker pull busybox:latest - - name: Pull the docker image used by the tests. - run: docker pull busybox:latest + - name: Run PHPUnit test suite + run: composer run-script test-ci - - name: Run PHPUnit test suite - run: composer run-script test-ci + - name: Publish code coverage + if: github.repository == 'beluga-php/docker-php' && github.event_name != 'pull_request' + uses: paambaati/codeclimate-action@a1831d7162ea1fbc612ffe5fb3b90278b7999d59 # v5.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + with: + coverageCommand: composer run-script test-coverage + coverageLocations: | + ${{github.workspace}}/clover.xml:clover - - name: Publish code coverage - uses: paambaati/codeclimate-action@a1831d7162ea1fbc612ffe5fb3b90278b7999d59 # v5.0.0 - env: - CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} - with: - coverageCommand: composer run-script test-coverage - coverageLocations: | - ${{github.workspace}}/clover.xml:clover - if: github.event_name != 'pull_request' diff --git a/.gitignore b/.gitignore index 64afb0b5..8d49b551 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ bin/ composer.lock .vagrant /.php-cs-fixer.cache +/.phpunit.result.cache diff --git a/composer.json b/composer.json index 2e80e384..f680bd44 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "nyholm/psr7": "^1.8", "php-http/client-common": "^2.7", "php-http/discovery": "^1.19", - "php-http/socket-client": "^2.1", + "php-http/socket-client": "^2.3", "psr/http-message": "^2.0", "symfony/filesystem": "^6.3 || ^7.0", "symfony/process": "^6.3 || ^7.0", @@ -26,8 +26,8 @@ "friendsofphp/php-cs-fixer": "^3.8", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5", - "psy/psysh": "^0.12", + "phpunit/phpunit": "^10.5.46", + "psy/psysh": "^0.12.8", "roave/security-advisories": "dev-latest" }, "conflict": { diff --git a/src/Context/Context.php b/src/Context/Context.php index 1cc9b1ec..320f131f 100644 --- a/src/Context/Context.php +++ b/src/Context/Context.php @@ -52,7 +52,7 @@ class Context implements ContextInterface * @param string $format Format to use when sending the call (stream or tar: string) * @param Filesystem $fs filesystem object for cleaning the context directory on destruction */ - public function __construct($directory, $format = self::FORMAT_STREAM, Filesystem $fs = null) + public function __construct($directory, $format = self::FORMAT_STREAM, ?Filesystem $fs = null) { $this->directory = $directory; $this->format = $format; diff --git a/src/Context/ContextBuilder.php b/src/Context/ContextBuilder.php index 0464b15a..cda9629f 100644 --- a/src/Context/ContextBuilder.php +++ b/src/Context/ContextBuilder.php @@ -41,7 +41,7 @@ class ContextBuilder /** * @param \Symfony\Component\Filesystem\Filesystem $fs */ - public function __construct(Filesystem $fs = null) + public function __construct(?Filesystem $fs = null) { $this->fs = $fs ?: new Filesystem(); $this->format = Context::FORMAT_STREAM; diff --git a/src/Docker.php b/src/Docker.php index b63c99cd..9333e7e3 100644 --- a/src/Docker.php +++ b/src/Docker.php @@ -66,7 +66,7 @@ public function imageBuild($requestBody = null, array $queryParameters = [], arr /** * {@inheritdoc} */ - public function imageCreate(string $requestBody = null, array $queryParameters = [], array $headerParameters = [], string $fetch = self::FETCH_OBJECT) + public function imageCreate(?string $requestBody = null, array $queryParameters = [], array $headerParameters = [], string $fetch = self::FETCH_OBJECT) { return $this->executeEndpoint(new ImageCreate($requestBody, $queryParameters, $headerParameters), $fetch); } diff --git a/src/DockerClientFactory.php b/src/DockerClientFactory.php index 74a43dd8..0b6fbfb8 100644 --- a/src/DockerClientFactory.php +++ b/src/DockerClientFactory.php @@ -16,7 +16,7 @@ final class DockerClientFactory { - public static function create(array $config = [], PluginClientFactory $pluginClientFactory = null): PluginClient + public static function create(array $config = [], ?PluginClientFactory $pluginClientFactory = null): PluginClient { if (!\array_key_exists('remote_socket', $config)) { $config['remote_socket'] = 'unix:///var/run/docker.sock'; @@ -46,7 +46,7 @@ public static function create(array $config = [], PluginClientFactory $pluginCli ); } - public static function createFromEnv(PluginClientFactory $pluginClientFactory = null): PluginClient + public static function createFromEnv(?PluginClientFactory $pluginClientFactory = null): PluginClient { $options = [ 'remote_socket' => getenv('DOCKER_HOST') ? getenv('DOCKER_HOST') : 'unix:///var/run/docker.sock', diff --git a/src/Endpoint/ContainerAttach.php b/src/Endpoint/ContainerAttach.php index 571ec225..1c776639 100644 --- a/src/Endpoint/ContainerAttach.php +++ b/src/Endpoint/ContainerAttach.php @@ -11,7 +11,7 @@ class ContainerAttach extends BaseEndpoint { - protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, string $contentType = null) + protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, ?string $contentType = null) { if (200 === $response->getStatusCode() && DockerRawStream::HEADER === $contentType) { return new DockerRawStream($response->getBody()); diff --git a/src/Endpoint/ExecStart.php b/src/Endpoint/ExecStart.php index 844a4906..e2d8985b 100644 --- a/src/Endpoint/ExecStart.php +++ b/src/Endpoint/ExecStart.php @@ -11,7 +11,7 @@ class ExecStart extends BaseEndpoint { - protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, string $contentType = null) + protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, ?string $contentType = null) { if (200 === $response->getStatusCode() && DockerRawStream::HEADER === $contentType) { return new DockerRawStream($response->getBody()); diff --git a/src/Endpoint/ImageBuild.php b/src/Endpoint/ImageBuild.php index c0ceb645..49239c4c 100644 --- a/src/Endpoint/ImageBuild.php +++ b/src/Endpoint/ImageBuild.php @@ -24,7 +24,7 @@ public function getBody(SerializerInterface $serializer, $streamFactory = null): return [['Content-Type' => ['application/octet-stream']], $body]; } - protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, string $contentType = null) + protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, ?string $contentType = null) { if (200 === $response->getStatusCode()) { return new BuildStream($response->getBody(), $serializer); diff --git a/src/Endpoint/ImageCreate.php b/src/Endpoint/ImageCreate.php index 3ea1aad0..3a50da2e 100644 --- a/src/Endpoint/ImageCreate.php +++ b/src/Endpoint/ImageCreate.php @@ -11,7 +11,7 @@ class ImageCreate extends BaseEndpoint { - protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, string $contentType = null) + protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, ?string $contentType = null) { if (200 === $response->getStatusCode()) { return new CreateImageStream($response->getBody(), $serializer); diff --git a/src/Endpoint/ImagePush.php b/src/Endpoint/ImagePush.php index 64ea660b..61e16591 100644 --- a/src/Endpoint/ImagePush.php +++ b/src/Endpoint/ImagePush.php @@ -16,7 +16,7 @@ public function getUri(): string return str_replace(['{name}'], [urlencode($this->name)], '/images/{name}/push'); } - protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, string $contentType = null) + protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, ?string $contentType = null) { if (200 === $response->getStatusCode()) { return new PushStream($response->getBody(), $serializer); diff --git a/src/Endpoint/SystemEvents.php b/src/Endpoint/SystemEvents.php index 339a6062..3f57e916 100644 --- a/src/Endpoint/SystemEvents.php +++ b/src/Endpoint/SystemEvents.php @@ -11,7 +11,7 @@ class SystemEvents extends BaseEndpoint { - protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, string $contentType = null) + protected function transformResponseBody(ResponseInterface $response, SerializerInterface $serializer, ?string $contentType = null) { if (200 === $response->getStatusCode()) { return new EventStream($response->getBody(), $serializer); diff --git a/tests/Stream/MultiJsonStreamTest.php b/tests/Stream/MultiJsonStreamTest.php index 29d65739..6d4a46ac 100644 --- a/tests/Stream/MultiJsonStreamTest.php +++ b/tests/Stream/MultiJsonStreamTest.php @@ -41,11 +41,18 @@ public function testReadJsonEscapedDoubleQuote(string $jsonStream, array $jsonPa $serializer = $this->getMockBuilder(SerializerInterface::class) ->getMock(); + $callIndex = 0; $serializer ->expects($this->exactly(\count($jsonParts))) ->method('deserialize') - ->withConsecutive(...array_map(fn ($part) => [$part, BuildInfo::class, 'json', []], $jsonParts)) - ; + ->willReturnCallback(function ($data, $class, $format, $context) use ($jsonParts, &$callIndex) { + $this->assertEquals($jsonParts[$callIndex], $data); + $this->assertEquals(BuildInfo::class, $class); + $this->assertEquals('json', $format); + $this->assertEquals([], $context); + $callIndex++; + return null; + }); $stub = $this->getMockForAbstractClass(MultiJsonStream::class, [$stream, $serializer]); $stub->expects($this->any())