Accélérer l’intégration continue d’un projet PHP

L’analyse statique d’un projet PHP par une PIC telle que Jenkins nécessite une optimisation des règles d’exclusion des répertoires ne faisant pas partis du code développé. Vous verrez quelques astuces pour accélérer l’intégration continue d’un projet PHP.

Les outils d’analyse statique

J’ai récemment repris la maintenance d’un projet PHP open source et je souhaitais l’intégrer dans une PIC (Plateforme d’Intégration Continue) afin d’obtenir des indicateurs sur la qualité du code. Ces indicateurs ne sont pas produits par Jenkins lui-même, mais par des outils tiers (pour la plupart, c’est un portage – pour le PHP – d’outils d’analyse provenant du monde Java) tels que :

Ces utilitaires peuvent être utilisés en dehors de la PIC pour vérifier tel ou tel aspect. Il existe d’autres utilitaires PHP d’analyse de code comme PhpCheckstyle ou Yasca (audit de sécurité). Le but de ce post n’est pas de parler des autres outils intégrables à la PIC (phpunit, selenium…), mais de l’optimisation des outils de contrôle précités qui s’avèrent très gourmands en ressources système.

L’absence de règles d’exclusion met la CPU au supplice

Le problème est que les applications PHP modernes s’appuient sur des frameworks PHP (on peut citer Zend, Symfony, cakePHP…), Javascript (Dojo, JQuery…)  et des composants tiers (diverses bibliothèques telles que PHPExcel, PHPWord, pChart) voire des sous-systèmes (CMS Drupal ou Joomla). Ces applications peuvent peser 100 à 200Mo avec plusieurs dizaines ou centaines de milliers de fichiers.

Le but n’étant pas d’obtenir des indicateurs de qualité de ces produits, mais de votre logiciel il faut exclure les fichiers sources de votre analyse. Sans quoi, chaque vérification mettra 24 à 48h sur un PC moyen (sans blague, on a fait le test au boulot).

Les règles d’exclusion

Voici le détail des règles d’exclusion outil par outil qui part du principe que le répertoire courant (.) contient les sources à analyser. Vous trouverez un exemple de fichier build.xml (pour intégration dans Jenkins) vers la fin de l’article.

pdepend

http://pdepend.org/documentation/handbook/command-line.html

pdepend --jdepend-xml=./build/logs/jdepend.xml --jdepend-chart=./build/pdepend/dependencies.svg --overview-pyramid=./build/pdepend/overview-pyramid.svg --ignore=library/,tests/,utils/,build/,js/,drupal/,bin/ --suffix=php .

phpmd

