Symfony2プロジェクトをGitLabで管理してVagrantで立てたJenkinsでCIする(6)

第6回です。

前回のおさらい
イテレーション D: JenkinsでCIする
Jenkinでプロジェクトをビルドできるようになりました。

今回の内容
PHPMDやPHPCS等の各種ツールを導入し、Jenkinsと連携してみます。


いまどこ?

  1. イテレーション 0: 準備
    1. タスク 0-1: 必要なソフトウェアをインストールする
    2. タスク 0-2: GitLabのアカウントを作成する
  2. イテレーション A: Symfony2でプロジェクトをはじめる
    1. タスク A-1: Symfony2プロジェクトを作成する
    2. タスク A-2: GitLabでソースコードを管理する
    3. タスク A-3: PHPUnitを導入する
  3. イテレーション B: Phingでプロジェクトをビルドする
    1. タスク B-1: Phingを導入する
    2. タスク B-2: PhingとPHPUnitを連携する
  4. イテレーション C: JenkinsをVagrantで構築する
    1. タスク C-1: VMを初期化する
    2. タスク C-2: 構築に必要なCookbooksを取得・作成する
    3. タスク C-3: Jenkinsを起動する
  5. イテレーション D: JenkinsでCIする
    1. タスク D-1: Jenkinsにプロジェクトを設定する
    2. タスク D-2: テストレポートを表示できるように設定する
    3. タスク D-3: コードカバレッジレポートを表示できるように設定する
  6. イテレーション E: 各種ツールの導入 ←いまココ!
    1. タスク E-1 PHPMDを導入する
    2. タスク E-2 PHPCSを導入する


イテレーション E: 各種ツールの導入

タスク E-1 PHPMDを導入する

  • 依存関係の追加
C:\workspace\Symfony2>php composer.phar require --dev phpmd/phpmd dev-master
composer.json has been updated
Loading composer repositories with package information
(中略)
Installing assets using the hard copy option
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution

  • 単体で実行
C:\workspace\Symfony2>bin\phpmd src xml cleancode
<?xml version="1.0" encoding="UTF-8" ?>
<pmd version="@package_version@" timestamp="2013-05-22T19:12:09+09:00">

(中略)

    <violation beginline="59" endline="59" rule="StaticAccess" ruleset="Clean Code Rules" externalInfoUrl="http://phpmd.org/rules/design.html#staticaccess" priority="1">
      Avoid using static access to class '\ReflectionClass' in method 'getControllerCode'.
    </violation>
  </file>
</pmd>

  • Phingから実行

Phingでプロジェクトをビルドする でも登場した素晴らしい Gist を参考にbuild.xmlを修正します。
不親切で申し訳ないですが、全文載せると長いので、変更点のみを。

@@ -15,9 +15,14 @@

     <!-- Default target -->
     <target name="build:main"
-            depends="build:clean, build:prepare, build:test"
+            depends="build:clean, build:prepare, build:check, build:test"
             description="Run all test and build everything" />

+    <!-- Check target -->
+    <target name="build:check"
+          depends="check:md"
+          description="Analyzes app code." />
+
     <!-- Test target -->
     <target name="build:test"
             depends="test:unit"
@@ -46,4 +51,13 @@
             --coverage-html   ${dir.reports.coverage}/
             -c ${dir.app}"/>
     </target>
+
+    <!-- Mess detector -->
+    <target name="check:md" description="Generate code metrics.">
+        <echo msg="Generating code metrics ..." />
+        <phpmd rulesets="cleancode,codesize,unusedcode">
+            <fileset refid="sourcecode" />
+            <formatter type="xml" outfile="${dir.reports}/pmd.xml" />
+        </phpmd>
+    </target>
 </project>
\ No newline at end of file

編集を保存したら実行します。

C:\workspace\Symfony2>bin\phing -logger phing.listener.DefaultLogger check:md
Buildfile: C:\workspace\Symfony2\build.xml

Symfony2 > check:md:

     [echo] Generating code metrics ...
    [phpmd] Processing files...
    [phpmd] Finished processing files

BUILD FINISHED

Total time: 3.3765 seconds

「C:\workspace\Symfony2\build\logs\pmd.xml」が生成されていることが確認できたら、
ここまでの変更内容をコミットして、GitLabに反映しておきます。

  • Jenkinsと連携

プラグインマネージャから「PMD Plugin」をインストールします。
その後は前回と同様に、「プロジェクト設定」から「「ビルド後の処理」の追加をします。
f:id:piccagliani:20130522145943p:plain

設定変更を保存したらビルドします。

ビルドが完了すると、プロジェクトトップに「PMD警告」というリンクが新たに表示されますので、クリックして以下の画面が表示されればOKです。
f:id:piccagliani:20130522151139p:plain

タスク E-2 PHPCSを導入する

大きな流れはPHPMDと同様となります。

  • 依存関係の追加

