Merge pull request #3325 from rdohms/implementing-abandoned-packages
Abandoned Package Warningspull/3442/head
commit
6f4be698a5
|
@ -294,6 +294,16 @@ EOT
|
|||
$output->writeln('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
|
||||
$output->writeln('<info>names</info> : ' . implode(', ', $package->getNames()));
|
||||
|
||||
if ($package->isAbandoned()) {
|
||||
$replacement = ($package->getReplacementPackage() !== null)
|
||||
? ' The author suggests using the ' . $package->getReplacementPackage(). ' package instead.'
|
||||
: null;
|
||||
|
||||
$output->writeln(
|
||||
sprintf('<error>Attention: This package is abandoned and no longer maintained.%s</error>', $replacement)
|
||||
);
|
||||
}
|
||||
|
||||
if ($package->getSupport()) {
|
||||
$output->writeln("\n<info>support</info>");
|
||||
foreach ($package->getSupport() as $type => $value) {
|
||||
|
|
|
@ -31,6 +31,7 @@ use Composer\Installer\NoopInstaller;
|
|||
use Composer\IO\IOInterface;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\CompletePackage;
|
||||
use Composer\Package\Link;
|
||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||
use Composer\Package\Locker;
|
||||
|
@ -240,6 +241,25 @@ class Installer
|
|||
}
|
||||
}
|
||||
|
||||
# Find abandoned packages and warn user
|
||||
foreach ($localRepo->getPackages() as $package) {
|
||||
if (!$package instanceof CompletePackage || !$package->isAbandoned()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$replacement = (is_string($package->getReplacementPackage()))
|
||||
? 'Use ' . $package->getReplacementPackage() . ' instead'
|
||||
: 'No replacement was suggested';
|
||||
|
||||
$this->io->write(
|
||||
sprintf(
|
||||
"<error>Package %s is abandoned, you should avoid using it. %s.</error>",
|
||||
$package->getPrettyName(),
|
||||
$replacement
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->dryRun) {
|
||||
// write lock
|
||||
if ($this->update || !$this->locker->isLocked()) {
|
||||
|
|
|
@ -333,6 +333,14 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
|
|||
{
|
||||
return $this->aliasOf->getArchiveExcludes();
|
||||
}
|
||||
public function isAbandoned()
|
||||
{
|
||||
return $this->aliasOf->isAbandoned();
|
||||
}
|
||||
public function getReplacementPackage()
|
||||
{
|
||||
return $this->aliasOf->getReplacementPackage();
|
||||
}
|
||||
public function __toString()
|
||||
{
|
||||
return parent::__toString().' (alias of '.$this->aliasOf->getVersion().')';
|
||||
|
|
|
@ -27,6 +27,7 @@ class CompletePackage extends Package implements CompletePackageInterface
|
|||
protected $homepage;
|
||||
protected $scripts = array();
|
||||
protected $support = array();
|
||||
protected $abandoned = false;
|
||||
|
||||
/**
|
||||
* @param array $scripts
|
||||
|
@ -169,4 +170,30 @@ class CompletePackage extends Package implements CompletePackageInterface
|
|||
{
|
||||
return $this->support;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAbandoned()
|
||||
{
|
||||
return (boolean) $this->abandoned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean|string $abandoned
|
||||
*/
|
||||
public function setAbandoned($abandoned)
|
||||
{
|
||||
$this->abandoned = $abandoned;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the package is abandoned and has a suggested replacement, this method returns it
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getReplacementPackage()
|
||||
{
|
||||
return is_string($this->abandoned)? $this->abandoned : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,4 +78,18 @@ interface CompletePackageInterface extends PackageInterface
|
|||
* @return array
|
||||
*/
|
||||
public function getSupport();
|
||||
|
||||
/**
|
||||
* Returns if the package is abandoned or not
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAbandoned();
|
||||
|
||||
/**
|
||||
* If the package is abandoned and has a suggested replacement, this method returns it
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getReplacementPackage();
|
||||
}
|
||||
|
|
|
@ -105,6 +105,10 @@ class ArrayDumper
|
|||
if (isset($data['keywords']) && is_array($data['keywords'])) {
|
||||
sort($data['keywords']);
|
||||
}
|
||||
|
||||
if ($package->isAbandoned()) {
|
||||
$data['abandoned'] = $package->getReplacementPackage() ?: true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($package instanceof RootPackageInterface) {
|
||||
|
|
|
@ -195,6 +195,10 @@ class ArrayLoader implements LoaderInterface
|
|||
if (isset($config['support'])) {
|
||||
$package->setSupport($config['support']);
|
||||
}
|
||||
|
||||
if (isset($config['abandoned'])) {
|
||||
$package->setAbandoned($config['abandoned']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($aliasNormalized = $this->getBranchAlias($config)) {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
--TEST--
|
||||
Abandoned packages are flagged
|
||||
--COMPOSER--
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{ "name": "a/a", "version": "1.0.0", "abandoned": true }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{ "name": "c/c", "version": "1.0.0", "abandoned": "b/b" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"a/a": "1.0.0",
|
||||
"c/c": "1.0.0"
|
||||
}
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
--EXPECT-OUTPUT--
|
||||
<info>Loading composer repositories with package information</info>
|
||||
<info>Installing dependencies (including require-dev)</info>
|
||||
<error>Package a/a is abandoned, you should avoid using it. No replacement was suggested.</error>
|
||||
<error>Package c/c is abandoned, you should avoid using it. Use b/b instead.</error>
|
||||
<info>Writing lock file</info>
|
||||
<info>Generating autoload files</info>
|
||||
|
||||
--EXPECT--
|
||||
Installing a/a (1.0.0)
|
||||
Installing c/c (1.0.0)
|
|
@ -70,4 +70,4 @@ update
|
|||
"platform-dev": []
|
||||
}
|
||||
--EXPECT--
|
||||
Updating a/a (dev-master 1234) to a/a (dev-master master)
|
||||
Updating a/a (dev-master 1234) to a/a (dev-master master)
|
||||
|
|
|
@ -306,7 +306,7 @@ class InstallerTest extends TestCase
|
|||
die(sprintf('Test "%s" is not valid, did not match the expected format.', str_replace($fixturesDir.'/', '', $file)));
|
||||
}
|
||||
|
||||
$tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $composer, $lock, $installed, $run, $expectLock, $expectOutput, $expect, $expectExitCode);
|
||||
$tests[basename($file)] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $composer, $lock, $installed, $run, $expectLock, $expectOutput, $expect, $expectExitCode);
|
||||
}
|
||||
|
||||
return $tests;
|
||||
|
|
|
@ -62,12 +62,33 @@ class ArrayDumperTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertSame('dev', $config['minimum-stability']);
|
||||
}
|
||||
|
||||
public function testDumpAbandoned()
|
||||
{
|
||||
$this->packageExpects('isAbandoned', true);
|
||||
$this->packageExpects('getReplacementPackage', true);
|
||||
|
||||
$config = $this->dumper->dump($this->package);
|
||||
|
||||
$this->assertSame(true, $config['abandoned']);
|
||||
}
|
||||
|
||||
public function testDumpAbandonedReplacement()
|
||||
{
|
||||
$this->packageExpects('isAbandoned', true);
|
||||
$this->packageExpects('getReplacementPackage', 'foo/bar');
|
||||
|
||||
$config = $this->dumper->dump($this->package);
|
||||
|
||||
$this->assertSame('foo/bar', $config['abandoned']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getKeys
|
||||
*/
|
||||
public function testKeys($key, $value, $method = null, $expectedValue = null)
|
||||
{
|
||||
$this->packageExpects('get'.ucfirst($method ?: $key), $value);
|
||||
$this->packageExpects('isAbandoned', $value);
|
||||
|
||||
$config = $this->dumper->dump($this->package);
|
||||
|
||||
|
|
|
@ -117,7 +117,8 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
|
|||
'archive' => array(
|
||||
'exclude' => array('/foo/bar', 'baz', '!/foo/bar/baz'),
|
||||
),
|
||||
'transport-options' => array('ssl' => array('local_cert' => '/opt/certs/test.pem'))
|
||||
'transport-options' => array('ssl' => array('local_cert' => '/opt/certs/test.pem')),
|
||||
'abandoned' => 'foo/bar'
|
||||
);
|
||||
|
||||
$package = $this->loader->load($config);
|
||||
|
@ -138,4 +139,28 @@ class ArrayLoaderTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertInstanceOf('Composer\Package\AliasPackage', $package);
|
||||
$this->assertEquals('1.0.x-dev', $package->getPrettyVersion());
|
||||
}
|
||||
|
||||
public function testAbandoned()
|
||||
{
|
||||
$config = array(
|
||||
'name' => 'A',
|
||||
'version' => '1.2.3.4',
|
||||
'abandoned' => 'foo/bar'
|
||||
);
|
||||
|
||||
$package = $this->loader->load($config);
|
||||
$this->assertTrue($package->isAbandoned());
|
||||
$this->assertEquals('foo/bar', $package->getReplacementPackage());
|
||||
}
|
||||
|
||||
public function testNotAbandoned()
|
||||
{
|
||||
$config = array(
|
||||
'name' => 'A',
|
||||
'version' => '1.2.3.4'
|
||||
);
|
||||
|
||||
$package = $this->loader->load($config);
|
||||
$this->assertFalse($package->isAbandoned());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue