diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index ed4155c01..42c509580 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/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); } diff --git a/src/Composer/Repository/Vcs/GitLabDriver.php b/src/Composer/Repository/Vcs/GitLabDriver.php index c5d794321..3db305641 100644 --- a/src/Composer/Repository/Vcs/GitLabDriver.php +++ b/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 = '#^(?:(?Phttps?)://(?P.+?)/|git@(?P[^:]+):)(?P[^/]+)/(?P[^/]+?)(?:\.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('Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your credentials'); + $this->io->writeError('Failed to clone the '.$url.' repository, try running in interactive mode so that you can enter your credentials'); 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); diff --git a/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php index 2190410e3..02d40813b 100644 --- a/tests/Composer/Test/Repository/Vcs/GitLabDriverTest.php +++ b/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 = <<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'); } }