packagistに
squizlabs/php_codesniffer - Packagist
があるのですが、バージョン番号が正常に表示されなかったりと、なんかアヤシイので、PEAR提供のものを利用します。
【php】PEARをインストールする(Composerで) at softelメモを参考にさせていただきました。

PEARライブラリをcomposerで利用可能とするために、composer.jsonを以下のように編集します。

@@ -4,6 +4,12 @@
     "autoload": {
         "psr-0": { "": "src/" }
     },
+    "repositories": [
+        {
+            "type": "pear",
+            "url": "http://pear.php.net/"
+        }
+    ],
     "require": {
         "php": ">=5.3.3",
         "symfony/symfony": "2.2.*",
@@ -47,6 +53,7 @@
     },

そして、いつものrequireです。

C:\workspace\Symfony2>php composer.phar require --dev pear-pear.php.net/PHP_CodeSniffer 1.4.*

  • 単体で実行

何も指摘されないと面白くないので、
src\Acme\DemoBundle\Controller\DemoController.php をイケてない状態にします。

@@ -10,14 +10,12 @@ use Acme\DemoBundle\Form\ContactType;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

-class DemoController extends Controller
-{
+class DemoController extends Controller {
     /**
      * @Route("/", name="_demo")
      * @Template()
      */
-    public function indexAction()
-    {
+    public function indexAction() {
         return array();
     }

PSR2でチェックします。

C:\workspace\Symfony2>bin\phpcs -s -w --standard=PSR2 src

FILE: C:\workspace\Symfony2\src\Acme\DemoBundle\Controller\DemoController.php
--------------------------------------------------------------------------------
FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
--------------------------------------------------------------------------------
 13 | ERROR | Opening brace of a class must be on the line after the definition
    |       | (PSR2.Classes.ClassDeclaration.OpenBraceNewLine)
 18 | ERROR | Opening brace should be on a new line
    |       | (Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine)
--------------------------------------------------------------------------------


FILE: ...workspace\Symfony2\src\Acme\DemoBundle\Twig\Extension\DemoExtension.php
--------------------------------------------------------------------------------
FOUND 0 ERROR(S) AND 2 WARNING(S) AFFECTING 2 LINE(S)
--------------------------------------------------------------------------------
 36 | WARNING | Line exceeds 120 characters; contains 147 characters
    |         | (Generic.Files.LineLength.TooLong)
 64 | WARNING | Line exceeds 120 characters; contains 146 characters
    |         | (Generic.Files.LineLength.TooLong)
--------------------------------------------------------------------------------

Time: 0 seconds, Memory: 2.50Mb

イケてない状態がちゃんと指摘されています。

  • Phingから実行

build.xmlを編集します。
おなじみ素晴らしい Gist のとおり、「phpcodesniffer」タスクを利用すると、

PhpCodeSnifferTask requires PHP_CodeSniffer version >= 1.2.2

と怒られた(phpcsコマンドが見つからない??)ので(なぜphpmdは大丈夫なの?)「exec」タスクを使います。

@@ -20,7 +20,7 @@

     <!-- Check target -->
     <target name="build:check"
-          depends="check:md"
+          depends="check:md, check:cs"
           description="Analyzes app code." />

     <!-- Test target -->
@@ -60,4 +60,16 @@
             <formatter type="xml" outfile="${dir.reports}/pmd.xml" />
         </phpmd>
     </target>
+
+    <!-- code sniffer -->
+    <target name="check:cs" description="Checks coding standard.">
+        <echo msg="Checking coding standard ..." />
+        <exec command="${dir.bin}/phpcs
+            -s -w
+            --standard=PSR2
+            --report=checkstyle
+            --report-checkstyle=${dir.reports}/checkstyle.xml
+            ${dir.src}
+            "/>
+    </target>
 </project>

Jenkinsとの連携のため、レポートを「checkstyle」形式にしています。

実行してみます。

C:\workspace\Symfony2>bin\phing -logger phing.listener.DefaultLogger check:cs
Buildfile: C:\workspace\Symfony2\build.xml

Symfony2 > check:cs:

     [echo] Checking coding standard ...

BUILD FINISHED

Total time: 0.7612 seconds

「C:\workspace\Symfony2\build\logs\checkstyle.xml」が生成されていることが確認できたら、
ここまでの変更内容をコミットして、GitLabに反映しておきます。

  • Jenkinsと連携

プラグインマネージャから「Checkstyle Plugin」をインストールします。
「プロジェクト設定」から「「ビルド後の処理」の追加をします。
f:id:piccagliani:20130522193117p:plain

設定変更を保存したらビルドします。

ビルドが完了すると、プロジェクトトップに「Checkstyle警告」というリンクが新たに表示されますので、クリックして以下の画面が表示されればOKです。
f:id:piccagliani:20130522193416p:plain

最後に

phpmd, phpcs以外のツールたちも、上のような手順でJenkinsと連携できるはずです。
機会があれば別個のエントリとして書いてみようと思います。


以上です。