Merge pull request #2375 from gena01/github-ee

Fixing #728 Adding basic support for Github Enterprise
main
Jordi Boggiano 11 years ago
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…
Cancel
Save