Skip to content

Commit 7efa55b

Browse files
committed
Merge remote-tracking branch 'origin/master' into v1-prep
2 parents 58ab933 + 3623b9d commit 7efa55b

File tree

8 files changed

+258
-4
lines changed

8 files changed

+258
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ composer.lock
44
diff.txt
55
phpmd.xml
66
phpmd-tests.xml
7+
diffFilter.phar

CreatePhar.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
<?php
22

3+
chdir(__DIR__);
4+
35
$pharName = 'diffFilter.phar';
6+
7+
cleanUp($pharName);
8+
49
$pharFile = getcwd() . '/diffFilter.phar';
510

611
if (file_exists($pharFile)) {
@@ -47,8 +52,20 @@ function addDir($dir, $phar)
4752
foreach ($iterator as $file) {
4853
$fullPath = $file->getPathname();
4954
$path = $dir . substr($fullPath, $codeLength);
55+
56+
if (strpos($path, '/test/') !== false) {
57+
continue;
58+
}
59+
5060
if (is_file($path)) {
51-
$phar->addFile($path);
61+
$phar->addFromString($path, php_strip_whitespace($path));
5262
}
5363
}
5464
}
65+
66+
function cleanUp($pharName)
67+
{
68+
shell_exec("rm -rf vendor");
69+
shell_exec("rm $pharName");
70+
shell_exec("composer install --no-dev -o");
71+
}

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Phar is a packaged format which should be a single download. The latest Phar can
2626
After downloading run `chmod +x diffFilter.phar` and then call as `./diffFilter.phar` followed by the normal options
2727

2828
## Manually
29-
Clone this repository somewhere your your build plan can be accessed, composer install is prefered but there is a non composer class loader which will be used if composer is not installed. If composer is not used some PHP specific features will not work as expected.
29+
Clone this repository somewhere your your build plan can be accessed, composer install is preferred but there is a non composer class loader which will be used if composer is not installed. If composer is not used some PHP specific features will not work as expected.
3030
Then call the script you need
3131

3232

