Merge pull request #2375 from gena01/github-ee
Fixing #728 Adding basic support for Github Enterprisepull/2397/head
commit
d3ff302194
|
@ -655,6 +655,8 @@ The following options are supported:
|
|||
* **prepend-autoloader:** Defaults to `true`. If false, the composer autoloader
|
||||
will not be prepended to existing autoloaders. This is sometimesrequired to fix
|
||||
interoperability issues with other autoloaders.
|
||||
* **github-domains:** Defaults to `["github.com"]`. A list of domains to use in
|
||||
github mode. This is used for GitHub Enterprise setups.
|
||||
* **notify-on-install:** Defaults to `true`. Composer allows repositories to
|
||||
define a notification URL, so that they get notified whenever a package from
|
||||
that repository is installed. This option allows you to disable that behaviour.
|
||||
|
|
|
@ -179,6 +179,13 @@
|
|||
"prepend-autoloader": {
|
||||
"type": "boolean",
|
||||
"description": "If false, the composer autoloader will not be prepended to existing autoloaders, defaults to true."
|
||||
},
|
||||
"github-domains": {
|
||||
"type": "array",
|
||||
"description": "A list of domains to use in github mode. This is used for GitHub Enterprise setups, defaults to [\"github.com\"].",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -308,6 +308,18 @@ EOT
|
|||
return $vals;
|
||||
}
|
||||
),
|
||||
'github-domains' => array(
|
||||
function ($vals) {
|
||||
if (!is_array($vals)) {
|
||||
return 'array expected';
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
function ($vals) {
|
||||
return $vals;
|
||||
}
|
||||
),
|
||||
);
|
||||
|
||||
foreach ($uniqueConfigValues as $name => $callbacks) {
|
||||
|
|
|
@ -36,6 +36,7 @@ class Config
|
|||
'cache-files-maxsize' => '300MiB',
|
||||
'discard-changes' => false,
|
||||
'prepend-autoloader' => true,
|
||||
'github-domains' => array('github.com'),
|
||||
);
|
||||
|
||||
public static $defaultRepositories = array(
|
||||
|
|
|
@ -293,7 +293,7 @@ class GitDownloader extends VcsDownloader
|
|||
}
|
||||
|
||||
// public github, autoswitch protocols
|
||||
if (preg_match('{^(?:https?|git)(://github.com/.*)}', $url, $match)) {
|
||||
if (preg_match('{^(?:https?|git)(://'.$this->getGitHubDomainsRegex().'/.*)}', $url, $match)) {
|
||||
$protocols = $this->config->get('github-protocols');
|
||||
if (!is_array($protocols)) {
|
||||
throw new \RuntimeException('Config value "github-protocols" must be an array, got '.gettype($protocols));
|
||||
|
@ -317,7 +317,7 @@ class GitDownloader extends VcsDownloader
|
|||
$command = call_user_func($commandCallable, $url);
|
||||
if (0 !== $this->process->execute($command, $ignoredOutput, $cwd)) {
|
||||
// private github repository without git access, try https with auth
|
||||
if (preg_match('{^git@(github.com):(.+?)\.git$}i', $url, $match)) {
|
||||
if (preg_match('{^git@'.$this->getGitHubDomainsRegex().':(.+?)\.git$}i', $url, $match)) {
|
||||
if (!$this->io->hasAuthentication($match[1])) {
|
||||
$gitHubUtil = new GitHub($this->io, $this->config, $this->process);
|
||||
$message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
|
||||
|
@ -368,6 +368,11 @@ class GitDownloader extends VcsDownloader
|
|||
}
|
||||
}
|
||||
|
||||
protected function getGitHubDomainsRegex()
|
||||
{
|
||||
return '('.implode('|', array_map('preg_quote', $this->config->get('github-domains'))).')';
|
||||
}
|
||||
|
||||
protected function throwException($message, $url)
|
||||
{
|
||||
if (0 !== $this->process->execute('git --version', $ignoredOutput)) {
|
||||
|
@ -385,11 +390,11 @@ class GitDownloader extends VcsDownloader
|
|||
protected function setPushUrl(PackageInterface $package, $path)
|
||||
{
|
||||
// set push url for github projects
|
||||
if (preg_match('{^(?:https?|git)://github.com/([^/]+)/([^/]+?)(?:\.git)?$}', $package->getSourceUrl(), $match)) {
|
||||
if (preg_match('{^(?:https?|git)://'.$this->getGitHubDomainsRegex().'/([^/]+)/([^/]+?)(?:\.git)?$}', $package->getSourceUrl(), $match)) {
|
||||
$protocols = $this->config->get('github-protocols');
|
||||
$pushUrl = 'git@github.com:'.$match[1].'/'.$match[2].'.git';
|
||||
$pushUrl = 'git@'.$match[1].':'.$match[2].'/'.$match[3].'.git';
|
||||
if ($protocols[0] !== 'git') {
|
||||
$pushUrl = 'https://github.com/'.$match[1].'/'.$match[2].'.git';
|
||||
$pushUrl = 'https://' . $match[1] . '/'.$match[2].'/'.$match[3].'.git';
|
||||
}
|
||||
$cmd = sprintf('git remote set-url --push origin %s', escapeshellarg($pushUrl));
|
||||
$this->process->execute($cmd, $ignoredOutput, $path);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Repository\Vcs;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
|
@ -140,7 +141,7 @@ class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false)
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
|
||||
{
|
||||
if (!preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $url)) {
|
||||
return false;
|
||||
|
|
|
@ -18,6 +18,7 @@ use Composer\Util\Filesystem;
|
|||
use Composer\Util\Git as GitUtil;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Cache;
|
||||
use Composer\Config;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
|
@ -211,7 +212,7 @@ class GitDriver extends VcsDriver
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false)
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
|
||||
{
|
||||
if (preg_match('#(^git://|\.git$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) {
|
||||
return true;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Repository\Vcs;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\Downloader\TransportException;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Cache;
|
||||
|
@ -45,10 +46,10 @@ class GitHubDriver extends VcsDriver
|
|||
*/
|
||||
public function initialize()
|
||||
{
|
||||
preg_match('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $this->url, $match);
|
||||
$this->owner = $match[1];
|
||||
$this->repository = $match[2];
|
||||
$this->originUrl = 'github.com';
|
||||
preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):)([^/]+)/(.+?)(?:\.git)?$#', $this->url, $match);
|
||||
$this->owner = $match[3];
|
||||
$this->repository = $match[4];
|
||||
$this->originUrl = isset($match[1]) ? $match[1] : $match[2];
|
||||
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
|
||||
|
||||
$this->fetchRootIdentifier();
|
||||
|
@ -75,7 +76,21 @@ class GitHubDriver extends VcsDriver
|
|||
return $this->gitDriver->getUrl();
|
||||
}
|
||||
|
||||
return 'https://github.com/'.$this->owner.'/'.$this->repository.'.git';
|
||||
return 'https://' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getApiUrl()
|
||||
{
|
||||
if ('github.com' === $this->originUrl) {
|
||||
$apiUrl = 'api.github.com';
|
||||
} else {
|
||||
$apiUrl = $this->originUrl . '/api/v3';
|
||||
}
|
||||
|
||||
return 'https://' . $apiUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +120,8 @@ class GitHubDriver extends VcsDriver
|
|||
if ($this->gitDriver) {
|
||||
return $this->gitDriver->getDist($identifier);
|
||||
}
|
||||
$url = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/zipball/'.$identifier;
|
||||
|
||||
$url = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/zipball/'.$identifier;
|
||||
|
||||
return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
|
||||
}
|
||||
|
@ -127,7 +143,7 @@ class GitHubDriver extends VcsDriver
|
|||
$notFoundRetries = 2;
|
||||
while ($notFoundRetries) {
|
||||
try {
|
||||
$resource = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/contents/composer.json?ref='.urlencode($identifier);
|
||||
$resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/contents/composer.json?ref='.urlencode($identifier);
|
||||
$composer = JsonFile::parseJson($this->getContents($resource));
|
||||
if (empty($composer['content']) || $composer['encoding'] !== 'base64' || !($composer = base64_decode($composer['content']))) {
|
||||
throw new \RuntimeException('Could not retrieve composer.json from '.$resource);
|
||||
|
@ -149,16 +165,16 @@ class GitHubDriver extends VcsDriver
|
|||
$composer = JsonFile::parseJson($composer, $resource);
|
||||
|
||||
if (!isset($composer['time'])) {
|
||||
$resource = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/commits/'.urlencode($identifier);
|
||||
$resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/commits/'.urlencode($identifier);
|
||||
$commit = JsonFile::parseJson($this->getContents($resource), $resource);
|
||||
$composer['time'] = $commit['commit']['committer']['date'];
|
||||
}
|
||||
if (!isset($composer['support']['source'])) {
|
||||
$label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier;
|
||||
$composer['support']['source'] = sprintf('https://github.com/%s/%s/tree/%s', $this->owner, $this->repository, $label);
|
||||
$composer['support']['source'] = sprintf('https://%s/%s/%s/tree/%s', $this->originUrl, $this->owner, $this->repository, $label);
|
||||
}
|
||||
if (!isset($composer['support']['issues']) && $this->hasIssues) {
|
||||
$composer['support']['issues'] = sprintf('https://github.com/%s/%s/issues', $this->owner, $this->repository);
|
||||
$composer['support']['issues'] = sprintf('https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +197,7 @@ class GitHubDriver extends VcsDriver
|
|||
return $this->gitDriver->getTags();
|
||||
}
|
||||
if (null === $this->tags) {
|
||||
$resource = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags';
|
||||
$resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/tags';
|
||||
$tagsData = JsonFile::parseJson($this->getContents($resource), $resource);
|
||||
$this->tags = array();
|
||||
foreach ($tagsData as $tag) {
|
||||
|
@ -201,7 +217,7 @@ class GitHubDriver extends VcsDriver
|
|||
return $this->gitDriver->getBranches();
|
||||
}
|
||||
if (null === $this->branches) {
|
||||
$resource = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads';
|
||||
$resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads';
|
||||
$branchData = JsonFile::parseJson($this->getContents($resource), $resource);
|
||||
$this->branches = array();
|
||||
foreach ($branchData as $branch) {
|
||||
|
@ -216,9 +232,14 @@ class GitHubDriver extends VcsDriver
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false)
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
|
||||
{
|
||||
if (!preg_match('#^((?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url)) {
|
||||
if (!preg_match('#^((?:https?|git)://([^/]+)/|git@([^:]+):)([^/]+)/(.+?)(?:\.git)?$#', $url, $matches)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$originUrl = isset($matches[2]) ? $matches[2] : $matches[3];
|
||||
if (!in_array($originUrl, $config->get('github-domains'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -240,7 +261,7 @@ class GitHubDriver extends VcsDriver
|
|||
*/
|
||||
protected function generateSshUrl()
|
||||
{
|
||||
return 'git@github.com:'.$this->owner.'/'.$this->repository.'.git';
|
||||
return 'git@' . $this->originUrl . ':'.$this->owner.'/'.$this->repository.'.git';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -357,7 +378,7 @@ class GitHubDriver extends VcsDriver
|
|||
*/
|
||||
protected function fetchRootIdentifier()
|
||||
{
|
||||
$repoDataUrl = 'https://api.github.com/repos/'.$this->owner.'/'.$this->repository;
|
||||
$repoDataUrl = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository;
|
||||
|
||||
$repoData = JsonFile::parseJson($this->getContents($repoDataUrl, true), $repoDataUrl);
|
||||
if (null === $repoData && null !== $this->gitDriver) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Repository\Vcs;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
|
@ -150,7 +151,7 @@ class HgBitbucketDriver extends VcsDriver
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false)
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
|
||||
{
|
||||
if (!preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url)) {
|
||||
return false;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Repository\Vcs;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\Util\Filesystem;
|
||||
|
@ -189,7 +190,7 @@ class HgDriver extends VcsDriver
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false)
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
|
||||
{
|
||||
if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) {
|
||||
return true;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Repository\Vcs;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\Util\Perforce;
|
||||
|
@ -158,7 +159,7 @@ class PerforceDriver extends VcsDriver
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false)
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
|
||||
{
|
||||
if ($deep || preg_match('#\b(perforce|p4)\b#i', $url)) {
|
||||
return Perforce::checkServerExists($url, new ProcessExecutor);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
namespace Composer\Repository\Vcs;
|
||||
|
||||
use Composer\Cache;
|
||||
use Composer\Config;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\Util\Filesystem;
|
||||
|
@ -241,7 +242,7 @@ class SvnDriver extends VcsDriver
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false)
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false)
|
||||
{
|
||||
$url = self::normalizeUrl($url);
|
||||
if (preg_match('#(^svn://|^svn\+ssh://|svn\.)#i', $url)) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Repository\Vcs;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\IO\IOInterface;
|
||||
|
||||
/**
|
||||
|
@ -90,10 +91,11 @@ interface VcsDriverInterface
|
|||
/**
|
||||
* Checks if this driver can handle a given url
|
||||
*
|
||||
* @param IOInterface $io IO instance
|
||||
* @param string $url
|
||||
* @param bool $deep unless true, only shallow checks (url matching typically) should be done
|
||||
* @param IOInterface $io IO instance
|
||||
* @param Config $config current $config
|
||||
* @param string $url URL to validate/check
|
||||
* @param bool $deep unless true, only shallow checks (url matching typically) should be done
|
||||
* @return bool
|
||||
*/
|
||||
public static function supports(IOInterface $io, $url, $deep = false);
|
||||
public static function supports(IOInterface $io, Config $config, $url, $deep = false);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ class VcsRepository extends ArrayRepository
|
|||
}
|
||||
|
||||
foreach ($this->drivers as $driver) {
|
||||
if ($driver::supports($this->io, $this->url)) {
|
||||
if ($driver::supports($this->io, $this->config, $this->url)) {
|
||||
$driver = new $driver($this->repoConfig, $this->io, $this->config);
|
||||
$driver->initialize();
|
||||
|
||||
|
@ -89,7 +89,7 @@ class VcsRepository extends ArrayRepository
|
|||
}
|
||||
|
||||
foreach ($this->drivers as $driver) {
|
||||
if ($driver::supports($this->io, $this->url, true)) {
|
||||
if ($driver::supports($this->io, $this->config, $this->url, true)) {
|
||||
$driver = new $driver($this->repoConfig, $this->io, $this->config);
|
||||
$driver->initialize();
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ class GitHub
|
|||
*/
|
||||
public function authorizeOAuth($originUrl)
|
||||
{
|
||||
if ('github.com' !== $originUrl) {
|
||||
if (!in_array($originUrl, $this->config->get('github-domains'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,8 @@ class GitHub
|
|||
{
|
||||
$attemptCounter = 0;
|
||||
|
||||
$apiUrl = ('github.com' === $originUrl) ? 'api.github.com' : $originUrl . '/api/v3';
|
||||
|
||||
if ($message) {
|
||||
$this->io->write($message);
|
||||
}
|
||||
|
@ -95,7 +97,7 @@ class GitHub
|
|||
$appName .= ' on ' . trim($output);
|
||||
}
|
||||
|
||||
$contents = JsonFile::parseJson($this->remoteFilesystem->getContents($originUrl, 'https://api.github.com/authorizations', false, array(
|
||||
$contents = JsonFile::parseJson($this->remoteFilesystem->getContents($originUrl, 'https://'. $apiUrl . '/authorizations', false, array(
|
||||
'http' => array(
|
||||
'method' => 'POST',
|
||||
'follow_location' => false,
|
||||
|
|
|
@ -24,10 +24,7 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase
|
|||
$executor = $executor ?: $this->getMock('Composer\Util\ProcessExecutor');
|
||||
$filesystem = $filesystem ?: $this->getMock('Composer\Util\Filesystem');
|
||||
if (!$config) {
|
||||
$config = $this->getMock('Composer\Config');
|
||||
$config->expects($this->any())
|
||||
->method('has')
|
||||
->will($this->returnValue(false));
|
||||
$config = new Config();
|
||||
}
|
||||
|
||||
return new GitDownloader($io, $config, $executor, $filesystem);
|
||||
|
|
|
@ -104,7 +104,6 @@ class PerforceDriverTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testHasComposerFile()
|
||||
{
|
||||
$this->setUp();
|
||||
$repoConfig = array(
|
||||
'url' => 'TEST_PERFORCE_URL',
|
||||
'depot' => 'TEST_DEPOT_CONFIG',
|
||||
|
@ -131,17 +130,17 @@ class PerforceDriverTest extends \PHPUnit_Framework_TestCase
|
|||
$result = $driver->hasComposerFile($identifier);
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that supports() simply return false.
|
||||
*
|
||||
*
|
||||
* @covers \Composer\Repository\Vcs\PerforceDriver::supports
|
||||
*
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSupportsReturnsFalseNoDeepCheck()
|
||||
{
|
||||
$this->expectOutputString('');
|
||||
$this->assertFalse(PerforceDriver::supports($this->io, 'existing.url'));
|
||||
$this->assertFalse(PerforceDriver::supports($this->io, $this->config, 'existing.url'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,10 +80,8 @@ class SvnDriverTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testSupport($url, $assertion)
|
||||
{
|
||||
if ($assertion === true) {
|
||||
$this->assertTrue(SvnDriver::supports($this->getMock('Composer\IO\IOInterface'), $url));
|
||||
} else {
|
||||
$this->assertFalse(SvnDriver::supports($this->getMock('Composer\IO\IOInterface'), $url));
|
||||
}
|
||||
$config = new Config();
|
||||
$result = SvnDriver::supports($this->getMock('Composer\IO\IOInterface'), $config, $url);
|
||||
$this->assertEquals($assertion, $result);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue