Skip to content

Commit 78c7a26

Browse files
committed
Add Installed class implementation
1 parent 6fad956 commit 78c7a26

5 files changed

Lines changed: 129 additions & 3 deletions

File tree

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"homepage": "https://github.com/roadrunner-php/version-checker",
1010
"license": "MIT",
1111
"require": {
12-
"php": "^8.1"
12+
"php": "^8.1",
13+
"symfony/process": "^5.4 || ^6.0"
1314
},
1415
"require-dev": {
1516
"phpunit/phpunit": "^9.6 || ^10.0",

src/Process/Process.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RoadRunner\VersionChecker\Process;
6+
7+
use Symfony\Component\Process\Exception\ProcessFailedException;
8+
9+
final class Process implements ProcessInterface
10+
{
11+
public function exec(array $command): string
12+
{
13+
$process = new \Symfony\Component\Process\Process($command);
14+
$process->run();
15+
16+
if (!$process->isSuccessful()) {
17+
throw new ProcessFailedException($process);
18+
}
19+
20+
return $process->getOutput();
21+
}
22+
}

src/Process/ProcessInterface.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RoadRunner\VersionChecker\Process;
6+
7+
interface ProcessInterface
8+
{
9+
public function exec(array $command): string;
10+
}

src/Version/Installed.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,40 @@
55
namespace RoadRunner\VersionChecker\Version;
66

77
use RoadRunner\VersionChecker\Exception\RoadrunnerNotInstalledException;
8+
use RoadRunner\VersionChecker\Process\Process;
9+
use RoadRunner\VersionChecker\Process\ProcessInterface;
10+
use Symfony\Component\Process\Exception\ProcessFailedException;
811

912
final class Installed implements InstalledInterface
1013
{
14+
/**
15+
* @param non-empty-string $executablePath
16+
*/
17+
public function __construct(
18+
private readonly ProcessInterface $process = new Process(),
19+
private readonly string $executablePath = './rr'
20+
) {
21+
}
22+
1123
/**
1224
* @return non-empty-string
1325
*
1426
* @throws RoadrunnerNotInstalledException
1527
*/
1628
public function getInstalledVersion(): string
1729
{
18-
// TODO need implementation
30+
try {
31+
$output = $this->process->exec([$this->executablePath, '--version']);
32+
} catch (ProcessFailedException) {
33+
throw new RoadrunnerNotInstalledException('Roadrunner is not installed.');
34+
}
35+
36+
\preg_match('/\bversion (\d+\.\d+\.\d+[\w.-]*)/', $output, $matches);
37+
38+
if (!empty($matches[1])) {
39+
return $matches[1];
40+
}
1941

20-
throw new RoadrunnerNotInstalledException();
42+
throw new RoadrunnerNotInstalledException('Unable to determine RoadRunner version.');
2143
}
2244
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace RoadRunner\VersionChecker\Tests\Unit;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use RoadRunner\VersionChecker\Exception\RoadrunnerNotInstalledException;
9+
use RoadRunner\VersionChecker\Process\ProcessInterface;
10+
use RoadRunner\VersionChecker\Version\Installed;
11+
use Symfony\Component\Process\Exception\ProcessFailedException;
12+
13+
final class InstalledTest extends TestCase
14+
{
15+
/**
16+
* @dataProvider outputDataProvider
17+
*/
18+
public function testGetInstalledVersion(string $version, string $output): void
19+
{
20+
$process = $this->createMock(ProcessInterface::class);
21+
$process
22+
->expects($this->once())
23+
->method('exec')
24+
->with(['./rr', '--version'])
25+
->willReturn($output);
26+
27+
$installed = new Installed($process);
28+
29+
$this->assertSame($version, $installed->getInstalledVersion());
30+
}
31+
32+
public function testGetInstalledVersionRoadRunnerIsNotInstalled(): void
33+
{
34+
$process = $this->createMock(ProcessInterface::class);
35+
$process
36+
->expects($this->once())
37+
->method('exec')
38+
->with(['./rr', '--version'])
39+
->willThrowException(
40+
(new \ReflectionClass(ProcessFailedException::class))->newInstanceWithoutConstructor()
41+
);
42+
43+
$installed = new Installed($process);
44+
45+
$this->expectException(RoadrunnerNotInstalledException::class);
46+
$installed->getInstalledVersion();
47+
}
48+
49+
public function testGetInstalledVersionUnableToDetermineVersion(): void
50+
{
51+
$process = $this->createMock(ProcessInterface::class);
52+
$process
53+
->expects($this->once())
54+
->method('exec')
55+
->with(['./rr', '--version'])
56+
->willReturn('foo');
57+
58+
$installed = new Installed($process);
59+
60+
$this->expectException(RoadrunnerNotInstalledException::class);
61+
$this->expectExceptionMessage('Unable to determine RoadRunner version.');
62+
$installed->getInstalledVersion();
63+
}
64+
65+
public static function outputDataProvider(): \Traversable
66+
{
67+
yield ['2.12.3', 'rr version 2.12.3 (build time: 2023-02-16T13:08:23+0000, go1.20), OS: darwin, arch: arm64'];
68+
yield ['2023.1.0-rc.2', 'rr version 2023.1.0-rc.2 (build time: 2023-02-16T13:08:23+0000, go1.20)'];
69+
yield ['2023.1.0-beta', 'version 2023.1.0-beta'];
70+
}
71+
}

0 commit comments

Comments
 (0)