Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add prefer-stable flag to pick stable package over unstable ones when possible #1740

Merged
merged 2 commits into from Apr 2, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/04-schema.md
Expand Up @@ -493,6 +493,13 @@ a given package can be done in `require` or `require-dev` (see
Available options (in order of stability) are `dev`, `alpha`, `beta`, `RC`,
and `stable`.

### prefer-stable <span>(root-only)</span>

When this is enabled, Composer will prefer more stable packages over unstable
ones when finding compatible stable packages is possible. If you require a
dev version or only alphas are available for a package, those will still be
selected granted that the minimum-stability allows for it.

### repositories <span>(root-only)</span>

Custom package repositories to use.
Expand Down
4 changes: 4 additions & 0 deletions res/composer-schema.json
Expand Up @@ -221,6 +221,10 @@
"type": ["string"],
"description": "The minimum stability the packages must have to be install-able. Possible values are: dev, alpha, beta, RC, stable."
},
"prefer-stable": {
"type": ["boolean"],
"description": "If set to true, stable packages will be prefered to dev packages when possible, even if the minimum-stability allows unstable packages."
},
"bin": {
"type": ["array"],
"description": "A set of files that should be treated as binaries and symlinked into bin-dir (from config).",
Expand Down
13 changes: 13 additions & 0 deletions src/Composer/DependencyResolver/DefaultPolicy.php
Expand Up @@ -14,15 +14,28 @@

use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
use Composer\Package\LinkConstraint\VersionConstraint;

/**
* @author Nils Adermann <naderman@naderman.de>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class DefaultPolicy implements PolicyInterface
{
private $preferStable;

public function __construct($preferStable = false)
{
$this->preferStable = $preferStable;
}

public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
{
if ($this->preferStable && ($stabA = $a->getStability()) !== ($stabB = $b->getStability())) {
return BasePackage::$stabilities[$stabA] < BasePackage::$stabilities[$stabB];
}

$constraint = new VersionConstraint($operator, $b->getVersion());
$version = new VersionConstraint('==', $a->getVersion());

Expand Down
9 changes: 7 additions & 2 deletions src/Composer/Installer.php
Expand Up @@ -234,7 +234,7 @@ public function run()

// split dev and non-dev requirements by checking what would be removed if we update without the dev requirements
if ($this->devMode && $this->package->getDevRequires()) {
$policy = new DefaultPolicy();
$policy = $this->createPolicy();
$pool = $this->createPool();
$pool->addRepository($installedRepo, $aliases);

Expand Down Expand Up @@ -308,7 +308,7 @@ protected function doInstall($localRepo, $installedRepo, $platformRepo, $aliases
$this->io->write('<info>Loading composer repositories with package information</info>');

// creating repository pool
$policy = new DefaultPolicy();
$policy = $this->createPolicy();
$pool = $this->createPool();
$pool->addRepository($installedRepo, $aliases);
if ($installFromLock) {
Expand Down Expand Up @@ -513,6 +513,11 @@ private function createPool()
return new Pool($minimumStability, $stabilityFlags);
}

private function createPolicy()
{
return new DefaultPolicy($this->package->getPreferStable());
}

private function createRequest(Pool $pool, RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
{
$request = new Request($pool);
Expand Down
4 changes: 4 additions & 0 deletions src/Composer/Package/Loader/RootPackageLoader.php
Expand Up @@ -91,6 +91,10 @@ public function load(array $config, $class = 'Composer\Package\RootPackage')
$package->setMinimumStability(VersionParser::normalizeStability($config['minimum-stability']));
}

if (isset($config['prefer-stable'])) {
$package->setPreferStable((bool) $config['prefer-stable']);
}

$repos = Factory::createDefaultRepositories(null, $this->config, $this->manager);
foreach ($repos as $repo) {
$this->manager->addRepository($repo);
Expand Down
19 changes: 19 additions & 0 deletions src/Composer/Package/RootPackage.php
Expand Up @@ -20,6 +20,7 @@
class RootPackage extends CompletePackage implements RootPackageInterface
{
protected $minimumStability = 'stable';
protected $preferStable = false;
protected $stabilityFlags = array();
protected $references = array();

Expand Down Expand Up @@ -59,6 +60,24 @@ public function getStabilityFlags()
return $this->stabilityFlags;
}

/**
* Set the preferStable
*
* @param bool $preferStable
*/
public function setPreferStable($preferStable)
{
$this->preferStable = $preferStable;
}

/**
* {@inheritDoc}
*/
public function getPreferStable()
{
return $this->preferStable;
}

/**
* Set the references
*
Expand Down
29 changes: 29 additions & 0 deletions tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php
Expand Up @@ -65,6 +65,35 @@ public function testSelectNewest()
$this->assertEquals($expected, $selected);
}

public function testSelectNewestPicksLatest()
{
$this->repo->addPackage($packageA1 = $this->getPackage('A', '1.0.0'));
$this->repo->addPackage($packageA2 = $this->getPackage('A', '1.0.1-alpha'));
$this->pool->addRepository($this->repo);

$literals = array($packageA1->getId(), $packageA2->getId());
$expected = array($packageA2->getId());

$selected = $this->policy->selectPreferedPackages($this->pool, array(), $literals);

$this->assertEquals($expected, $selected);
}

public function testSelectNewestPicksLatestStableWithPreferStable()
{
$this->repo->addPackage($packageA1 = $this->getPackage('A', '1.0.0'));
$this->repo->addPackage($packageA2 = $this->getPackage('A', '1.0.1-alpha'));
$this->pool->addRepository($this->repo);

$literals = array($packageA1->getId(), $packageA2->getId());
$expected = array($packageA1->getId());

$policy = new DefaultPolicy(true);
$selected = $policy->selectPreferedPackages($this->pool, array(), $literals);

$this->assertEquals($expected, $selected);
}

public function testSelectNewestOverInstalled()
{
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0'));
Expand Down