diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d56b4bc1d9bb08f650c32d05a24f4408a3caefd8..13fe2e05641daccb4e81674411f6e8b1513d6c05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,15 +73,21 @@ jobs: uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" - coverage: "pcov" + coverage: "xdebug" - name: "Install dependencies with Composer" run: "./tools/composer update --no-ansi --no-interaction --no-progress" - name: "Run tests with PHPUnit" - run: "vendor/bin/phpunit --coverage-clover=coverage.xml" + run: "vendor/bin/phpunit --log-junit junit.xml --coverage-clover=coverage.xml" - - name: "Send code coverage report to Codecov.io" - env: - CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" - run: "bash <(curl -s https://codecov.io/bash) || true" + - name: Upload test results to Codecov.io + if: ${{ !cancelled() }} + uses: codecov/test-results-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Upload code coverage data to Codecov.io + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.phive/phars.xml b/.phive/phars.xml index 4817da71b394359dd9a4e623de1ab849dab53d4c..0ff594ab4db6bcc5dd79e31792b46a70d962823f 100644 --- a/.phive/phars.xml +++ b/.phive/phars.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <phive xmlns="https://phar.io/phive"> - <phar name="php-cs-fixer" version="^3.59" installed="3.59.3" location="./tools/php-cs-fixer" copy="true"/> - <phar name="composer" version="^2.7" installed="2.7.7" location="./tools/composer" copy="true"/> - <phar name="phpstan" version="^1.11" installed="1.11.5" location="./tools/phpstan" copy="true"/> + <phar name="php-cs-fixer" version="^3.59" installed="3.63.1" location="./tools/php-cs-fixer" copy="true"/> + <phar name="composer" version="^2.7" installed="2.7.8" location="./tools/composer" copy="true"/> + <phar name="phpstan" version="^1.11" installed="1.11.11" location="./tools/phpstan" copy="true"/> </phive> diff --git a/ChangeLog.md b/ChangeLog.md index 970f762489ce21a793cc43d106a58cda79c077b4..bc3d8707044bb93098ad4b384da44aa62f32be32 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [5.1.0] - 2024-08-27 + +### Added + +* [#83](https://github.com/sebastianbergmann/php-file-iterator/pull/83): Support for "Globstar" pattern + ## [5.0.1] - 2024-07-03 ### Changed @@ -162,6 +168,7 @@ No changes * [#23](https://github.com/sebastianbergmann/php-file-iterator/pull/23): Added support for wildcards (glob) in exclude +[5.1.0]: https://github.com/sebastianbergmann/php-file-iterator/compare/5.0.1...5.1.0 [5.0.1]: https://github.com/sebastianbergmann/php-file-iterator/compare/5.0.0...5.0.1 [5.0.0]: https://github.com/sebastianbergmann/php-file-iterator/compare/4.1...5.0.0 [4.1.0]: https://github.com/sebastianbergmann/php-file-iterator/compare/4.0.2...4.1.0 diff --git a/README.md b/README.md index f012ba73581ec2e52baf22d12c7f44aec1f8abf0..5bc7da65d8950af6a13be4f59bda71c95707cd5f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[](https://packagist.org/packages/phpunit/php-file-iterator) +[](https://packagist.org/packages/phpunit/php-file-iterator) [](https://github.com/sebastianbergmann/php-file-iterator/actions) [](https://shepherd.dev/github/sebastianbergmann/php-file-iterator) [](https://codecov.io/gh/sebastianbergmann/php-file-iterator) diff --git a/src/Factory.php b/src/Factory.php index a2ebce6c184f7f4c2aa9e5e3c614f95ab18f68f3..1b5012891ef99f0c2a4cc55690e91ccf10c1c4c5 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -13,11 +13,15 @@ use const GLOB_ONLYDIR; use function array_filter; use function array_map; use function array_merge; +use function array_unique; use function array_values; use function glob; use function is_dir; use function is_string; use function realpath; +use function sort; +use function stripos; +use function substr; use AppendIterator; use FilesystemIterator; use RecursiveDirectoryIterator; @@ -92,7 +96,7 @@ final class Factory $_paths = [[]]; foreach ($paths as $path) { - if ($locals = glob($path, GLOB_ONLYDIR)) { + if ($locals = $this->globstar($path)) { $_paths[] = array_map('\realpath', $locals); } else { // @codeCoverageIgnoreStart @@ -103,4 +107,48 @@ final class Factory return array_values(array_filter(array_merge(...$_paths))); } + + /** + * @see https://gist.github.com/funkjedi/3feee27d873ae2297b8e2370a7082aad + * + * @return list<string> + */ + private function globstar(string $pattern) + { + if (stripos($pattern, '**') === false) { + $files = glob($pattern, GLOB_ONLYDIR); + } else { + $position = stripos($pattern, '**'); + $rootPattern = substr($pattern, 0, $position - 1); + $restPattern = substr($pattern, $position + 2); + + $patterns = [$rootPattern . $restPattern]; + $rootPattern .= '/*'; + + while ($dirs = glob($rootPattern, GLOB_ONLYDIR)) { + $rootPattern .= '/*'; + + foreach ($dirs as $dir) { + $patterns[] = $dir . $restPattern; + } + } + + $files = []; + + foreach ($patterns as $pat) { + $files = array_merge($files, $this->globstar($pat)); + } + } + + if ($files !== false) { + $files = array_unique($files); + sort($files); + + return $files; + } + + // @codeCoverageIgnoreStart + return []; + // @codeCoverageIgnoreEnd + } } diff --git a/tests/fixture/a/c/d/i/PrefixSuffix.php b/tests/fixture/a/c/d/i/PrefixSuffix.php new file mode 100644 index 0000000000000000000000000000000000000000..e42bdc2f2ca75b1277b7872c7b16ad6ea56ffd7b --- /dev/null +++ b/tests/fixture/a/c/d/i/PrefixSuffix.php @@ -0,0 +1,9 @@ +<?php declare(strict_types=1); +/* + * This file is part of phpunit/php-file-iterator. + * + * (c) Sebastian Bergmann <sebastian@phpunit.de> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ diff --git a/tests/fixture/b/e/g/i/PrefixSuffix.php b/tests/fixture/b/e/g/i/PrefixSuffix.php new file mode 100644 index 0000000000000000000000000000000000000000..e42bdc2f2ca75b1277b7872c7b16ad6ea56ffd7b --- /dev/null +++ b/tests/fixture/b/e/g/i/PrefixSuffix.php @@ -0,0 +1,9 @@ +<?php declare(strict_types=1); +/* + * This file is part of phpunit/php-file-iterator. + * + * (c) Sebastian Bergmann <sebastian@phpunit.de> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ diff --git a/tests/fixture/b/e/i/PrefixSuffix.php b/tests/fixture/b/e/i/PrefixSuffix.php new file mode 100644 index 0000000000000000000000000000000000000000..e42bdc2f2ca75b1277b7872c7b16ad6ea56ffd7b --- /dev/null +++ b/tests/fixture/b/e/i/PrefixSuffix.php @@ -0,0 +1,9 @@ +<?php declare(strict_types=1); +/* + * This file is part of phpunit/php-file-iterator. + * + * (c) Sebastian Bergmann <sebastian@phpunit.de> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ diff --git a/tests/fixture/b/f/h/i/PrefixSuffix.php b/tests/fixture/b/f/h/i/PrefixSuffix.php new file mode 100644 index 0000000000000000000000000000000000000000..e42bdc2f2ca75b1277b7872c7b16ad6ea56ffd7b --- /dev/null +++ b/tests/fixture/b/f/h/i/PrefixSuffix.php @@ -0,0 +1,9 @@ +<?php declare(strict_types=1); +/* + * This file is part of phpunit/php-file-iterator. + * + * (c) Sebastian Bergmann <sebastian@phpunit.de> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ diff --git a/tests/unit/FacadeTest.php b/tests/unit/FacadeTest.php index 3200790702ef77a884fcde09daa994fd456b51ea..722194e731c7b95163ee5c24ae007d04a69eab02 100644 --- a/tests/unit/FacadeTest.php +++ b/tests/unit/FacadeTest.php @@ -41,11 +41,15 @@ final class FacadeTest extends TestCase $fixtureDirectoryRealpath . '/a/c/d/Prefix.php', $fixtureDirectoryRealpath . '/a/c/d/PrefixSuffix.php', $fixtureDirectoryRealpath . '/a/c/d/Suffix.php', + $fixtureDirectoryRealpath . '/a/c/d/i/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/g/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/g/i/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/i/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/f/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/f/h/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/f/h/i/PrefixSuffix.php', ], __DIR__ . '/../fixture', '', @@ -59,6 +63,8 @@ final class FacadeTest extends TestCase $fixtureDirectoryRealpath . '/b/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/g/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/g/i/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/i/PrefixSuffix.php', ], __DIR__ . '/../fixture', '', @@ -76,11 +82,15 @@ final class FacadeTest extends TestCase $fixtureDirectoryRealpath . '/a/c/PrefixSuffix.php', $fixtureDirectoryRealpath . '/a/c/d/Prefix.php', $fixtureDirectoryRealpath . '/a/c/d/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/a/c/d/i/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/g/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/g/i/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/i/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/f/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/f/h/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/f/h/i/PrefixSuffix.php', ], __DIR__ . '/../fixture', '', @@ -95,11 +105,15 @@ final class FacadeTest extends TestCase $fixtureDirectoryRealpath . '/a/c/Suffix.php', $fixtureDirectoryRealpath . '/a/c/d/PrefixSuffix.php', $fixtureDirectoryRealpath . '/a/c/d/Suffix.php', + $fixtureDirectoryRealpath . '/a/c/d/i/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/e/g/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/g/i/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/i/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/f/PrefixSuffix.php', $fixtureDirectoryRealpath . '/b/f/h/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/f/h/i/PrefixSuffix.php', ], __DIR__ . '/../fixture', 'Suffix.php', @@ -115,12 +129,33 @@ final class FacadeTest extends TestCase $fixtureDirectoryRealpath . '/a/c/d/Prefix.php', $fixtureDirectoryRealpath . '/a/c/d/PrefixSuffix.php', $fixtureDirectoryRealpath . '/a/c/d/Suffix.php', + $fixtureDirectoryRealpath . '/a/c/d/i/PrefixSuffix.php', ], __DIR__ . '/../fixture/*/c', '', '', [], ], + 'globstar, filter prefix: no, filter suffix: no, excludes: none' => [ + [ + + $fixtureDirectoryRealpath . '/a/c/d/i/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/g/i/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/e/i/PrefixSuffix.php', + $fixtureDirectoryRealpath . '/b/f/h/i/PrefixSuffix.php', + ], + __DIR__ . '/../fixture/**/i', + '', + '', + [], + ], + 'invalid path, filter prefix: no, filter suffix: no, excludes: none' => [ + [], + __DIR__ . '/../fixture/**/this/path/does/not/exists', + '', + '', + [], + ], ]; }