feature #21539 Introduce weak vendors mode (greg0ire)
This PR was merged into the 3.3-dev branch.
Discussion
----------
Introduce weak vendors mode
Deprecations coming from the vendors are segregated from other
deprecations. A new mode is introduced, in which deprecations coming
from the vendors are not taken into account when deciding to exit with
an error code.
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| License | MIT
| Doc PR | https://github.com/symfony/symfony-docs/pull/7453
<!--
- Bug fixes must be submitted against the lowest branch where they apply
(lowest branches are regularly merged to upper ones so they get the fixes too).
- Features and deprecations must be submitted against the master branch.
- Please fill in this template according to the PR you're about to submit.
- Replace this comment by a description of what your PR is solving.
-->
Sample output :
# Weak vendor mode
## With both vendors and non-vendor errors
```
WARNINGS!
Tests: 1068, Assertions: 2714, Warnings: 6, Skipped: 15.
Remaining deprecation notices (1)
some error: 1x
1x in SonataAdminBundleTest::testBuild from Sonata\AdminBundle\Tests
Remaining vendor deprecation notices (4)
Legacy deprecation notices (48)
```
Exit code is 1
## After fixing non-vendor errors
```
WARNINGS!
Tests: 1068, Assertions: 2714, Warnings: 6, Skipped: 15.
Remaining vendor deprecation notices (4)
Legacy deprecation notices (48)
```
Exit code is 0
# TODO
- [x] fix colorization issues (vendor deprecation notices are always in red)
- [x] make the vendor detection more robust
- [x] make the vendor dir configurable
- [x] ~figure out how to run tests and~ add more of them
- [x] test on non-vendor file
- [x] test on vendor file
- [x] do not change the output of other modes
Commits
-------
61fd043dd5
Introduce weak vendors mode
This commit is contained in:
commit
43bff2279b
@ -19,6 +19,7 @@ namespace Symfony\Bridge\PhpUnit;
|
||||
class DeprecationErrorHandler
|
||||
{
|
||||
const MODE_WEAK = 'weak';
|
||||
const MODE_WEAK_VENDORS = 'weak_vendors';
|
||||
const MODE_DISABLED = 'disabled';
|
||||
|
||||
private static $isRegistered = false;
|
||||
@ -28,6 +29,7 @@ class DeprecationErrorHandler
|
||||
*
|
||||
* The following reporting modes are supported:
|
||||
* - use "weak" to hide the deprecation report but keep a global count;
|
||||
* - use "weak_vendors" to act as "weak" but only for vendors;
|
||||
* - use "/some-regexp/" to stop the test suite whenever a deprecation
|
||||
* message matches the given regular expression;
|
||||
* - use a number to define the upper bound of allowed deprecations,
|
||||
@ -52,13 +54,37 @@ class DeprecationErrorHandler
|
||||
if (false === $mode) {
|
||||
$mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
|
||||
}
|
||||
if (DeprecationErrorHandler::MODE_WEAK !== $mode && (!isset($mode[0]) || '/' !== $mode[0])) {
|
||||
if (DeprecationErrorHandler::MODE_WEAK !== $mode && DeprecationErrorHandler::MODE_WEAK_VENDORS !== $mode && (!isset($mode[0]) || '/' !== $mode[0])) {
|
||||
$mode = preg_match('/^[1-9][0-9]*$/', $mode) ? (int) $mode : 0;
|
||||
}
|
||||
|
||||
return $memoizedMode = $mode;
|
||||
};
|
||||
|
||||
$inVendors = function ($path) {
|
||||
/** @var string[] absolute paths to vendor directories */
|
||||
static $vendors;
|
||||
if (null === $vendors) {
|
||||
foreach (get_declared_classes() as $class) {
|
||||
if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
|
||||
$r = new \ReflectionClass($class);
|
||||
$v = dirname(dirname($r->getFileName()));
|
||||
if (file_exists($v.'/composer/installed.json')) {
|
||||
$vendors[] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$path = realpath($path) ?: $path;
|
||||
foreach ($vendors as $vendor) {
|
||||
if (0 === strpos($path, $vendor) && false !== strpbrk(substr($path, strlen($vendor), 1), '/'.DIRECTORY_SEPARATOR)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$deprecations = array(
|
||||
'unsilencedCount' => 0,
|
||||
'remainingCount' => 0,
|
||||
@ -69,7 +95,13 @@ class DeprecationErrorHandler
|
||||
'legacy' => array(),
|
||||
'other' => array(),
|
||||
);
|
||||
$deprecationHandler = function ($type, $msg, $file, $line, $context) use (&$deprecations, $getMode, $UtilPrefix) {
|
||||
if (self::MODE_WEAK_VENDORS === $mode) {
|
||||
$deprecations += array(
|
||||
'remaining vendorCount' => 0,
|
||||
'remaining vendor' => array(),
|
||||
);
|
||||
}
|
||||
$deprecationHandler = function ($type, $msg, $file, $line, $context) use (&$deprecations, $getMode, $UtilPrefix, $inVendors) {
|
||||
$mode = $getMode();
|
||||
if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || DeprecationErrorHandler::MODE_DISABLED === $mode) {
|
||||
$ErrorHandler = $UtilPrefix.'ErrorHandler';
|
||||
@ -80,6 +112,8 @@ class DeprecationErrorHandler
|
||||
$trace = debug_backtrace(true);
|
||||
$group = 'other';
|
||||
|
||||
$isWeak = DeprecationErrorHandler::MODE_WEAK === $mode || (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $isVendor = $inVendors($file));
|
||||
|
||||
$i = count($trace);
|
||||
while (1 < $i && (!isset($trace[--$i]['class']) || ('ReflectionMethod' === $trace[$i]['class'] || 0 === strpos($trace[$i]['class'], 'PHPUnit_') || 0 === strpos($trace[$i]['class'], 'PHPUnit\\')))) {
|
||||
// No-op
|
||||
@ -99,6 +133,8 @@ class DeprecationErrorHandler
|
||||
|| in_array('legacy', $Test::getGroups($class, $method), true)
|
||||
) {
|
||||
$group = 'legacy';
|
||||
} elseif (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $isVendor) {
|
||||
$group = 'remaining vendor';
|
||||
} else {
|
||||
$group = 'remaining';
|
||||
}
|
||||
@ -117,13 +153,13 @@ class DeprecationErrorHandler
|
||||
|
||||
exit(1);
|
||||
}
|
||||
if ('legacy' !== $group && DeprecationErrorHandler::MODE_WEAK !== $mode) {
|
||||
if ('legacy' !== $group && !$isWeak) {
|
||||
$ref = &$deprecations[$group][$msg]['count'];
|
||||
++$ref;
|
||||
$ref = &$deprecations[$group][$msg][$class.'::'.$method];
|
||||
++$ref;
|
||||
}
|
||||
} elseif (DeprecationErrorHandler::MODE_WEAK !== $mode) {
|
||||
} elseif (!$isWeak) {
|
||||
$ref = &$deprecations[$group][$msg]['count'];
|
||||
++$ref;
|
||||
}
|
||||
@ -167,9 +203,18 @@ class DeprecationErrorHandler
|
||||
return $b['count'] - $a['count'];
|
||||
};
|
||||
|
||||
foreach (array('unsilenced', 'remaining', 'legacy', 'other') as $group) {
|
||||
$groups = array('unsilenced', 'remaining');
|
||||
if (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode) {
|
||||
$groups[] = 'remaining vendor';
|
||||
}
|
||||
array_push($groups, 'legacy', 'other');
|
||||
|
||||
foreach ($groups as $group) {
|
||||
if ($deprecations[$group.'Count']) {
|
||||
echo "\n", $colorize(sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']), 'legacy' !== $group), "\n";
|
||||
echo "\n", $colorize(
|
||||
sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']),
|
||||
'legacy' !== $group && 'remaining vendor' !== $group
|
||||
), "\n";
|
||||
|
||||
uasort($deprecations[$group], $cmp);
|
||||
|
||||
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
eval(<<<'EOPHP'
|
||||
namespace PHPUnit\Util;
|
||||
|
||||
class Test
|
||||
{
|
||||
public static function getGroups()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
EOPHP
|
||||
);
|
||||
|
||||
@trigger_error('root deprecation', E_USER_DEPRECATED);
|
||||
|
||||
class FooTestCase
|
||||
{
|
||||
public function testLegacyFoo()
|
||||
{
|
||||
@trigger_error('silenced foo deprecation', E_USER_DEPRECATED);
|
||||
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
public function testNonLegacyBar()
|
||||
{
|
||||
@trigger_error('silenced bar deprecation', E_USER_DEPRECATED);
|
||||
trigger_error('unsilenced bar deprecation', E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new FooTestCase();
|
||||
$foo->testLegacyFoo();
|
||||
$foo->testNonLegacyBar();
|
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/composer/autoload_real.php';
|
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
class ComposerAutoloaderInitFake
|
||||
{
|
||||
}
|
@ -0,0 +1 @@
|
||||
{"just here": "for the detection"}
|
@ -0,0 +1,74 @@
|
||||
--TEST--
|
||||
Test DeprecationErrorHandler in weak vendors mode on a non vendor file
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors');
|
||||
putenv('ANSICON');
|
||||
putenv('ConEmuANSI');
|
||||
putenv('TERM');
|
||||
|
||||
$vendor = __DIR__;
|
||||
while (!file_exists($vendor.'/vendor')) {
|
||||
$vendor = dirname($vendor);
|
||||
}
|
||||
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
|
||||
require PHPUNIT_COMPOSER_INSTALL;
|
||||
require_once __DIR__.'/../../bootstrap.php';
|
||||
|
||||
@trigger_error('root deprecation', E_USER_DEPRECATED);
|
||||
|
||||
eval(<<<'EOPHP'
|
||||
namespace PHPUnit\Util;
|
||||
|
||||
class Test
|
||||
{
|
||||
public static function getGroups()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
EOPHP
|
||||
);
|
||||
|
||||
class FooTestCase
|
||||
{
|
||||
public function testLegacyFoo()
|
||||
{
|
||||
@trigger_error('silenced foo deprecation', E_USER_DEPRECATED);
|
||||
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
|
||||
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
public function testNonLegacyBar()
|
||||
{
|
||||
@trigger_error('silenced bar deprecation', E_USER_DEPRECATED);
|
||||
trigger_error('unsilenced bar deprecation', E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new FooTestCase();
|
||||
$foo->testLegacyFoo();
|
||||
$foo->testNonLegacyBar();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Unsilenced deprecation notices (3)
|
||||
|
||||
unsilenced foo deprecation: 2x
|
||||
2x in FooTestCase::testLegacyFoo
|
||||
|
||||
unsilenced bar deprecation: 1x
|
||||
1x in FooTestCase::testNonLegacyBar
|
||||
|
||||
Remaining deprecation notices (1)
|
||||
|
||||
silenced bar deprecation: 1x
|
||||
1x in FooTestCase::testNonLegacyBar
|
||||
|
||||
Legacy deprecation notices (1)
|
||||
|
||||
Other deprecation notices (1)
|
||||
|
||||
root deprecation: 1x
|
||||
|
@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Test DeprecationErrorHandler in weak vendors mode on vendor file
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors');
|
||||
putenv('ANSICON');
|
||||
putenv('ConEmuANSI');
|
||||
putenv('TERM');
|
||||
|
||||
$vendor = __DIR__;
|
||||
while (!file_exists($vendor.'/vendor')) {
|
||||
$vendor = dirname($vendor);
|
||||
}
|
||||
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
|
||||
require PHPUNIT_COMPOSER_INSTALL;
|
||||
require_once __DIR__.'/../../bootstrap.php';
|
||||
require __DIR__.'/fake_vendor/autoload.php';
|
||||
require __DIR__.'/fake_vendor/acme/lib/deprecation_riddled.php';
|
||||
--EXPECTF--
|
||||
Unsilenced deprecation notices (2)
|
||||
|
||||
Remaining vendor deprecation notices (1)
|
||||
|
||||
Legacy deprecation notices (1)
|
||||
|
||||
Other deprecation notices (1)
|
Reference in New Issue
Block a user