Skip to content

Introduce weak vendors mode #21539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 28, 2017
Merged

Introduce weak vendors mode #21539

merged 1 commit into from
Feb 28, 2017

Conversation

greg0ire
Copy link
Contributor

@greg0ire greg0ire commented Feb 5, 2017

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 symfony/symfony-docs#7453

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

  • fix colorization issues (vendor deprecation notices are always in red)
  • make the vendor detection more robust
  • make the vendor dir configurable
  • figure out how to run tests and add more of them
    • test on non-vendor file
    • test on vendor file
  • do not change the output of other modes

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Feb 5, 2017

I see two issues here:

  • the first, minor, is that the vendor dir is not always called "vendors"
  • the second is more serious: any code in vendors is always called by some code in userland. Code don't get called magically - but because userland asked for it - thus there is not such thing as "vendor deprecations" vs others. Or do you have a way to decide that works reliably?

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 5, 2017

  1. Yes that's an issue (see my todo list), maybe I can work around that with another env var?
  2. Not an issue IMO, I'm only looking at the first file of the stack trace, which is the one where trigger_error is written. Quoting the manual : "The third parameter is optional, errfile, which contains the filename that the error was raised in, as a string. " So to sum up, a deprecation is a "vendor deprecations" iff the trigger_error that raises it is written in a file that lives in vendor

@@ -76,6 +83,10 @@ public static function register($mode = 0)
$trace = debug_backtrace(true);
$group = 'other';

$isVendor = (strpos($file, '/vendor/') !== false);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nicolas-grekas : we're outside the while on $trace here, so really, we're not looking at every file of the stack trace, but only at the file that has the error triggered in it.

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 5, 2017

Third issue, even more minor, some people might have a vendor directory inside their src (why not). Might be solvable with __DIR__ though.

@nicolas-grekas
Copy link
Member

I'm only looking at the first file of the stack trace

That means you target deprecations triggered by code in src/. Ok.

For vendors, see my PR about ComposerResource.

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 5, 2017

I'm only looking at the first file of the stack trace

Actually that was wrong and has nothing to do with the stack trace, I'm looking at the $errfile argument of the error handler function. So if I have a file in src, that calls a function from the vendor dir, that has a trigger_error in it, $errfile will be vendor/callee.php, and not src/caller.php, right?

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 5, 2017

For vendors, see my PR about ComposerResource.

link for the lazy

@ogizanagi
Copy link
Contributor

link for the laziest 😄

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 5, 2017

Maybe I should explain a bit more the goal of this PR, I feel I'm being unclear.

This is going to used way more in libs than in project, that seldom use deprecation notices themselves. @nicolas-grekas I think that's why you talk about userland vs vendors.

Let there be lib X, that has n dependencies. Anytime any of the n dependencies introduces a new deprecation, I have to fix it, and no PR can be merged during that time, unless I use SYMFONY_DEPRECATIONS_HELPER=weak.

And that's what I do most of the time, because I don't want to shift the burden of fixing these to anyone who wants to contribute anything unrelated to the vendor lib, and has the bad luck of doing so at the wrong time.

Now let's suppose a contributor submits a new PR, and let's suppose that that PR introduces a deprecation notice in the codebase of the lib , and by that I don't mean a deprecated call to another lib, I mean a call to trigger_error directly. Then they must be careful to mark all corresponding tests with @group legacy, and fix all calls throughout the codebase of the lib so that they use the new way of doing things.

In my experience, many people forget to do that, and deprecations are introduced, that could easily be avoided. See this PR where I end up doing the work that should have been done by the contributor from the start.

@nicolas-grekas
Copy link
Member

Doc PR would be really nice before merging since the use case should be explained there :)

@stof
Copy link
Member

stof commented Feb 6, 2017

@greg0ire the issue is that your logic looks wrong. Vendor deprecations must not be distinguished based on the location of the deprecation, but based on the caller location.
You will almost never call your own deprecated code, as you are also the one deprecating it. However, you are very likely to be calling a deprecated method of one of your dependency. In this case, trigger_error is inside the vendor folder, but the place needing to be fixed is inside your own code.
And using the backtrace to identify whether it is called from your own code or no is fragile, because your code may not be the direct caller. We have cases in Symfony where we have more classes between your own code and the code triggering the deprecation for instance, while the fix is still needed in your own code, for instance when asking to migrate from a type name to a class name to reference form types in Symfony 2.8

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 6, 2017

