Browse Source

Fix gitlab driver issues not asking for auth when token is missing, and not falling back properly to git driver

Jordi Boggiano 8 years ago
parent
commit
f200343cf2

+ 2 - 1
src/Composer/Repository/Vcs/GitHubDriver.php

@@ -212,7 +212,8 @@ class GitHubDriver extends VcsDriver
     /**
      * {@inheritdoc}
      */
-    public function getChangeDate($identifier) {
+    public function getChangeDate($identifier)
+    {
         if ($this->gitDriver) {
             return $this->gitDriver->getChangeDate($identifier);
         }

+ 66 - 4
src/Composer/Repository/Vcs/GitLabDriver.php

@@ -59,6 +59,13 @@ class GitLabDriver extends VcsDriver
      */
     protected $gitDriver;
 
+    /**
+     * Defaults to true unless we can make sure it is public
+     *
+     * @var bool defines whether the repo is private or not
+     */
+    private $isPrivate = true;
+
     const URL_REGEX = '#^(?:(?P<scheme>https?)://(?P<domain>.+?)/|git@(?P<domain2>[^:]+):)(?P<owner>[^/]+)/(?P<repo>[^/]+?)(?:\.git|/)?$#';
 
     /**
@@ -100,6 +107,10 @@ class GitLabDriver extends VcsDriver
      */
     public function getFileContent($file, $identifier)
     {
+        if ($this->gitDriver) {
+            return $this->gitDriver->getFileContent($file, $identifier);
+        }
+
         // Convert the root identifier to a cachable commit id
         if (!preg_match('{[a-f0-9]{40}}i', $identifier)) {
             $branches = $this->getBranches();
@@ -127,6 +138,10 @@ class GitLabDriver extends VcsDriver
      */
     public function getChangeDate($identifier)
     {
+        if ($this->gitDriver) {
+            return $this->gitDriver->getChangeDate($identifier);
+        }
+
         if (isset($this->commits[$identifier])) {
             return new \DateTime($this->commits[$identifier]['committed_date']);
         }
@@ -140,7 +155,7 @@ class GitLabDriver extends VcsDriver
      */
     public function getRepositoryUrl()
     {
-        return $this->project['public'] ? $this->project['http_url_to_repo'] : $this->project['ssh_url_to_repo'];
+        return $this->isPrivate ? $this->project['ssh_url_to_repo'] : $this->project['http_url_to_repo'];
     }
 
     /**
@@ -148,6 +163,10 @@ class GitLabDriver extends VcsDriver
      */
     public function getUrl()
     {
+        if ($this->gitDriver) {
+            return $this->gitDriver->getUrl();
+        }
+
         return $this->project['web_url'];
     }
 
@@ -166,6 +185,10 @@ class GitLabDriver extends VcsDriver
      */
     public function getSource($identifier)
     {
+        if ($this->gitDriver) {
+            return $this->gitDriver->getSource($identifier);
+        }
+
         return array('type' => 'git', 'url' => $this->getRepositoryUrl(), 'reference' => $identifier);
     }
 
@@ -174,6 +197,10 @@ class GitLabDriver extends VcsDriver
      */
     public function getRootIdentifier()
     {
+        if ($this->gitDriver) {
+            return $this->gitDriver->getRootIdentifier();
+        }
+
         return $this->project['default_branch'];
     }
 
@@ -182,6 +209,10 @@ class GitLabDriver extends VcsDriver
      */
     public function getBranches()
     {
+        if ($this->gitDriver) {
+            return $this->gitDriver->getBranches();
+        }
+
         if (!$this->branches) {
             $this->branches = $this->getReferences('branches');
         }
@@ -194,6 +225,10 @@ class GitLabDriver extends VcsDriver
      */
     public function getTags()
     {
+        if ($this->gitDriver) {
+            return $this->gitDriver->getTags();
+        }
+
         if (!$this->tags) {
             $this->tags = $this->getReferences('tags');
         }
@@ -257,21 +292,28 @@ class GitLabDriver extends VcsDriver
         // we need to fetch the default branch from the api
         $resource = $this->getApiUrl();
         $this->project = JsonFile::parseJson($this->getContents($resource, true), $resource);
+        $this->isPrivate = !$this->project['public'];
     }
 
     protected function attemptCloneFallback()
     {
         try {
+            if ($this->isPrivate === false) {
+                $url = $this->generatePublicUrl();
+            } else {
+                $url = $this->generateSshUrl();
+            }
+
             // If this repository may be private and we
             // cannot ask for authentication credentials (because we
             // are not interactive) then we fallback to GitDriver.
-            $this->setupGitDriver($this->generateSshUrl());
+            $this->setupGitDriver($url);
 
             return;
         } catch (\RuntimeException $e) {
             $this->gitDriver = null;
 
-            $this->io->writeError('<error>Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your credentials</error>');
+            $this->io->writeError('<error>Failed to clone the '.$url.' repository, try running in interactive mode so that you can enter your credentials</error>');
             throw $e;
         }
     }
@@ -286,6 +328,11 @@ class GitLabDriver extends VcsDriver
         return 'git@' . $this->originUrl . ':'.$this->owner.'/'.$this->repository.'.git';
     }
 
+    protected function generatePublicUrl()
+    {
+        return 'https://' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
+    }
+
     protected function setupGitDriver($url)
     {
         $this->gitDriver = new GitDriver(
@@ -304,7 +351,22 @@ class GitLabDriver extends VcsDriver
     protected function getContents($url, $fetchingRepoData = false)
     {
         try {
-            return parent::getContents($url);
+            $res = parent::getContents($url);
+
+            if ($fetchingRepoData) {
+                $json = JsonFile::parseJson($res, $url);
+
+                // force auth as the unauthenticated version of the API is broken
+                if (!isset($json['default_branch'])) {
+                    if (!empty($json['id'])) {
+                        $this->isPrivate = false;
+                    }
+
+                    throw new TransportException('GitLab API seems to not be authenticated as it did not return a default_branch', 401);
+                }
+            }
+
+            return $res;
         } catch (TransportException $e) {
             $gitLabUtil = new GitLab($this->io, $this->config, $this->process, $this->remoteFilesystem);
 

+ 23 - 0
tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php

@@ -293,8 +293,31 @@ JSON;
         $url = 'https://mycompany.com/gitlab/mygroup/my-pro.ject';
         $apiUrl = 'https://mycompany.com/gitlab/api/v3/projects/mygroup%2Fmy-pro%2Eject';
 
+        $projectData = <<<JSON
+{
+    "id": 17,
+    "default_branch": "mymaster",
+    "public": false,
+    "http_url_to_repo": "https://gitlab.com/mygroup/my-pro.ject",
+    "ssh_url_to_repo": "git@gitlab.com:mygroup/my-pro.ject.git",
+    "last_activity_at": "2014-12-01T09:17:51.000+01:00",
+    "name": "My Project",
+    "name_with_namespace": "My Group / My Project",
+    "path": "myproject",
+    "path_with_namespace": "mygroup/my-pro.ject",
+    "web_url": "https://gitlab.com/mygroup/my-pro.ject"
+}
+JSON;
+
+        $this->remoteFilesystem
+            ->getContents('mycompany.com/gitlab', $apiUrl, false)
+            ->willReturn($projectData)
+            ->shouldBeCalledTimes(1)
+        ;
+
         $driver  = new GitLabDriver(array('url' => $url), $this->io->reveal(), $this->config, $this->process->reveal(), $this->remoteFilesystem->reveal());
         $driver->initialize();
+
         $this->assertEquals($apiUrl, $driver->getApiUrl(), 'API URL is derived from the repository URL');
     }
 }