Browse Source

Feature checkstyle reporter

Kévin Gomez 7 years ago
parent
commit
14a4ec6182

+ 6 - 2
README.rst

@@ -137,9 +137,13 @@ to merge paths from the config file and from the argument:
 
     $ php php-cs-fixer.phar fix --path-mode=intersection /path/to/dir
 
-The ``--format`` option for the output format. Supported formats are ``txt`` (default one), ``json``, ``xml`` and ``junit``.
+The ``--format`` option for the output format. Supported formats are ``txt`` (default one), ``json``, ``xml``, ``checkstyle`` and ``junit``.
+
+NOTE: the output for the following formats are generated in accordance with XML schemas
+
+* ``junit`` follows the `JUnit xml schema from Jenkins </doc/junit-10.xsd>`_
+* ``checkstyle`` follows the common `"checkstyle" xml schema </doc/checkstyle.xsd>`_
 
-NOTE: When using ``junit`` format report generates in accordance with JUnit xml schema from Jenkins (see docs/junit-10.xsd).
 
 The ``--verbose`` option will show the applied rules. When using the ``txt`` format it will also displays progress notifications.
 

+ 44 - 0
doc/checkstyle.xsd

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright 2016 LinkedIn Corp.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+  <xs:element name="checkstyle" type="checkstyleType"/>
+  <xs:complexType name="fileType">
+    <xs:sequence>
+      <xs:element type="errorType" name="error" maxOccurs="unbounded" minOccurs="0"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="name" use="optional"/>
+  </xs:complexType>
+  <xs:complexType name="errorType">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="line" use="optional"/>
+        <xs:attribute type="xs:string" name="severity" use="optional"/>
+        <xs:attribute type="xs:string" name="message" use="optional"/>
+        <xs:attribute type="xs:string" name="source" use="optional"/>
+        <xs:attribute type="xs:string" name="column" use="optional"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="checkstyleType">
+    <xs:sequence>
+      <xs:element type="fileType" name="file" maxOccurs="unbounded" minOccurs="0"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="version"/>
+  </xs:complexType>
+</xs:schema>

+ 6 - 2
src/Console/Command/HelpCommand.php

@@ -58,9 +58,13 @@ to merge paths from the config file and from the argument:
 
     <info>$ php %command.full_name% --path-mode=intersection /path/to/dir</info>
 
-The <comment>--format</comment> option for the output format. Supported formats are ``txt`` (default one), ``json``, ``xml`` and ``junit``.
+The <comment>--format</comment> option for the output format. Supported formats are ``txt`` (default one), ``json``, ``xml``, ``checkstyle`` and ``junit``.
+
+NOTE: the output for the following formats are generated in accordance with XML schemas
+
+* ``junit`` follows the `JUnit xml schema from Jenkins </doc/junit-10.xsd>`_
+* ``checkstyle`` follows the common `"checkstyle" xml schema </doc/checkstyle.xsd>`_
 
-NOTE: When using ``junit`` format report generates in accordance with JUnit xml schema from Jenkins (see docs/junit-10.xsd).
 
 The <comment>--verbose</comment> option will show the applied rules. When using the ``txt`` format it will also displays progress notifications.
 

+ 75 - 0
src/Report/CheckstyleReporter.php

@@ -0,0 +1,75 @@
+<?php
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\Report;
+
+use Symfony\Component\Console\Formatter\OutputFormatter;
+
+/**
+ * @author Kévin Gomez <contact@kevingomez.fr>
+ *
+ * @internal
+ */
+final class CheckstyleReporter implements ReporterInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormat()
+    {
+        return 'checkstyle';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function generate(ReportSummary $reportSummary)
+    {
+        if (!extension_loaded('dom')) {
+            throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
+        }
+
+        $dom = new \DOMDocument('1.0', 'UTF-8');
+        $checkstyles = $dom->appendChild($dom->createElement('checkstyle'));
+
+        foreach ($reportSummary->getChanged() as $filePath => $fixResult) {
+            /** @var \DOMElement $file */
+            $file = $checkstyles->appendChild($dom->createElement('file'));
+            $file->setAttribute('name', $filePath);
+
+            foreach ($fixResult['appliedFixers'] as $appliedFixer) {
+                $error = $this->createError($dom, $appliedFixer);
+                $file->appendChild($error);
+            }
+        }
+
+        $dom->formatOutput = true;
+
+        return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($dom->saveXML()) : $dom->saveXML();
+    }
+
+    /**
+     * @param \DOMDocument $dom
+     * @param string       $appliedFixer
+     *
+     * @return \DOMElement
+     */
+    private function createError(\DOMDocument $dom, $appliedFixer)
+    {
+        $error = $dom->createElement('error');
+        $error->setAttribute('severity', 'warning');
+        $error->setAttribute('source', 'PHP-CS-Fixer.'.$appliedFixer);
+        $error->setAttribute('message', 'Found violation(s) of type: '.$appliedFixer);
+
+        return $error;
+    }
+}

+ 1 - 1
tests/Console/ConfigurationResolverTest.php

