Skip to content
This repository has been archived by the owner on Apr 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #32 from niels-nijens/fix-git-1.7-pull
Browse files Browse the repository at this point in the history
Fix git pull on a checked out tag in GitAdapter
  • Loading branch information
niels-nijens committed Jun 6, 2016
2 parents b0c1a4d + 923b81c commit ca8c622
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 92 deletions.
28 changes: 24 additions & 4 deletions src/Adapter/GitAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function supportsRepository()
return false;
}

if (preg_match('#(^git://|\.git$|git(?:olite)?@|//git\.|//github.com/)#i', $this->repositoryUrl)) {
if (preg_match('#(^git://|\.git$|git(?:olite)?@|//git\.|//github.com/)#i', $this->repositoryUrl) === 1) {
return true;
}

Expand All @@ -44,7 +44,7 @@ public function getBranches()
if ($result->isSuccessful()) {
foreach ($result->getOutputAsArray() as $branch) {
$matches = array();
if (preg_match('#^([a-f0-9]{40})\s+refs\/heads\/(\S+)$#', $branch, $matches)) {
if (preg_match('#^([a-f0-9]{40})\s+refs\/heads\/(\S+)$#', $branch, $matches) === 1) {
$branches[$matches[1]] = $matches[2];
}
}
Expand All @@ -64,7 +64,7 @@ public function getTags()
if ($result->isSuccessful()) {
foreach ($result->getOutputAsArray() as $tag) {
$matches = array();
if (preg_match('#^([a-f0-9]{40})\s+refs\/tags\/([\S]+)\^{}$#', $tag, $matches)) {
if (preg_match('#^([a-f0-9]{40})\s+refs\/tags\/([\S]+)\^{}$#', $tag, $matches) === 1) {
$tags[$matches[1]] = $matches[2];
}
}
Expand All @@ -82,7 +82,27 @@ public function checkout($version)

$escapedVersion = ProcessUtils::escapeArgument($version);
if ($this->processExecutor->isDirectory($this->repositoryDirectory) && $this->processExecutor->execute('git rev-parse --is-inside-work-tree', $this->repositoryDirectory)->isSuccessful()) {
$checkoutSuccesful = ($this->processExecutor->execute('git fetch', $this->repositoryDirectory, $this->getEnvironmentVariables())->isSuccessful() && $this->processExecutor->execute(sprintf('git checkout %s', $escapedVersion), $this->repositoryDirectory, $this->getEnvironmentVariables())->isSuccessful() && $this->processExecutor->execute('git pull', $this->repositoryDirectory, $this->getEnvironmentVariables())->isSuccessful());
$commands = array(
'git fetch',
sprintf('git checkout %s', $escapedVersion),
);

$checkoutSuccesful = true;
foreach ($commands as $command) {
$result = $this->processExecutor->execute($command, $this->repositoryDirectory, $this->getEnvironmentVariables());
if ($result->isSuccessful() === false) {
$checkoutSuccesful = false;

break;
}
}

$result = $this->processExecutor->execute('git branch', $this->repositoryDirectory, $this->getEnvironmentVariables());

$checkoutSuccesful = $checkoutSuccesful && $result->isSuccessful();
if (preg_match('#^ \*.*(?:no branch|HEAD detached at)#', $result->getOutput()) === 0) {
$checkoutSuccesful = $checkoutSuccesful && $this->processExecutor->execute('git pull', $this->repositoryDirectory, $this->getEnvironmentVariables())->isSuccessful();
}
} else {
$escapedRepositoryUrl = ProcessUtils::escapeArgument($this->repositoryUrl);
$escapedRepositoryDirectory = ProcessUtils::escapeArgument($this->repositoryDirectory);
Expand Down
264 changes: 176 additions & 88 deletions tests/Adapter/GitAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@
*/
class GitAdapterTest extends PHPUnit_Framework_TestCase
{
/**
* The URL of the repository used for testing.
*
* @var string
*/
private $repositoryUrl = 'https://github.com/accompli/chrono.git';

/**
* The expected clone command.
*
* @var string
*/
private $cloneCommand = "git clone -b '0.1.0' --single-branch 'https://github.com/accompli/chrono.git' '/git/working-directory'";

/**
* Tests if GitAdapter::supportsRepository returns the expected result.
*
Expand All @@ -41,7 +55,7 @@ public function testSupportsRepository($repositoryUrl, ProcessExecutorInterface
*/
public function testGetBranches(ProcessExecutorInterface $processExecutor, array $expectedResult)
{
$gitAdapter = new GitAdapter('https://github.com/accompli/chrono.git', '', $processExecutor);
$gitAdapter = new GitAdapter($this->repositoryUrl, '', $processExecutor);

$this->assertSame($expectedResult, $gitAdapter->getBranches());
}
Expand All @@ -56,24 +70,175 @@ public function testGetBranches(ProcessExecutorInterface $processExecutor, array
*/
public function testGetTags(ProcessExecutorInterface $processExecutor, array $expectedResult)
{
$gitAdapter = new GitAdapter('https://github.com/accompli/chrono.git', '', $processExecutor);
$gitAdapter = new GitAdapter($this->repositoryUrl, '', $processExecutor);

$this->assertSame($expectedResult, $gitAdapter->getTags());
}

/**
* Tests if GitAdapter::checkout returns the expected result.
*
* @dataProvider provideTestCheckout
*
* @param ProcessExecutorInterface $processExecutor
* @param bool $expectedResult
* Tests if GitAdapter::checkout clones when the specified working directory does not exist.
*/
public function testCheckout(ProcessExecutorInterface $processExecutor, $expectedResult)
public function testCheckoutWithoutExistingCloneSuccesful()
{
$gitAdapter = new GitAdapter('https://github.com/accompli/chrono.git', '/git/working-directory', $processExecutor);
$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->with($this->equalTo('/git/working-directory'))
->willReturn(false);
$processExecutorMock->expects($this->once())
->method('execute')
->with($this->equalTo($this->cloneCommand), $this->equalTo(null), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
->willReturn(new ProcessExecutionResult(0, '', ''));

$gitAdapter = new GitAdapter($this->repositoryUrl, '/git/working-directory', $processExecutorMock);

$this->assertSame($expectedResult, $gitAdapter->checkout('0.1.0'));
$this->assertTrue($gitAdapter->checkout('0.1.0'));
}

/**
* Tests if GitAdapter::checkout clones when the specified working directory does not exist and returns false when it fails.
*/
public function testCheckoutWithoutExistingCloneFailure()
{
$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->with($this->equalTo('/git/working-directory'))
->willReturn(false);
$processExecutorMock->expects($this->once())
->method('execute')
->with($this->equalTo($this->cloneCommand), $this->equalTo(null), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
->willReturn(new ProcessExecutionResult(1, '', ''));

$gitAdapter = new GitAdapter($this->repositoryUrl, '/git/working-directory', $processExecutorMock);

$this->assertFalse($gitAdapter->checkout('0.1.0'));
}

/**
* Tests if GitAdapter::checkout calls the commands to checkout a tag.
*/
public function testCheckoutTagWithExistingClone()
{
$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->with($this->equalTo('/git/working-directory'))
->willReturn(true);
$processExecutorMock->expects($this->exactly(4))
->method('execute')
->withConsecutive(
array($this->equalTo('git rev-parse --is-inside-work-tree'), $this->equalTo('/git/working-directory'), $this->equalTo(null)),
array($this->equalTo('git fetch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo("git checkout '0.1.0'"), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo('git branch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
)
->willReturnOnConsecutiveCalls(
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, " * (no branch)\n", '')
);

$gitAdapter = new GitAdapter($this->repositoryUrl, '/git/working-directory', $processExecutorMock);

$this->assertTrue($gitAdapter->checkout('0.1.0'));
}

/**
* Tests if GitAdapter::checkout calls the commands to checkout a tag and returns false when it fails.
*/
public function testCheckoutTagWithExistingCloneFailure()
{
$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->with($this->equalTo('/git/working-directory'))
->willReturn(true);
$processExecutorMock->expects($this->exactly(3))
->method('execute')
->withConsecutive(
array($this->equalTo('git rev-parse --is-inside-work-tree'), $this->equalTo('/git/working-directory'), $this->equalTo(null)),
array($this->equalTo('git fetch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo('git branch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
)
->willReturnOnConsecutiveCalls(
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(1, '', ''),
new ProcessExecutionResult(0, " * (no branch)\n", '')
);

$gitAdapter = new GitAdapter($this->repositoryUrl, '/git/working-directory', $processExecutorMock);

$this->assertFalse($gitAdapter->checkout('0.1.0'));
}

/**
* Tests if GitAdapter::checkout calls the commands to checkout a branch.
*/
public function testCheckoutBranchWithExistingClone()
{
$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->with($this->equalTo('/git/working-directory'))
->willReturn(true);
$processExecutorMock->expects($this->exactly(5))
->method('execute')
->withConsecutive(
array($this->equalTo('git rev-parse --is-inside-work-tree'), $this->equalTo('/git/working-directory'), $this->equalTo(null)),
array($this->equalTo('git fetch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo("git checkout 'master'"), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo('git branch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo('git pull'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
)
->willReturnOnConsecutiveCalls(
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, " * master\n", ''),
new ProcessExecutionResult(0, '', '')
);

$gitAdapter = new GitAdapter($this->repositoryUrl, '/git/working-directory', $processExecutorMock);

$this->assertTrue($gitAdapter->checkout('master'));
}

/**
* Tests if GitAdapter::checkout calls the commands to checkout a branch and returns false when it fails.
*/
public function testCheckoutBranchWithExistingCloneFailure()
{
$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->with($this->equalTo('/git/working-directory'))
->willReturn(true);
$processExecutorMock->expects($this->exactly(4))
->method('execute')
->withConsecutive(
array($this->equalTo('git rev-parse --is-inside-work-tree'), $this->equalTo('/git/working-directory'), $this->equalTo(null)),
array($this->equalTo('git fetch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo("git checkout 'master'"), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo('git branch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
)
->willReturnOnConsecutiveCalls(
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(1, '', '')
);

$gitAdapter = new GitAdapter($this->repositoryUrl, '/git/working-directory', $processExecutorMock);

$this->assertFalse($gitAdapter->checkout('master'));
}

/**
Expand Down Expand Up @@ -199,81 +364,4 @@ public function provideTestGetTags()

return $provideTest;
}

/**
* Returns the test data and expected results for testing GitAdapter::checkout.
*
* @return array
*/
public function provideTestCheckout()
{
$cloneCommand = sprintf('git clone -b %s --single-branch %s %s', ProcessUtils::escapeArgument('0.1.0'), ProcessUtils::escapeArgument('https://github.com/accompli/chrono.git'), ProcessUtils::escapeArgument('/git/working-directory'));
$checkoutCommand = sprintf('git checkout %s', ProcessUtils::escapeArgument('0.1.0'));

$provideTest = array();

$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->willReturn(false);
$processExecutorMock->expects($this->once())
->method('execute')
->with($this->equalTo($cloneCommand), $this->equalTo(null), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
->willReturn(new ProcessExecutionResult(1, '', ''));
$provideTest[] = array($processExecutorMock, false);

$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->willReturn(true);
$processExecutorMock->expects($this->exactly(3))
->method('execute')
->withConsecutive(
array($this->equalTo('git rev-parse --is-inside-work-tree'), $this->equalTo('/git/working-directory'), $this->equalTo(null)),
array($this->equalTo('git fetch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo($checkoutCommand), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
)
->willReturnOnConsecutiveCalls(
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(1, '', '')
);
$provideTest[] = array($processExecutorMock, false);

$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->willReturn(false);
$processExecutorMock->expects($this->once())
->method('execute')
->with($this->equalTo($cloneCommand), $this->equalTo(null), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
->willReturn(new ProcessExecutionResult(0, '', ''));
$provideTest[] = array($processExecutorMock, true);

$processExecutorMock = $this->getMockBuilder(ProcessExecutorInterface::class)
->getMock();
$processExecutorMock->expects($this->once())
->method('isDirectory')
->willReturn(true);
$processExecutorMock->expects($this->exactly(4))
->method('execute')
->withConsecutive(
array($this->equalTo('git rev-parse --is-inside-work-tree'), $this->equalTo('/git/working-directory'), $this->equalTo(null)),
array($this->equalTo('git fetch'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo($checkoutCommand), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo'))),
array($this->equalTo('git pull'), $this->equalTo('/git/working-directory'), $this->equalTo(array('GIT_TERMINAL_PROMPT' => '0', 'GIT_ASKPASS' => 'echo')))
)
->willReturnOnConsecutiveCalls(
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', ''),
new ProcessExecutionResult(0, '', '')
);
$provideTest[] = array($processExecutorMock, true);

return $provideTest;
}
}

0 comments on commit ca8c622

Please sign in to comment.