diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index fae48d5a..b696ac2c 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -13,21 +13,55 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 - name: Validate composer.json - run: composer validate --strict --no-check-lock - cs-fixer: + run: | + (cd src/Bundle && composer validate --strict --no-check-lock) + tests: runs-on: ubuntu-20.04 - name: PHP-CS-Fixer + strategy: + fail-fast: false + matrix: + include: + - description: 'Symfony 6.3 DEV' + php: '8.2' + symfony: '6.3.*@dev' + - description: 'Symfony 6.2' + php: '8.2' + symfony: '6.2.*' + - description: 'Symfony 6.0' + php: '8.1' + symfony: '6.0.*' + - description: 'Symfony 5.4' + php: '7.3' + symfony: '5.4.*' + - description: 'Beta deps' + php: '7.2' + beta: true + name: PHP ${{ matrix.php }} tests (${{ matrix.description }}) steps: - name: Checkout uses: actions/checkout@v3 + - name: Cache + uses: actions/cache@v3 + with: + path: ~/.composer/cache/files + key: composer-${{ matrix.php }}-${{ matrix.symfony }}-${{ matrix.composer_option }} - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.3' - - run: composer install --prefer-dist --no-interaction --no-progress --ansi - - run: vendor/bin/php-cs-fixer fix --diff --dry-run --verbose - tests: - runs-on: ubuntu-20.04 + php-version: ${{ matrix.php }} + - run: | + sed -ri 's/"symfony\/(.+)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony }}'"/' src/Bundle/composer.json; + if: matrix.symfony + - run: | + composer config minimum-stability dev + composer config prefer-stable true + if: matrix.beta + - run: | + (cd src/Bundle && composer update --prefer-dist --no-interaction --no-progress --ansi ${{ matrix.composer_option }}) + - run: | + (cd src/Bundle && vendor/bin/phpunit) + tests-windows: + runs-on: windows-2022 strategy: fail-fast: false matrix: @@ -41,19 +75,13 @@ jobs: - description: 'Symfony 6.0' php: '8.1' symfony: '6.0.*' - - description: 'Symfony 5.0' + - description: 'Symfony 5.4' php: '7.3' - symfony: '5.0.*' - - description: 'Symfony 4.4' - php: '7.1' - symfony: '4.3.*@dev' - - description: 'Symfony 3.4' - php: '7.3' - symfony: '3.4.*' + symfony: '5.4.*' - description: 'Beta deps' php: '7.2' beta: true - name: PHP ${{ matrix.php }} tests (${{ matrix.description }}) + name: "[WINDOWS] PHP ${{ matrix.php }} tests (${{ matrix.description }})" steps: - name: Checkout uses: actions/checkout@v3 @@ -67,16 +95,13 @@ jobs: with: php-version: ${{ matrix.php }} - run: | - sed -ri 's/"symfony\/(.+)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony }}'"/' composer.json; + (Get-Content composer.json) -replace '("symfony/[^"]+": )"[^"]+"', '$1"${{ matrix.symfony }}"' | Out-File -encoding ASCII src/Bundle/composer.json if: matrix.symfony - run: | composer config minimum-stability dev composer config prefer-stable true if: matrix.beta - - name: remove cs-fixer for Symfony 6 - if: contains(matrix.symfony, '6.3.*@dev') - run: | - composer remove --dev friendsofphp/php-cs-fixer pedrotroller/php-cs-custom-fixer --no-update - - run: composer update --prefer-dist --no-interaction --no-progress --ansi ${{ matrix.composer_option }} - - run: vendor/bin/phpunit - - run: vendor/bin/phpstan analyse --ansi --no-progress + - run: | + {cd src/Bundle && composer update --prefer-dist --no-interaction --no-progress --ansi ${{ matrix.composer_option }}} + - run: | + {cd src/Bundle && vendor/bin/phpunit} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..3be777ab --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM composer:2.6.3 as composer + +############################### + +FROM php:8.2.10-fpm-alpine3.18 + +WORKDIR /src + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +COPY ./entrypoint /usr/local/share/entrypoint +COPY ./src /src + +ENTRYPOINT ["/usr/local/share/entrypoint"] diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..43e1b76a --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +IMAGE_TAG:=knplabs/snappy:test + +.PHONY: build +build: + docker build ./ -t "${IMAGE_TAG}" + +.PHONY: test +test: build + $(MAKE) -C src/Bundle test IMAGE_TAG="${IMAGE_TAG}" ARGS="${ARGS}" diff --git a/entrypoint b/entrypoint new file mode 100755 index 00000000..4713216b --- /dev/null +++ b/entrypoint @@ -0,0 +1,8 @@ +#!/bin/sh + +set -o pipefail +set -o errexit + +(cd /src/Bundle && composer install) + +exec "${@}" diff --git a/src/Bundle/.gitattributes b/src/Bundle/.gitattributes index ea3019f9..01a37eca 100644 --- a/src/Bundle/.gitattributes +++ b/src/Bundle/.gitattributes @@ -1,3 +1,4 @@ -/spec/ export-ignore +/Tests/ export-ignore /.gitattributes export-ignore /.gitignore export-ignore +/phpunit.xml.dist export-ignore diff --git a/src/Bundle/.gitignore b/src/Bundle/.gitignore index ff72e2d0..5e0f1797 100644 --- a/src/Bundle/.gitignore +++ b/src/Bundle/.gitignore @@ -1,2 +1,3 @@ /composer.lock /vendor +.phpunit.result.cache diff --git a/src/Bundle/DependencyInjection/Configuration.php b/src/Bundle/DependencyInjection/Configuration.php new file mode 100644 index 00000000..ae9d19ef --- /dev/null +++ b/src/Bundle/DependencyInjection/Configuration.php @@ -0,0 +1,49 @@ +getRootNode() + ->children() + ->arrayNode('backends') + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->scalarNode('driver') + ->isRequired() + ->validate() + ->ifNotInArray(['wkhtmltopdf', 'chromium']) + ->thenInvalid('Invalid backend driver %s') + ->end() + ->end() + ->integerNode('timeout') + ->min(1) + ->defaultValue(30) + ->end() + ->scalarNode('binary_path') + ->isRequired() + ->cannotBeEmpty() + ->end() + ->arrayNode('options') + ->useAttributeAsKey('name') + ->scalarPrototype()->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ; + + return $treeBuilder; + } +} diff --git a/src/Bundle/DependencyInjection/SnappyExtension.php b/src/Bundle/DependencyInjection/SnappyExtension.php new file mode 100644 index 00000000..52d5f46c --- /dev/null +++ b/src/Bundle/DependencyInjection/SnappyExtension.php @@ -0,0 +1,18 @@ +processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'my_minimally_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'binary_path' => '/usr/bin/wkhtmltopdf', + ], + ], + ]] + ); + + $expected = [ + 'backends' => [ + 'my_minimally_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'timeout' => 30, + 'binary_path' => '/usr/bin/wkhtmltopdf', + 'options' => [], + ], + ], + ]; + + $this->assertEquals($config, $expected); + } + + public function testItProcessesAFullWkhtmltopdfConfiguration(): void + { + $config = (new Processor())->processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'my_fully_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'timeout' => 60, + 'binary_path' => '/usr/bin/wkhtmltopdf', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + ], + ]] + ); + + $expected = [ + 'backends' => [ + 'my_fully_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'timeout' => 60, + 'binary_path' => '/usr/bin/wkhtmltopdf', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + ], + ]; + + $this->assertEquals($config, $expected); + } + + public function testItProcessesAMinimalChromiumConfiguration(): void + { + $config = (new Processor())->processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'my_minimally_configured_chromium_backend' => [ + 'driver' => 'chromium', + 'binary_path' => '/usr/bin/chromium', + ], + ], + ]] + ); + + $expected = [ + 'backends' => [ + 'my_minimally_configured_chromium_backend' => [ + 'driver' => 'chromium', + 'timeout' => 30, + 'binary_path' => '/usr/bin/chromium', + 'options' => [], + ], + ], + ]; + + $this->assertEquals($config, $expected); + } + + public function testItProcessesAFullChromiumConfiguration(): void + { + $config = (new Processor())->processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'my_fully_configured_chromium_backend' => [ + 'driver' => 'chromium', + 'timeout' => 60, + 'binary_path' => '/usr/bin/chromium', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + ], + ]] + ); + + $expected = [ + 'backends' => [ + 'my_fully_configured_chromium_backend' => [ + 'driver' => 'chromium', + 'timeout' => 60, + 'binary_path' => '/usr/bin/chromium', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + ], + ]; + + $this->assertEquals($config, $expected); + } + + public function testItProcessesAMultiBackendConfiguration(): void + { + $config = (new Processor())->processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'my_minimally_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'binary_path' => '/usr/bin/wkhtmltopdf', + ], + 'my_fully_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'timeout' => 60, + 'binary_path' => '/usr/bin/wkhtmltopdf', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + 'my_fully_configured_chromium_backend' => [ + 'driver' => 'chromium', + 'timeout' => 60, + 'binary_path' => '/usr/bin/chromium', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + ], + ]] + ); + + $expected = [ + 'backends' => [ + 'my_minimally_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'timeout' => 30, + 'binary_path' => '/usr/bin/wkhtmltopdf', + 'options' => [], + ], + 'my_fully_configured_wkhtmltopdf_backend' => [ + 'driver' => 'wkhtmltopdf', + 'timeout' => 60, + 'binary_path' => '/usr/bin/wkhtmltopdf', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + 'my_fully_configured_chromium_backend' => [ + 'driver' => 'chromium', + 'timeout' => 60, + 'binary_path' => '/usr/bin/chromium', + 'options' => [ + 'key1' => 'val', + 'key2' => null, + 'key3', + ], + ], + ], + ]; + + $this->assertEquals($config, $expected); + } + + public function testItThrowsWhenProcessingAnInvalidDriverConfiguration(): void + { + $this->expectException(InvalidConfigurationException::class); + + (new Processor())->processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'invalid_backend' => [ + 'driver' => 'non-existing-driver', + 'binary_path' => '/usr/bin/non-existing-binary', + ], + ], + ]] + ); + } + + public function testItThrowsWhenProcessingAnInvalidBinaryPathConfiguration(): void + { + $this->expectException(InvalidConfigurationException::class); + + (new Processor())->processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'invalid_backend' => [ + 'driver' => 'wkhtmltopdf', + ], + ], + ]] + ); + } + + public function testItThrowsWhenProcessingAnInvalidTimeoutConfiguration(): void + { + $this->expectException(InvalidConfigurationException::class); + + (new Processor())->processConfiguration( + new Configuration(), + [[ + 'backends' => [ + 'invalid_backend' => [ + 'driver' => 'wkhtmltopdf', + 'timeout' => 0, + 'binary_path' => '/usr/bin/wkhtmltopdf', + ], + ], + ]] + ); + } +} diff --git a/src/Bundle/composer.json b/src/Bundle/composer.json index 421b3f90..c6afaa35 100644 --- a/src/Bundle/composer.json +++ b/src/Bundle/composer.json @@ -16,18 +16,23 @@ } ], "require": { - "php": ">=8.0", - "symfony/http-kernel": "^5.4|^6.2" + "php": ">=7.2.5", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0" }, "autoload": { "psr-4": { "KnpLabs\\Snappy\\Bundle\\": "" }, "exclude-from-classmap": [ - "/spec/" + "/Tests/" ] }, "autoload-dev": { "psr-4": { - "KnpLabs\\Snappy\\Bundle\\Spec\\": "spec/" + "Tests\\KnpLabs\\Snappy\\Bundle\\": "Tests/" } + }, + "require-dev": { + "phpunit/phpunit": "<7.5|^9.6" } } diff --git a/src/Bundle/phpunit.xml.dist b/src/Bundle/phpunit.xml.dist new file mode 100644 index 00000000..7be3ea8e --- /dev/null +++ b/src/Bundle/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + + ./tests + ./vendor + + +