@@ -317,7 +317,7 @@ final class ConfigurationResolverTest extends TestCase
     {
         $this->setExpectedExceptionRegExp(
             \PhpCsFixer\ConfigurationException\InvalidConfigurationException::class,
-            '/^The format "xls" is not defined, supported are "json", "junit", "txt", "xml"\.$/'
+            '/^The format "xls" is not defined, supported are "checkstyle", "json", "junit", "txt", "xml"\.$/'
         );
 
         $dirBase = $this->getFixtureDir();

+ 138 - 0
tests/Report/CheckstyleReporterTest.php

@@ -0,0 +1,138 @@
+<?php
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\Tests\Report;
+
+use GeckoPackages\PHPUnit\Constraints\XML\XMLMatchesXSDConstraint;
+use PhpCsFixer\Report\CheckstyleReporter;
+use Symfony\Component\Console\Formatter\OutputFormatter;
+
+/**
+ * @author Kévin Gomez <contact@kevingomez.fr>
+ *
+ * @internal
+ *
+ * @covers \PhpCsFixer\Report\CheckstyleReporter
+ */
+final class CheckstyleReporterTest extends AbstractReporterTestCase
+{
+    /**
+     * "checkstyle" XML schema.
+     *
+     * @var string
+     */
+    private static $xsd;
+
+    public static function setUpBeforeClass()
+    {
+        self::$xsd = file_get_contents(__DIR__.'/../../doc/checkstyle.xsd');
+    }
+
+    public static function tearDownAfterClass()
+    {
+        self::$xsd = null;
+    }
+
+    public function createNoErrorReport()
+    {
+        return <<<'XML'
+<?xml version="1.0" encoding="UTF-8"?>
+<checkstyle />
+XML;
+    }
+
+    public function createSimpleReport()
+    {
+        return <<<'XML'
+<?xml version="1.0" encoding="UTF-8"?>
+<checkstyle>
+  <file name="someFile.php">
+    <error severity="warning" source="PHP-CS-Fixer.some_fixer_name_here" message="Found violation(s) of type: some_fixer_name_here" />
+  </file>
+</checkstyle>
+XML;
+    }
+
+    public function createWithDiffReport()
+    {
+        // NOTE: checkstyle format does NOT include diffs
+        return <<<'XML'
+<?xml version="1.0" encoding="UTF-8"?>
+<checkstyle>
+  <file name="someFile.php">
+    <error severity="warning" source="PHP-CS-Fixer.some_fixer_name_here" message="Found violation(s) of type: some_fixer_name_here" />
+  </file>
+</checkstyle>
+XML;
+    }
+
+    public function createWithAppliedFixersReport()
+    {
+        return <<<'XML'
+<?xml version="1.0" encoding="UTF-8"?>
+<checkstyle>
+  <file name="someFile.php">
+    <error severity="warning" source="PHP-CS-Fixer.some_fixer_name_here_1" message="Found violation(s) of type: some_fixer_name_here_1" />
+    <error severity="warning" source="PHP-CS-Fixer.some_fixer_name_here_2" message="Found violation(s) of type: some_fixer_name_here_2" />
+  </file>
+</checkstyle>
+XML;
+    }
+
+    public function createWithTimeAndMemoryReport()
+    {
+        // NOTE: checkstyle format does NOT include time or memory
+        return <<<'XML'
+<?xml version="1.0" encoding="UTF-8"?>
+<checkstyle>
+  <file name="someFile.php">
+    <error severity="warning" source="PHP-CS-Fixer.some_fixer_name_here" message="Found violation(s) of type: some_fixer_name_here" />
+  </file>
+</checkstyle>
+XML;
+    }
+
+    public function createComplexReport()
+    {
+        return <<<'XML'
+<?xml version="1.0" encoding="UTF-8"?>
+<checkstyle>
+  <file name="someFile.php">
+    <error severity="warning" source="PHP-CS-Fixer.some_fixer_name_here_1" message="Found violation(s) of type: some_fixer_name_here_1" />
+    <error severity="warning" source="PHP-CS-Fixer.some_fixer_name_here_2" message="Found violation(s) of type: some_fixer_name_here_2" />
+  </file>
+  <file name="anotherFile.php">
+    <error severity="warning" source="PHP-CS-Fixer.another_fixer_name_here" message="Found violation(s) of type: another_fixer_name_here" />
+  </file>
+</checkstyle>
+XML;
+    }
+
+    protected function createReporter()
+    {
+        return new CheckstyleReporter();
+    }
+
+    protected function getFormat()
+    {
+        return 'checkstyle';
+    }
+
+    protected function assertFormat($expected, $input)
+    {
+        $formatter = new OutputFormatter();
+        $input = $formatter->format($input);
+
+        $this->assertThat($input, new XMLMatchesXSDConstraint(self::$xsd));
+        $this->assertXmlStringEqualsXmlString($expected, $input);
+    }
+}

+ 1 - 1
tests/Report/ReporterFactoryTest.php

@@ -51,7 +51,7 @@ final class ReporterFactoryTest extends TestCase
 
         $builder->registerBuiltInReporters();
         $this->assertSame(
-            ['json', 'junit', 'txt', 'xml'],
+            ['checkstyle', 'json', 'junit', 'txt', 'xml'],
             $builder->getFormats()
         );
     }

+ 1 - 1
tests/TextDiffTest.php

@@ -93,7 +93,7 @@ TEST;
         sort($formats);
 
         $this->assertSame(
-            ['json', 'junit', 'txt', 'xml'],
+            ['checkstyle', 'json', 'junit', 'txt', 'xml'],
             $formats
         );
     }