瀏覽代碼

Update origin remote URL when package URL changed and origin still uses the same url as the composer remote, fixes #3874

Jordi Boggiano 9 年之前
父節點
當前提交
73139a59bf
共有 2 個文件被更改,包括 115 次插入11 次删除
  1. 27 6
      src/Composer/Downloader/GitDownloader.php
  2. 88 5
      tests/Composer/Test/Downloader/GitDownloaderTest.php

+ 27 - 6
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<url>\S+)}m', $output, $originMatch)
+            && preg_match('{^composer\s+(?P<url>\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

+ 88 - 5
tests/Composer/Test/Downloader/GitDownloaderTest.php

@@ -288,16 +288,87 @@ 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($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));
+
+        $this->fs->ensureDirectoryExists($this->workingDir.'/.git');
+        $downloader = $this->getDownloaderMock(null, new Config(), $processExecutor);
+        $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);
@@ -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($expectedSecondGitUpdateCommand))
+            ->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(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));