From 73139a59bfc90ece25c112a27ec6ea7aa2b67451 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 18 Apr 2016 10:10:12 +0100 Subject: [PATCH] Update origin remote URL when package URL changed and origin still uses the same url as the composer remote, fixes #3874 --- src/Composer/Downloader/GitDownloader.php | 33 +++++-- .../Test/Downloader/GitDownloaderTest.php | 95 +++++++++++++++++-- 2 files changed, 116 insertions(+), 12 deletions(-) diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index a167ee962..f98190d73 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -54,10 +54,10 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface $this->gitUtil->runCommand($commandCallable, $url, $path, true); if ($url !== $package->getSourceUrl()) { - $url = $package->getSourceUrl(); - $this->process->execute(sprintf('git remote set-url origin %s', ProcessExecutor::escape($url)), $output, $path); + $this->updateOriginUrl($path, $package->getSourceUrl()); + } else { + $this->setPushUrl($path, $url); } - $this->setPushUrl($path, $url); if ($newRef = $this->updateToCommit($path, $ref, $package->getPrettyVersion(), $package->getReleaseDate())) { if ($package->getDistReference() === $package->getSourceReference()) { @@ -77,6 +77,17 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface throw new \RuntimeException('The .git directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } + $updateOriginUrl = false; + if ( + 0 === $this->process->execute('git remote -v', $output, $path) + && preg_match('{^origin\s+(?P\S+)}m', $output, $originMatch) + && preg_match('{^composer\s+(?P\S+)}m', $output, $composerMatch) + ) { + if ($originMatch['url'] === $composerMatch['url'] && $composerMatch['url'] !== $target->getSourceUrl()) { + $updateOriginUrl = true; + } + } + $ref = $target->getSourceReference(); $this->io->writeError(" Checking out ".$ref); $command = 'git remote set-url composer %s && git fetch composer && git fetch --tags composer'; @@ -86,25 +97,29 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface }; $this->gitUtil->runCommand($commandCallable, $url, $path); - if ($newRef = $this->updateToCommit($path, $ref, $target->getPrettyVersion(), $target->getReleaseDate())) { + if ($newRef = $this->updateToCommit($path, $ref, $target->getPrettyVersion(), $target->getReleaseDate())) { if ($target->getDistReference() === $target->getSourceReference()) { $target->setDistReference($newRef); } $target->setSourceReference($newRef); } + + if ($updateOriginUrl) { + $this->updateOriginUrl($path, $target->getSourceUrl()); + } } /** * {@inheritDoc} */ - public function getLocalChanges(PackageInterface $package, $path, $showUntracked = false) + public function getLocalChanges(PackageInterface $package, $path) { GitUtil::cleanEnv(); if (!$this->hasMetadataRepository($path)) { return; } - $command = 'git status --porcelain' . ($showUntracked ? '' : ' --untracked-files=no'); + $command = 'git status --porcelain --untracked-files=no'; if (0 !== $this->process->execute($command, $output, $path)) { throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); } @@ -354,6 +369,12 @@ class GitDownloader extends VcsDownloader implements DvcsDownloaderInterface throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput()); } + protected function updateOriginUrl($path, $url) + { + $this->process->execute(sprintf('git remote set-url origin %s', ProcessExecutor::escape($url)), $output, $path); + $this->setPushUrl($path, $url); + } + protected function setPushUrl($path, $url) { // set push url for github projects diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index d5b57a287..1ad627aac 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -288,13 +288,17 @@ class GitDownloaderTest extends TestCase ->will($this->returnValue(0)); $processExecutor->expects($this->at(3)) ->method('execute') - ->with($this->equalTo($this->winCompat($expectedGitUpdateCommand)), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) + ->with($this->equalTo($this->winCompat("git remote -v"))) ->will($this->returnValue(0)); $processExecutor->expects($this->at(4)) ->method('execute') - ->with($this->equalTo('git branch -r')) + ->with($this->equalTo($this->winCompat($expectedGitUpdateCommand)), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) ->will($this->returnValue(0)); $processExecutor->expects($this->at(5)) + ->method('execute') + ->with($this->equalTo('git branch -r')) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(6)) ->method('execute') ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) ->will($this->returnValue(0)); @@ -304,6 +308,73 @@ class GitDownloaderTest extends TestCase $downloader->update($packageMock, $packageMock, $this->workingDir); } + public function testUpdateWithNewRepoUrl() + { + $expectedGitUpdateCommand = $this->winCompat("git remote set-url composer 'https://github.com/composer/composer' && git fetch composer && git fetch --tags composer"); + + $packageMock = $this->getMock('Composer\Package\PackageInterface'); + $packageMock->expects($this->any()) + ->method('getSourceReference') + ->will($this->returnValue('ref')); + $packageMock->expects($this->any()) + ->method('getSourceUrls') + ->will($this->returnValue(array('https://github.com/composer/composer'))); + $packageMock->expects($this->any()) + ->method('getSourceUrl') + ->will($this->returnValue('https://github.com/composer/composer')); + $packageMock->expects($this->any()) + ->method('getPrettyVersion') + ->will($this->returnValue('1.0.0')); + $processExecutor = $this->getMock('Composer\Util\ProcessExecutor'); + $processExecutor->expects($this->at(0)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git show-ref --head -d"))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(1)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git status --porcelain --untracked-files=no"))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(2)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git remote -v"))) + ->will($this->returnCallback(function ($cmd, &$output, $cwd) { + $output = 'origin https://github.com/old/url (fetch) +origin https://github.com/old/url (push) +composer https://github.com/old/url (fetch) +composer https://github.com/old/url (push) +'; + return 0; + })); + $processExecutor->expects($this->at(3)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git remote -v"))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(4)) + ->method('execute') + ->with($this->equalTo($this->winCompat($expectedGitUpdateCommand)), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(5)) + ->method('execute') + ->with($this->equalTo('git branch -r')) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(6)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(7)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git remote set-url origin 'https://github.com/composer/composer'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(8)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git remote set-url --push origin 'git@github.com:composer/composer.git'")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) + ->will($this->returnValue(0)); + + $this->fs->ensureDirectoryExists($this->workingDir.'/.git'); + $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor); + $downloader->update($packageMock, $packageMock, $this->workingDir); + } + /** * @group failing * @expectedException \RuntimeException @@ -333,6 +404,10 @@ class GitDownloaderTest extends TestCase ->with($this->equalTo($this->winCompat("git remote -v"))) ->will($this->returnValue(0)); $processExecutor->expects($this->at(3)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git remote -v"))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(4)) ->method('execute') ->with($this->equalTo($expectedGitUpdateCommand)) ->will($this->returnValue(1)); @@ -368,22 +443,30 @@ class GitDownloaderTest extends TestCase ->with($this->equalTo($this->winCompat("git remote -v"))) ->will($this->returnValue(0)); $processExecutor->expects($this->at(3)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git remote -v"))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(4)) ->method('execute') ->with($this->equalTo($expectedFirstGitUpdateCommand)) ->will($this->returnValue(1)); - $processExecutor->expects($this->at(5)) + $processExecutor->expects($this->at(6)) ->method('execute') ->with($this->equalTo($this->winCompat("git --version"))) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(6)) + $processExecutor->expects($this->at(7)) ->method('execute') ->with($this->equalTo($this->winCompat("git remote -v"))) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(7)) + $processExecutor->expects($this->at(8)) + ->method('execute') + ->with($this->equalTo($this->winCompat("git remote -v"))) + ->will($this->returnValue(0)); + $processExecutor->expects($this->at(9)) ->method('execute') ->with($this->equalTo($expectedSecondGitUpdateCommand)) ->will($this->returnValue(0)); - $processExecutor->expects($this->at(9)) + $processExecutor->expects($this->at(11)) ->method('execute') ->with($this->equalTo($this->winCompat("git checkout 'ref' -- && git reset --hard 'ref' --")), $this->equalTo(null), $this->equalTo($this->winCompat($this->workingDir))) ->will($this->returnValue(0));