Skip to content

Commit

Permalink
Merge pull request #27 from codelicia/report
Browse files Browse the repository at this point in the history
Add checkstyle output
  • Loading branch information
EHER authored May 15, 2020
2 parents 360ae30 + 28bf3e3 commit 288a235
Show file tree
Hide file tree
Showing 13 changed files with 234 additions and 24 deletions.
31 changes: 24 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@
[![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

**Xulieta** is a light php binary that find code snippets thought out
documentation files — as for example `*.md`, `*.markdown` and `*.rst`
**Xulieta** is a light php binary that find code snippets thought out
documentation files — as for example `*.md`, `*.markdown` and `*.rst`
— and lint the pieces of code, so you can find basic documentation errors.

**NOTE**: For now we just lint PHP code.
**NOTE**: For now we just lint PHP code.

### Installation

```shell script
composer require codelicia/xulieta
composer require codelicia/xulieta
```

### Checking for errors

<table>
<tr>
<td><img src="./meme.jpg" alt="Xulieta" width="300" height="214"/></td>
<td><img src="./meme.jpg" alt="Xulieta" width="300" height="214"/></td>
<td>
In order to lint the basics of documentation structure, one just needs to provide a path for a
In order to lint the basics of documentation structure, one just needs to provide a path for a
directory or file to be linted.

```shell script
Expand All @@ -33,7 +33,24 @@ directory or file to be linted.
</tr>
</table>

### Configuration
### Integration with GitHub Actions

We provide out of the box an `output` format that you can use to have
automatic feedback from GitHub CI. That is done by specifying the
`checkstyle` output and passing it to some external binary that does the
commenting.

We recommend the usage of [cs2pr](https://github.com/staabm/annotate-pull-request-from-checkstyle).

```
./vendor/bin/xulieta check:erromeu <directory> --output=checkstyle | cs2pr
```

#### Commenting example

<img src="./github-action.png" alt="Codelicia\Xulieta" />

### Advanced Configuration

**Xulieta** tries to find a `.xulieta.xml` file in the root of your project
with the following configuration format:
Expand Down
Binary file added github-action.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions src/Command/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
namespace Codelicia\Xulieta\Command;

use Codelicia\Xulieta\DocFinder;
use Codelicia\Xulieta\Output\Checkstyle;
use Codelicia\Xulieta\Output\Stdout;
use Codelicia\Xulieta\Plugin\MultiplePlugin;
use Codelicia\Xulieta\Plugin\Plugin;
use InvalidArgumentException;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\SplFileInfo;
use Webmozart\Assert\Assert;
Expand Down Expand Up @@ -42,6 +45,13 @@ protected function configure() : void
$this
->setName('check:erromeu')
->setDescription('Lint code snippets through the documentation "directory"')
->addOption(
'output',
'o',
InputOption::VALUE_OPTIONAL,
'Specify output format, it can be "checkstyle" or "stdout"',
'stdout'
)
->addArgument(
'directory',
InputArgument::REQUIRED,
Expand All @@ -55,9 +65,15 @@ protected function configure() : void
* @throws InvalidArgumentException
* @throws RuntimeException
*/
protected function execute(InputInterface $input, OutputInterface $output) : int
protected function execute(InputInterface $input, OutputInterface $symfonyOutput) : int
{
$directory = $input->getArgument('directory');
$directory = $input->getArgument('directory');
$outputOption = $input->getOption('output');
$output = new Stdout($symfonyOutput);

if ($outputOption === 'checkstyle') {
$output = new Checkstyle($symfonyOutput);
}

Assert::string($directory);
Assert::interfaceExists(Plugin::class);
Expand Down
48 changes: 48 additions & 0 deletions src/Output/Checkstyle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Codelicia\Xulieta\Output;

use Codelicia\Xulieta\ValueObject\Violation;
use Symfony\Component\Console\Output\OutputInterface;
use function htmlspecialchars;

final class Checkstyle implements OutputFormatter
{
private OutputInterface $output;

public function __construct(OutputInterface $output)
{
$this->output = $output;
$this->output->writeln('<?xml version="1.0" encoding="UTF-8"?>');
$this->output->writeln('<checkstyle>');
}

public function addViolation(Violation $violation) : void
{
$this->output->writeln(' <file name="' . htmlspecialchars($violation->file()) . '">');

$error = ' ';
$error .= '<error';
$error .= ' line="' . $violation->absoluteLine() . '"';
$error .= ' column="1"';
$error .= ' severity="error"';
$error .= ' message="Codelicia/Xulieta: ' . htmlspecialchars($violation->message()) . '"';
$error .= ' source="Codelicia/Xulieta"';
$error .= '/>';

$this->output->writeln($error);
$this->output->writeln(' </file>');
}

public function __destruct()
{
echo '</checkstyle>';
}

public function writeln(string $text) : void
{
// Intentionally left empty
}
}
14 changes: 14 additions & 0 deletions src/Output/OutputFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Codelicia\Xulieta\Output;

use Codelicia\Xulieta\ValueObject\Violation;

interface OutputFormatter
{
public function addViolation(Violation $violation) : void;

public function writeln(string $text) : void;
}
31 changes: 31 additions & 0 deletions src/Output/Stdout.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Codelicia\Xulieta\Output;

use Codelicia\Xulieta\ValueObject\Violation;
use Symfony\Component\Console\Output\OutputInterface;
use const PHP_EOL;

final class Stdout implements OutputFormatter
{
private OutputInterface $output;

public function __construct(OutputInterface $output)
{
$this->output = $output;
}

public function addViolation(Violation $violation) : void
{
$this->writeln('<error>Wrong code on file: ' . $violation->code()->file() . '</error>');
$this->writeln($violation->message() . PHP_EOL);
$this->writeln($violation->code()->code());
}

public function writeln(string $text) : void
{
$this->output->writeln($text);
}
}
4 changes: 2 additions & 2 deletions src/Plugin/MultiplePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Codelicia\Xulieta\Plugin;

use Assert\Assert;
use Symfony\Component\Console\Output\OutputInterface;
use Codelicia\Xulieta\Output\OutputFormatter;
use Symfony\Component\Finder\SplFileInfo;
use function array_map;
use function array_merge_recursive;
Expand Down Expand Up @@ -44,7 +44,7 @@ public function canHandle(SplFileInfo $file) : bool
return false;
}

public function __invoke(SplFileInfo $file, OutputInterface $output) : bool
public function __invoke(SplFileInfo $file, OutputFormatter $output) : bool
{
foreach ($this->plugins as $plugin) {
if ($plugin->canHandle($file)) {
Expand Down
17 changes: 11 additions & 6 deletions src/Plugin/PhpOnMarkdownPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
use Codelicia\Xulieta\External\Markinho;
use Codelicia\Xulieta\Lint\Lint;
use Codelicia\Xulieta\Lint\PhpLint;
use Symfony\Component\Console\Output\OutputInterface;
use Codelicia\Xulieta\Output\OutputFormatter;
use Codelicia\Xulieta\ValueObject\Violation;
use Symfony\Component\Finder\SplFileInfo;
use function in_array;
use const PHP_EOL;
use function preg_match;

final class PhpOnMarkdownPlugin implements Plugin
{
Expand All @@ -32,17 +33,21 @@ public function canHandle(SplFileInfo $file) : bool
return in_array($file->getExtension(), $this->supportedExtensions(), true);
}

public function __invoke(SplFileInfo $file, OutputInterface $output) : bool
public function __invoke(SplFileInfo $file, OutputFormatter $output) : bool
{
foreach (Markinho::extractCodeBlocks($file->getPathname(), $file->getContents()) as $codeBlock) {
if ($codeBlock->language() !== 'php') {
continue;
}

if ($this->phpLint->hasViolation($codeBlock->code())) {
$output->writeln('<error>Wrong code on file: ' . $codeBlock->file() . '</error>');
$output->writeln($this->phpLint->getViolation($codeBlock->code()) . PHP_EOL);
$output->writeln($codeBlock->code());
$message = $this->phpLint->getViolation($codeBlock->code());

preg_match('{on line (\d+)}', $message, $line);

$validationErrorInLine = $line[1] ?? 0;

$output->addViolation(new Violation($codeBlock, $message, (int) $validationErrorInLine));

return false;
}
Expand Down
16 changes: 11 additions & 5 deletions src/Plugin/PhpOnRstPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

use Codelicia\Xulieta\Lint\Lint;
use Codelicia\Xulieta\Lint\PhpLint;
use Codelicia\Xulieta\Output\OutputFormatter;
use Codelicia\Xulieta\Parser\Parser;
use Codelicia\Xulieta\Parser\RstParser;
use Symfony\Component\Console\Output\OutputInterface;
use Codelicia\Xulieta\ValueObject\Violation;
use Symfony\Component\Finder\SplFileInfo;
use function in_array;
use function preg_match;
use const PHP_EOL;

final class PhpOnRstPlugin implements Plugin
Expand All @@ -35,7 +37,7 @@ public function canHandle(SplFileInfo $file) : bool
return in_array($file->getExtension(), $this->supportedExtensions(), true);
}

public function __invoke(SplFileInfo $file, OutputInterface $output) : bool
public function __invoke(SplFileInfo $file, OutputFormatter $output) : bool
{
if (! $this->rstParser->isValid($file)) {
$output->writeln(PHP_EOL . '<error>Error parsing file: ' . $file->getRelativePath() . '</error>');
Expand All @@ -49,9 +51,13 @@ public function __invoke(SplFileInfo $file, OutputInterface $output) : bool
}

if ($this->phpLint->hasViolation($sampleCode->code())) {
$output->writeln('<error>Wrong code on file: ' . $sampleCode->file() . '</error>');
$output->writeln($this->phpLint->getViolation($sampleCode->code()) . PHP_EOL);
$output->writeln($sampleCode->code());
$message = $this->phpLint->getViolation($sampleCode->code());

preg_match('{on line (\d+)}', $message, $line);

$validationErrorInLine = $line[1] ?? 0;

$output->addViolation(new Violation($sampleCode, $message, (int) $validationErrorInLine));

return false;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Plugin/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Codelicia\Xulieta\Plugin;

use Symfony\Component\Console\Output\OutputInterface;
use Codelicia\Xulieta\Output\OutputFormatter;
use Symfony\Component\Finder\SplFileInfo;

interface Plugin
Expand All @@ -14,5 +14,5 @@ public function supportedExtensions() : array;

public function canHandle(SplFileInfo $file) : bool;

public function __invoke(SplFileInfo $file, OutputInterface $output) : bool;
public function __invoke(SplFileInfo $file, OutputFormatter $output) : bool;
}
47 changes: 47 additions & 0 deletions src/ValueObject/Violation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Codelicia\Xulieta\ValueObject;

final class Violation
{
private SampleCode $code;
private string $message;
private int $violationLine;

public function __construct(
SampleCode $code,
string $message,
int $violationLine = 0
) {
$this->code = $code;
$this->message = $message;
$this->violationLine = $violationLine;
}

public function code() : SampleCode
{
return $this->code;
}

public function file() : string
{
return $this->code->file();
}

public function violationLine() : int
{
return $this->violationLine;
}

public function message() : string
{
return $this->message;
}

public function absoluteLine() : int
{
return $this->code()->position() + $this->violationLine();
}
}
10 changes: 10 additions & 0 deletions tests/assets/syntax-error-checkstyle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This code has a missing semi comma on the echo statement.

```php
<?php

if (true) {
echo 'Hello World!'
}
```

16 changes: 16 additions & 0 deletions tests/functional/md-syntax-error-checkstyle.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Report a warning using checkstyle in case of missing PHP open tag
--FILE--
<?php

$checkRunner = require __DIR__ . '/init.php';

$checkRunner('tests/assets/syntax-error-checkstyle.md --output=checkstyle');

--EXPECTF--
<?xml version="1.0" encoding="UTF-8"?>
<checkstyle>
<file name="tests/assets/syntax-error-checkstyle.md">
<error line="7" column="1" severity="error" message="Codelicia/Xulieta: Syntax error, unexpected '}', expecting ';' on line 5" source="Codelicia/Xulieta"/>
</file>
</checkstyle>

0 comments on commit 288a235

Please sign in to comment.