Continuous integration/PHP CodeSniffer

Draft to implement MediaWiki coding conventions using the PHP_CodeSniffer tool.

PHP_CodeSniffer is a style check tool for PHP. It is highly modular: each rule is an independent class; to write a standard you would create a  that includes the class you want to check your code against. Each module can thus reuse other modules' rules as well as implement its own rules.

Installing
First you want to install PHP_CodeSniffer using pear, the tool will be then made available as phpcs.

$ pear install PHP_CodeSniffer $ phpcs --version PHP_CodeSniffer version 1.4.3 (stable) by Squiz Pty Ltd. (http://www.squiz.com.au) $

You will want to grab the MediaWiki standard for PHP_CodeSniffer, it is available in the WMF git repository mediawiki/tools/codesniffer.git/:


 * Gitweb: https://gerrit.wikimedia.org/r/gitweb?p=mediawiki/tools/codesniffer.git
 * Clone anon:  https://gerrit.wikimedia.org/r/p/mediawiki/tools/codesniffer.git 
 * Clone auth:  ssh://gerrit.wikimedia.org:29418/mediawiki/tools/codesniffer.git 

To load the MediaWiki standard, you will have to pass the full path to the phpcs command:

$ phpcs --standard=/path/to/mediawiki/tools/codesniffer/MediaWiki

You will want to make an alias for it:

$ alias phpcsmw='phpcs --standard=/path/to/mediawiki/tools/codesniffer/MediaWiki'

Using
cd /path/to/mediawiki phpcsmw -s -v.


 * Useful options:
 * -v verbose mode (show the files being parsed)
 * -p gives you some progress (output E/. for each file kind of like PHPUnit)
 * -s shows the sniff name in the report, really useful

To get a nice report for a directory:

phpcsmw -v -s includes/api --report-summary

Where:
 * -v show the progress
 * -s report the snif name
 * --report-summary build a report per file and, since -s was given, per sniff.

If you want to actually fix errors, you will want to stop after each file and eventually recheck your changes. PHP_CodeSniffer comes with an interactive mode (with -a) which does exactly that:

$ phpcsmw -v -a. Registering sniffs in MediaWiki standard... DONE (36 sniffs registered) Creating file list... DONE (91 files in queue) Changing into directory /srv/trunk/includes/api Processing ApiBase.php [13888 tokens in 1663 lines]... DONE in 1 second (7 errors, 0 warnings)

FILE: /srv/trunk/includes/api/ApiBase.php

FOUND 7 ERROR(S) AFFECTING 7 LINE(S)

69 | ERROR | There must not be more than one property declared per statement 108 | ERROR | The abstract declaration must precede the visibility |      | declaration 657 | ERROR | Expected 1 space after comma in function call; 2 found 812 | ERROR | A cast statement must be followed by a single space 1367 | ERROR | A cast statement must be followed by a single space 1540 | ERROR | There must not be more than one property declared per statement 1596 | ERROR | There must not be more than one property declared per statement

 to recheck, [s] to skip or [q] to quit :

Fix the errors, press enter and you get a new run :-] Rinse until everything is fine.

getting details
One can list the available coding standards using phpcs -i. As of version 1.4.3, that does not show a standard loaded using --standard like our phpcsmw alias. Anyway, a list of standards would be:

$ phpcsmw -i The installed coding standards are MySource, PEAR, PHPCS, PSR1, PSR2, Squiz and Zend $

To list the rule for a standard, pass the '-e' option:

$ phpcsmw --standard=PSR1 -e

The PSR1 standard contains 7 sniffs

Generic (4 sniffs) -- Generic.Files.ByteOrderMark Generic.NamingConventions.CamelCapsFunctionName Generic.NamingConventions.UpperCaseConstantName Generic.PHP.DisallowShortOpenTag

PSR1 (2 sniffs) --- PSR1.Classes.ClassDeclaration PSR1.Files.SideEffects

Squiz (1 sniffs)

Squiz.Classes.ValidClassName

Below each section is a list of sniffs which are really a PHP class which can then be reused by a module. That is exactly what we are doing for our MediaWiki module, instead of reinventing the wheel, we include sniffs from other modules.