diff --git a/doc/04-schema.md b/doc/04-schema.md index 7c66813af..6e273c1a0 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -276,10 +276,11 @@ Example: All links are optional fields. -`require` and `require-dev` additionally support stability flags ([root-only](04-schema.md#root-package)). +`require` and `require-dev` additionally support _stability flags_ ([root-only](04-schema.md#root-package)). +They take the form "_constraint_@_stability flag_". These allow you to further restrict or expand the stability of a package beyond the scope of the [minimum-stability](#minimum-stability) setting. You can apply -them to a constraint, or apply them to an empty constraint if you want to +them to a constraint, or apply them to an empty _constraint_ if you want to allow unstable packages of a dependency for example. Example: diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index 329230e2e..56e994036 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -111,6 +111,14 @@ To disable packagist: You can alter repositories in the global config.json file by passing in the --global option. +To add or edit suggested packages you can use: + + %command.full_name% suggest.package reason for the suggestion + +To add or edit extra properties you can use: + + %command.full_name% extra.property value + To edit the file in an external editor: %command.full_name% --editor @@ -478,6 +486,23 @@ EOT return 0; } + // handle preferred-install per-package config + if (preg_match('/^preferred-install\.(.+)/', $settingKey, $matches)) { + if ($input->getOption('unset')) { + $this->configSource->removeConfigSetting($settingKey); + + return 0; + } + + list($validator) = $uniqueConfigValues['preferred-install']; + if (!$validator($values[0])) { + throw new \RuntimeException('Invalid value for '.$settingKey.'. Should be one of: auto, source, or dist'); + } + + $this->configSource->addConfigSetting($settingKey, $values[0]); + + return 0; + } // handle properties $uniqueProps = array( @@ -601,6 +626,26 @@ EOT return 0; } + // handle suggest + if (preg_match('/^suggest\.(.+)/', $settingKey, $matches)) { + if ($input->getOption('unset')) { + $this->configSource->removeProperty($settingKey); + + return 0; + } + + $this->configSource->addProperty($settingKey, implode(' ', $values)); + + return 0; + } + + // handle unsetting extra/suggest + if (in_array($settingKey, array('suggest', 'extra'), true) && $input->getOption('unset')) { + $this->configSource->removeProperty($settingKey); + + return 0; + } + // handle platform if (preg_match('/^platform\.(.+)/', $settingKey, $matches)) { if ($input->getOption('unset')) { @@ -613,6 +658,8 @@ EOT return 0; } + + // handle unsetting platform if ($settingKey === 'platform' && $input->getOption('unset')) { $this->configSource->removeConfigSetting($settingKey); diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index d953809a7..b2b08e6f0 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -172,6 +172,8 @@ EOT $io->write(sprintf('PHP binary path: %s', PHP_BINARY)); } + $io->write(sprintf('OpenSSL version: %s', OPENSSL_VERSION_TEXT)); + return $this->exitCode; } diff --git a/src/Composer/Command/ExecCommand.php b/src/Composer/Command/ExecCommand.php index c9184c707..d530def66 100644 --- a/src/Composer/Command/ExecCommand.php +++ b/src/Composer/Command/ExecCommand.php @@ -39,7 +39,7 @@ class ExecCommand extends BaseCommand ->setHelp( <<setVerbosity(OutputInterface::VERBOSITY_QUIET); } + // If the CWD was modified, we restore it to what it was initially, as it was + // most likely modified by the global command, and we want exec to run in the local working directory + // not the global one + if (getcwd() !== $this->getApplication()->getInitialWorkingDirectory()) { + try { + chdir($this->getApplication()->getInitialWorkingDirectory()); + } catch (\Exception $e) { + throw new \RuntimeException('Could not switch back to working directory "'.$this->getApplication()->getWorkingDirectory().'"', 0, $e); + } + } + return $dispatcher->dispatchScript('__exec_command', true, $input->getArgument('args')); } } diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 1c7704e83..92db88cfa 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -438,11 +438,34 @@ EOT } $versionParser = new VersionParser(); + + // Collect existing packages + $composer = $this->getComposer(false); + $installedRepo = $composer ? $composer->getRepositoryManager()->getLocalRepository() : null; + $existingPackages = []; + if ($installedRepo) { + foreach ($installedRepo->getPackages() as $package) { + $existingPackages[] = $package->getName(); + } + } + foreach ($requires as $requiredPackage) { + $existingPackages[] = substr($requiredPackage, 0, strpos($requiredPackage, ' ')); + } + unset($composer, $installedRepo, $requiredPackage); + $io = $this->getIO(); while (null !== $package = $io->ask('Search for a package: ')) { $matches = $this->findPackages($package); if (count($matches)) { + // Remove existing packages from search results. + foreach ($matches as $position => $foundPackage) { + if (in_array($foundPackage['name'], $existingPackages, true)) { + unset($matches[$position]); + } + } + $matches = array_values($matches); + $exactMatch = null; $choices = array(); foreach ($matches as $position => $foundPackage) { @@ -540,6 +563,7 @@ EOT if (false !== $package) { $requires[] = $package; + $existingPackages[] = substr($package, 0, strpos($package, ' ')); } } } @@ -794,7 +818,13 @@ EOT } $similarPackages = array(); + $installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository(); + foreach ($results as $result) { + if ($installedRepo->findPackage($result['name'], '*')) { + // Ignore installed package + continue; + } $similarPackages[$result['name']] = levenshtein($package, $result['name']); } asort($similarPackages); diff --git a/src/Composer/Command/ValidateCommand.php b/src/Composer/Command/ValidateCommand.php index 5aba74adf..7ec15ccb9 100644 --- a/src/Composer/Command/ValidateCommand.php +++ b/src/Composer/Command/ValidateCommand.php @@ -93,7 +93,7 @@ EOT $composer = Factory::create($io, $file, $input->hasParameterOption('--no-plugins')); $locker = $composer->getLocker(); if ($locker->isLocked() && !$locker->isFresh()) { - $lockErrors[] = 'The lock file is not up to date with the latest changes in composer.json, it is recommended that you run `composer update`.'; + $lockErrors[] = 'The lock file is not up to date with the latest changes in composer.json, it is recommended that you run `composer update` or `composer update `.'; } $this->outputResult($io, $file, $errors, $warnings, $checkPublish, $publishErrors, $checkLock, $lockErrors, true, $isStrict); diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php index d9e7a4a56..4182298d6 100644 --- a/src/Composer/Console/Application.php +++ b/src/Composer/Console/Application.php @@ -62,6 +62,11 @@ class Application extends BaseApplication private $hasPluginCommands = false; private $disablePluginsByDefault = false; + /** + * @var string Store the initial working directory at startup time + */ + private $initialWorkingDirectory = ''; + public function __construct() { static $shutdownRegistered = false; @@ -91,6 +96,8 @@ class Application extends BaseApplication $this->io = new NullIO(); + $this->initialWorkingDirectory = getcwd(); + parent::__construct('Composer', Composer::getVersion()); } @@ -131,6 +138,7 @@ class Application extends BaseApplication if ($newWorkDir = $this->getNewWorkingDir($input)) { $oldWorkingDir = getcwd(); chdir($newWorkDir); + $this->initialWorkingDirectory = $newWorkDir; $io->writeError('Changed CWD to ' . getcwd(), true, IOInterface::DEBUG); } @@ -497,4 +505,14 @@ class Application extends BaseApplication return $commands; } + + /** + * Get the working directoy at startup time + * + * @return string + */ + public function getInitialWorkingDirectory() + { + return $this->initialWorkingDirectory; + } } diff --git a/src/Composer/Installer.php b/src/Composer/Installer.php index 87412f7ea..646bb4fcf 100644 --- a/src/Composer/Installer.php +++ b/src/Composer/Installer.php @@ -586,7 +586,7 @@ class Installer $request = $this->createRequest($this->fixedRootPackage, $platformRepo, $lockedRepository); if (!$this->locker->isFresh()) { - $this->io->writeError('Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.', true, IOInterface::QUIET); + $this->io->writeError('Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update `.', true, IOInterface::QUIET); } foreach ($lockedRepository->getPackages() as $package) { diff --git a/src/Composer/Json/JsonManipulator.php b/src/Composer/Json/JsonManipulator.php index e64a56f71..e1ee43485 100644 --- a/src/Composer/Json/JsonManipulator.php +++ b/src/Composer/Json/JsonManipulator.php @@ -167,6 +167,10 @@ class JsonManipulator public function addProperty($name, $value) { + if (substr($name, 0, 8) === 'suggest.') { + return $this->addSubNode('suggest', substr($name, 8), $value); + } + if (substr($name, 0, 6) === 'extra.') { return $this->addSubNode('extra', substr($name, 6), $value); } @@ -180,6 +184,10 @@ class JsonManipulator public function removeProperty($name) { + if (substr($name, 0, 8) === 'suggest.') { + return $this->removeSubNode('suggest', substr($name, 8)); + } + if (substr($name, 0, 6) === 'extra.') { return $this->removeSubNode('extra', substr($name, 6)); } diff --git a/src/Composer/Package/Archiver/ZipArchiver.php b/src/Composer/Package/Archiver/ZipArchiver.php index 65694cb88..b6cfaf73f 100644 --- a/src/Composer/Package/Archiver/ZipArchiver.php +++ b/src/Composer/Package/Archiver/ZipArchiver.php @@ -45,6 +45,18 @@ class ZipArchiver implements ArchiverInterface } else { $zip->addFile($filepath, $localname); } + + /** + * ZipArchive::setExternalAttributesName is available from >= PHP 5.6 + */ + if (PHP_VERSION_ID >= 50600) { + $perms = fileperms($filepath); + + /** + * Ensure to preserve the permission umasks for the filepath in the archive. + */ + $zip->setExternalAttributesName($localname, ZipArchive::OPSYS_UNIX, $perms << 16); + } } if ($zip->close()) { return $target; diff --git a/src/Composer/Package/Version/VersionGuesser.php b/src/Composer/Package/Version/VersionGuesser.php index d655bc080..918e9706a 100644 --- a/src/Composer/Package/Version/VersionGuesser.php +++ b/src/Composer/Package/Version/VersionGuesser.php @@ -60,7 +60,7 @@ class VersionGuesser * @param array $packageConfig * @param string $path Path to guess into * - * @return null|array versionData, 'version', 'pretty_version' and 'commit' keys + * @return null|array versionData, 'version', 'pretty_version' and 'commit' keys, if the version is a feature branch, 'feature_version' and 'feature_pretty_version' keys may also be returned */ public function guessVersion(array $packageConfig, $path) { @@ -89,10 +89,18 @@ class VersionGuesser private function postprocess(array $versionData) { + if (!empty($versionData['feature_version']) && $versionData['feature_version'] === $versionData['version'] && $versionData['feature_pretty_version'] === $versionData['feature_pretty_version']) { + unset($versionData['feature_version'], $versionData['feature_pretty_version']); + } + if ('-dev' === substr($versionData['version'], -4) && preg_match('{\.9{7}}', $versionData['version'])) { $versionData['pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['version']); } + if (!empty($versionData['feature_version']) && '-dev' === substr($versionData['feature_version'], -4) && preg_match('{\.9{7}}', $versionData['feature_version'])) { + $versionData['feature_pretty_version'] = preg_replace('{(\.9{7})+}', '.x', $versionData['feature_version']); + } + return $versionData; } @@ -102,6 +110,8 @@ class VersionGuesser $commit = null; $version = null; $prettyVersion = null; + $featureVersion = null; + $featurePrettyVersion = null; $isDetached = false; // try to fetch current version from git branch @@ -136,6 +146,8 @@ class VersionGuesser } if ($isFeatureBranch) { + $featureVersion = $version; + $featurePrettyVersion = $prettyVersion; // try to find the best (nearest) version branch to assume this feature's version $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path); $version = $result['version']; @@ -148,6 +160,8 @@ class VersionGuesser if ($result) { $version = $result['version']; $prettyVersion = $result['pretty_version']; + $featureVersion = null; + $featurePrettyVersion = null; } } @@ -158,6 +172,10 @@ class VersionGuesser } } + if ($featureVersion) { + return array('version' => $version, 'commit' => $commit, 'pretty_version' => $prettyVersion, 'feature_version' => $featureVersion, 'feature_pretty_version' => $featurePrettyVersion); + } + return array('version' => $version, 'commit' => $commit, 'pretty_version' => $prettyVersion); } @@ -200,6 +218,8 @@ class VersionGuesser // try to find the best (nearest) version branch to assume this feature's version $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"', $path); $result['commit'] = ''; + $result['feature_version'] = $version; + $result['feature_pretty_version'] = $version; return $result; } diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 02f2a05fe..8ff6da589 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -391,6 +391,14 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $this->loadProviderListings($this->loadRootServerFile()); } + if ($this->hasPartialPackages) { + if (null === $this->partialPackagesByName) { + $this->initializePartialPackages(); + } + + return array_keys($this->partialPackagesByName); + } + if ($this->lazyProvidersUrl) { // Can not determine list of provided packages for lazy repositories return array(); diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php index 2f26af2f7..4db774579 100644 --- a/src/Composer/Repository/PathRepository.php +++ b/src/Composer/Repository/PathRepository.php @@ -159,19 +159,26 @@ class PathRepository extends ArrayRepository implements ConfigurableRepositoryIn } } + $output = ''; + if (is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute('git log -n1 --pretty=%H', $output, $path)) { + $package['dist']['reference'] = trim($output); + } + if (!isset($package['version'])) { $versionData = $this->versionGuesser->guessVersion($package, $path); if (is_array($versionData) && $versionData['pretty_version']) { + // if there is a feature branch detected, we add a second packages with the feature branch version + if (!empty($versionData['feature_pretty_version'])) { + $package['version'] = $versionData['feature_pretty_version']; + $this->addPackage($this->loader->load($package)); + } + $package['version'] = $versionData['pretty_version']; } else { $package['version'] = 'dev-master'; } } - $output = ''; - if (is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute('git log -n1 --pretty=%H', $output, $path)) { - $package['dist']['reference'] = trim($output); - } $package = $this->loader->load($package); $this->addPackage($package); } diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index c9ed229b8..f99ad625f 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -35,6 +35,7 @@ class GitHubDriver extends VcsDriver protected $hasIssues; protected $infoCache = array(); protected $isPrivate = false; + private $isArchived = false; /** * Git Driver @@ -163,6 +164,9 @@ class GitHubDriver extends VcsDriver if (!isset($composer['support']['issues']) && $this->hasIssues) { $composer['support']['issues'] = sprintf('https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository); } + if (!isset($composer['abandoned']) && $this->isArchived) { + $composer['abandoned'] = true; + } } if ($this->shouldCache($identifier)) { @@ -432,6 +436,7 @@ class GitHubDriver extends VcsDriver $this->rootIdentifier = 'master'; } $this->hasIssues = !empty($this->repoData['has_issues']); + $this->isArchived = !empty($this->repoData['archived']); } protected function attemptCloneFallback() diff --git a/src/Composer/Repository/Vcs/GitLabDriver.php b/src/Composer/Repository/Vcs/GitLabDriver.php index a1f810bfa..f1cd5f76c 100644 --- a/src/Composer/Repository/Vcs/GitLabDriver.php +++ b/src/Composer/Repository/Vcs/GitLabDriver.php @@ -120,6 +120,42 @@ class GitLabDriver extends VcsDriver $this->httpDownloader = $httpDownloader; } + /** + * {@inheritDoc} + */ + public function getComposerInformation($identifier) + { + if ($this->gitDriver) { + return $this->gitDriver->getComposerInformation($identifier); + } + + if (!isset($this->infoCache[$identifier])) { + if ($this->shouldCache($identifier) && $res = $this->cache->read($identifier)) { + return $this->infoCache[$identifier] = JsonFile::parseJson($res); + } + + $composer = $this->getBaseComposerInformation($identifier); + + if ($composer) { + // specials for gitlab (this data is only available if authentication is provided) + if (!isset($composer['support']['issues']) && isset($this->project['_links']['issues'])) { + $composer['support']['issues'] = $this->project['_links']['issues']; + } + if (!isset($composer['abandoned']) && !empty($this->project['archived'])) { + $composer['abandoned'] = true; + } + } + + if ($this->shouldCache($identifier)) { + $this->cache->write($identifier, json_encode($composer)); + } + + $this->infoCache[$identifier] = $composer; + } + + return $this->infoCache[$identifier]; + } + /** * {@inheritdoc} */ diff --git a/tests/Composer/Test/Json/JsonManipulatorTest.php b/tests/Composer/Test/Json/JsonManipulatorTest.php index 8bc7831af..063fcbc5e 100644 --- a/tests/Composer/Test/Json/JsonManipulatorTest.php +++ b/tests/Composer/Test/Json/JsonManipulatorTest.php @@ -1814,6 +1814,91 @@ class JsonManipulatorTest extends TestCase ', $manipulator->getContents()); } + public function testAddConfigWithPackage() { + $manipulator = new JsonManipulator('{ + "repositories": [ + { + "type": "package", + "package": { + "authors": [], + "extra": { + "package-xml": "package.xml" + } + } + } + ], + "config": { + "platform": { + "php": "5.3.9" + } + } +}'); + + $this->assertTrue($manipulator->addConfigSetting('preferred-install.my-organization/stable-package', 'dist')); + $this->assertEquals('{ + "repositories": [ + { + "type": "package", + "package": { + "authors": [], + "extra": { + "package-xml": "package.xml" + } + } + } + ], + "config": { + "platform": { + "php": "5.3.9" + }, + "preferred-install": { + "my-organization/stable-package": "dist" + } + } +} +', $manipulator->getContents()); + } + + public function testAddSuggestWithPackage() + { + $manipulator = new JsonManipulator('{ + "repositories": [ + { + "type": "package", + "package": { + "authors": [], + "extra": { + "package-xml": "package.xml" + } + } + } + ], + "suggest": { + "package": "Description" + } +}'); + + $this->assertTrue($manipulator->addProperty('suggest.new-package', 'new-description')); + $this->assertEquals('{ + "repositories": [ + { + "type": "package", + "package": { + "authors": [], + "extra": { + "package-xml": "package.xml" + } + } + } + ], + "suggest": { + "package": "Description", + "new-package": "new-description" + } +} +', $manipulator->getContents()); + } + public function testAddRepositoryCanInitializeEmptyRepositories() { $manipulator = new JsonManipulator('{ diff --git a/tests/Composer/Test/Package/Version/VersionGuesserTest.php b/tests/Composer/Test/Package/Version/VersionGuesserTest.php index fe229d679..6eeafd122 100644 --- a/tests/Composer/Test/Package/Version/VersionGuesserTest.php +++ b/tests/Composer/Test/Package/Version/VersionGuesserTest.php @@ -126,13 +126,15 @@ class VersionGuesserTest extends TestCase $this->assertEquals("9999999-dev", $versionArray['version']); $this->assertEquals("dev-master", $versionArray['pretty_version']); + $this->assertArrayNotHasKey('feature_version', $versionArray); + $this->assertArrayNotHasKey('feature_pretty_version', $versionArray); $this->assertEquals($commitHash, $versionArray['commit']); } public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationForArbitraryNaming() { $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; - $anotherCommitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; + $anotherCommitHash = '13a15d220da53c52eddd5f32ffca64a7b3801bea'; $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') ->setMethods(array('execute')) @@ -172,12 +174,14 @@ class VersionGuesserTest extends TestCase $this->assertEquals("dev-arbitrary", $versionArray['version']); $this->assertEquals($anotherCommitHash, $versionArray['commit']); + $this->assertEquals("dev-current", $versionArray['feature_version']); + $this->assertEquals("dev-current", $versionArray['feature_pretty_version']); } public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationForArbitraryNamingRegex() { $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; - $anotherCommitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; + $anotherCommitHash = '13a15d220da53c52eddd5f32ffca64a7b3801bea'; $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') ->setMethods(array('execute')) @@ -217,12 +221,14 @@ class VersionGuesserTest extends TestCase $this->assertEquals("dev-latest-testing", $versionArray['version']); $this->assertEquals($anotherCommitHash, $versionArray['commit']); + $this->assertEquals("dev-current", $versionArray['feature_version']); + $this->assertEquals("dev-current", $versionArray['feature_pretty_version']); } public function testGuessVersionReadsAndRespectsNonFeatureBranchesConfigurationForArbitraryNamingWhenOnNonFeatureBranch() { $commitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; - $anotherCommitHash = '03a15d220da53c52eddd5f32ffca64a7b3801bea'; + $anotherCommitHash = '13a15d220da53c52eddd5f32ffca64a7b3801bea'; $executor = $this->getMockBuilder('\\Composer\\Util\\ProcessExecutor') ->setMethods(array('execute')) @@ -251,6 +257,8 @@ class VersionGuesserTest extends TestCase $this->assertEquals("dev-latest-testing", $versionArray['version']); $this->assertEquals($commitHash, $versionArray['commit']); + $this->assertArrayNotHasKey('feature_version', $versionArray); + $this->assertArrayNotHasKey('feature_pretty_version', $versionArray); } public function testDetachedHeadBecomesDevHash() diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 22a58cf4f..313f8b7b6 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -283,4 +283,33 @@ class ComposerRepositoryTest extends TestCase ), ); } + + public function testGetProviderNamesWillReturnPartialPackageNames() + { + $rfs = $this->getMockBuilder('Composer\Util\RemoteFilesystem') + ->disableOriginalConstructor() + ->getMock(); + + $rfs->expects($this->at(0)) + ->method('getContents') + ->with('example.org', 'http://example.org/packages.json', false) + ->willReturn(json_encode(array( + 'providers-lazy-url' => '/foo/p/%package%.json', + 'packages' => array('foo/bar' => array( + 'dev-branch' => array(), + 'v1.0.0' => array(), + )) + ))); + + $repository = new ComposerRepository( + array('url' => 'http://example.org/packages.json'), + new NullIO(), + FactoryMock::createConfig(), + null, + $rfs + ); + + $this->assertTrue($repository->hasProviders()); + $this->assertEquals(array('foo/bar'), $repository->getProviderNames()); + } } diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php index 977a4a7aa..4115b65da 100644 --- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -216,7 +216,49 @@ class GitHubDriverTest extends TestCase $this->assertEquals($repoUrl, $source['url']); $this->assertEquals($sha, $source['reference']); - $gitHubDriver->getComposerInformation($identifier); + $data = $gitHubDriver->getComposerInformation($identifier); + + $this->assertArrayNotHasKey('abandoned', $data); + } + + public function testPublicRepositoryArchived() + { + $repoUrl = 'http://github.com/composer/packagist'; + $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $identifier = 'v0.0.0'; + $sha = 'SOMESHA'; + $composerJsonUrl = 'https://api.github.com/repos/composer/packagist/contents/composer.json?ref=' . $sha; + + $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock(); + $io->expects($this->any()) + ->method('isInteractive') + ->will($this->returnValue(true)); + + $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem') + ->setConstructorArgs(array($io)) + ->getMock(); + + $remoteFilesystem->expects($this->at(0)) + ->method('getContents') + ->with($this->equalTo('github.com'), $this->equalTo($repoApiUrl), $this->equalTo(false)) + ->will($this->returnValue('{"master_branch": "test_master", "owner": {"login": "composer"}, "name": "packagist", "archived": true}')); + + $remoteFilesystem->expects($this->at(1)) + ->method('getContents') + ->with($this->equalTo('github.com'), $this->equalTo($composerJsonUrl), $this->equalTo(false)) + ->will($this->returnValue('{"encoding": "base64", "content": "' . base64_encode('{"name": "composer/packagist"}') . '"}')); + + $repoConfig = array( + 'url' => $repoUrl, + ); + + $gitHubDriver = new GitHubDriver($repoConfig, $io, $this->config, null, $remoteFilesystem); + $gitHubDriver->initialize(); + $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); + + $data = $gitHubDriver->getComposerInformation($sha); + + $this->assertTrue($data['abandoned']); } public function testPrivateRepositoryNoInteraction() diff --git a/tests/Composer/Test/Util/ProcessExecutorTest.php b/tests/Composer/Test/Util/ProcessExecutorTest.php index 29723b4a5..63ed0b7de 100644 --- a/tests/Composer/Test/Util/ProcessExecutorTest.php +++ b/tests/Composer/Test/Util/ProcessExecutorTest.php @@ -108,7 +108,7 @@ class ProcessExecutorTest extends TestCase public function testConsoleIODoesNotFormatSymfonyConsoleStyle() { $output = new BufferedOutput(OutputInterface::VERBOSITY_NORMAL, true); - $process = new ProcessExecutor(new ConsoleIO(new ArrayInput([]), $output, new HelperSet([]))); + $process = new ProcessExecutor(new ConsoleIO(new ArrayInput(array()), $output, new HelperSet(array()))); $process->execute('echo \'foo\''); $this->assertSame('foo'.PHP_EOL, $output->fetch());