Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use merge-base (three dot diff) instead of direct diff for git-diff-ase (#1653) #1654

Merged
merged 8 commits into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/mt-annotations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2

with:
fetch-depth: 0
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand Down Expand Up @@ -47,5 +48,5 @@ jobs:

- name: Run Infection for added files only
run: |
git fetch --depth=1 origin $GITHUB_BASE_REF
git fetch origin $GITHUB_BASE_REF
php bin/infection -j2 --git-diff-lines --git-diff-base=origin/$GITHUB_BASE_REF --logger-github --ignore-msi-with-no-mutations --only-covered
29 changes: 27 additions & 2 deletions src/Logger/GitHub/GitDiffFileProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
use function escapeshellarg;
use Infection\Process\ShellCommandLineExecutor;
use function Safe\sprintf;
use Symfony\Component\Process\Exception\ProcessFailedException;
use function trim;

/**
* @final
Expand All @@ -54,9 +56,11 @@ public function __construct(private ShellCommandLineExecutor $shellCommandLineEx

public function provide(string $gitDiffFilter, string $gitDiffBase): string
{
$referenceCommit = $this->findReferenceCommit($gitDiffBase);

$filter = $this->shellCommandLineExecutor->execute(sprintf(
'git diff %s --diff-filter=%s --name-only | grep src/ | paste -s -d "," -',
escapeshellarg($gitDiffBase),
escapeshellarg($referenceCommit),
escapeshellarg($gitDiffFilter)
));

Expand All @@ -69,9 +73,30 @@ public function provide(string $gitDiffFilter, string $gitDiffBase): string

public function provideWithLines(string $gitDiffBase): string
{
$referenceCommit = $this->findReferenceCommit($gitDiffBase);

return $this->shellCommandLineExecutor->execute(sprintf(
"git diff %s --unified=0 --diff-filter=AM | grep -v -e '^[+-]' -e '^index'",
escapeshellarg($gitDiffBase)
escapeshellarg($referenceCommit)
));
}

private function findReferenceCommit(string $gitDiffBase): string
{
try {
$comparisonCommit = trim($this->shellCommandLineExecutor->execute(sprintf(
'git merge-base %s HEAD',
escapeshellarg($gitDiffBase))
)
);
} catch (ProcessFailedException) {
/**
* there is no common ancestor commit, or we are in a shallow checkout and do have a copy of it.
* Fall back to direct diff
*/
$comparisonCommit = $gitDiffBase;
}

return $comparisonCommit;
}
}
54 changes: 48 additions & 6 deletions tests/phpunit/Logger/GitHub/GitDiffFileProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class GitDiffFileProviderTest extends TestCase
public function test_it_throws_no_code_to_mutate_exception_when_diff_is_empty(): void
{
$shellCommandLineExecutor = $this->createMock(ShellCommandLineExecutor::class);
$shellCommandLineExecutor->expects($this->once())
$shellCommandLineExecutor
->method('execute')
->willReturn('');

Expand All @@ -58,21 +58,63 @@ public function test_it_throws_no_code_to_mutate_exception_when_diff_is_empty():

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 "," -';
$expectedMergeBaseCommandLine = 'git merge-base \'master\' HEAD';
$expectedDiffCommandLine = 'git diff \'0ABCMERGE_BASE_342\' --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 "," -';
$expectedMergeBaseCommandLine = 'git merge-base "master" HEAD';
$expectedDiffCommandLine = 'git diff "0ABCMERGE_BASE_342" --diff-filter="AM" --name-only | grep src/ | paste -s -d "," -';
}

$shellCommandLineExecutor = $this->createMock(ShellCommandLineExecutor::class);
$shellCommandLineExecutor->expects($this->once())

$shellCommandLineExecutor->expects($this->any())
->method('execute')
->with($expectedCommandLine)
->willReturn('src/A.php,src/B.php');
->willReturnCallback(function (string $command) use ($expectedDiffCommandLine, $expectedMergeBaseCommandLine): string {
switch ($command) {
case $expectedMergeBaseCommandLine:
return "0ABCMERGE_BASE_342\n";
case $expectedDiffCommandLine:
return 'src/A.php,src/B.php';
default:
$this->fail("Unexpected shell command: $command");
}
});

$diffProvider = new GitDiffFileProvider($shellCommandLineExecutor);
$filter = $diffProvider->provide('AM', 'master');

$this->assertSame('src/A.php,src/B.php', $filter);
}

public function test_it_provides_lines_filter_as_a_string(): void
{
$expectedMergeBaseCommandLine = 'git merge-base \'master\' HEAD';
$expectedDiffCommandLine = 'git diff \'0ABCMERGE_BASE_342\' --unified=0 --diff-filter=AM | grep -v -e \'^[+-]\' -e \'^index\'';

if (PHP_OS_FAMILY === 'Windows') {
$expectedMergeBaseCommandLine = 'git merge-base "master" HEAD';
$expectedDiffCommandLine = 'git diff "0ABCMERGE_BASE_342" --unified=0 --diff-filter=AM | grep -v -e \'^[+-]\' -e \'^index\'';
}

$shellCommandLineExecutor = $this->createMock(ShellCommandLineExecutor::class);

$shellCommandLineExecutor->expects($this->any())
->method('execute')
->willReturnCallback(function (string $command) use ($expectedDiffCommandLine, $expectedMergeBaseCommandLine): string {
switch ($command) {
case $expectedMergeBaseCommandLine:
return '0ABCMERGE_BASE_342';
case $expectedDiffCommandLine:
return '<LINE BY LINE GIT DIFF>';
default:
$this->fail("Unexpected shell command: $command");
}
});

$diffProvider = new GitDiffFileProvider($shellCommandLineExecutor);
$filter = $diffProvider->provideWithLines('master');

$this->assertSame('<LINE BY LINE GIT DIFF>', $filter);
}
}