Skip to content

Commit

Permalink
Merge branch 'phpro:v2.x' into patch-2
Browse files Browse the repository at this point in the history
  • Loading branch information
peterjaap authored Dec 3, 2024
2 parents a935884 + 6e95a02 commit 5646362
Show file tree
Hide file tree
Showing 18 changed files with 342 additions and 217 deletions.
394 changes: 200 additions & 194 deletions composer.lock

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions doc/tasks/infection.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ grumphp:
mutators: []
ignore_patterns: []
triggered_by: [php]
skip_initial_tests: false
coverage: ~
```
**threads**
Expand Down Expand Up @@ -112,3 +114,16 @@ With this option you can skip files like tests. Leave this option blank to run a
This option will specify which file extensions will trigger the infection task.
By default, infection will be triggered by altering a php file.
You can overwrite this option to whatever file you want to use!

**skip_initial_tests**

*Default: false*

Skip running the initial tests. If set to `true`, it is necessary to set `coverage` to the
path where `coverage-xml` and `log-junit` is written by `phpunit` task.

**coverage**

*Default: ~*

Path where `coverage-xml` and `log-junit` is written by `phpunit` task.
6 changes: 4 additions & 2 deletions resources/config/util.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ services:
'7.3': '2021-12-06 23:59:59'
'7.4': '2022-11-28 23:59:59'
'8.0': '2023-11-26 23:59:59'
'8.1': '2024-11-25 23:59:59'
'8.2': '2025-12-08 23:59:59'
'8.1': '2025-12-31 23:59:59'
'8.2': '2026-12-31 23:59:59'
'8.3': '2027-12-31 23:59:59'
'8.4': '2028-12-31 23:59:59'
11 changes: 11 additions & 0 deletions spec/Process/ProcessBuilderSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ public function getMatchers(): array
{
return [
'beQuoted' => function ($subject, $string) {
if ('\\' === DIRECTORY_SEPARATOR) {
if ($subject !== $string) {
throw new FailureException(sprintf(
'Expected %s, got %s.',
$string,
$subject
));
}
return true;
}

$regex = sprintf('{^([\'"])%s\1$}', preg_quote($string));
if (!preg_match($regex, $subject)) {
throw new FailureException(sprintf(
Expand Down
11 changes: 11 additions & 0 deletions spec/Process/ProcessFactorySpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ public function getMatchers(): array
{
return [
'beQuoted' => function ($subject, $string) {
if ('\\' === DIRECTORY_SEPARATOR) {
if ($subject !== $string) {
throw new FailureException(sprintf(
'Expected %s, got %s.',
$string,
$subject
));
}
return true;
}

$regex = sprintf('{^([\'"])%s\1$}', preg_quote($string));
if (!preg_match($regex, $subject)) {
throw new FailureException(sprintf(
Expand Down
4 changes: 2 additions & 2 deletions src/Configuration/Loader/DistFileLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ public function __construct(LoaderInterface $loader)
$this->loader = $loader;
}

public function load(mixed $resource, string $type = null): mixed
public function load(mixed $resource, ?string $type = null): mixed
{
return $this->loader->load($resource, $type);
}

public function supports(mixed $resource, string $type = null): bool
public function supports(mixed $resource, ?string $type = null): bool
{
if (!\is_string($resource)) {
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/Console/Command/ConfigureCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ protected function buildConfiguration(InputInterface $input, OutputInterface $ou
];
}

protected function createQuestionString(string $question, string $default = null, string $separator = ':'): string
protected function createQuestionString(string $question, ?string $default = null, string $separator = ':'): string
{
return null !== $default ?
sprintf('<fg=green>%s</fg=green> [<fg=yellow>%s</fg=yellow>]%s ', $question, $default, $separator) :
Expand Down
2 changes: 1 addition & 1 deletion src/Event/Dispatcher/Bridge/SymfonyEventDispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function __construct($eventDispatcher)
$this->dispatcher = $eventDispatcher;
}

public function dispatch(Event $event, string $name = null): void
public function dispatch(Event $event, ?string $name = null): void
{
$interfacesImplemented = class_implements($this->dispatcher);
if (in_array(SymfonyEventDispatcherContract::class, $interfacesImplemented, true)) {
Expand Down
2 changes: 1 addition & 1 deletion src/Event/Dispatcher/EventDispatcherInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@

interface EventDispatcherInterface
{
public function dispatch(Event $event, string $name = null): void;
public function dispatch(Event $event, ?string $name = null): void;
}
46 changes: 44 additions & 2 deletions src/Locator/GitRepositoryDirLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,55 @@ public function locate(string $gitDir): string

$gitRepositoryDir = $matches[1];

if ($this->filesystem->isAbsolutePath($gitRepositoryDir)) {
return $gitRepositoryDir;
if ($this->isWorktree($gitRepositoryDir)) {
return $this->locateWorktreeRoot($gitRepositoryDir);
}

return $this->filesystem->buildPath(
dirname($gitDir),
$gitRepositoryDir
);
}

/**
* If a given path (from gitdir value) is absolute and there is a commondir file, it is
* a worktree.
*/
private function isWorktree(string $gitDir): bool
{
return $this->filesystem->isAbsolutePath($gitDir)
&& $this->filesystem->isFile($gitDir.DIRECTORY_SEPARATOR.'commondir');
}

/**
* Retreiving repository dir for worktree nominally returns path to the configured worktree,
* which does not hold hooks. We need to resolve the actual repository root.
*
* Example directory structure:
* ```
* /project
* .git/
* .git/hooks/
* .git/worktrees/
* worktree1
* commondir: relative path to /project/.git
* /worktree1
* .git: file with path to /project/.git/worktrees/worktree1
* ```
*/
private function locateWorktreeRoot(string $gitRepositoryDir): string
{
$worktreeRelativeRoot = trim(
$this->filesystem->readPath(
$gitRepositoryDir.DIRECTORY_SEPARATOR.'commondir'
)
);

return $this->filesystem->realpath(
$this->filesystem->makePathAbsolute(
$worktreeRelativeRoot,
$gitRepositoryDir
)
);
}
}
2 changes: 1 addition & 1 deletion src/Parser/Php/Configurator/TraverserConfigurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function registerVisitorId(string $alias, string $visitorId): void
/**
* @throws \GrumPHP\Exception\RuntimeException
*/
public function registerStandardEnabledVisitor(string $alias, array $visitorOptions = null): void
public function registerStandardEnabledVisitor(string $alias, ?array $visitorOptions = null): void
{
if (array_key_exists($alias, $this->standardEnabledVisitors)) {
throw new RuntimeException(
Expand Down
2 changes: 1 addition & 1 deletion src/Process/ProcessBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function __construct(ExternalCommand $externalCommandLocator, IOInterface
*/
public function createArgumentsForCommand(
string $command,
callable $pathManipulator = null
?callable $pathManipulator = null
): ProcessArgumentsCollection {
$executable = $this->externalCommandLocator->locate($command);
$manipulatedExecutable = $pathManipulator ? $pathManipulator($executable) : $executable;
Expand Down
2 changes: 1 addition & 1 deletion src/Runner/TaskRunnerContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class TaskRunnerContext
*/
public function __construct(
ContextInterface $taskContext,
TestSuiteInterface $testSuite = null,
?TestSuiteInterface $testSuite = null,
array $taskNames = []
) {
$this->taskContext = $taskContext;
Expand Down
6 changes: 6 additions & 0 deletions src/Task/Infection.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
'mutators' => [],
'ignore_patterns' => [],
'triggered_by' => ['php'],
'skip_initial_tests' => false,
'coverage' => null,
]);

$resolver->addAllowedTypes('threads', ['null', 'int']);
Expand All @@ -47,6 +49,8 @@ public static function getConfigurableOptions(): ConfigOptionsResolver
$resolver->addAllowedTypes('mutators', ['array']);
$resolver->addAllowedTypes('ignore_patterns', ['array']);
$resolver->addAllowedTypes('triggered_by', ['array']);
$resolver->addAllowedTypes('skip_initial_tests', ['bool']);
$resolver->addAllowedTypes('coverage', ['null', 'string']);

return ConfigOptionsResolver::fromOptionsResolver($resolver);
}
Expand Down Expand Up @@ -84,6 +88,8 @@ public function run(ContextInterface $context): TaskResultInterface
$arguments->addOptionalArgument('--configuration=%s', $config['configuration']);
$arguments->addOptionalArgument('--min-msi=%s', $config['min_msi']);
$arguments->addOptionalArgument('--min-covered-msi=%s', $config['min_covered_msi']);
$arguments->addOptionalArgument('--coverage=%s', $config['coverage']);
$arguments->addOptionalArgument('--skip-initial-tests', $config['skip_initial_tests']);
$arguments->addOptionalCommaSeparatedArgument('--mutators=%s', $config['mutators']);

if ($context instanceof GitPreCommitContext) {
Expand Down
16 changes: 9 additions & 7 deletions test/E2E/AbstractE2ETestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ protected function initializeGitSubModule(string $gitPath, string $submodulePath
$process = new Process(
[
$this->executableFinder->find('git'),
'-c',
'protocol.file.allow=always',
'submodule',
'add',
'-f',
Expand Down Expand Up @@ -174,7 +176,7 @@ protected function mergeComposerConfig(string $composerFile, array $config, $rec
$this->dumpFile($composerFile, json_encode($newSource, $flags));
}

protected function ensureHooksExist(string $gitPath = null, string $containsPattern = '{grumphp}')
protected function ensureHooksExist(?string $gitPath = null, string $containsPattern = '{grumphp}')
{
$gitPath = $gitPath ?: $this->rootDir;
$hooks = ['pre-commit', 'commit-msg'];
Expand Down Expand Up @@ -346,7 +348,7 @@ protected function installComposer(string $path, array $arguments = [])
$this->runCommand('install composer', $process);
}

protected function commitAll(string $gitPath = null)
protected function commitAll(?string $gitPath = null)
{
$gitPath = $gitPath ?: $this->rootDir;
$git = $this->executableFinder->find('git');
Expand All @@ -362,7 +364,7 @@ protected function commitAll(string $gitPath = null)
* --all: Tell the command to automatically stage files that have been modified and deleted,
* but new files you have not told Git about are not affected.
*/
protected function commitModifiedAndDeleted(string $gitPath = null)
protected function commitModifiedAndDeleted(?string $gitPath = null)
{
$gitPath = $gitPath ?: $this->rootDir;
$git = $this->executableFinder->find('git');
Expand All @@ -382,7 +384,7 @@ protected function runGrumphp(string $projectPath, string $vendorPath = './vendo
{
$projectPath = $this->relativeRootPath($projectPath);
$process = new Process(
[$vendorPath.'/bin/grumphp', 'run', '-vvv'],
[$this->executableFinder->find('php'), $vendorPath.'/bin/grumphp', 'run', '-vvv'],
$projectPath
);

Expand All @@ -396,7 +398,7 @@ protected function runGrumphpWithConfig(string $projectPath, string $grumphpFile
$projectPath = $this->relativeRootPath($projectPath);
$this->runCommand('grumphp run with config',
new Process(
[$vendorPath.'/bin/grumphp', 'run', '-vvv', '--config='.$grumphpFile],
[$this->executableFinder->find('php'), $vendorPath.'/bin/grumphp', 'run', '-vvv', '--config='.$grumphpFile],
$projectPath
)
);
Expand All @@ -407,7 +409,7 @@ protected function runGrumphpInfo(string $projectPath, $vendorPath = './vendor')
$projectPath = $this->relativeRootPath($projectPath);
$this->runCommand('grumphp info',
new Process(
[$vendorPath.'/bin/grumphp'],
[$this->executableFinder->find('php'), $vendorPath.'/bin/grumphp'],
$projectPath
)
);
Expand All @@ -418,7 +420,7 @@ protected function initializeGrumphpGitHooksWithConfig(string $grumphpFile, $ven
$this->runCommand(
'grumphp git:init',
new Process(
[$vendorPath.'/bin/grumphp', 'git:init', '--config='.$grumphpFile],
[$this->executableFinder->find('php'), $vendorPath.'/bin/grumphp', 'git:init', '--config='.$grumphpFile],
$this->rootDir
)
);
Expand Down
2 changes: 1 addition & 1 deletion test/E2E/GitHookParametersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function it_can_specify_hook_exec_command_with_additional_arguments()

$this->installComposer($this->rootDir);

$hookPattern = sprintf('{[\'"]%s[\'"] [\'"]-d date\.timezone=Europe/Brussels[\'"]}', preg_quote($php));
$hookPattern = sprintf('{([\'"]?)%s([\'"]?) [\'"]-d date\.timezone=Europe/Brussels[\'"]}', preg_quote($php));
$this->ensureHooksExist($this->rootDir, $hookPattern);

$this->enableValidatePathsTask($grumphpFile, $this->rootDir);
Expand Down
10 changes: 7 additions & 3 deletions test/Unit/Locator/GitRepositoryDirLocatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ protected function setUp(): void

$this->filesystem = new Filesystem();
$this->locator = new GitRepositoryDirLocator($this->filesystem);
$this->gitDir = $this->workspace . DIRECTORY_SEPARATOR . '.git';
$this->gitDir = $this->workspace . DIRECTORY_SEPARATOR . '.git';
}

/**
Expand Down Expand Up @@ -69,7 +69,11 @@ public function it_can_passthrough_git_dir_path_if_file_is_not_parseable(): void
*/
public function it_can_locate_git_dir_in_workspaces(): void
{
$this->filesystem->dumpFile($this->gitDir, 'gitdir: /dev/null');
$this->assertEquals('/dev/null', $this->locator->locate($this->gitDir));
$ourWorktreeProject = $this->workspace.'/project1/';
$worktreeGitRoot = $this->gitDir.'/worktrees/worktree1/';
mkdir($worktreeGitRoot, 0777, true);
$this->filesystem->dumpFile($worktreeGitRoot.'/commondir', '../..');
$this->filesystem->dumpFile($ourWorktreeProject.'/.git', 'gitdir: '.$this->gitDir.'/worktrees/worktree1');
$this->assertEquals($this->gitDir, $this->locator->locate($this->gitDir));
}
}
26 changes: 26 additions & 0 deletions test/Unit/Task/InfectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public function provideConfigurableOptions(): iterable
'mutators' => [],
'ignore_patterns' => [],
'triggered_by' => ['php'],
'skip_initial_tests' => false,
'coverage' => null
]
];
}
Expand Down Expand Up @@ -233,5 +235,29 @@ public function provideExternalTaskRuns(): iterable
'--filter=hello.php,hello2.php'
]
];
yield 'skip-initial-tests' => [
[
'skip_initial_tests' => true,
],
$this->mockContext(RunContext::class, ['hello.php', 'hello2.php']),
'infection',
[
'--no-interaction',
'--ignore-msi-with-no-mutations',
'--skip-initial-tests'
]
];
yield 'coverage' => [
[
'coverage' => '/path/to/coverage',
],
$this->mockContext(RunContext::class, ['hello.php', 'hello2.php']),
'infection',
[
'--no-interaction',
'--ignore-msi-with-no-mutations',
'--coverage=/path/to/coverage'
]
];
}
}

0 comments on commit 5646362

Please sign in to comment.