Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
This is a follow-up to #1266444: DrupalCI should return failed for poor code style - php
Problem/Motivation
We want drupalci to be able to provide a coding standards report for PHP, for core or contrib under test.
#1266444: DrupalCI should return failed for poor code style - php gave us a plugin to work with.
Proposed resolution
Modify the simpletest test definition to use phpcs, for core and contrib.
Add more tests for the core use-case.
Expand capability and tests for contrib use-case.
Comments
Comment #2
Mile23Comment #3
Mile23Comment #4
BerdirWould be awesome to have this, but I think it would be important for contrib to be able to opt-in to this, at least for an initial phase and maybe opt-out later.
There are pretty large contrib projects out there, quite a few (co-)maintained by me and I fear that forcing this would bring development of them to a halt until all coding standards issues are fixed, which could be quite some work.
Comment #5
Mile23That's part of the point here: Figure out the use-case for contrib.
So far the idea is that if the contrib project doesn't have a phpcs.xml.dist file, then there's no sniffing.
We're also just making a report at this point, and not doing the failing until there's a way to configure it through d.o.
Comment #6
hass CreditAttribution: hass commentedI fear more that it complains about non-poor code just because the software is too stupid. We have seen this in many cases in past where coder* was used. There have been tons of fail positives and a test runner was used that checked for non-core code style.
Comment #9
Mile23Added better behavior for phpcs plugin.
Don't sniff if:
There's no longer a config for config_directory because start_directory should be where your phpcs.xml.dist file resides.
Added a test which uses Examples as a fixture. Added this issue to the Examples project to provide a place to park patches: #2842832: Dummy issue for DrupalCI
Comment #10
MixologicShould we add phpcs to the php containers, like we do with drush/composer? Does it even need to run in the version under test, or is phpcs something that can run on the host machine?
Comment #11
MixologicEr rather I see now they run inside the container. I'll assume that means it cant be on the host, but phpcs *could* be installed globally if we wanted.
I took the liberty of tweaking our jenkins testing job to add some additional things, like, actually looking for checkstyle.xml, and being able to set the drupalci_testbot branch:
Couple of things: sniff_only_changed FALSE didnt work.
The checkstyle report produced inside the container has the container paths in it. which makes jenkins full of java exception hate:
https://dispatcher.drupalci.org/job/drupalci_test_containers/736/checkst...
I wonder if we can change the
'<file name="/var/www/html/'
in the xml to the build source directory? I wonder if that even matters after the fact -> i.e. I dont know if the checkstyle plugin for jenkins is doing the copy from the workspace when you click on the file or after it parses the results and therefore stashes it.https://dispatcher.drupalci.org/job/drupalci_test_containers/735/
Other than that, hella sweets.
Comment #12
MixologicAlso, for posterity and the eventual drupal.org displayin:
https://dispatcher.drupalci.org/job/drupalci_test_containers/736/checkst...
Comment #13
MixologicOne more thing, we also might want to consider how to handle only changing phpcs.xml.dist. If a patch changes the rules, it ought to sniff the whole codebase? Not sure.
also, do we care about d7? does anything act differently if we do?
Comment #14
Mile23Coder/phpcs should be a dependency of the project, and we only check if it's there. This is the same problem solved by composering under the container: If the project specifies a version of coder/phpcs that can't be resolved under the platform constraints, then it's a bad idea to run it, and the maintainer should find out about it.
So once the compser-within-the-container thing happens, this part will solve itself.
I'll look at other output formats because it would be much better to not have to modify anything in the report file. Otherwise we end up with the same container vs. host path problem, which is a bunch of string functions traversing an XML file.
This is a good point. If either phpcs.xml or the dist is changed, then sniff everything.
Comment #15
MixologicI was thinking something much more brute forceish than caring if its XML:
Something along the lines of:
The checkstyle plugin is definitely the format we want from jenkins, and I dont think we can really get away from the inside vs outside container path without translating it back, unless we run it from the outside to begin with.
As another totally random aside to this, should we be using phpcs to check our javascript? (https://github.com/squizlabs/PHP_CodeSniffer/wiki/Configuration-Options#...) Or are we settled on ESLint as whats needed there?
Comment #16
Mile23It turns out core has a package.json file, which does all the specifying for eslint. #2809477: Add ES6 to ES5 build process So we'd do an
npm
plugin and then arun-jslint
plugin, both in the container. I think our implementation issues for that are #2600626: [PP-1] Ensure availability of node/npm in the testrunners and #2575501: [PP-2] DrupalCI should return failed for poor code style - JSComment #18
Mile23ada601ee adds a behavior where if phpcs.xml or phpcs.xml.dist is changed, then the sniff is run against the whole project, with a test. Also we strongarm the checkstyle file paths to be host paths, as per #15.
Comment #20
Mile23Comment #21
Mile23Comment #24
MixologicOkay, been reviewing this one, and I think there's a few things Im trying to sort out. Lets start with something minor:
The value '/phpcs/phpcs_checkstyle.xml' shows up a few times. maybe we set that on a property on this plugin and use that instead (if it ever has to move, or if we ever decide that we're going to do something like automagically namespace plugin artifacts in the artifact dir, it'll be nice not to forget to change it everywhere)
so..
getPhpcsExecutable() -> Im kinda not sure we should be so rigid with our check. I think we ought to maybe leave room for a phpcs that just happens to live inside the executable containers, much like composer does, because we might want to have codesniffing for d7 modules (especially somewhere like project applications kind of work), and Im not sure its going to come in the same way. Or maybe it does.. just trying to imagine the d7 use case here. I like the idea of not codesniffing a project that does not have a phpcs.xml file, but I dont think we should extend that to whether or not the project also requires phpcs as a dependency... i.e. force coder/force phpcs I think is the way to go with the testing infra.
finally, lets ensure that whatever needs d7 overriding can easilly be done so in a phpcsD7 plugin.. I didnt fully look it over, maybe its already that way.
Be sure to pull.. I merged dev back into this. manytimes.
Comment #25
MixologicComment #26
Mile23We really should be doing this generically anyway, so that it's always
/{pluginname}/some_report.xml
. But I'll make that a follow-up and allow configuring the report filepath.D8 core is doing coding standards by adding individual rules in manageable patches, against a specific version of coder. That means we will always be requiring coder at a specific version, until maintainers decide to move on to the next one. Coder will always require the phpcs executable.
This means we can let core do all the work of determining whether phcps should be there, and what version it is.
This also means we can let Composer do the work of telling us when there are version and platform constraint problems wrt phpcs.
Also: In order for phpcs to work with coder, it has to be configured with
installed_paths
to use the composer-specified version of coder. That has to be the container path to/vendor/drupal/coder/coder_sniffer/
.Basically it's all the same reasons we should be re-running
composer install
inside the container.I also think checking-for-the-tool is going to be a common pattern, too, because for JS linting we'll be doing an
npm install
and then checking whethereslint
is present where we expect it.We can't really test the behavior for D7 core because no config file. Find a D7 contrib with a phpcs.xml.dist and we can work on it. I think D7 core/contrib should be a follow-up when someone asks for it. It's really clear what D8's needs are, but not so much D7.
Comment #27
Mile23...IN FACT....
We have to run composer install inside the container for this to work with #2744463: Add phpcs, coder 8.2.8 as --dev requirements for drupal/core.
Because we run a composer post-install event which we use to configure phpcs to use coder.
We could work-around since we already know the installed_paths directory is a requirement, and the plugin does that, but it'd be better to have the composer step in the container.
Comment #29
Mile23This adds the report_file_path config per #24 and updates the tests for the new dev environment.
We're basically postponed here for core 8's use-case while we figure out #2845802: Run composer install inside the container to allow for platform constraints, path-based config
After a certain point, core will perform the config of phpcs to use coder, so we won't need the installed_path config for D8.
Core D7 doesn't have a phpcs.xml (or a composer.json to depend on phcps), so it's unclear how to proceed.
Contrib for D8 could have a phpcs.xml file, but no composer.json, in which case it would inherit whatever versions core is using. That could lead to wrong reporting. If the contrib has a composer.json, it might need a helping hand with installed_path config. Or not. How should we proceed with a merged dev dependency that might be satisfied by core and installed by core?
We were unable to find a D7 contrib project with a phpcs.xml file, so it's not a use case at the moment. Obviously that can change.
In IRC we talked about having a global code quality metric where we could just run coder against all the projects. That's out of scope here, but it's an interesting idea. It kind of suffers from the same ambiguity as the above situations, though.
Comment #30
MixologicI don't think that we need to support project specific versions of phpcs or coder. The only thing that should be configurable on a per project basis is phpcs.xml. We have "Drupal" coding standards, not project specific coding standards. A maintainer can enable/disable whatever rules they are ready to support, but we're not going to allow adding new rules that only a specific project supports. So, if core says we use coder 8.2.8 and phpcs version >=2.5.1, then thats what contrib is going to to inherit.
For d7 , we would either composer require coder and phpcs (since we do have a fake composer.json), or just download them somewhere else. Composer isn't an essential step in acquiring phpcs - its packaged as a phar, and coder is really just a git repo that we need to be downloaded to somewhere.
Comment #31
MixologicThere was much IRC conversing. I think we landed on supporting just about everything.
https://docs.google.com/spreadsheets/d/1Oq-sM5yJmeAYPwFXRX2QFcQnNvqTGHgM... has more details about the combinations of d7/d8/core/contrib with coder/phpcs.xml and not, and how those ought to be handled.
Comment #32
MixologicAlso, this should probably be marked as a dupe: #2589853: Integrate PHP CodeSniffer test with drupal.org
Comment #37
Mile23The principles that we decided on in IRC are: Everything gets sniffed, and if you want to control how your project is sniffed, add a
phpcs.xml.dist
file. If the project doesn't require coder or phpcs, we require the latest stable of drupal/coder. If the project has aphpcs.xml(.dist)
file, we use that, otherwise we use the current Drupal standard.OK, so there's a matrix of test cases you can see here: http://cgit.drupalcode.org/drupalci_testbot/tree/tests/DrupalCI/Tests/Pl...
They represent a bunch of use-cases.
The use cases are a matrix of the following components per project:
While there's a way to cause this thing to stop the build based on CS errors (thus failing the test), that's off by default. You only end up with a phpcs report in your artifact folder.
What still needs to happen:
D7 tests, more contrib tests, and most of all, the following:
This plugin uses Composer inside the PHP container to resolve dependencies. This means it does not have access to the cache of metadata goodness which lives in the host. We need to map
/opt/drupalci/composer-cache
from the host to a similar place in the PHP container. Then Composer takes only a few seconds to figure out which drupal/coder to use, instead of 30.Comment #42
Mile23Added more tests.
Needs a follow-up to determine what's installed using a better technique than looking for a phpcs executable.
Other than that I think we should move forward and learn more things before trying any more.
Comment #43
Mile23Follow-up #2847519: Phpcs plugin should use installed.json to figure out what's installed.
Comment #44
MixologicSo yeah, this is in production, and producing checkstyle.xml files. Patch testing cant use it yet though because checkstyle makes jenkins faint.
Comment #45
Mixologic