You will almost never call your own deprecated code, as you are also the one deprecating it

That's precisely the case I'm trying to help fix however. There are contributors that contribute new deprecations, and forget to fix these calls. Then it get merged, but could have easily be prevented. Also, there are tests that are marked with @group Legacy (note the capital), which does not work either. That could also have been prevented easily. Or they just outright forget to mark tests with @group legacy That's what I want to catch here.

And using the backtrace to identify whether it is called from your own code or no is fragile

I'm not doing that (I think). I'm not indentify the caller location, I'm identifying the callee location. When developing a lib, the lib is always calling others or itself, but no other lib is calling my lib. So in that case, I think it's safe to want to know "is there any call to a deprecated method of my lib in the codebase of my lib?"

horizontally: caller / vertically: callee my lib my dependency
my lib This is the case I want to catch. It can only be introduced in new contributions that come with a deprecation notice Cannot happen in the context of testing a library. If it happens, it means the dependency knows the lib, and that we have a circular dependency.
my dependency This is the case I don't want to catch, because it would make the build fail randomly Can't happen either in the context of testing lib.

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 6, 2017

Doc PR would be really nice before merging since the use case should be explained there :)

Didn't notice your comment. Will do!

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 7, 2017

Here is the docs PR

@nicolas-grekas
Copy link
Member

Thanks, just posted a few short notes

@@ -50,7 +52,10 @@ public static function register($mode = 0)
if (false === $mode) {
$mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
}
if (DeprecationErrorHandler::MODE_WEAK !== $mode && (!isset($mode[0]) || '/' !== $mode[0])) {
if (!in_array($mode, array(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing true as a 3rd parameter for in_array: https://3v4l.org/hsgBm

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the in_array + line splits look unreadable to me - what about using two comparisons on a single line instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a matter of taste, because to me the more readable version is of course mine. Plus it's less repetitive. I'll do as you say though, b/c you're probably more aware of what the sf style is.

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 8, 2017

I changed the code so that other modes output is no longer split into vendors / non-vendors.

@greg0ire greg0ire force-pushed the weak_vendors branch 2 times, most recently from 028a816 to bd8f0b3 Compare February 8, 2017 22:49
@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 8, 2017

I fixed the colorization issue, deprecation notices are always in yellow now.

@fabpot
Copy link
Member

fabpot commented Feb 12, 2017

fabbot reports errors that should be fixed.

@greg0ire
Copy link
Contributor Author

@fab{b,p}ot : fixed

@greg0ire
Copy link
Contributor Author

I rebased again, can anyone review and remove the "Needs work" label? This is supposed to be finished.

@greg0ire
Copy link
Contributor Author

Changed the poor man's error handler from var_dump to print_r after discussing with @Nek-

@@ -160,16 +196,26 @@ public static function register($mode = 0)
$colorize = function ($str) { return $str; };
}
if ($currErrorHandler !== $deprecationHandler) {
print_r(error_get_last());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated, and very fragile to me, should be removed from this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok let's remove it.

Copy link
Contributor Author

@greg0ire greg0ire Feb 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what exactly qualifies as fragile here though. I think both methods are rock solid.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the link between error_get_last() and the error handler change - maybe I'm wrong - it's still unrelated so please open another PR if you want to investigate the idea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated indeed. Will do

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. In
this mode, deprecations coming from the vendors are segregated from
other deprecations.
@greg0ire
Copy link
Contributor Author

This is supposed to be ready on my end, please review again.

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@fabpot
Copy link
Member

fabpot commented Feb 28, 2017

Thank you @greg0ire.

@fabpot fabpot merged commit 61fd043 into symfony:master Feb 28, 2017
fabpot added a commit that referenced this pull request Feb 28, 2017
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        | symfony/symfony-docs#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
-------

61fd043 Introduce weak vendors mode
@greg0ire greg0ire deleted the weak_vendors branch February 28, 2017 07:08
@greg0ire
Copy link
Contributor Author

Made a separate PR for the poor man's error handling : #21795

xabbuh added a commit to symfony/symfony-docs that referenced this pull request Mar 13, 2017
This PR was merged into the master branch.

Discussion
----------

Document the weak_vendors value

See symfony/symfony#21539

Commits
-------

abe88c6 Document the weak_vendors value
@nicolas-grekas nicolas-grekas modified the milestones: 3.x, 3.3 Mar 24, 2017
@fabpot fabpot mentioned this pull request May 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants