Integrating JavaScript files with JSHint, Phing and Jenkins [EN]

I wrote an article about integrating JavaScript Node.js projects with Jenkins more than year ago. Recently I wanted to solve a bit different issue. I wanted to add JSHint validation as a part of a Phing build (our project is PHP/Zend Framework based with some JS files).

It can be done it a few steps (I will go through them in more detail later):

  1. Install Node.js
  2. Install JSHint
  3. Add JSHint task to a buildfile
  4. Set up reporting in Jenkins

1) Installing Node.js

Node.js can be installed via MSI installer on Windows, via package manager in most Linux distros (except for Debian stable which we are using). So I had to compile it myself (Ubuntu PPA packages does not work because of unmet dependencies). As long as we use Node.js just for JSHint validation, there is no need to upgrade it to latest versions, and therefore I put the package in our salt repository and it can be installed automatically next time (we have whole Jenkins server salted).

2) Installing JSHint

If you have the Node.js running, installing JSHint is pretty easy. You just run

npm install jshint -g

To verify that it is installed correctly, run jshint -v which should print the jshint version.

3) Adding JSHint task to a buildfile

This is the hardest step in the whole process. There was no JsHintTask in the standard Phing distribution, so I had to write it myself. I have issued a PullRequest, so it may be part of some future version of Phing.

The first step is to download the task and put it somewhere, where Phing can access it. Next code snippet assumes, that it is a part of the project and it is located in the support/phing/JsHintTask.php file.

Second step is to link the file from the buildfile:

<path id="project.class.path">
        <pathelement dir="${project.basedir}/support/phing/"/>
</path>

<taskdef name="jshint" classname="JsHintTask">
        <classpath refid="project.class.path"/>
</taskdef>

Last step is to create a jshint target (you can check the detailed description of the parameters in the docs). Most important is the checkstyleReportPath attribute, which defines where the checkstyle report will be saved and the fileset element, which defines which files should be checked.

<target name="jshint" description="Javascript Lint">
        <mkdir dir="${project.basedir}/build/checkstyle-jshint"/>
        <jshint
                        haltOnError="false"
                        haltOnWarning="false"
                        checkstyleReportPath="${project.basedir}/build/checkstyle-jshint/checkstyle-jshint.xml"
                >
                <fileset dir="${project.basedir}/public_html/www/js">
                        <include name="**/**.js"/>
                        <exclude name="js-cache/**"/>
                        <exclude name="jquery-1.*.min.js"/>
                        <exclude name="bootstrap/bootstrap.js"/>
                </fileset>
        </jshint>
</target>

JSHint supports config file, where you can set which issues you want to get reported. It is easy – you just create .jshintrc file in the project root directory and JSHint will load it automatically. File should contain a JSON object with configuration options. See the docs. And you can check the .jshintrc file we are using:

{
        "maxerr"        :       1000,
        "camelcase"     :       true,
        "immed"         :       true,
        "latedef"       :       true,
        "newcap"        :       true,
        "quotmark"      :       "single",
        "trailing"      :       true,
        "jquery"        :       true,
        "white"         :       true,
        "globals"       :       {}
}

4) Setting up the reporting in Jenkins

Just add a Post-build action – Report Violations and put the path in there. 

After the build finishes, you can check the errors in the Violations section of the build report.

Conclusion

It is really easy to set-up JavaScript files validation in a PHP project, so why not have it? If you have any trouble setting it up, just ask in the comments and I'll try to help you. I would be also happy, if you share your way of validating JS files.

Jak v Jenkinsu buildovat branche z forků?

bakalářce jsem psal o tom, jak nastavit a používat Jenkins pro statickou analýzu PHP projektů. V té době jsme ještě na Shopiu používali Subversion, takže build byl nastavený pro trunk a všechno bylo krásné a sluníčkové.

Po přechodu na git (a Github) jsme začali používat koncept „forků“ a PullRequestů (každý vývojář má svoji kopii – fork – hlavního repositáře, jednotlivé změny dělá v branchích a ty pak odešle jako PullRequest a jiný vývojář je zkontroluje a mergne).

Problémem bylo, že přestože většinou spouštíme testy lokálně před vytvořením PullRequestu, tak občas po mergnutí build na Jenkinsu spadnul na neprocházejících testech. Jenkins běží na Linuxu, vyvíjíme na Windows, takže občas šlo o problém s konci řádků, ale většinou o nějaký problém s pořadím testů (na Linuxu je jiné, a ano, vím že je velmi špatně mít testy závislé na stavu prostředí, ale lepší mít takové než žádné). A občas šlo samozřejmě o chybu a nespuštěné testy na localhostu („Tohle přece žádný test rozbít nemůže!“). Takže by bylo super testy spouštět automaticky pro každou změnu v jakékoliv branchi ve forku každého vývojáře.

V Jenkinsu to nakonec šlo nastavit velmi snadno – vytvořit jsem pro každý fork samostatný projekt a nastavil cesty k jednotlivým Githubovým repositářům. Pak je důležité nastavit, aby se v rámci buildu forku spouštěl jen phpunit a nic jiného – chceme co nejdříve vědět, že testy neprocházejí a nějaké porušení coding standards nás v tu chvíli tolik netrápí.

Druhou věcí, co je potřeba nastavit jsou branche pro buildování: 

A samozřejmě nastavit, aby v případě failu přišel mail danému vývojáři: 

Ještě jedna věc – je dobré, pokud mají tyhle rychlé buildy přidělené svoje vlákno, aby nečekaly dobu ve frontě, než doběhne jiný projekt (tohle zatím nastavené nemáme, ale budeme mít brzy).

Pro opensource projekty existuje super věc – TravisCI, který dělá přibližně to samé – builduje všechny vaše branche a na Githubu se dokonce stav branche ukazuje u PullRequestu

HipHop for PHP

Dalším zajímavým nástrojem, který by bylo možné zařadit do kontinuální integrace, je HipHop for PHP vyvinutý společností Facebook Inc. Jeho primárním účelem je převod skriptů v jazyce PHP do jazyka C++, nicméně je možné ho využít pro statickou analýzu (umí odhalit chyby, které jiné nástroje neodhalí). A případně ho zařadit jako jeden z nástrojů kontinuální integrace.

Instalace nástroje

Nástroj je nutné zkompilovat ze zdrojových kódů, nejsou k dispozici instalační balíčky. Zároveň je nutné nejdříve zkompilovat několik knihoven třetích stran. K dispozici jsou postupy na wiki projektu na githubu, zvolte ten odpovídající vaší linuxové distribuci.

Já jsem instaloval na VirtualMasteru, takže jsem zvolil návod pro Ubuntu 10.04

Pokud si chcete HipHop jen vyzkoušet, tak je zbytečné trávit čas kompilací. Proto jsem na VirtualMasteru vytvořil veřejnou šablonu s připraveným HipHop for PHP

Použití nástroje

Poté, co máme nástroj nainstalovaný (buď podle postupu a nebo vytvořením serveru z image výše), nastavíme potřebné cesty:

cd /root/hiphop/
export HPHP_HOME=`/bin/pwd`
export HPHP_LIB=`/bin/pwd`/bin

A zkusíme spustit analýzu. Já jsem zkoušel Zend Framework 1.

cd /tmp
svn export http://framework.zend.com/svn/framework/standard/trunk/library zf1
cd zf1
/root/hiphop/hiphop-php/src/hphp/hphp -t analyze --input-dir ./Zend/ --include-path ./

Výstup je poté uložen v /tmp/hphp_AFDvIh/CodeError.js (resp. v podobně nazvaném adresáři).

Když jsem prosěl výstup z kontroly ZF1, tak jsem postupně přidal 12 issues do ZF – od ZF-12225 do ZF-12236

Zařazení nástroje do CI

Sebastian Bergmann vyvinul nástroj obalující HipHop do PHP s možností exportu výsledků ve formátu pro CheckStyle. Nicméně do CI jsem ho zatím nenasadil, protože se bojím, že bych kompilací a instalací zkompilovaných věcí mohl poblbnout server.

Závěrem

Pokud chcete ztratit iluze o svých zdrojácích, zkuste na ně spustit HipHop :)

phpDocumentor 2 místo DocBloxu

bakalářce jsem popisoval rozhodování mezi různými nástroji na generování PHP API dokumentace v rámci kontinuální integrace. Teď se výběr zjednodušil, proto z nástroje DocBlox se stal se phpDocumentor 2. Sice se v článku mluví o „merge“, ale ve skutečnosti jde o přejmenování s tím, že původní phpDocumentor se přestane vyvíjet.

Nainstalovat ho můžeme pomocí:

pear channel-discover pear.phpdoc.org
pear install phpdoc/phpDocumentor-alpha

Kromě výchozí šablony jsou k dispozici i nějaké další, ale nešly mi doinstalovat starým postupem tak jako u DocBloxu, ale musel jsem přes PEAR:

pear install phpdoc/phpDocumentor_Template_checkstyle
pear install phpdoc/phpDocumentor_Template_zend

Přehled všech dostupných šablon najdete na http://pear.phpdoc.org/

Generování funguje pořád stejně, jen je potřeba vyměnit docblox za phpdoc:

phpdoc -f phpdoc01.php
phpdoc -f phpdoc01.php --template checkstyle

Na výchozí šabloně mě překvapilo, že v detailu třídy nikde není vypsané její jméno. Holt je to ještě alpha.

Až bude phpDocumentor 2 stabilní, tak určitě bude dobré znovu zvážit výběr nástroje na generování API dokumentace. Přechod z DocBloxu je jasný, ale pokud se objeví i šablona podobná té v ApiGenu, tak bych kvůli cachování analyzovaných souborů (zrychlení oceníte hlavně u větších projektů) zvážil přechod na phpDocumentor.

Čím generujte API dokumentaci v PHP vy?

PHP_CodeBrowser 1.0.3 a změna PEAR kanálu

Pro reportování chyb z PHP_CodeSniffer, PHPCPD a PMD jsem při nasazení kontinuální integrace použil PHP_CodeBrowser. Nicméně, nelíbilo se mi, že jsou v reportu vypsané i soubory, které žádné chyby neobsahují – pak se hůře hledají ty, ve kterých chyby jsou.

