Repository: symfony/ux
Pull request #2766 (2025-05-23 05:05:59)

[Turbo] Fix Turbo CI (PHPStan & Functional tests)
| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Docs?         | no <!-- required for new features -->
| Issues        | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT

<!--
Replace this notice by a description of your feature/bugfix.
This will help reviewers and should be a good start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - For new features, provide some code snippets to help understand usage.
 - Features and deprecations must be submitted against branch main.
 - Update/add documentation as required (we can help!)
 - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
 - Never break backward compatibility (see https://symfony.com/bc).
-->

Looks like the CI for Turbo was broken for a moment... let's fix it :)

kbond: Turbo tests still erroring?

Patch:
diff --git a/.github/workflows/code-quality.yaml b/.github/workflows/code-quality.yaml
index 84896b53..bf9fd038 100644
--- a/.github/workflows/code-quality.yaml
+++ b/.github/workflows/code-quality.yaml
@@ -35,7 +35,17 @@ jobs:
         strategy:
             fail-fast: false
             matrix:
-                package: ${{ fromJson(needs.php-packages-matrix.outputs.packages) }}
+                php-version: [ '8.1', '8.2', '8.3', '8.4']
+                dependency-version: ['']
+                symfony-version: ['']
+                minimum-stability: ['stable']
+                include:
+                    # lowest deps
+                    -   php-version: '8.1'
+                        dependency-version: 'lowest'
+                    # LTS version of Symfony
+                    -   php-version: '8.1'
+                        symfony-version: '6.4.*'
         steps:
             -   name: Checkout
                 uses: actions/checkout@v4
@@ -43,8 +53,9 @@ jobs:
             - name: Configure environment
               run: |
                   echo COLUMNS=120 >> $GITHUB_ENV
-                  echo COMPOSER_MIN_STAB='composer config minimum-stability stable --ansi' >> $GITHUB_ENV
-                  echo COMPOSER_UP='composer update --no-progress --no-interaction --ansi' >> $GITHUB_ENV
+                  echo COMPOSER_MIN_STAB='composer config minimum-stability ${{ matrix.minimum-stability || 'stable' }} --ansi' >> $GITHUB_ENV
+                  echo COMPOSER_UP='composer update ${{ matrix.dependency-version == 'lowest' && '--prefer-lowest' || '' }} --no-progress --no-interaction --ansi' >> $GITHUB_ENV
+                  echo PHPUNIT_INSTALL='vendor/bin/simple-phpunit install' >> $GITHUB_ENV
                   echo PHPSTAN='vendor/bin/phpstan' >> $GITHUB_ENV
 
                   # TODO: Only Turbo has PHPStan configuration, let's improve this later :)
@@ -69,4 +80,4 @@ jobs:
               run: |
                   source .github/workflows/.utils.sh
 
-                  echo "$PACKAGES" | xargs -n1 | parallel -j +3 "_run_task {} '(cd src/{} && $COMPOSER_MIN_STAB && $COMPOSER_UP && $PHPSTAN)'"
+                  echo "$PACKAGES" | xargs -n1 | parallel -j +3 "_run_task {} '(cd src/{} && $COMPOSER_MIN_STAB && $COMPOSER_UP && $PHPUNIT_INSTALL && $PHPSTAN)'"
diff --git a/src/Turbo/.gitattributes b/src/Turbo/.gitattributes
index cf5f476a..34736d42 100644
--- a/src/Turbo/.gitattributes
+++ b/src/Turbo/.gitattributes
@@ -1,7 +1,7 @@
 /.git* export-ignore
 /.symfony.bundle.yaml export-ignore
 /phpunit.xml.dist export-ignore
-/phpstan.neon.dist export-ignore
+/phpstan.dist.neon export-ignore
 /assets/src export-ignore
 /assets/test export-ignore
 /assets/vitest.config.js export-ignore
diff --git a/src/Turbo/composer.json b/src/Turbo/composer.json
index b98a77b1..797f2cdd 100644
--- a/src/Turbo/composer.json
+++ b/src/Turbo/composer.json
@@ -40,14 +40,14 @@
     "require-dev": {
         "doctrine/doctrine-bundle": "^2.4.3",
         "doctrine/orm": "^2.8 | 3.0",
-        "phpstan/phpstan": "^1.10",
+        "phpstan/phpstan": "^2.1.17",
         "symfony/asset-mapper": "^6.4|^7.0",
         "symfony/debug-bundle": "^5.4|^6.0|^7.0",
         "symfony/form": "^5.4|^6.0|^7.0",
         "symfony/framework-bundle": "^6.4|^7.0",
         "symfony/mercure-bundle": "^0.3.7",
         "symfony/messenger": "^5.4|^6.0|^7.0",
-        "symfony/panther": "^2.1",
+        "symfony/panther": "^2.2",
         "symfony/phpunit-bridge": "^5.4|^6.0|^7.0",
         "symfony/process": "^5.4|6.3.*|^7.0",
         "symfony/property-access": "^5.4|^6.0|^7.0",
@@ -57,7 +57,8 @@
         "symfony/twig-bundle": "^6.4|^7.0",
         "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0",
         "symfony/expression-language": "^5.4|^6.0|^7.0",
-        "dbrekelmans/bdi": "dev-main"
+        "dbrekelmans/bdi": "dev-main",
+        "php-webdriver/webdriver": "^1.15"
     },
     "conflict": {
         "symfony/flex": "<1.13"
diff --git a/src/Turbo/phpstan.neon.dist b/src/Turbo/phpstan.dist.neon
similarity index 82%
rename from src/Turbo/phpstan.neon.dist
rename to src/Turbo/phpstan.dist.neon
index 74ef7289..5c5b5c17 100644
--- a/src/Turbo/phpstan.neon.dist
+++ b/src/Turbo/phpstan.dist.neon
@@ -7,6 +7,8 @@ parameters:
 		- tests/app/var/*
 		# The Symfony Configuration API isn't good enough to be analysed
 		- src/DependencyInjection/Configuration.php
+	# to allow installing with various phsptan versions without reporting old errors here
+	reportUnmatchedIgnoredErrors: false
 	inferPrivatePropertyTypeFromConstructor: true
 	bootstrapFiles:
 		- vendor/bin/.phpunit/phpunit/vendor/autoload.php
@@ -36,16 +38,6 @@ parameters:
 			count: 1
 			path: src/Bridge/Mercure/TurboStreamListenRenderer.php
 
-		-
-			message: "#^Call to an undefined method Doctrine\\\\ORM\\\\Event\\\\OnFlushEventArgs\\:\\:getEntityManager\\(\\)\\.$#"
-			count: 1
-			path: src/Doctrine/BroadcastListener.php
-
-		-
-			message: "#^Call to an undefined method Doctrine\\\\ORM\\\\Event\\\\PostFlushEventArgs\\:\\:getEntityManager\\(\\)\\.$#"
-			count: 1
-			path: src/Doctrine/BroadcastListener.php
-
 		-
 			message: "#^Method Symfony\\\\UX\\\\Turbo\\\\TurboStreamResponse::__construct\\(\\) has parameter \\$headers with no value type specified in iterable type array\\.$#"
 			count: 1
diff --git a/src/Turbo/src/Attribute/Broadcast.php b/src/Turbo/src/Attribute/Broadcast.php
index f1679868..53672580 100644
--- a/src/Turbo/src/Attribute/Broadcast.php
+++ b/src/Turbo/src/Attribute/Broadcast.php
@@ -42,6 +42,7 @@ final class Broadcast
      */
     public function __construct(...$options)
     {
+        // @phpstan-ignore function.alreadyNarrowedType
         if ([0] === array_keys($options) && \is_array($options[0]) && \is_string(key($options[0]))) {
             $options = $options[0];
         }
diff --git a/src/Turbo/src/Bridge/Mercure/Broadcaster.php b/src/Turbo/src/Bridge/Mercure/Broadcaster.php
index 4df8cd58..7caeb210 100644
--- a/src/Turbo/src/Bridge/Mercure/Broadcaster.php
+++ b/src/Turbo/src/Bridge/Mercure/Broadcaster.php
@@ -68,6 +68,7 @@ final class Broadcaster implements BroadcasterInterface
         $topics = [];
 
         foreach ((array) ($options['topics'] ?? []) as $topic) {
+            // @phpstan-ignore function.alreadyNarrowedType ($topic should always be a string given the PHPDoc... could be removed in 3.x)
             if (!\is_string($topic)) {
                 $topics[] = $topic;
                 continue;
diff --git a/src/Turbo/src/Doctrine/BroadcastListener.php b/src/Turbo/src/Doctrine/BroadcastListener.php
index a020fb29..b3a7cad3 100644
--- a/src/Turbo/src/Doctrine/BroadcastListener.php
+++ b/src/Turbo/src/Doctrine/BroadcastListener.php
@@ -61,6 +61,7 @@ final class BroadcastListener implements ResetInterface
             return;
         }
 
+        // @phpstan-ignore function.alreadyNarrowedType, method.notFound (`getEntityManager()` has been removed in Doctrine 3.0)
         $em = method_exists($eventArgs, 'getObjectManager') ? $eventArgs->getObjectManager() : $eventArgs->getEntityManager();
         $uow = $em->getUnitOfWork();
         foreach ($uow->getScheduledEntityInsertions() as $entity) {
@@ -85,6 +86,7 @@ final class BroadcastListener implements ResetInterface
             return;
         }
 
+        // @phpstan-ignore function.alreadyNarrowedType, method.notFound (`getEntityManager()` has been removed in Doctrine 3.0)
         $em = method_exists($eventArgs, 'getObjectManager') ? $eventArgs->getObjectManager() : $eventArgs->getEntityManager();
 
         try {


Test patch:
diff --git a/.github/workflows/functional-tests.yml b/.github/workflows/functional-tests.yml
index 27990123..c4963af0 100644
--- a/.github/workflows/functional-tests.yml
+++ b/.github/workflows/functional-tests.yml
@@ -3,9 +3,11 @@ name: Functional Tests
 on:
     push:
         paths:
+            - '.github/workflows/functional-tests.yml'
             - 'src/Turbo/**'
     pull_request:
         paths:
+            - '.github/workflows/functional-tests.yml'
             - 'src/Turbo/**'
 
 jobs:
@@ -30,7 +32,7 @@ jobs:
                        symfony-version: '6.4.*'
 
         env:
-            SYMFONY_REQUIRE: ${{ matrix.symfony-version }}
+            SYMFONY_REQUIRE: ${{ matrix.symfony-version || '>=5.4' }}
         services:
             mercure:
                 image: dunglas/mercure
diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml
index f9ee2aab..655b6cce 100644
--- a/.github/workflows/unit-tests.yaml
+++ b/.github/workflows/unit-tests.yaml
@@ -38,7 +38,7 @@ jobs:
                         symfony-version: '6.4.*'
 
         env:
-            SYMFONY_REQUIRE: ${{ matrix.symfony-version }}
+            SYMFONY_REQUIRE: ${{ matrix.symfony-version || '>=5.4' }}
         steps:
             - uses: actions/checkout@v4