-
Notifications
You must be signed in to change notification settings - Fork 3
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
Introduce Required Parameter Sniff #76
Conversation
Just saying "Thank you" to me will do ;-) Other than that, I'll have a look & review the sniff in a little. |
I was too wrapped up in getting the context that I didn't even read your comment on the issue until I created the PR. Have read it now and added commits accordingly 😊 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed. Besides the remarks I've left inline, I'm wondering what the goal is of the checks currently in the sniff.
Is your intention that the param should always be set ?
Or that the param is always set to true
/yes
?
The default is true
/yes
for add_option()
and whatever was set when the option was originally added for update_option()
, defaulting to true
/yes
when the option doesn't exist yet.
So what are you really trying to archive with this sniff ?
Tests/bootstrap.php
Outdated
* This aliasing has to be done before any of the test classes are loaded by the | ||
* PHPCS native unit test suite to prevent fatal errors. | ||
* | ||
* @package WPCS\WordPressCodingStandards |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this docblock still needs adjusting, credit should be given for the file to WPCS, but the package, link and since tags should be for YoastCS.
Tests/bootstrap.php
Outdated
} | ||
|
||
// Load our class aliases. | ||
require_once dirname( __DIR__ ) . $ds . 'autoload-bootstrap.php'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The path to the WP alias file is different in a test situation, compared to a "run" situation, so loading the ruleset bootstrap here won't work as the paths won't match, so you need to load the alias file directly.
require_once dirname( __DIR__ ) . '/vendor/wp-coding-standards/wpcs/WordPress/PHPCSAliases.php';
In a test situation, YoastCS is the root.
In a "run" situation, YoastCS is installed in the vendor directory of a project.
Yoast/Sniffs/Files/FileNameSniff.php
Outdated
@@ -11,7 +11,6 @@ | |||
|
|||
use PHP_CodeSniffer\Sniffs\Sniff; | |||
use PHP_CodeSniffer\Files\File; | |||
use PHP_CodeSniffer\Util\Tokens; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change does not belong in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically correct. Will it stop you from merging the PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will not ;-)
continue; | ||
} | ||
|
||
$message = '%s() is expected to be called with the "%s" argument at #%s.'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence does not read right. Might help to change at #%s
to at position %d
.
$position, | ||
); | ||
|
||
$this->addMessage( $message, $stackPtr, $parameter_args['enforce'], $code, $data, 0 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$severity
is optional and should normally not be set, so please remove it.
Tests/bootstrap.php
Outdated
* | ||
* Load the PHPCS autoloader and the WPCS PHPCS cross-version helpers. | ||
* | ||
* {@internal We need to load the PHPCS autoloader first, so as to allow their |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is not needed in the context of the YoastCS standard as YoastCS does not need the aliasing as such.
It could be changed to refer to the fact that WPCS at this point in time still needs the aliases and that as you extend a WPCS class, it is needed here too.
As a side-note: WPCS will be dropping PHPCS 3.x support by the end of the summer, so at that time, the aliases will be removed from WPCS completely.
/** | ||
* The group name for this group of functions. | ||
* | ||
* Intended to be overruled in the child class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment line is superfluous as this is a child class.
Yoast/ruleset.xml
Outdated
@@ -2,6 +2,9 @@ | |||
<ruleset name="Yoast" namespace="YoastCS\Yoast"> | |||
<description>Yoast Coding Standards</description> | |||
|
|||
<!-- Autoload the autoloaders of the dependencies. --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've ran some tests, but I don't think this is actually needed as the ruleset includes the WPCS WordPress
ruleset and that ruleset already loads the WPCS autoload. This can be (and should be) removed.
autoload-bootstrap.php
Outdated
@@ -0,0 +1,16 @@ | |||
<?php |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per the comment about autoload in the ruleset + the comment about the paths being different in a test situation and needing to include the WPCS alias file directly for a test situation, this whole file isn't necessary.
autoload-bootstrap.php
Outdated
* @author Jip Moors | ||
*/ | ||
|
||
if ( file_exists( __DIR__ . '/vendor/wimg/php-compatibility/PHPCSAliases.php' ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Side-note/Teaching moment: the PHPCompatibility alias file would not be needed anyway as - again - their own ruleset loads it.
Basically, the only time when you need to load the alias files of another standard is when you just load sniffs from another standard, not the standard itself.
So, for the QA-WP project, I load them as those rulesets don't include the whole WP standard, but only individual sniffs.
For the unit tests you need to load them as the sniffs are tested individually, independent of the ruleset.
Oh.. and two more things:
|
The main goal of the Sniff is to make sure the Having the default @jdevalk has a ticket in progress/in mind where the level of options will be extended with |
I've processed all the feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@moorscode Looking good. Nearly there, though I still have a couple of remarks:
1. Travis script
The Travis script was set up to:
- pull in PHPCS at a
PHPCS_BRANCH
version, set in the matrix, so the unit tests would be run against the minimum and maximum supported PHPCS version. - pull in WPCS and PHPCompatibility for the CS check of the YoastCS code only, so using the
master
branch was fine.
However, now you need WPCS (not PHPCompatibility) for unit testing the sniffs too.
But the sniffs will normally be installed using Composer, which fixes WPCS at a certain version range, so using the WPCS master
branch does not guarantee that the sniffs are unit tested based on the code which the "end-users" will use.
In other words: as the version of WPCS has now become important, the Travis script needs to be changed. It has to pass the exact branch(es) needed for WPCS to the git clone
command.
In the future, the matrix might also need to be extended to test against the minimum and maximum supported version of WPCS if more than one version is supported.
At this time, WPCS 0.14.0
and 0.14.1
are supported, but as 0.14.1
contains no significant changes compared to 0.14.0
for the abstract sniff you are using, just testing against 0.14.1
will be fine.
You could also consider switching over to using Composer to install the dependencies, but there are some snakes under the grass with that so if you want, I could pull that change separately later.
2. The parameter should be set
The main goal of the Sniff is to make sure the autoload is set according to intend.
If that's the case, an explicit value of null
for the parameter should not be accepted, as the parameter in that case is still not set.
To fix this, you can test the raw
value of the parameter, so I would suggest changing line 75 of the sniff:
if ( isset( $parameters[ $position ] ) ) {
to:
if ( isset( $parameters[ $position ] ) && $parameters[ $position ]['raw'] !== 'null' ) {
3. Unit tests
My previous remark And what about when the param has been set to false/ no ?
was not intended to say that every single possible value needs to be tested.
I was just looking to see some more variety in the unit tests.
Testing every possible value is just testing the same thing several times.
For this particular group of functions, I think testing each function with each type of value, i.e. no param, null
, a boolean and a string, should be sufficient.
Between those test cases, you can then have the suggested variety by having one of the functions use true
, the other false
etc.
Other
Will you clean up the branch to topical commits ? Or shall I squash on merge ?
Tests/bootstrap.php
Outdated
|
||
// Get the PHPCS dir from an environment variable. | ||
$phpcsDir = getenv( 'PHPCS_DIR' ); | ||
$phpcsComposerDir = implode( $ds, array( dirname( __DIR__ ), 'vendor', 'squizlabs', 'php_codesniffer' ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implode logic feels like something which should be abstracted to a helper function as it's used more than once.
Aside from that, it may be useful to set a $phpcsComposerBaseDir = dirname( __DIR__ );
above this line.
Tests/bootstrap.php
Outdated
} | ||
} | ||
else { | ||
echo 'Uh oh... can\'t find PHPCS. Are you sure you are using PHPCS 3.x ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This second part of this line is in WPCS as it still supports both PHPCS 2.x as well as 3.x. It is not needed in YoastCS.
Tests/bootstrap.php
Outdated
} | ||
|
||
// Get the WPCS dir from an environment variable. | ||
$wpcsDir = getenv( 'WPCS_DIR' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Tests/bootstrap.php
Outdated
$wpcsDir = realpath( $wpcsDir ); | ||
} | ||
|
||
// Try and load the PHPCS autoloader. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHPCS
-> WPCS
Yoast/Sniffs/Files/FileNameSniff.php
Outdated
@@ -11,7 +11,6 @@ | |||
|
|||
use PHP_CodeSniffer\Sniffs\Sniff; | |||
use PHP_CodeSniffer\Files\File; | |||
use PHP_CodeSniffer\Util\Tokens; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will not ;-)
continue; | ||
} | ||
|
||
$message = '%s() is expected to be called with the "%s" argument at the %d position.'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And just wondering - is expected to
sounds like a warning
, not an error
, while depending on context you throw either an error
or a warning
.
Should this phrase be changed depending on the error
/warning
context to sound stricter ? %s() must be called with the ...
add_option( 'a', 'b', '', 'no' ); | ||
|
||
// Ok. | ||
add_option( 'a', 'b', '', null ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null
is not a valid value to pass to add_option()
. See my remark in my overall review comment.
use WordPress\AbstractFunctionParameterSniff; | ||
|
||
/** | ||
* Verifies that optional parameters are set, when they should be set. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
, when they should be set
is redundant. These parameters are optional as stated in the first part of the sentence, so there is no should be set, other than that the YoastCS standard wants them to be, which is what the sniffs is all about in the first place.
* | ||
* @since 0.6 | ||
*/ | ||
class RequiredParametersSniff extends AbstractFunctionParameterSniff { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering - would RequiredOptionalParameters
better describe what the sniff covers ?
/** | ||
* Bootstrap file for running the tests. | ||
* | ||
* Load the PHPCS autoloader and the WPCS PHPCS cross-version helpers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You asked about giving credit, but don't mention that the bulk of the code in this file comes from/is inspired by WPCS at all now....
I'd say a squash would be fine for this one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@moorscode We're very nearly there. Looking good indeed 👍, just some dotting of the i's and crossing of the t's left.
There is just one last issue I'd like to discuss based on the last round of changes:
You currently have one error message with one error code being thrown from this sniff.
This message can be either a warning or an error and the content of the message changes based on two, three different things.
The idea behind the error codes is that each code identifies a unique message. This enables modular disabling/enabling of sniffs and codes, both from the ruleset as well as inline.
The current message does not comply with that as it basically has four different messages folded into one, all using the same error code.
So, what about actually having two different errors and each having two different codes based on their error/warning status ?
I'm thinking along the lines of:
%s() is %s to be called with the "%s" argument at position %d%s.
with depending on error/warning status a different error code, something along the lines ofParamRequired
/ParamExpected
/ParamMissing
.
Take your pick or come up with your own better alternative.Passing null to the "%s" argument of %s() is %s
where the last%s
would expand toforbidden
ordiscouraged
.
For the error code you could then, for instance, useNullForbidden
andNullDiscouraged
.
Other than that, some practical points:
- 👍 I will squash the commits. Let's plan that dev session about having a clean & useful git history via Slack.
- Would you like me to create a PR to change the Travis file to use Composer ? As per Introduce Required Parameter Sniff #76 (review)
- You are rightfully using version
0.6.0
for this sniff, as the introduction of a new sniff should up the version minor.
There have been some PRs merged between the0.5.0
tag and now. Should0.5.1
be tagged before this PR is merged ? Or should those other merged PRs be retagged as0.6.x
?
Tests/bootstrap.php
Outdated
* | ||
* Load the PHPCS autoloader and the WPCS PHPCS cross-version helpers. | ||
* | ||
* Code has been inspired on the phpcs3-bootstrap.php used in the WordPress Coding Standards project |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: inspired by
or based on
. Inspired on is grammatically incorrect.
Nitpick 2: The see
keyword/tag in docblocks is intended to be used for FQCN, the @link
tag for URLs. And for documentation purposes, linking to the actual file is better as now another dev would still need to dig through the WPCS repo to find the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you have multiple @link
tags in a documentation block? As there already is one referencing to the project itself a couple of lines down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can, but more than that, you can use inline @link
tags, which in this case would probably be more appropriate. {@link URL link text}
and PHPDocumentor will handle it perfectly ;-)
See: https://docs.phpdoc.org/references/phpdoc/tags/link.html
* (string) Function name. => array( | ||
* (int) Target parameter position, 1-based. => array( | ||
* 'name' => (string) The name of the argument that should be set. | ||
* 'enforce' => (boolean) If this should trigger an error or warning. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation for allow_null
missing.
'allow_null' => false, | ||
), | ||
), | ||
); // End $target_functions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These type of // End
comments are not needed/required. Is there a particular reason why you are adding it ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was present in the file I copied it from (the abstract class this is extending).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abstract class doesn't actually have the end tag. I think you may have copied it from the WP.DeprecatedParameters
sniff, but that's a different situation as the array there is nearly 200 lines long.
/** | ||
* Process the parameters of a matched function. | ||
* | ||
* This method has to be made concrete in child classes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Superfluous comment line: You are in the child class.
} | ||
|
||
/** | ||
* Determines if the parameter provided is valid, if any. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammatically better: "Determines if a valid parameter has been provided."
* @param int $position The position of the parameter to check. | ||
* @param array $parameter_args The configuration of the function check. | ||
* | ||
* @return bool True if a valid parameter has been given. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➕ False otherwise.
return false; | ||
} | ||
|
||
if ( ! $parameter_args['allow_null'] && $parameters[ $position ]['raw'] === 'null' ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this check always need to be executed ? In other words: will allow_null
always be set ?
use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; | ||
|
||
/** | ||
* Unit test class for the RequiredParameters sniff. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RequiredParameters
=>RequiredOptionalParameters
I have split up the error and warning messages to have their own identifiers. Examples:
|
FYI - the Travis script change over to use Composer as discussed in #76 (review), is included in PR #81. |
8073f26
to
b2e087f
Compare
46be857
to
4d3bb89
Compare
Applicable to the `update_option()` and `add_option()` functions from WordPress. Ensures that options are not autoloaded without a conscious decision.
Because we use WPCS 1.x, which still supports PHPCS 2.x, we need to make sure the WPCS alias file which adds cross-version support for PHPCS 2.x and 3.x is loaded, when running the unit tests. As this introduces a YoastCS PHPUnit bootstrap file, this file should also take case of loading the PHPCS 3.1+ PHPUnit bootstrap which sorts out PHPUnit cross-version compatibility for PHPCS. Once WPCS 2.0 has been released and bumped, this workaround can be removed.
4d3bb89
to
ca5fe4e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@moorscode I've reviewed the sniff again and left some (minor) inline remarks.
Aside from that, a couple of generic points I'd like to discuss with you when you have the time:
- The way the logic is written now, the mental overhead to read the code is quite high.
- Even though, the errorcode is now modular, IMO you are trying to do to much with one error.
Why not have two separate checks ? One that the parameter is set and a second that it's notnull
? and have separate errors for each. - Both errors and warnings should be solvable by other means that adding an
phpcs:ignore
comment.
If an option is being added withadd_option()
with the$autoload
parameter set and in another part of the code that same option is updated usingupdate_option()
without setting the$autoload
parameter - to prevent overruling whatever was set withadd_option()
-, there is currently no easy way to "fix" this in the code, other than duplicating the$autoload
parameter used in the originaladd_option()
call and creating a potential maintenance/debug nightmare where every singleadd_option()
andupdate_option()
call for each option has to be kept in line with each other and if the$autoload
is changed for one, it has to be changed in every singleupdate_option()
call for that same option.
I think this needs to be thought through a little more before this sniff can be merged.
22 => 1, | ||
24 => 1, | ||
); | ||
} // end getErrorList() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
End comments are not needed.
/** | ||
* Returns the lines where warnings should occur. | ||
* | ||
* The key of the array should represent the line number and the value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This "long description" can be removed (as it has been in the method above and in all the other test files).
ca5fe4e
to
9ca9009
Compare
As the new sniff is based on WPCS, we need to make sure that the sniff works both with the lowest supported WPCS version as well as with the current `develop` branch. This commit adds high/low WPCS versions into the matrix mix.
Another point which will need looking into - now or later (non-urgent): the unit tests against PHP I'm not sure if this is PHPCS. WPCS or YoastCS related as I haven't looked into it. |
These As the We have only one usage of If the same option is updated on multiple locations the autoload context must be thought about anyway. If we change if something needs to be autoloaded doing a search would be logical to determine where it is actually set/used. /cc @atimmer |
Co-Authored-By: moorscode <jhp.moors@gmail.com>
Co-Authored-By: moorscode <jhp.moors@gmail.com>
@moorscode So.. how about we try and prevent this PR having a one-year anniversary ? Did you have a chance to think over the things we discussed in December ? |
Initially only checking
update_option
for theautoload
parameter to be set.This is an optional parameter, but we want to make sure it is set with intent.
As this class is based upon the
AbstractFunctionParameterSniff
-class from WPCS, some class-aliases need to be loaded to make it work.These are being provided in the autoload-bootstrap.php file.
To make sure the tests also know where to find them, a test bootstrap file had to be added as well.
@jrfnl do I need to give props for the inspirational files and extended class and if so, how?
Fixes #74