Doprogramoval jsem tedy možnost takové soubory skrýt.

--excludeOK    Exclude files with no issues from the report

Před pár dny vyšla verze 1.0.3, která už vylepšení obsahuje. Zároveň došlo ke změně PEAR kanálu pro instalaci balíčku.

Pro upgrade je tedy potřeba starou verzi nejdříve odinstalovat:

pear uninstall phpunit/PHP_CodeBrowser

Pak přidat nový kanál a nainstalovat PHP_CodeBrowser z něj:

pear channel-discover pear.phpqatools.org
pear install phpqatools/PHP_CodeBrowser

A do build skriptu stačí přidat přepínač --excludeOK, takže příkaz pro generování pomocí phpcb bude vypadat takto:

phpcb  --log ${project.basedir}/build --source ${project.basedir} --output ${project.basedir}/build/code-browser --excludeOK

Používáte také PHP_CodeBrowser nebo si v Jenkinsu vystačíte s Violations?

Kontinuální integrace při vývoji webových aplikací v PHP (bakalářská práce)

Když jsem si vybíral téma na bakalářskou práci, tak jsem chtěl zpracovat něco, co bude užitečné a někdo si to přečte, protože ho to bude zajímat. Nakonec jsem si vybral Continuous Integration (neboli hezky česky Kontinuální integraci).

Věřím, že se mi to docela povedlo a práce je užitečná a snad i docela čtivá.

Vzhledem k tomu, že mám obhajobu až v červnu, tak ještě nemám posudky, tudíž není akademicky posvěcená. Ale věci kolem kontinuální integrace se pořád mění, tak mi přijde škoda ji nechat dva měsíce zbytečně zastarávat.

Zároveň vzhledem k tomu, že u BP není zvykem vydávat aktualizované verze, plánuju tu a tam napsat na blog o různých novinkách, které kolem CI vyzkouším (takže sledujte blog, případně Twitter)

Kontinuální integrace při vývoji webových aplikací v PHP (Bakalářská práce)

Ke stažení ve formátu PDF

Co na ni říkáte? Pokud vám pomůže s nasazením kontinuální integrace na váš projekt, tak budu rád, když mi napíšete do komentářů nebo na e-mail.

Moje články o kontinuální integraci:

Integrating JavaScript/Node.js projects with JSHint, Mocha and Jenkins [EN]

Update 15. 9. 2013: See how I set up CI for JS files inside a PHP project (using Phing)

I've set up the Continuous Integration for PHP projects on Jenkins recently. It went quite well, but the fact that CI tools for PHP are not as mature as those for Java was obvious. (Most of the PHP CI tools are ports of their Java originals.)

Apart from PHP projects, my colleague just started working on a new project, using JavaScript and Node.js, so I thought it would be nice to add it to Jenkins too.

After some experiments, I came to this:

  • Java: It is normal to use CI in Java world.
  • PHP: QA and CI are being adapted in PHP world.
  • JavaScript: Very few people are using CI. Lots of WTF.

However, I was able to create a basic setup with Mocha for unit testing and JSHint for static analysis. Here is how I did it:

JavaScript environment

First, I wanted to add JS environment to the server we use for PHP integration. But then I realized that Node.js is available only in Debian unstable and it has more dependencies (from unstable) then the Jenkins and Java altogether. I didn't want to break anything on this server, so I used Jenkins' Slave feature and connected to server used for JS development (so all the JS stuff is already running there).

Setting up Mocha

Mocha is a JavaScript test framework. It worked fine on the server: 

So I just needed to find out, if it has some output usable for CI. Surprisingly, it has and it works fine despite the fact, it is poorly documented :-) 

Setting up JSHint

JSHint can be installed via npm:

npm install jshint -g

It checks JS like this:

jshint myfile.js

And yes, it can produce XML report:

jshint ./app --jslint-reporter > jshint.xml

Making it all work

You need Copy To Slave, xUnit and Violations plugins in Jenkins.

We will need two Jenkins jobs. First will run all the stuff, gather the XMLs with results and trigger the reporting job. The second job will just process results and display them. This is necessary, because I realized that Violations plugin runs earlier that the Copy to Slave, and therefore, it had no data.

In the first job, we bind it to our Node.js slave and add a build step (Execute shell):

cd /var/jenkins/workspace/nodejs && mocha -R xunit > xunit.xml && jshint ./app ./public/javascripts/app/ --config .jshintrc --jslint-reporter > jshint.xml || exit 0

Then we need to gather the results from slave node via Copy to Slave plugin: 

Second job

Second job has no build steps, it only processes the results. The test results worked for me, when I set them as PHPUnit ones:

The JSHint results can be processed via Violations plugin: 

However, there is an issue when using Violations plugin for JS files. It is not possible to browse the errors in files, as it is possible for other reports. But I'm not only one who experiences this issue.

Conclusion:

We have basic continuous integration for JS code up and running. 

JavaScript community is growing strong, so I hope that there will soon be loads of different CI tools for JS. I'm only afraid of their fragmentation (There are many new JS frameworks built every day).