Browse Source

Support GitLab repositories w/ port over HTTPs

When we have self-hosted GitLab, over HTTPs, on a different port.

rel composer/composer#6894
Renoir Boulanger 7 years ago
parent
commit
9f723ba381

+ 16 - 2
src/Composer/Repository/Vcs/GitLabDriver.php

@@ -66,7 +66,12 @@ class GitLabDriver extends VcsDriver
      */
     private $isPrivate = true;
 
-    const URL_REGEX = '#^(?:(?P<scheme>https?)://(?P<domain>.+?)/|git@(?P<domain2>[^:]+):)(?P<parts>.+)/(?P<repo>[^/]+?)(?:\.git|/)?$#';
+    /**
+     * @var int port number
+     */
+    protected $portNumber;
+
+    const URL_REGEX = '#^(?:(?P<scheme>https?)://(?P<domain>.+?)\:?(?P<port>[0-9]+)?/|git@(?P<domain2>[^:]+):)(?P<parts>.+)/(?P<repo>[^/]+?)(?:\.git|/)?$#';
 
     /**
      * Extracts information from the repository url.
@@ -90,6 +95,12 @@ class GitLabDriver extends VcsDriver
             : (isset($this->repoConfig['secure-http']) && $this->repoConfig['secure-http'] === false ? 'http' : 'https')
         ;
         $this->originUrl = $this->determineOrigin($configuredDomains, $guessedDomain, $urlParts);
+
+        if (!empty($match['port']) && true === is_numeric($match['port'])) {
+            // If it is an HTTP based URL, and it has a port
+            $this->portNumber = (int) $match['port'];
+        }
+
         $this->namespace = implode('/', $urlParts);
         $this->repository = preg_replace('#(\.git)$#', '', $match['repo']);
 
@@ -248,7 +259,9 @@ class GitLabDriver extends VcsDriver
      */
     public function getApiUrl()
     {
-        return $this->scheme.'://'.$this->originUrl.'/api/v4/projects/'.$this->urlEncodeAll($this->namespace).'%2F'.$this->urlEncodeAll($this->repository);
+        $domainName = $this->originUrl;
+        $portNumber = (true === is_numeric($this->portNumber)) ? sprintf(':%s', $this->portNumber) : '';
+        return $this->scheme.'://'.$domainName.$portNumber.'/api/v4/projects/'.$this->urlEncodeAll($this->namespace).'%2F'.$this->urlEncodeAll($this->repository);
     }
 
     /**
@@ -436,6 +449,7 @@ class GitLabDriver extends VcsDriver
      */
     public static function supports(IOInterface $io, Config $config, $url, $deep = false)
     {
+
         if (!preg_match(self::URL_REGEX, $url, $match)) {
             return false;
         }

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

@@ -38,6 +38,7 @@ class GitLabDriverTest extends TestCase
                 'home' => $this->home,
                 'gitlab-domains' => array(
                     'mycompany.com/gitlab',
+                    'gitlab.mycompany.com',
                     'othercompany.com/nested/gitlab',
                     'gitlab.com',
                 ),
@@ -180,6 +181,45 @@ JSON;
         return $driver;
     }
 
+    /**
+     * Also support repositories over HTTP (TLS) and has a port number.
+     *
+     * @group gitlabHttpPort
+     */
+    public function testInitializeWithPortNumber()
+    {
+        $domain = 'gitlab.mycompany.com';
+        $port = '5443';
+        $namespace = 'mygroup/myproject';
+        $url = sprintf('https://%1$s:%2$s/%3$s', $domain, $port, $namespace);
+        $apiUrl = sprintf('https://%1$s:%2$s/api/v4/projects/%3$s', $domain, $port, urlencode($namespace));
+
+        // An incomplete single project API response payload.
+        // @link http://doc.gitlab.com/ce/api/projects.html#get-single-project
+        $projectData = <<<'JSON'
+{
+    "default_branch": "1.0.x",
+    "http_url_to_repo": "https://%1$s:%2$s/%3$s.git",
+    "path": "myproject",
+    "path_with_namespace": "%3$s",
+    "web_url": "https://%1$s:%2$s/%3$s"
+}
+JSON;
+
+        $this->remoteFilesystem
+            ->getContents($domain, $apiUrl, false, array())
+            ->willReturn(sprintf($projectData, $domain, $port, $namespace))
+            ->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');
+        $this->assertEquals('1.0.x', $driver->getRootIdentifier(), 'Root identifier is the default branch in GitLab');
+        $this->assertEquals($url.'.git', $driver->getRepositoryUrl(), 'The repository URL is the SSH one by default');
+        $this->assertEquals($url, $driver->getUrl());
+    }
+
     public function testGetDist()
     {
         $driver = $this->testInitialize('https://gitlab.com/mygroup/myproject', 'https://gitlab.com/api/v4/projects/mygroup%2Fmyproject');
@@ -380,6 +420,7 @@ JSON;
     }
 
     /**
+     * @group gitlabHttpPort
      * @dataProvider dataForTestSupports
      */
     public function testSupports($url, $expected)
@@ -391,10 +432,14 @@ JSON;
     {
         return array(
             array('http://gitlab.com/foo/bar', true),
+            array('http://gitlab.mycompany.com:5443/foo/bar', true),
             array('http://gitlab.com/foo/bar/', true),
+            array('http://gitlab.com/foo/bar/', true),
+            array('http://gitlab.com/foo/bar.git', true),
             array('http://gitlab.com/foo/bar.git', true),
             array('http://gitlab.com/foo/bar.baz.git', true),
             array('https://gitlab.com/foo/bar', extension_loaded('openssl')), // Platform requirement
+            array('https://gitlab.mycompany.com:5443/foo/bar', extension_loaded('openssl')), // Platform requirement
             array('git@gitlab.com:foo/bar.git', extension_loaded('openssl')),
             array('git@example.com:foo/bar.git', false),
             array('http://example.com/foo/bar', false),