diff --git a/src/Command/RunCommand.php b/src/Command/RunCommand.php index 0a0969527..da22c4f1d 100644 --- a/src/Command/RunCommand.php +++ b/src/Command/RunCommand.php @@ -53,6 +53,7 @@ use Infection\FileSystem\Locator\FileOrDirectoryNotFound; use Infection\FileSystem\Locator\Locator; use Infection\Logger\ConsoleLogger; +use Infection\Logger\GitHub\NoFilesInDiffToMutate; use Infection\Metrics\MinMsiCheckFailed; use Infection\Process\Runner\InitialTestsFailed; use Infection\TestFramework\TestFrameworkTypes; @@ -329,26 +330,30 @@ protected function executeCommand(IO $io): bool $container = $this->createContainer($io, $logger); $consoleOutput = new ConsoleOutput($logger); - $this->startUp($container, $consoleOutput, $logger, $io); - - $engine = new Engine( - $container->getConfiguration(), - $container->getTestFrameworkAdapter(), - $container->getCoverageChecker(), - $container->getEventDispatcher(), - $container->getInitialTestsRunner(), - $container->getMemoryLimiter(), - $container->getMutationGenerator(), - $container->getMutationTestingRunner(), - $container->getMinMsiChecker(), - $consoleOutput, - $container->getMetricsCalculator(), - $container->getTestFrameworkExtraOptionsFilter() - ); - try { + $this->startUp($container, $consoleOutput, $logger, $io); + + $engine = new Engine( + $container->getConfiguration(), + $container->getTestFrameworkAdapter(), + $container->getCoverageChecker(), + $container->getEventDispatcher(), + $container->getInitialTestsRunner(), + $container->getMemoryLimiter(), + $container->getMutationGenerator(), + $container->getMutationTestingRunner(), + $container->getMinMsiChecker(), + $consoleOutput, + $container->getMetricsCalculator(), + $container->getTestFrameworkExtraOptionsFilter() + ); + $engine->execute(); + return true; + } catch (NoFilesInDiffToMutate $e) { + $io->success($e->getMessage()); + return true; } catch (InitialTestsFailed | MinMsiCheckFailed $exception) { // TODO: we can move that in a dedicated logger later and handle those cases in the diff --git a/src/Container.php b/src/Container.php index 1530b8556..8e0922964 100644 --- a/src/Container.php +++ b/src/Container.php @@ -104,6 +104,7 @@ use Infection\Process\Runner\MutationTestingRunner; use Infection\Process\Runner\ParallelProcessRunner; use Infection\Process\Runner\ProcessRunner; +use Infection\Process\ShellCommandLineExecutor; use Infection\Resource\Memory\MemoryFormatter; use Infection\Resource\Memory\MemoryLimiter; use Infection\Resource\Memory\MemoryLimiterEnvironment; @@ -654,8 +655,11 @@ public static function create(): self DiffSourceCodeMatcher::class => static function (): DiffSourceCodeMatcher { return new DiffSourceCodeMatcher(); }, - GitDiffFileProvider::class => static function (): GitDiffFileProvider { - return new GitDiffFileProvider(); + ShellCommandLineExecutor::class => static function (): ShellCommandLineExecutor { + return new ShellCommandLineExecutor(); + }, + GitDiffFileProvider::class => static function (self $container): GitDiffFileProvider { + return new GitDiffFileProvider($container->getShellCommandLineExecutor()); }, ]); @@ -1256,6 +1260,11 @@ public function getDiffSourceCodeMatcher(): DiffSourceCodeMatcher return $this->get(DiffSourceCodeMatcher::class); } + public function getShellCommandLineExecutor(): ShellCommandLineExecutor + { + return $this->get(ShellCommandLineExecutor::class); + } + public function getGitDiffFileProvider(): GitDiffFileProvider { return $this->get(GitDiffFileProvider::class); diff --git a/src/Logger/GitHub/GitDiffFileProvider.php b/src/Logger/GitHub/GitDiffFileProvider.php index 75122603c..cf2211288 100644 --- a/src/Logger/GitHub/GitDiffFileProvider.php +++ b/src/Logger/GitHub/GitDiffFileProvider.php @@ -36,8 +36,8 @@ namespace Infection\Logger\GitHub; use function escapeshellarg; +use Infection\Process\ShellCommandLineExecutor; use function Safe\sprintf; -use function shell_exec; /** * @final @@ -48,14 +48,25 @@ class GitDiffFileProvider { public const DEFAULT_BASE = 'origin/master'; + private ShellCommandLineExecutor $shellCommandLineExecutor; + + public function __construct(ShellCommandLineExecutor $shellCommandLineExecutor) + { + $this->shellCommandLineExecutor = $shellCommandLineExecutor; + } + public function provide(string $gitDiffFilter, string $gitDiffBase): string { - return (string) shell_exec( - sprintf( - 'git diff %s --diff-filter=%s --name-only | grep src/ | paste -s -d "," -', - escapeshellarg($gitDiffBase), - escapeshellarg($gitDiffFilter) - ) - ); + $filter = $this->shellCommandLineExecutor->execute(sprintf( + 'git diff %s --diff-filter=%s --name-only | grep src/ | paste -s -d "," -', + escapeshellarg($gitDiffBase), + escapeshellarg($gitDiffFilter) + )); + + if ($filter === '') { + throw NoFilesInDiffToMutate::create(); + } + + return $filter; } } diff --git a/src/Logger/GitHub/NoFilesInDiffToMutate.php b/src/Logger/GitHub/NoFilesInDiffToMutate.php new file mode 100644 index 000000000..91b416f09 --- /dev/null +++ b/src/Logger/GitHub/NoFilesInDiffToMutate.php @@ -0,0 +1,49 @@ +mustRun()->getOutput()); + } +} diff --git a/tests/phpunit/AutoReview/ProjectCode/ProjectCodeProvider.php b/tests/phpunit/AutoReview/ProjectCode/ProjectCodeProvider.php index c1702e802..fac494948 100644 --- a/tests/phpunit/AutoReview/ProjectCode/ProjectCodeProvider.php +++ b/tests/phpunit/AutoReview/ProjectCode/ProjectCodeProvider.php @@ -58,7 +58,6 @@ use Infection\FileSystem\Finder\ComposerExecutableFinder; use Infection\FileSystem\Finder\NonExecutableFinder; use Infection\FileSystem\Finder\TestFrameworkFinder; -use Infection\Logger\GitHub\GitDiffFileProvider; use Infection\Logger\Http\StrykerCurlClient; use Infection\Logger\Http\StrykerDashboardClient; use Infection\Metrics\MetricsCalculator; @@ -67,6 +66,7 @@ use Infection\Mutator\NodeMutationGenerator; use Infection\Process\OriginalPhpProcess; use Infection\Process\Runner\IndexedProcessBearer; +use Infection\Process\ShellCommandLineExecutor; use Infection\TestFramework\AdapterInstaller; use Infection\TestFramework\Coverage\JUnit\TestFileTimeData; use Infection\TestFramework\Coverage\NodeLineRangeData; @@ -114,7 +114,7 @@ final class ProjectCodeProvider XdebugHandler::class, NullSubscriber::class, FormatterName::class, - GitDiffFileProvider::class, + ShellCommandLineExecutor::class, ]; /** diff --git a/tests/phpunit/Logger/GitHub/GitDiffFileProviderTest.php b/tests/phpunit/Logger/GitHub/GitDiffFileProviderTest.php new file mode 100644 index 000000000..1ae7bd9a4 --- /dev/null +++ b/tests/phpunit/Logger/GitHub/GitDiffFileProviderTest.php @@ -0,0 +1,78 @@ +createMock(ShellCommandLineExecutor::class); + $shellCommandLineExecutor->expects($this->once()) + ->method('execute') + ->willReturn(''); + + $this->expectException(NoFilesInDiffToMutate::class); + + $diffProvider = new GitDiffFileProvider($shellCommandLineExecutor); + $diffProvider->provide('AM', 'master'); + } + + public function test_it_executes_diff_and_returns_filter_as_a_string(): void + { + $expectedCommandLine = 'git diff \'master\' --diff-filter=\'AM\' --name-only | grep src/ | paste -s -d "," -'; + + if (PHP_OS_FAMILY === 'Windows') { + $expectedCommandLine = 'git diff "master" --diff-filter="AM" --name-only | grep src/ | paste -s -d "," -'; + } + + $shellCommandLineExecutor = $this->createMock(ShellCommandLineExecutor::class); + $shellCommandLineExecutor->expects($this->once()) + ->method('execute') + ->with($expectedCommandLine) + ->willReturn('src/A.php,src/B.php'); + + $diffProvider = new GitDiffFileProvider($shellCommandLineExecutor); + $filter = $diffProvider->provide('AM', 'master'); + + $this->assertSame('src/A.php,src/B.php', $filter); + } +} diff --git a/tests/phpunit/Logger/GitHub/NoFilesInDiffToMutateTest.php b/tests/phpunit/Logger/GitHub/NoFilesInDiffToMutateTest.php new file mode 100644 index 000000000..a351c35fc --- /dev/null +++ b/tests/phpunit/Logger/GitHub/NoFilesInDiffToMutateTest.php @@ -0,0 +1,53 @@ +assertInstanceOf(NoFilesInDiffToMutate::class, $exception); + $this->assertSame( + 'No files in diff found, skipping mutation analysis.', + $exception->getMessage() + ); + } +}