Skip to content

Commit d5de2fb

Browse files
committed
Add CommandInterface & deprecate passing a command not implementing it
1 parent 3b52787 commit d5de2fb

10 files changed

Lines changed: 87 additions & 4 deletions

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* Add `getLastCommit()` method
55
* Improve tests & fix them locally
66
* Increase PHPStan level to 7
7+
* Deprecate passing a command class that does not implement `Leapt\GitWrapper\CommandInterface`
8+
* Throw an exception if passing a command class that does not have a `run()` method
79

810
1.2.0
911
-----

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
],
1919
"require": {
2020
"php": "^8.0",
21+
"symfony/deprecation-contracts": "^3.0",
2122
"symfony/process": "^5.2 || ^6.0 || ^7.0"
2223
},
2324
"require-dev": {

phpstan-baseline.neon

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: "#^Parameter \\#1 \\$commandClass of static method Leapt\\\\GitWrapper\\\\Repository\\:\\:createCommand\\(\\) expects class\\-string, string given\\.$#"
5+
count: 3
6+
path: src/Repository.php

phpstan.neon

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
includes:
2+
- phpstan-baseline.neon
3+
14
parameters:
25
paths:
36
- src

src/Command.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Leapt\GitWrapper\Exception\GitRuntimeException;
88
use Symfony\Component\Process\Process;
99

10-
class Command
10+
class Command implements CommandInterface
1111
{
1212
private string $commandString;
1313

src/CommandInterface.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 Leapt\GitWrapper;
6+
7+
interface CommandInterface
8+
{
9+
public function run(): string;
10+
}

src/Repository.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static function create(string $directory, bool $debug = false, array $opt
5353
{
5454
$options = array_merge(self::DEFAULT_OPTIONS, $options);
5555
$commandString = $options['git_executable'] . ' init';
56-
$command = new $options['command_class']($directory, $commandString, $debug);
56+
$command = self::createCommand($options['command_class'], $directory, $commandString, $debug);
5757
\assert(method_exists($command, 'run'));
5858
$command->run();
5959

@@ -69,7 +69,7 @@ public static function cloneUrl(string $url, string $directory, bool $debug = fa
6969
{
7070
$options = array_merge(self::DEFAULT_OPTIONS, $options);
7171
$commandString = $options['git_executable'] . ' clone ' . escapeshellarg($url) . ' ' . escapeshellarg($directory);
72-
$command = new $options['command_class'](getcwd(), $commandString, $debug);
72+
$command = self::createCommand($options['command_class'], (string) getcwd(), $commandString, $debug);
7373
\assert(method_exists($command, 'run'));
7474
$command->run();
7575

@@ -157,7 +157,7 @@ public function git(string $commandString): string
157157
$commandString = preg_replace('/^git\s/', '', $commandString);
158158
$commandString = $this->options['git_executable'] . ' ' . $commandString;
159159

160-
$command = new $this->options['command_class']($this->directory, $commandString, $this->debug);
160+
$command = self::createCommand($this->options['command_class'], $this->directory, $commandString, $this->debug);
161161
\assert(method_exists($command, 'run'));
162162

163163
return $command->run();
@@ -168,6 +168,22 @@ public function getDirectory(): string
168168
return $this->directory;
169169
}
170170

171+
/**
172+
* @param class-string $commandClass
173+
*/
174+
public static function createCommand(string $commandClass, string $directory, string $commandString, bool $debug): object
175+
{
176+
if (!\in_array(CommandInterface::class, class_implements($commandClass), true)) {
177+
trigger_deprecation('leapt/git-wrapper', '1.3', 'Passing a Command class that does not implement "%s" is deprecated.', CommandInterface::class);
178+
179+
if (!method_exists($commandClass, 'run')) {
180+
throw new \RuntimeException(sprintf('The Command class must implement a "public function run(): string" method, the "%s" class does not.', $commandClass));
181+
}
182+
}
183+
184+
return new $commandClass($directory, $commandString, $debug);
185+
}
186+
171187
/**
172188
* Convert a formatted log string into an array.
173189
*
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Leapt\GitWrapper\Tests\Fixtures;
6+
7+
final class CommandThatDoesNotHaveRunMethod
8+
{
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Leapt\GitWrapper\Tests\Fixtures;
6+
7+
final class CommandThatDoesNotImplementInterface
8+
{
9+
public function run(): string
10+
{
11+
return '';
12+
}
13+
}

tests/RepositoryTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
use Leapt\GitWrapper\Exception\GitRuntimeException;
99
use Leapt\GitWrapper\Exception\InvalidGitRepositoryDirectoryException;
1010
use Leapt\GitWrapper\Repository;
11+
use Leapt\GitWrapper\Tests\Fixtures\CommandThatDoesNotHaveRunMethod;
12+
use Leapt\GitWrapper\Tests\Fixtures\CommandThatDoesNotImplementInterface;
1113
use PHPUnit\Framework\TestCase;
1214

1315
final class RepositoryTest extends TestCase
@@ -170,6 +172,27 @@ public function testInitializeInvalidDirectoryMustFail(): void
170172
new Repository($directory);
171173
}
172174

175+
public function testCreateCommandThrowsExceptionIfDoesNotHaveRunMethod(): void
176+
{
177+
self::expectException(\RuntimeException::class);
178+
Repository::createCommand(CommandThatDoesNotHaveRunMethod::class, 'test', 'test', false);
179+
}
180+
181+
public function testCreateCommandThrowsDeprecationIfCommandClassDoesNotImplementInterface(): void
182+
{
183+
set_error_handler(
184+
static function ($errno, $errstr) {
185+
restore_error_handler();
186+
throw new \Exception($errstr, $errno);
187+
},
188+
\E_ALL,
189+
);
190+
191+
self::expectException(\Exception::class);
192+
self::expectExceptionMessage('Passing a Command class that does not implement "Leapt\GitWrapper\CommandInterface" is deprecated.');
193+
Repository::createCommand(CommandThatDoesNotImplementInterface::class, 'test', 'test', false);
194+
}
195+
173196
/**
174197
* @param array<string, string> $options
175198
*/

0 commit comments

Comments
 (0)