Skip to content

Commit e61a782

Browse files
authored
Support for relative paths in editorUrl for Docker environment
1 parent 518b413 commit e61a782

File tree

5 files changed

+70
-34
lines changed

5 files changed

+70
-34
lines changed

conf/config.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,6 +1954,7 @@ services:
19541954
errorFormatter.table:
19551955
class: PHPStan\Command\ErrorFormatter\TableErrorFormatter
19561956
arguments:
1957+
simpleRelativePathHelper: @simpleRelativePathHelper
19571958
showTipsOfTheDay: %tipsOfTheDay%
19581959
editorUrl: %editorUrl%
19591960

src/Command/ErrorFormatter/TableErrorFormatter.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Command\AnalysisResult;
88
use PHPStan\Command\Output;
99
use PHPStan\File\RelativePathHelper;
10+
use PHPStan\File\SimpleRelativePathHelper;
1011
use Symfony\Component\Console\Formatter\OutputFormatter;
1112
use function array_map;
1213
use function count;
@@ -19,6 +20,7 @@ class TableErrorFormatter implements ErrorFormatter
1920

2021
public function __construct(
2122
private RelativePathHelper $relativePathHelper,
23+
private SimpleRelativePathHelper $simpleRelativePathHelper,
2224
private CiDetectedErrorFormatter $ciDetectedErrorFormatter,
2325
private bool $showTipsOfTheDay,
2426
private ?string $editorUrl,
@@ -78,7 +80,11 @@ public function formatErrors(
7880
}
7981
if (is_string($this->editorUrl)) {
8082
$editorFile = $error->getTraitFilePath() ?? $error->getFilePath();
81-
$url = str_replace(['%file%', '%line%'], [$editorFile, (string) $error->getLine()], $this->editorUrl);
83+
$url = str_replace(
84+
['%file%', '%relFile%', '%line%'],
85+
[$editorFile, $this->simpleRelativePathHelper->getRelativePath($editorFile), (string) $error->getLine()],
86+
$this->editorUrl,
87+
);
8288
$message .= "\n✏️ <href=" . OutputFormatter::escape($url) . '>' . $this->relativePathHelper->getRelativePath($editorFile) . '</>';
8389
}
8490
$rows[] = [

src/Testing/ErrorFormatterTestCase.php

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,38 +25,46 @@ abstract class ErrorFormatterTestCase extends PHPStanTestCase
2525

2626
protected const DIRECTORY_PATH = '/data/folder/with space/and unicode 😃/project';
2727

28-
private ?StreamOutput $outputStream = null;
28+
private const KIND_DECORATED = 'decorated';
29+
private const KIND_PLAIN = 'plain';
2930

30-
private ?Output $output = null;
31+
/** @var array<string, StreamOutput> */
32+
private array $outputStream = [];
3133

32-
private function getOutputStream(): StreamOutput
34+
/** @var array<string, Output> */
35+
private array $output = [];
36+
37+
private function getOutputStream(bool $decorated = false): StreamOutput
3338
{
34-
if ($this->outputStream === null) {
39+
$kind = $decorated ? self::KIND_DECORATED : self::KIND_PLAIN;
40+
if (!isset($this->outputStream[$kind])) {
3541
$resource = fopen('php://memory', 'w', false);
3642
if ($resource === false) {
3743
throw new ShouldNotHappenException();
3844
}
39-
$this->outputStream = new StreamOutput($resource, StreamOutput::VERBOSITY_NORMAL, false);
45+
$this->outputStream[$kind] = new StreamOutput($resource, StreamOutput::VERBOSITY_NORMAL, $decorated);
4046
}
4147

42-
return $this->outputStream;
48+
return $this->outputStream[$kind];
4349
}
4450

45-
protected function getOutput(): Output
51+
protected function getOutput(bool $decorated = false): Output
4652
{
47-
if ($this->output === null) {
48-
$errorConsoleStyle = new ErrorsConsoleStyle(new StringInput(''), $this->getOutputStream());
49-
$this->output = new SymfonyOutput($this->getOutputStream(), new SymfonyStyle($errorConsoleStyle));
53+
$kind = $decorated ? self::KIND_DECORATED : self::KIND_PLAIN;
54+
if (!isset($this->output[$kind])) {
55+
$outputStream = $this->getOutputStream($decorated);
56+
$errorConsoleStyle = new ErrorsConsoleStyle(new StringInput(''), $outputStream);
57+
$this->output[$kind] = new SymfonyOutput($outputStream, new SymfonyStyle($errorConsoleStyle));
5058
}
5159

52-
return $this->output;
60+
return $this->output[$kind];
5361
}
5462

55-
protected function getOutputContent(): string
63+
protected function getOutputContent(bool $decorated = false): string
5664
{
57-
rewind($this->getOutputStream()->getStream());
65+
rewind($this->getOutputStream($decorated)->getStream());
5866

59-
$contents = stream_get_contents($this->getOutputStream()->getStream());
67+
$contents = stream_get_contents($this->getOutputStream($decorated)->getStream());
6068
if ($contents === false) {
6169
throw new ShouldNotHappenException();
6270
}

tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPStan\Command\Symfony\SymfonyOutput;
1111
use PHPStan\File\FuzzyRelativePathHelper;
1212
use PHPStan\File\NullRelativePathHelper;
13+
use PHPStan\File\SimpleRelativePathHelper;
1314
use PHPStan\ShouldNotHappenException;
1415
use PHPStan\Testing\PHPStanTestCase;
1516
use Symfony\Component\Console\Input\InputInterface;
@@ -67,10 +68,16 @@ private function runPath(string $path, int $expectedStatusCode): string
6768
$memoryLimitFile = self::getContainer()->getParameter('memoryLimitFile');
6869

6970
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), __DIR__, [], DIRECTORY_SEPARATOR);
70-
$errorFormatter = new TableErrorFormatter($relativePathHelper, new CiDetectedErrorFormatter(
71-
new GithubErrorFormatter($relativePathHelper),
72-
new TeamcityErrorFormatter($relativePathHelper),
73-
), false, null);
71+
$errorFormatter = new TableErrorFormatter(
72+
$relativePathHelper,
73+
new SimpleRelativePathHelper(__DIR__),
74+
new CiDetectedErrorFormatter(
75+
new GithubErrorFormatter($relativePathHelper),
76+
new TeamcityErrorFormatter($relativePathHelper),
77+
),
78+
false,
79+
null,
80+
);
7481
$analysisResult = $analyserApplication->analyse(
7582
[$path],
7683
true,

tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PHPStan\Command\AnalysisResult;
77
use PHPStan\File\FuzzyRelativePathHelper;
88
use PHPStan\File\NullRelativePathHelper;
9+
use PHPStan\File\SimpleRelativePathHelper;
910
use PHPStan\Testing\ErrorFormatterTestCase;
1011
use function putenv;
1112
use function sprintf;
@@ -164,11 +165,7 @@ public function testFormatErrors(
164165
if (PHP_VERSION_ID >= 80100) {
165166
self::markTestSkipped('Skipped on PHP 8.1 because of different result');
166167
}
167-
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/');
168-
$formatter = new TableErrorFormatter($relativePathHelper, new CiDetectedErrorFormatter(
169-
new GithubErrorFormatter($relativePathHelper),
170-
new TeamcityErrorFormatter($relativePathHelper),
171-
), false, null);
168+
$formatter = $this->createErrorFormatter(null);
172169

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

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

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

187+
public function testEditorUrlWithRelativePath(): void
188+
{
189+
$formatter = $this->createErrorFormatter('editor://custom/path/%relFile%/%line%');
190+
$error = new Error('Test', 'Foo.php', 12, true, self::DIRECTORY_PATH . '/rel/Foo.php');
191+
$formatter->formatErrors(new AnalysisResult([$error], [], [], [], false, null, true), $this->getOutput(true));
192+
193+
$this->assertStringContainsString('editor://custom/path/rel/Foo.php', $this->getOutputContent(true));
194+
}
195+
194196
public function testBug6727(): void
195197
{
196198
putenv('COLUMNS=30');
197-
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/');
198-
$formatter = new TableErrorFormatter($relativePathHelper, new CiDetectedErrorFormatter(
199-
new GithubErrorFormatter($relativePathHelper),
200-
new TeamcityErrorFormatter($relativePathHelper),
201-
), false, null);
199+
$formatter = $this->createErrorFormatter(null);
202200
$formatter->formatErrors(
203201
new AnalysisResult(
204202
[
@@ -220,4 +218,20 @@ public function testBug6727(): void
220218
self::expectNotToPerformAssertions();
221219
}
222220

221+
private function createErrorFormatter(?string $editorUrl): TableErrorFormatter
222+
{
223+
$relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), self::DIRECTORY_PATH, [], '/');
224+
225+
return new TableErrorFormatter(
226+
$relativePathHelper,
227+
new SimpleRelativePathHelper(self::DIRECTORY_PATH),
228+
new CiDetectedErrorFormatter(
229+
new GithubErrorFormatter($relativePathHelper),
230+
new TeamcityErrorFormatter($relativePathHelper),
231+
),
232+
false,
233+
$editorUrl,
234+
);
235+
}
236+
223237
}

0 commit comments

Comments
 (0)