8000 Introduce weak_lagging_vendors mode · symfony/symfony@0a10c00 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0a10c00

Browse files
greg0ireGrégoire Paris
authored andcommitted
Introduce weak_lagging_vendors mode
In this mode, failures coming from vendors that call other vendors in a deprecated way are not taken into account when deciding to make the build fail. They also appear in a separate group.
1 parent 6c5e8d4 commit 0a10c00

File tree

5 files changed

+172
-7
lines changed

5 files changed

+172
-7
lines changed

src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php

Lines changed: 74 additions & 7 deletions
6D4E
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class DeprecationErrorHandler
2020
{
2121
const MODE_WEAK = 'weak';
2222
const MODE_WEAK_VENDORS = 'weak_vendors';
23+
const MODE_WEAK_LAGGING_VENDORS = 'weak_lagging_vendors';
2324
const MODE_DISABLED = 'disabled';
2425

2526
private static $isRegistered = false;
@@ -30,6 +31,8 @@ class DeprecationErrorHandler
3031
* The following reporting modes are supported:
3132
* - use "weak" to hide the deprecation report but keep a global count;
3233
* - use "weak_vendors" to act as "weak" but only for vendors;
34+
* - use "weak_lagging_vendors" to act as "weak" but only for vendors that
35+
* failed to keep up with their upstream dependencies deprecations;
3336
* - use "/some-regexp/" to stop the test suite whenever a deprecation
3437
* message matches the given regular expression;
3538
* - use a number to define the upper bound of allowed deprecations,
@@ -54,24 +57,29 @@ public static function register($mode = 0)
5457
if (false === $mode) {
5558
$mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
5659
}
57-
if (DeprecationErrorHandler::MODE_WEAK !== $mode && DeprecationErrorHandler::MODE_WEAK_VENDORS !== $mode && (!isset($mode[0]) || '/' !== $mode[0])) {
60+
if (!in_array($mode, array(
61+
DeprecationErrorHandler::MODE_WEAK,
62+
DeprecationErrorHandler::MODE_WEAK_VENDORS,
63+
DeprecationErrorHandler::MODE_WEAK_LAGGING_VENDORS,
64+
), true) && (!isset($mode[0]) || '/' !== $mode[0])) {
5865
$mode = preg_match('/^[1-9][0-9]*$/', $mode) ? (int) $mode : 0;
5966
}
6067

6168
return $memoizedMode = $mode;
6269
};
6370

64-
6571
$deprecations = array(
6672
'unsilencedCount' => 0,
6773
'remainingCount' => 0,
6874
'legacyCount' => 0,
6975
'otherCount' => 0,
76+
'lagging vendorCount' => 0,
7077
'remaining vendorCount' => 0,
7178
'unsilenced' => array(),
7279
'remaining' => array(),
7380
'legacy' => array(),
7481
'other' => array(),
82+
'lagging vendor' => array(),
7583
'remaining vendor' => array(),
7684
);
7785
$deprecationHandler = function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, $getMode, $UtilPrefix) {
@@ -85,8 +93,9 @@ public static function register($mode = 0)
8593
$trace = debug_backtrace(true);
8694
$group = 'other';
8795
$isVendor = false;
88-
$isWeak = DeprecationErrorHandler::MODE_WEAK === $mode || (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $isVendor = self::inVendors($file));
89-
96+
$isWeak = DeprecationErrorHandler::MODE_WEAK === $mode ||
97+
(DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $isVendor = self::inVendors($file)) ||
98+
(DeprecationErrorHandler::MODE_WEAK_LAGGING_VENDORS === $mode && $isLaggingVendor = self::isLaggingVendor($trace));
9099
$i = count($trace);
91100
while (1 < $i && (!isset($trace[--$i]['class']) || ('ReflectionMethod' === $trace[$i]['class'] || 0 === strpos($trace[$i]['class'], 'PHPUnit_') || 0 === strpos($trace[$i]['class'], 'PHPUnit\\')))) {
92101
// No-op
@@ -119,6 +128,8 @@ public static function register($mode = 0)
119128
|| in_array('legacy', $Test::getGroups($class, $method), true)
120129
) {
121130
$group = 'legacy';
131+
} elseif (DeprecationErrorHandler::MODE_WEAK_LAGGING_VENDORS === $mode && $isLaggingVendor) {
132+
$group = 'lagging vendor';
122133
} elseif (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $isVendor) {
123134
$group = 'remaining vendor';
124135
} else {
@@ -193,13 +204,16 @@ public static function register($mode = 0)
193204
if (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode) {
194205
$groups[] = 'remaining vendor';
195206
}
207+
if (DeprecationErrorHandler::MODE_WEAK_LAGGING_VENDORS === $mode) {
208+
$groups[] = 'lagging vendor';
209+
}
196210
array_push($groups, 'legacy', 'other');
197211

198212
foreach ($groups as $group) {
199213
if ($deprecations[$group.'Count']) {
200214
echo "\n", $colorize(
201215
sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']),
202-
'legacy' !== $group && 'remaining vendor' !== $group
216+
!in_array($group, array('legacy', 'remaining vendor', 'lagging vendor'), true)
203217
), "\n";
204218

205219
uasort($deprecations[$group], $cmp);
@@ -228,11 +242,58 @@ public static function register($mode = 0)
228242
}
229243
}
230244

231-
private static function inVendors(string $path): bool
245+
private static function isLaggingVendor(array $trace): bool
246+
{
247+
$erroringFile = $erroringPackage = null;
248+
foreach ($trace as $line) {
249+
if (!isset($line['file'])) {
250+
continue;
251+
}
252+
$file = $line['file'];
253+
if ('-' === $file) {
254+
continue;
255+
}
256+
if (!self::inVendors($file)) {
257+
return false;
258+
}
259+
if (null !== $erroringFile && null !== $erroringPackage) {
260+
if (self::getPackage($file) !== $erroringPackage) {
261+
return true;
262+
}
263+
} else {
264+
$erroringFile = $file;
265+
$erroringPackage = self::getPackage($file);
266+
}
267+
}
268+
269+
return false;
270+
}
271+
272+
/**
273+
* inVendors() should always be called prior to calling this method.
274+
*/
275+
private static function getPackage(string $path): string
276+
{
277+
$path = realpath($path) ?: $path;
278+
foreach (self::getVendors() as $vendorRoot) {
279+
if (0 === strpos($path, $vendorRoot)) {
280+
$relativePath = substr($path, strlen($vendorRoot) + 1);
281+
$vendor = strstr($relativePath, DIRECTORY_SEPARATOR, true);
282+
283+
return $vendor.'/'.strstr(substr($relativePath, strlen($vendor) + 1), DIRECTORY_SEPARATOR, true);
284+
}
285+
}
286+
287+
throw new \RuntimeException('No vendors found');
288+
}
289+
290+
private static function getVendors(): array
232291
{
233292
/** @var string[] absolute paths to vendor directories */
234293
static $vendors;
294+
235295
if (null === $vendors) {
296+
$vendors = array();
236297
foreach (get_declared_classes() as $class) {
237298
if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
238299
$r = new \ReflectionClass($class);
@@ -243,8 +304,14 @@ private static function inVendors(string $path): bool
243304
}
244305
}
245306
}
307+
308+
return $vendors;
309+
}
310+
311+
private static function inVendors(string $path): bool
312+
{
246313
$path = realpath($path) ?: $path;
247-
foreach ($vendors as $vendor) {
314+
foreach (self::getVendors() as $vendor) {
248315
if (0 === strpos($path, $vendor) && false !== strpbrk(substr($path, strlen($vendor), 1), '/'.DIRECTORY_SEPARATOR)) {
249316
return true;
250317
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
/* We have not caught up on the deprecations yet and still call the other lib
3+
in a deprecated way. */
4+
5+
include __DIR__.'/../lib/SomeService.php';
6+
$defraculator = new \acme\lib\SomeService();
7+
$defraculator->deprecatedApi();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace acme\lib;
4+
5+
class SomeService
6+
{
7+
public function deprecatedApi()
8+
{
9+
@trigger_error(
10+
__FUNCTION__.' is deprecated! You should stop relying on it!',
11+
E_USER_DEPRECATED
12+
);
13+
}
14+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
Test DeprecationErrorHandler in weak vendors mode when calling deprecated api
3+
--FILE--
4+
<?php
5+
6+
putenv('SYMFONY_DEPRECATIONS_HELPER=weak_lagging_vendors');
7+
putenv('ANSICON');
8+
putenv('ConEmuANSI');
9+
putenv('TERM');
10+
11+
$vendor = __DIR__;
12+
while (!file_exists($vendor.'/vendor')) {
13+
$vendor = dirname($vendor);
14+
}
15+
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
16+
require PHPUNIT_COMPOSER_INSTALL;
17+
require_once __DIR__.'/../../bootstrap.php';
18+
eval(<<<'EOPHP'
19+
namespace PHPUnit\Util;
20+
21+
class Test
22+
{
23+
public static function getGroups()
24+
{
25+
return array();
26+
}
27+
}
28+
EOPHP
29+
);
30+
require __DIR__.'/fake_vendor/autoload.php';
31+
require __DIR__.'/fake_vendor/acme/lib/SomeService.php';
32+
$defraculator = new \Acme\Lib\SomeService();
33+
$defraculator->deprecatedApi();
34+
35+
36+
?>
37+
--EXPECTF--
38+
Remaining deprecation notices (1)
39+
40+
deprecatedApi is deprecated! You should stop relying on it!: 1x
41+
1x in SomeService::deprecatedApi from acme\lib
42+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Test DeprecationErrorHandler in weak vendors mode on vendor file
3+
--FILE--
4+
<?php
5+
6+
putenv('SYMFONY_DEPRECATIONS_HELPER=weak_lagging_vendors');
7+
putenv('ANSICON');
8+
putenv('ConEmuANSI');
9+
putenv('TERM');
10+
11+
$vendor = __DIR__;
12+
while (!file_exists($vendor.'/vendor')) {
13+
$vendor = dirname($vendor);
14+
}
15+
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
16+
require PHPUNIT_COMPOSER_INSTALL;
17+
require_once __DIR__.'/../../bootstrap.php';
18+
eval(<<<'EOPHP'
19+
namespace PHPUnit\Util;
20+
21+
class Test
22+
{
23+
public static function getGroups()
24+
{
25+
return array();
26+
}
27+
}
28+
EOPHP
29+
);
30+
require __DIR__.'/fake_vendor/autoload.php';
31+
require __DIR__.'/fake_vendor/acme/lagging-lib/lagging_file.php';
32+
33+
?>
34+
--EXPECTF--
35+
Lagging vendor deprecation notices (1)

0 commit comments

Comments
 (0)
0