http://phpmd.org/documentation/index.html
phpmd . xml codesize,design,naming,unusedcode --reportfile ./build/logs/pmd.xml --exclude *library/*,*tests/*,*utils/*,*build/*,*js/*,*drupal/*,*bin/*

phpcpd

https://github.com/sebastianbergmann/phpcpd
phpcpd --log-pmd ./build/logs/pmd-cpd.xml --exclude library --exclude tests --exclude utils --exclude build --exclude js --exclude drupal --exclude bin --suffixes php .

phploc

https://github.com/sebastianbergmann/phploc
phploc --log-csv ./build/logs/phploc.csv --exclude library --exclude tests --exclude utils --exclude build --exclude js --exclude drupal --exclude bin --suffixes php .

phpcs

https://github.com/squizlabs/PHP_CodeSniffer
http://pear.php.net/manual/en/package.php.php-codesniffer.php
phpcs --report=checkstyle --report-file=./build/logs/checkstyle.xml --standard=PEAR --extensions=php --ignore=*library/*,*tests/*,*utils/*,*build/*,*js/*,*drupal/*,*bin/* .

phpdoc

http://www.phpdoc.org/
phpdoc -d . -t ./build/api --ignoresymlinks --ignore *library/*,*tests/*,*utils/*,*build/*,*js/*,*drupal/*,*bin/*

phpcb

http://www.waterproof.fr/products/phpCodeBeautifier/
phpcb --log ./build/logs --source . --output ./build/code-browser --ignore=library/,tests/,utils/,build/,js/,drupal/,bin/

PhpCheckstyle

Bien que phpCheckstyle ne soit pas intégrable dans Jenkins, je donne quand même un exemple de règle d’exclusion pour ceux qui souhaiteraient l’utiliser ou l’essayer :
php run.php --src /var/www/sqa-tcm --exclude library --exclude tests --exclude utils --exclude build --exclude js --exclude drupal --exclude bin

Exemple de fichier build.xml

logo de la PIC jenkins

logo de la PIC jenkins

Il s’agit d’un exemple concret que j’ai utilisé pour intégrer un projet PHP volumineux dans Jenkins.


<project name="sqa-tcm" default="build" basedir=".">
 <property name="source" value="."/>
<target name="clean" description="Clean up and create artifact directories">
 <delete dir="${basedir}/build/api"/>
 <delete dir="${basedir}/build/code-browser"/>
 <delete dir="${basedir}/build/coverage"/>
 <delete dir="${basedir}/build/logs"/>
 <delete dir="${basedir}/build/pdepend"/>
<mkdir dir="${basedir}/build/api"/>
 <mkdir dir="${basedir}/build/code-browser"/>
 <mkdir dir="${basedir}/build/coverage"/>
 <mkdir dir="${basedir}/build/logs"/>
 <mkdir dir="${basedir}/build/pdepend"/>
 </target>
<target name="phpunit" description="Run unit tests using PHPUnit and generates junit.xml and clover.xml">
 <exec executable="phpunit" failonerror="false"/>
 </target>
<target name="parallelTasks" description="Run the pdepend, phpmd, phpcpd, phpcs, phpdoc and phploc tasks in parallel using a maximum of 2 threads.">
 <parallel threadCount="2">
 <sequential>
 <antcall target="pdepend"/>
 <antcall target="phpmd"/>
 </sequential>
 <antcall target="phpcpd"/>
 <antcall target="phpcs"/>
 <antcall target="phpdoc"/>
 <antcall target="phploc"/>
 </parallel>
 </target>
<target name="pdepend" description="Generate jdepend.xml and software metrics charts using PHP_Depend">
 <exec executable="pdepend">
 <arg line="--jdepend-xml=${basedir}/build/logs/jdepend.xml
 --jdepend-chart=${basedir}/build/pdepend/dependencies.svg
 --overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg
 --ignore=library/,tests/,utils/,build/,js/,drupal/,bin/
 --suffix=php
 ${source}" />
 </exec>
 </target>
<target name="phpmd" description="Generate pmd.xml using PHPMD">
 <exec executable="phpmd">
 <arg line="${source}
 xml
 codesize,design,naming,unusedcode
 --reportfile ${basedir}/build/logs/pmd.xml
 --exclude *library/*,*tests/*,*utils/*,*build/*,*js/*,*drupal/*,*bin/*" />
 </exec>
 </target>
<target name="phpcpd" description="Generate pmd-cpd.xml using PHPCPD">
 <exec executable="phpcpd">
 <arg line="--log-pmd ${basedir}/build/logs/pmd-cpd.xml
 --exclude library
 --exclude tests
 --exclude utils
 --exclude build
 --exclude js
 --exclude drupal
 --exclude bin
 --suffixes php
 ${source}" />
 </exec>
 </target>
<target name="phploc" description="Generate phploc.csv">
 <exec executable="phploc">
 <arg line="--log-csv ${basedir}/build/logs/phploc.csv
 --exclude library
 --exclude tests
 --exclude utils
 --exclude build
 --exclude js
 --exclude drupal
 --exclude bin
 --suffixes php
 ${source}" />
 </exec>
 </target>
<target name="phpcs" description="Generate checkstyle.xml using PHP_CodeSniffer">
 <exec executable="phpcs" output="/dev/null">
 <arg line="--report=checkstyle
 --report-file=${basedir}/build/logs/checkstyle.xml
 --standard=PEAR
 --ignore=*library/*,*tests/*,*utils/*,*build/*,*js/*,*drupal/*,*bin/*
 ${source}" />
 </exec>
 </target>
<target name="phpdoc" description="Generate API documentation using PHPDocumentor">
 <exec executable="phpdoc">
 <arg line="-d ${source} -t ${basedir}/build/api
 --ignoresymlinks
 --ignore *library/*,*tests/*,*utils/*,*build/*,*js/*,*drupal/*,*bin/*" />
 </exec>
 </target>
<target name="phpcb" description="Aggregate tool output with PHP_CodeBrowser">
 <exec executable="phpcb">
 <arg line="--log ${basedir}/build/logs
 --source ${source}
 --output ${basedir}/build/code-browser
 ---ignore=library/,tests/,utils/,build/,js/,drupal/,bin/" />
 </exec>
 </target>
<target name="build" depends="clean,parallelTasks,phpunit,phpcb"/>
</project>

J’avais pas mal galéré en testant un par un les outils par la ligne de commande et j’espère que ce post vous aidera pour fixer correctement les paramètres de votre PIC.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *