• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FriendsOfOpenTelemetry / opentelemetry-bundle / 24600302181

18 Apr 2026 07:57AM UTC coverage: 91.751%. Remained the same
24600302181

push

github

web-flow
chore(deps): upgrade PHPUnit to ^13 to clear security advisories (#216)

* chore(deps): upgrade PHPUnit to ^13 to clear security advisories

Bump phpunit/phpunit from ^11.5 to ^13.0 since all reachable 11.5.x releases
are now blocked by Packagist advisories (PKSA-5jz8-6tcw-pbk4, PKSA-z3gr-8qht-p93v).

PHPUnit 13 requires PHP 8.4+, so the PHPUnit CI job narrows to 8.4 only. To
preserve declared runtime compatibility with PHP 8.2/8.3, PHPStan now analyses
against a phpVersion range (min: 80200, max: 80400) — catching both too-new
syntax and features removed before 8.4. PHPStan still runs in CI across
8.2/8.3/8.4 as the static replacement for the dropped PHPUnit coverage.

PHP-CS-Fixer matrix collapses to PHP 8.2 only (its output is deterministic
across runtimes; 8.2 is the lowest supported, matching the tool's own guidance).

Also removes redundant @coversDefaultClass doc-comments from three test files;
each already carries an equivalent #[CoversClass] attribute.

* fix(ci): unblock PHPUnit coverage run and narrow PHPStan matrix

PHPUnit 13 rejects #[CoversClass] targets outside the <source> coverage
include when --coverage-clover is active. DummyLoggerService and
DummyMeterService live in the test application (tests/Functional/Application/src),
so the attributes were already incorrect — drop them; these are functional
integration tests, not unit coverage tests. Locally masked by XDEBUG_MODE=off
in composer run test.

Narrow PHPStan CI matrix to PHP 8.4 only. Installing project vendor on 8.2/8.3
now fails because phpunit/phpunit ^13 requires PHP 8.4+. Cross-version static
analysis is driven by phpVersion: {min: 80200, max: 80400} in phpstan.neon and
is runtime-independent — running PHPStan on three PHP versions was redundant.

2280 of 2485 relevant lines covered (91.75%)

15.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.35
/src/Instrumentation/Symfony/Framework/Routing/TraceableRouteLoader.php
1
<?php
2

3
namespace FriendsOfOpenTelemetry\OpenTelemetryBundle\Instrumentation\Symfony\Framework\Routing;
4

5
use FriendsOfOpenTelemetry\OpenTelemetryBundle\Instrumentation\Attribute\Traceable;
6
use Symfony\Component\Config\Loader\LoaderInterface;
7
use Symfony\Component\Config\Loader\LoaderResolverInterface;
8
use Symfony\Component\Routing\Route;
9
use Symfony\Component\Routing\RouteCollection;
10

11
class TraceableRouteLoader implements LoaderInterface
12
{
13
    public const DEFAULT_KEY = '_traceable';
14
    public const TRACER_KEY = '_tracer';
15
    public const OPTION_KEY = 'traceable';
16

17
    public function __construct(private LoaderInterface $loader)
18
    {
19
    }
8✔
20

21
    public function load(mixed $resource, ?string $type = null): RouteCollection
22
    {
23
        $routes = $this->loader->load($resource, $type);
8✔
24

25
        /** @var Route $route */
26
        foreach ($routes as $route) {
8✔
27
            self::parseAttribute($route);
8✔
28

29
            $traceable = $route->getOption(self::OPTION_KEY);
8✔
30
            if (null !== $traceable) {
8✔
31
                $route->addDefaults([
7✔
32
                    self::DEFAULT_KEY => $traceable,
7✔
33
                    self::TRACER_KEY => $route->getOption(self::TRACER_KEY),
7✔
34
                ]);
7✔
35
            }
36
        }
37

38
        return $routes;
8✔
39
    }
40

41
    public function supports(mixed $resource, ?string $type = null): bool
42
    {
43
        return $this->loader->supports($resource, $type);
×
44
    }
45

46
    public function getResolver(): LoaderResolverInterface
47
    {
48
        return $this->loader->getResolver();
×
49
    }
50

51
    public function setResolver(LoaderResolverInterface $resolver): void
52
    {
53
        $this->loader->setResolver($resolver);
×
54
    }
55

56
    private static function parseAttribute(Route $route): void
57
    {
58
        try {
59
            $controller = $route->getDefault('_controller');
8✔
60
            if (is_array($controller) && 2 === count($controller)) {
8✔
61
                $reflection = self::createReflectionMethod(sprintf('%s::%s', $controller[0], $controller[1]));
4✔
62
            } elseif (true === str_contains($controller, '::')) {
8✔
63
                $reflection = self::createReflectionMethod($controller);
6✔
64
            } else {
65
                $reflection = new \ReflectionClass($controller);
8✔
66
            }
67
        } catch (\ReflectionException) {
×
68
            return;
×
69
        }
70

71
        if ($reflection instanceof \ReflectionMethod) {
8✔
72
            $attribute = $reflection->getAttributes(Traceable::class)[0] ?? $reflection->getDeclaringClass()->getAttributes(Traceable::class)[0] ?? null;
6✔
73
        } else {
74
            $attribute = $reflection->getAttributes(Traceable::class)[0] ?? null;
6✔
75
        }
76

77
        if (null !== $attribute) {
8✔
78
            $traceable = $attribute->newInstance();
7✔
79
            $route->addOptions([
7✔
80
                self::OPTION_KEY => true,
7✔
81
                self::TRACER_KEY => $traceable->tracer ?? null,
7✔
82
            ]);
7✔
83
        }
84
    }
85

86
    private static function createReflectionMethod(string $method): \ReflectionMethod
87
    {
88
        if (\PHP_VERSION_ID >= 80400) {
6✔
89
            return \ReflectionMethod::createFromMethodName($method);
6✔
90
        }
91

92
        return new \ReflectionMethod($method);
×
93
    }
94
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc