diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index fd277044..ce3e0d44 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,52 +1,85 @@ --- -on: push +on: + push: + branches: + - master + pull_request: + branches: + - master + +permissions: + contents: read + +defaults: + run: + shell: bash jobs: test: name: "php${{ matrix.php }} symfony${{ matrix.symfony }} ${{matrix.minimumStability}} ${{ matrix.composerOptions }}" runs-on: ubuntu-latest strategy: + fail-fast: false matrix: php: - - '8.2' - - '8.3' - # - '8.4' waiting for phpspec/phpspec upgrade + - "8.2" + - "8.3" + - "8.4" + - "8.5" symfony: - - '5.4' - - '6.4' - - '7.4' + - "5.4" + - "6.4" + - "7.4" minimumStability: - - 'stable' + - "stable" composerOptions: - - '--prefer-stable --prefer-lowest' - - '--prefer-stable' + - "--prefer-stable --prefer-lowest" + - "--prefer-stable" include: - - symfony: '5.4' - php: '8.1' - minimumStability: 'stable' - composerOptions: '--prefer-stable --prefer-lowest' - - symfony: '5.4' - php: '8.1' - minimumStability: 'stable' - composerOptions: '--prefer-stable' + - symfony: "5.4" + php: "8.1" + minimumStability: "stable" + composerOptions: "--prefer-stable --prefer-lowest" + - symfony: "5.4" + php: "8.1" + minimumStability: "stable" + composerOptions: "--prefer-stable" + exclude: + # Symfony 5.4.0 and 6.4.0 emit PHP 8.4 deprecations. + - php: "8.4" + symfony: "5.4" + composerOptions: "--prefer-stable --prefer-lowest" + - php: "8.4" + symfony: "6.4" + composerOptions: "--prefer-stable --prefer-lowest" + # Current Symfony 5.4 emits PHP 8.5 deprecations. + - symfony: "5.4" + php: "8.5" + # Legacy dependency floors emit PHP 8.5 deprecations. + - php: "8.5" + composerOptions: "--prefer-stable --prefer-lowest" steps: - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: intl tools: composer + coverage: none + env: + fail-fast: true - uses: actions/checkout@v4 - run: | - curl -s https://raw.githubusercontent.com/symfony/symfony/${{ matrix.symfony }}/composer.json | jq '.replace | to_entries | map({key: .key, value: ("< " + "${{ matrix.symfony }}" + ".0 || >= " + ("${{ matrix.symfony }}" | (((.|tonumber + 0.1) * 10)|round / 10)|tostring) + ".0")}) | from_entries' > conflict.json - jq -s '.[0] + {conflict: .[1]}' composer.json conflict.json > composer.new.json + curl --fail --silent --show-error --location --retry 3 \ + --output symfony-composer.json \ + https://raw.githubusercontent.com/symfony/symfony/${{ matrix.symfony }}/composer.json + jq -e '.replace | to_entries | map({key: .key, value: ("< " + "${{ matrix.symfony }}" + ".0 || >= " + ("${{ matrix.symfony }}" | (((.|tonumber + 0.1) * 10)|round / 10)|tostring) + ".0")}) | from_entries' symfony-composer.json > conflict.json + jq -e -s '.[0] + {conflict: .[1]}' composer.json conflict.json > composer.new.json mv composer.new.json composer.json - rm conflict.json - cat composer.json + rm symfony-composer.json conflict.json - run: | - jq -s '.[0] + {"minimum-stability": "${{ matrix.minimumStability }}"}' composer.json > composer.new.json + jq -e -s '.[0] + {"minimum-stability": "${{ matrix.minimumStability }}"}' composer.json > composer.new.json mv composer.new.json composer.json - cat composer.json - - run: composer update ${{ matrix.composerOptions }} + - run: composer update --no-progress ${{ matrix.composerOptions }} - run: vendor/bin/phpstan analyse --no-progress --memory-limit=-1 - run: vendor/bin/phpspec run -v --config=phpspec.no-coverage.yml - run: bin/lint-twig src/ diff --git a/AGENTS.md b/AGENTS.md index 4cf59632..460b7281 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## OVERVIEW -Reusable Symfony bundle for declaring named dictionaries in application configuration and consuming them through DI, forms, validation, Twig, Faker, and the web profiler. PHP 8.1+; Symfony 5.4, 6.4, and 7.x; Twig 2.15/3.x. +Reusable Symfony bundle for declaring named dictionaries in application configuration and consuming them through DI, forms, validation, Twig, Faker, and the web profiler. Treat `composer.json` and the CI matrix as the sources of truth for supported runtime and framework versions. ## STRUCTURE @@ -24,7 +24,7 @@ DictionaryBundle/ | Service composition | `src/Knp/DictionaryBundle/Resources/config/services.yaml` | Imports explicit service fragments | | Dictionary behavior | `src/Knp/DictionaryBundle/Dictionary/` | Implementations, collection, wrappers, factories | | Framework adapters | `Form/`, `Validator/`, `Templating/`, `Faker/`, `DataCollector/` | All consume the shared collection | -| Behavioral specs | `spec/Knp/DictionaryBundle/` | Mirrors source paths; no PHPUnit suite | +| Behavioral specs | `spec/Knp/DictionaryBundle/` | Mirrors source paths | ## CONVENTIONS @@ -37,9 +37,9 @@ DictionaryBundle/ ## ANTI-PATTERNS (THIS PROJECT) - Do not eagerly evaluate callable or iterator-backed dictionaries. Their documented contract is lazy until first value access. -- Do not treat the README's `knp_dictionary.value_transformer` tag as implemented. No compiler pass or autoconfiguration consumes it. +- Before relying on a documented DI tag, verify that a compiler pass or autoconfiguration actually consumes it. - Do not reorder compiler passes or tagged factory definitions without tracing construction order and running the relevant specs. -- Do not copy the README's PHPStan or Rector commands; both sections are stale. Use the commands below. +- Use the configured quality-tool commands below as the source of truth when prose documentation differs. ## COMMANDS @@ -54,6 +54,6 @@ vendor/bin/rector process --dry-run ## NOTES -- CI rewrites `composer.json` to test Symfony minors with lowest and current dependencies; avoid relying on a single local dependency set. -- PHPStan level 8 covers `src` plus `spec/PHPSpec`, not the mirrored behavior specs. -- CI currently excludes PHP 8.4 pending PHPSpec compatibility. +- CI derives compatibility constraints at runtime to test both dependency floors and current releases; do not rely on a single local dependency set. +- Tool configuration files define analysis levels and paths; do not duplicate those values here. +- Keep runtime versions and temporary compatibility status out of this document. Declare them in `composer.json` and encode them in the CI matrix, with short inline comments for intentional exclusions. diff --git a/composer.json b/composer.json index 91ae3d6c..c352efd6 100644 --- a/composer.json +++ b/composer.json @@ -29,11 +29,11 @@ "require-dev": { "composer/semver": "3.4.0", "fakerphp/faker": "1.24.1", - "friends-of-phpspec/phpspec-code-coverage": "6.5.0", + "friends-of-phpspec/phpspec-code-coverage": "7.0.0", "friendsofphp/php-cs-fixer": "3.75.0", "pedrotroller/php-cs-custom-fixer": "2.33.2", - "phpspec/phpspec": "7.6.0", - "phpspec/prophecy": "1.22.0", + "phpspec/phpspec": "7.6.0 || 8.3.1", + "phpspec/prophecy": "1.22.0 || 1.26.1", "phpstan/extension-installer": "1.4.3", "phpstan/phpstan": "2.1.27", "phpstan/phpstan-symfony": "2.0.20", diff --git a/spec/Knp/DictionaryBundle/Dictionary/Factory/IteratorSpec.php b/spec/Knp/DictionaryBundle/Dictionary/Factory/IteratorSpec.php index 4ea20a1f..d4e042c8 100644 --- a/spec/Knp/DictionaryBundle/Dictionary/Factory/IteratorSpec.php +++ b/spec/Knp/DictionaryBundle/Dictionary/Factory/IteratorSpec.php @@ -57,7 +57,7 @@ function it_creates_a_dictionary($container, MockIterator $service) abstract class MockIterator implements \IteratorAggregate { - public function getIterator() + public function getIterator(): \Traversable { return yield from []; }