Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for relative paths in editorUrl #1414

Merged
merged 5 commits into from Jun 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions conf/config.neon
Expand Up @@ -1949,6 +1949,7 @@ services:
errorFormatter.table:
class: PHPStan\Command\ErrorFormatter\TableErrorFormatter
arguments:
simpleRelativePathHelper: @simpleRelativePathHelper
showTipsOfTheDay: %tipsOfTheDay%
editorUrl: %editorUrl%

Expand Down
8 changes: 7 additions & 1 deletion src/Command/ErrorFormatter/TableErrorFormatter.php
Expand Up @@ -7,6 +7,7 @@
use PHPStan\Command\AnalysisResult;
use PHPStan\Command\Output;
use PHPStan\File\RelativePathHelper;
use PHPStan\File\SimpleRelativePathHelper;
use Symfony\Component\Console\Formatter\OutputFormatter;
use function array_map;
use function count;
Expand All @@ -19,6 +20,7 @@ class TableErrorFormatter implements ErrorFormatter

public function __construct(
private RelativePathHelper $relativePathHelper,
private SimpleRelativePathHelper $simpleRelativePathHelper,
private CiDetectedErrorFormatter $ciDetectedErrorFormatter,
private bool $showTipsOfTheDay,
private ?string $editorUrl,
Expand Down Expand Up @@ -78,7 +80,11 @@ public function formatErrors(
}
if (is_string($this->editorUrl)) {
$editorFile = $error->getTraitFilePath() ?? $error->getFilePath();
$url = str_replace(['%file%', '%line%'], [$editorFile, (string) $error->getLine()], $this->editorUrl);
$url = str_replace(
['%file%', '%relFile%', '%line%'],
[$editorFile, $this->simpleRelativePathHelper->getRelativePath($editorFile), (string) $error->getLine()],
$this->editorUrl,
);
$message .= "\n鉁忥笍 <href=" . OutputFormatter::escape($url) . '>' . $this->relativePathHelper->getRelativePath($editorFile) . '</>';
}
$rows[] = [
Expand Down
36 changes: 22 additions & 14 deletions src/Testing/ErrorFormatterTestCase.php
Expand Up @@ -25,38 +25,46 @@ abstract class ErrorFormatterTestCase extends PHPStanTestCase

protected const DIRECTORY_PATH = '/data/folder/with space/and unicode 馃槂/project';

private ?StreamOutput $outputStream = null;
private const KIND_DECORATED = 'decorated';
private const KIND_PLAIN = 'plain';

private ?Output $output = null;
/** @var array<string, StreamOutput> */
private array $outputStream = [];

private function getOutputStream(): StreamOutput
/** @var array<string, Output> */
private array $output = [];

private function getOutputStream(bool $decorated = false): StreamOutput
{
if ($this->outputStream === null) {
$kind = $decorated ? self::KIND_DECORATED : self::KIND_PLAIN;
if (!isset($this->outputStream[$kind])) {
$resource = fopen('php://memory', 'w', false);
if ($resource === false) {
throw new ShouldNotHappenException();
}
$this->outputStream = new StreamOutput($resource, StreamOutput::VERBOSITY_NORMAL, false);
$this->outputStream[$kind] = new StreamOutput($resource, StreamOutput::VERBOSITY_NORMAL, $decorated);
}

return $this->outputStream;
return $this->outputStream[$kind];
}

protected function getOutput(): Output
protected function getOutput(bool $decorated = false): Output
{
if ($this->output === null) {
$errorConsoleStyle = new ErrorsConsoleStyle(new StringInput(''), $this->getOutputStream());
$this->output = new SymfonyOutput($this->getOutputStream(), new SymfonyStyle($errorConsoleStyle));
$kind = $decorated ? self::KIND_DECORATED : self::KIND_PLAIN;
if (!isset($this->output[$kind])) {
$outputStream = $this->getOutputStream($decorated);
$errorConsoleStyle = new ErrorsConsoleStyle(new StringInput(''), $outputStream);
$this->output[$kind] = new SymfonyOutput($outputStream, new SymfonyStyle($errorConsoleStyle));
}

return $this->output;
return $this->output[$kind];
}

protected function getOutputContent(): string
protected function getOutputContent(bool $decorated = false): string
{
rewind($this->getOutputStream()->getStream());
rewind($this->getOutputStream($decorated)->getStream());

$contents = stream_get_contents($this->getOutputStream()->getStream());
$contents = stream_get_contents($this->getOutputStream($decorated)->getStream());
if ($contents === false) {
throw new ShouldNotHappenException();
}
Expand Down
15 changes: 11 additions & 4 deletions tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php
Expand Up @@ -10,6 +10,7 @@
use PHPStan\Command\Symfony\SymfonyOutput;
use PHPStan\File\FuzzyRelativePathHelper;
use PHPStan\File\NullRelativePathHelper;
use PHPStan\File\SimpleRelativePathHelper;
use PHPStan\ShouldNotHappenException;
use PHPStan\Testing\PHPStanTestCase;
use Symfony\Component\Console\Input\InputInterface;
Expand Down Expand Up @@ -67,10 +68,16 @@ private function runPath(string $path, int $expectedStatusCode): string
$memoryLimitFile = self::getContainer()->getParameter('memoryLimitFile');

$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), __DIR__, [], DIRECTORY_SEPARATOR);
$errorFormatter = new TableErrorFormatter($relativePathHelper, new CiDetectedErrorFormatter(
new GithubErrorFormatter($relativePathHelper),
new TeamcityErrorFormatter($relativePathHelper),
), false, null);
$errorFormatter = new TableErrorFormatter(
$relativePathHelper,
new SimpleRelativePathHelper(__DIR__),
new CiDetectedErrorFormatter(
new GithubErrorFormatter($relativePathHelper),
new TeamcityErrorFormatter($relativePathHelper),
),
false,
null,
);
$analysisResult = $analyserApplication->analyse(
[$path],
true,
Expand Down
44 changes: 29 additions & 15 deletions tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php
Expand Up @@ -6,6 +6,7 @@
use PHPStan\Command\AnalysisResult;
use PHPStan\File\FuzzyRelativePathHelper;
use PHPStan\File\NullRelativePathHelper;
use PHPStan\File\SimpleRelativePathHelper;
use PHPStan\Testing\ErrorFormatterTestCase;
use function putenv;
use function sprintf;
Expand Down Expand Up @@ -164,11 +165,7 @@ public function testFormatErrors(
if (PHP_VERSION_ID >= 80100) {
self::markTestSkipped('Skipped on PHP 8.1 because of different result');
}
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/');
$formatter = new TableErrorFormatter($relativePathHelper, new CiDetectedErrorFormatter(
new GithubErrorFormatter($relativePathHelper),
new TeamcityErrorFormatter($relativePathHelper),
), false, null);
$formatter = $this->createErrorFormatter(null);

$this->assertSame($exitCode, $formatter->formatErrors(
$this->getAnalysisResult($numFileErrors, $numGenericErrors),
Expand All @@ -180,25 +177,26 @@ public function testFormatErrors(

public function testEditorUrlWithTrait(): void
{
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/');
$formatter = new TableErrorFormatter($relativePathHelper, new CiDetectedErrorFormatter(
new GithubErrorFormatter($relativePathHelper),
new TeamcityErrorFormatter($relativePathHelper),
), false, 'editor://%file%/%line%');
$formatter = $this->createErrorFormatter('editor://%file%/%line%');
$error = new Error('Test', 'Foo.php (in context of trait)', 12, true, 'Foo.php', 'Bar.php');
$formatter->formatErrors(new AnalysisResult([$error], [], [], [], false, null, true), $this->getOutput());

$this->assertStringContainsString('Bar.php', $this->getOutputContent());
}

public function testEditorUrlWithRelativePath(): void
{
$formatter = $this->createErrorFormatter('editor://custom/path/%relFile%/%line%');
$error = new Error('Test', 'Foo.php', 12, true, self::DIRECTORY_PATH . '/rel/Foo.php');
$formatter->formatErrors(new AnalysisResult([$error], [], [], [], false, null, true), $this->getOutput(true));

$this->assertStringContainsString('editor://custom/path/rel/Foo.php', $this->getOutputContent(true));
}

public function testBug6727(): void
{
putenv('COLUMNS=30');
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/');
$formatter = new TableErrorFormatter($relativePathHelper, new CiDetectedErrorFormatter(
new GithubErrorFormatter($relativePathHelper),
new TeamcityErrorFormatter($relativePathHelper),
), false, null);
$formatter = $this->createErrorFormatter(null);
$formatter->formatErrors(
new AnalysisResult(
[
Expand All @@ -220,4 +218,20 @@ public function testBug6727(): void
self::expectNotToPerformAssertions();
}

private function createErrorFormatter(?string $editorUrl): TableErrorFormatter
{
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/');

return new TableErrorFormatter(
$relativePathHelper,
new SimpleRelativePathHelper(self::DIRECTORY_PATH),
new CiDetectedErrorFormatter(
new GithubErrorFormatter($relativePathHelper),
new TeamcityErrorFormatter($relativePathHelper),
),
false,
$editorUrl,
);
}

}