@@ -38,7 +38,7 @@ First of all a diff is needed
3838
3939
See [here](https://github.com/exussum12/coverageChecker/wiki/Generating-a-diff) for a more in depth examples of what diff you should generate
4040

41-
Then the outut for the tool you wish to check (such as phpcs, PHPUnit, phpmd etc) for example
41+
Then the output for the tool you wish to check (such as phpcs, PHPUnit, phpmd etc) for example
4242

4343
phpcs --standard=psr2 --report=json || true > phpcs.json
4444
@@ -57,7 +57,7 @@ A more in depth guide can be [found on the wiki](https://github.com/exussum12/co
5757

5858
# Full list of available diff filters
5959

60-
Below is a list of all tools and a breif description
60+
Below is a list of all tools and a brief description
6161

6262
```
6363
--buddy Parses buddy (magic number detection) output
@@ -79,6 +79,7 @@ Below is a list of all tools and a breif description
7979
--phpstan Parses the text output of phpstan
8080
--phpunit Parses text output in clover (xml) format generated with coverage-clover=file.xml
8181
--pylint Parses PyLint output
82+
--psalm Parses Psalm output
8283
```
8384

8485

src/Loaders/Psalm.php

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
namespace exussum12\CoverageChecker\Loaders;
3+
4+
use exussum12\CoverageChecker\FileChecker;
5+
use XMLReader;
6+
7+
/**
8+
* Class Psalm
9+
* Used for parsing psalm output
10+
*
11+
* @package exussum12\CoverageChecker
12+
*/
13+
class Psalm implements FileChecker
14+
{
15+
/**
16+
* @var string
17+
*/
18+
protected $file;
19+
20+
/**
21+
* @var array
22+
*/
23+
protected $errors = [];
24+
25+
/**
26+
* @var array
27+
*/
28+
protected $errorRanges = [];
29+
30+
/**
31+
* Psalm constructor.
32+
*
33+
* @param string $file the path to the psalm xml file
34+
*/
35+
public function __construct($file)
36+
{
37+
$this->file = $file;
38+
}
39+
40+
/**
41+
* {@inheritdoc}
42+
*/
43+
public function parseLines(): array
44+
{
45+
$this->errors = [];
46+
$this->errorRanges = [];
47+
$reader = new XMLReader;
48+
$reader->open($this->file);
49+
50+
while ($reader->read()) {
51+
if ($this->isElementBeginning($reader, 'item')) {
52+
$this->parseItem($reader);
53+
}
54+
}
55+
56+
return array_keys($this->errors);
57+
}
58+
59+
/**
60+
* {@inheritdoc}
61+
*/
62+
public function getErrorsOnLine(string $file, int $lineNumber)
63+
{
64+
$errors = [];
65+
foreach ($this->errorRanges[$file] as $number => $error) {
66+
if ((
67+
$error['start'] <= $lineNumber
68+
&& $error['end'] >= $lineNumber
69+
)) {
70+
$errors[] = $error['error'];
71+
unset($this->errorRanges[$file][$number]);
72+
}
73+
}
74+
75+
return $errors;
76+
}
77+
78+
/**
79+
* @param XMLReader $reader
80+
*/
81+
protected function parseItem(XMLReader $reader)
82+
{
83+
$attributes = [];
84+
85+
while ($reader->read()) {
86+
if ($this->isElementEnd($reader, 'item')) {
87+
break;
88+
}
89+
90+
if ($reader->nodeType == XMLReader::ELEMENT) {
91+
$attributes[$reader->name] = $reader->readString();
92+
}
93+
}
94+
95+
$error = $attributes['message'];
96+
$start = $attributes['line_from'];
97+
$end = $attributes['line_to'];
98+
$fileName = $attributes['file_name'];
99+
100+
$this->errorRanges[$fileName][] = [
101+
'start' => $start,
102+
'end' => $end,
103+
'error' => $error,
104+
];
105+
106+
$this->addForAllLines($fileName, $start, $end, $error);
107+
}
108+
109+
/**
110+
* {@inheritdoc}
111+
*/
112+
public function handleNotFoundFile()
113+
{
114+
return true;
115+
}
116+
117+
/**
118+
* {@inheritdoc}
119+
*/
120+
public static function getDescription(): string
121+
{
122+
return 'Parses the xml report format of psalm';
123+
}
124+
125+
protected function addForAllLines($currentFile, $start, $end, $error)
126+
{
127+
for ($i = $start; $i <= $end; $i++) {
128+
if ((
129+
!isset($this->errors[$currentFile][$i])
130+
|| !in_array($error, $this->errors[$currentFile][$i])
131+
)
132+
) {
133+
$this->errors[$currentFile][$i][] = $error;
134+
}
135+
}
136+
}
137+
138+
protected function isElementBeginning(XMLReader $reader, string $name): bool
139+
{
140+
return $reader->name === $name && $reader->nodeType == XMLReader::ELEMENT;
141+
}
142+
143+
protected function isElementEnd(XMLReader $reader, string $name): bool
144+
{
145+
return $reader->name === $name && $reader->nodeType == XMLReader::END_ELEMENT;
146+
}
147+
}

src/Runners/generic.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
'phpstan' => 'PhpStan',
5858
'phpunit' => 'PhpUnit',
5959
'pylint' => 'Pylint',
60+
'psalm' => 'Psalm',
6061
];
6162

6263
$fileCheck = CoverageChecker\getFileChecker(

tests/PsalmDiffFilterTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
namespace exussum12\CoverageChecker\tests;
3+
4+
use PHPUnit\Framework\TestCase;
5+
use Exception;
6+
7+
/**
8+
* Ignored due to acceptance test needing to write values
9+
* @SuppressWarnings(PHPMD.Superglobals)
10+
*/
11+
class PsalmDiffFilterTest extends TestCase
12+
{
13+
14+
public function testValid()
15+
{
16+
$GLOBALS['argv'] = [
17+
'diffFilter',
18+
'--psalm',
19+
__DIR__ . '/fixtures/change.txt',
20+
__DIR__ . '/fixtures/psalm.xml'
21+
];
22+
ob_start();
23+
require(__DIR__ . "/../src/Runners/generic.php");
24+
$output = ob_get_clean();
25+
$this->assertContains('100.00% Covered', $output);
26+
}
27+
28+
public function testNoValidLines()
29+
{
30+
$GLOBALS['argv'] = [
31+
'diffFilter',
32+
'--psalm',
33+
__DIR__ . '/fixtures/change.txt',
34+
__DIR__ . '/fixtures/psalm-change.xml',
35+
];
36+
try {
37+
ob_start();
38+
require(__DIR__ . "/../src/Runners/generic.php");
39+
} catch (Exception $exception) {
40+
$output = ob_get_clean();
41+
$this->assertEquals(2, $exception->getCode());
42+
$this->assertContains('0.00%', $output);
43+
return;
44+
}
45+
$this->fail("no exception thrown");
46+
}
47+
}

tests/fixtures/psalm-change.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<report>
3+
<item>
4+
<severity>info</severity>
5+
<line_from>3</line_from>
6+
<line_to>4</line_to>
7+
<type>MissingPropertyType</type>
8+
<message>Violation message</message>
9+
<file_name>/full/path/to/file/src/changedFile.php</file_name>
10+
<file_path>/full/path/to/file/src/changedFile.php</file_path>
11+
<snippet> protected $foo;</snippet>
12+
<selected_text>protected $foo;</selected_text>
13+
<from>192</from>
14+
<to>222</to>
15+
<snippet_from>188</snippet_from>
16+
<snippet_to>222</snippet_to>
17+
<column_from>5</column_from>
18+
<column_to>35</column_to>
19+
</item>
20+
</report>

tests/fixtures/psalm.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<report>
3+
<item>
4+
<severity>info</severity>
5+
<line_from>11</line_from>
6+
<line_to>11</line_to>
7+
<type>MissingPropertyType</type>
8+
<message>Violation message</message>
9+
<file_name>full/path/to/file/src/CoverageCheck.php</file_name>
10+
<file_path>/full/path/to/file/src/CoverageCheck.php</file_path>
11+
<snippet> protected $foo;</snippet>
12+
<selected_text>protected $foo;</selected_text>
13+
<from>192</from>
14+
<to>222</to>
15+
<snippet_from>188</snippet_from>
16+
<snippet_to>222</snippet_to>
17+
<column_from>5</column_from>
18+
<column_to>35</column_to>
19+
</item>
20+
</report>

0 commit comments

Comments
 (0)