1
0
Fork 0

Add --sort-by-age to show/outdated commands, and also release date for latest package in --latest mode (#11762)

pull/11766/head
Jordi Boggiano 2023-12-20 15:37:27 +01:00 committed by GitHub
parent c8f1028ef9
commit 53a1f32061
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 19 deletions

View File

@ -556,6 +556,7 @@ php composer.phar show monolog/monolog 1.0.2
* **--major-only (-M):** Use with --latest or --outdated. Only shows packages that have major SemVer-compatible updates. * **--major-only (-M):** Use with --latest or --outdated. Only shows packages that have major SemVer-compatible updates.
* **--minor-only (-m):** Use with --latest or --outdated. Only shows packages that have minor SemVer-compatible updates. * **--minor-only (-m):** Use with --latest or --outdated. Only shows packages that have minor SemVer-compatible updates.
* **--patch-only:** Use with --latest or --outdated. Only shows packages that have patch-level SemVer-compatible updates. * **--patch-only:** Use with --latest or --outdated. Only shows packages that have patch-level SemVer-compatible updates.
* **--sort-by-age (-A):** Displays the installed version's age, and sorts packages oldest first. Use with the --latest or --outdated option.
* **--direct (-D):** Restricts the list of packages to your direct dependencies. * **--direct (-D):** Restricts the list of packages to your direct dependencies.
* **--strict:** Return a non-zero exit code when there are outdated packages. * **--strict:** Return a non-zero exit code when there are outdated packages.
* **--format (-f):** Lets you pick between text (default) or json output format. * **--format (-f):** Lets you pick between text (default) or json output format.
@ -589,6 +590,7 @@ The color coding is as such:
* **--major-only (-M):** Only shows packages that have major SemVer-compatible updates. * **--major-only (-M):** Only shows packages that have major SemVer-compatible updates.
* **--minor-only (-m):** Only shows packages that have minor SemVer-compatible updates. * **--minor-only (-m):** Only shows packages that have minor SemVer-compatible updates.
* **--patch-only (-p):** Only shows packages that have patch-level SemVer-compatible updates. * **--patch-only (-p):** Only shows packages that have patch-level SemVer-compatible updates.
* **--sort-by-age (-A):** Displays the installed version's age, and sorts packages oldest first.
* **--format (-f):** Lets you pick between text (default) or json output format. * **--format (-f):** Lets you pick between text (default) or json output format.
* **--no-dev:** Do not show outdated dev dependencies. * **--no-dev:** Do not show outdated dev dependencies.
* **--locked:** Shows updates for packages from the lock file, regardless of what is currently in vendor dir. * **--locked:** Shows updates for packages from the lock file, regardless of what is currently in vendor dir.

View File

@ -40,6 +40,7 @@ class OutdatedCommand extends BaseCommand
new InputOption('major-only', 'M', InputOption::VALUE_NONE, 'Show only packages that have major SemVer-compatible updates.'), new InputOption('major-only', 'M', InputOption::VALUE_NONE, 'Show only packages that have major SemVer-compatible updates.'),
new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates.'), new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates.'),
new InputOption('patch-only', 'p', InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates.'), new InputOption('patch-only', 'p', InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates.'),
new InputOption('sort-by-age', 'A', InputOption::VALUE_NONE, 'Displays the installed version\'s age, and sorts packages oldest first.'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['json', 'text']), new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['json', 'text']),
new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage(false)), new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it if you don\'t want to be informed about new versions of some packages.', null, $this->suggestInstalledPackage(false)),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'), new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'),
@ -97,6 +98,9 @@ EOT
if ($input->getOption('no-dev')) { if ($input->getOption('no-dev')) {
$args['--no-dev'] = true; $args['--no-dev'] = true;
} }
if ($input->getOption('sort-by-age')) {
$args['--sort-by-age'] = true;
}
$args['--ignore-platform-req'] = $input->getOption('ignore-platform-req'); $args['--ignore-platform-req'] = $input->getOption('ignore-platform-req');
if ($input->getOption('ignore-platform-reqs')) { if ($input->getOption('ignore-platform-reqs')) {
$args['--ignore-platform-reqs'] = true; $args['--ignore-platform-reqs'] = true;

View File

@ -98,6 +98,7 @@ class ShowCommand extends BaseCommand
new InputOption('major-only', 'M', InputOption::VALUE_NONE, 'Show only packages that have major SemVer-compatible updates. Use with the --latest or --outdated option.'), new InputOption('major-only', 'M', InputOption::VALUE_NONE, 'Show only packages that have major SemVer-compatible updates. Use with the --latest or --outdated option.'),
new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --latest or --outdated option.'), new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --latest or --outdated option.'),
new InputOption('patch-only', null, InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates. Use with the --latest or --outdated option.'), new InputOption('patch-only', null, InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates. Use with the --latest or --outdated option.'),
new InputOption('sort-by-age', 'A', InputOption::VALUE_NONE, 'Displays the installed version\'s age, and sorts packages oldest first. Use with the --latest or --outdated option.'),
new InputOption('direct', 'D', InputOption::VALUE_NONE, 'Shows only packages that are directly required by the root package'), new InputOption('direct', 'D', InputOption::VALUE_NONE, 'Shows only packages that are directly required by the root package'),
new InputOption('strict', null, InputOption::VALUE_NONE, 'Return a non-zero exit code when there are outdated packages'), new InputOption('strict', null, InputOption::VALUE_NONE, 'Return a non-zero exit code when there are outdated packages'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['json', 'text']), new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text', ['json', 'text']),
@ -450,7 +451,7 @@ EOT
if (isset($packages[$type])) { if (isset($packages[$type])) {
ksort($packages[$type]); ksort($packages[$type]);
$nameLength = $versionLength = $latestLength = 0; $nameLength = $versionLength = $latestLength = $releaseDateLength = 0;
if ($showLatest && $showVersion) { if ($showLatest && $showVersion) {
foreach ($packages[$type] as $package) { foreach ($packages[$type] as $package) {
@ -469,9 +470,20 @@ EOT
$writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion; $writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion;
$writeLatest = $writeVersion && $showLatest; $writeLatest = $writeVersion && $showLatest;
$writeDescription = !$input->getOption('name-only') && !$input->getOption('path'); $writeDescription = !$input->getOption('name-only') && !$input->getOption('path');
$writeReleaseDate = $writeLatest && $input->getOption('sort-by-age');
$hasOutdatedPackages = false; $hasOutdatedPackages = false;
if ($input->getOption('sort-by-age')) {
usort($packages[$type], function ($a, $b) {
if (is_object($a) && is_object($b)) {
return $a->getReleaseDate() <=> $b->getReleaseDate();
}
return 0;
});
}
$viewData[$type] = []; $viewData[$type] = [];
foreach ($packages[$type] as $package) { foreach ($packages[$type] as $package) {
$packageViewData = []; $packageViewData = [];
@ -505,6 +517,17 @@ EOT
$packageViewData['version'] = $package->getFullPrettyVersion(); $packageViewData['version'] = $package->getFullPrettyVersion();
$versionLength = max($versionLength, strlen($package->getFullPrettyVersion())); $versionLength = max($versionLength, strlen($package->getFullPrettyVersion()));
} }
if ($writeReleaseDate) {
if ($package->getReleaseDate() !== null) {
$packageViewData['release-age'] = str_replace(' ago', ' old', $this->getRelativeTime($package->getReleaseDate()));
if (!str_contains($packageViewData['release-age'], ' old')) {
$packageViewData['release-age'] = 'from '.$packageViewData['release-age'];
}
$releaseDateLength = max($releaseDateLength, strlen($packageViewData['release-age']));
} else {
$packageViewData['release-age'] = '';
}
}
if ($writeLatest && $latestPackage) { if ($writeLatest && $latestPackage) {
$packageViewData['latest'] = $latestPackage->getFullPrettyVersion(); $packageViewData['latest'] = $latestPackage->getFullPrettyVersion();
$packageViewData['latest-status'] = $this->getUpdateStatus($latestPackage, $package); $packageViewData['latest-status'] = $this->getUpdateStatus($latestPackage, $package);
@ -552,7 +575,9 @@ EOT
'nameLength' => $nameLength, 'nameLength' => $nameLength,
'versionLength' => $versionLength, 'versionLength' => $versionLength,
'latestLength' => $latestLength, 'latestLength' => $latestLength,
'releaseDateLength' => $releaseDateLength,
'writeLatest' => $writeLatest, 'writeLatest' => $writeLatest,
'writeReleaseDate' => $writeReleaseDate,
]; ];
if ($input->getOption('strict') && $hasOutdatedPackages) { if ($input->getOption('strict') && $hasOutdatedPackages) {
$exitCode = 1; $exitCode = 1;
@ -588,11 +613,14 @@ EOT
$nameLength = $viewMetaData[$type]['nameLength']; $nameLength = $viewMetaData[$type]['nameLength'];
$versionLength = $viewMetaData[$type]['versionLength']; $versionLength = $viewMetaData[$type]['versionLength'];
$latestLength = $viewMetaData[$type]['latestLength']; $latestLength = $viewMetaData[$type]['latestLength'];
$releaseDateLength = $viewMetaData[$type]['releaseDateLength'];
$writeLatest = $viewMetaData[$type]['writeLatest']; $writeLatest = $viewMetaData[$type]['writeLatest'];
$writeReleaseDate = $viewMetaData[$type]['writeReleaseDate'];
$versionFits = $nameLength + $versionLength + 3 <= $width; $versionFits = $nameLength + $versionLength + 3 <= $width;
$latestFits = $nameLength + $versionLength + $latestLength + 3 <= $width; $latestFits = $nameLength + $versionLength + $latestLength + 3 <= $width;
$descriptionFits = $nameLength + $versionLength + $latestLength + 24 <= $width; $releaseDateFits = $nameLength + $versionLength + $latestLength + $releaseDateLength + 3 <= $width;
$descriptionFits = $nameLength + $versionLength + $latestLength + $releaseDateLength + 24 <= $width;
if ($latestFits && !$io->isDecorated()) { if ($latestFits && !$io->isDecorated()) {
$latestLength += 2; $latestLength += 2;
@ -620,14 +648,14 @@ EOT
$io->writeError(''); $io->writeError('');
$io->writeError('<info>Direct dependencies required in composer.json:</>'); $io->writeError('<info>Direct dependencies required in composer.json:</>');
if (\count($directDeps) > 0) { if (\count($directDeps) > 0) {
$this->printPackages($io, $directDeps, $indent, $writeVersion && $versionFits, $latestFits, $writeDescription && $descriptionFits, $width, $versionLength, $nameLength, $latestLength); $this->printPackages($io, $directDeps, $indent, $writeVersion && $versionFits, $latestFits, $writeDescription && $descriptionFits, $width, $versionLength, $nameLength, $latestLength, $writeReleaseDate && $releaseDateFits, $releaseDateLength);
} else { } else {
$io->writeError('Everything up to date'); $io->writeError('Everything up to date');
} }
$io->writeError(''); $io->writeError('');
$io->writeError('<info>Transitive dependencies not required in composer.json:</>'); $io->writeError('<info>Transitive dependencies not required in composer.json:</>');
if (\count($transitiveDeps) > 0) { if (\count($transitiveDeps) > 0) {
$this->printPackages($io, $transitiveDeps, $indent, $writeVersion && $versionFits, $latestFits, $writeDescription && $descriptionFits, $width, $versionLength, $nameLength, $latestLength); $this->printPackages($io, $transitiveDeps, $indent, $writeVersion && $versionFits, $latestFits, $writeDescription && $descriptionFits, $width, $versionLength, $nameLength, $latestLength, $writeReleaseDate && $releaseDateFits, $releaseDateLength);
} else { } else {
$io->writeError('Everything up to date'); $io->writeError('Everything up to date');
} }
@ -635,7 +663,7 @@ EOT
if ($writeLatest && \count($packages) === 0) { if ($writeLatest && \count($packages) === 0) {
$io->writeError('All your direct dependencies are up to date'); $io->writeError('All your direct dependencies are up to date');
} else { } else {
$this->printPackages($io, $packages, $indent, $writeVersion && $versionFits, $writeLatest && $latestFits, $writeDescription && $descriptionFits, $width, $versionLength, $nameLength, $latestLength); $this->printPackages($io, $packages, $indent, $writeVersion && $versionFits, $writeLatest && $latestFits, $writeDescription && $descriptionFits, $width, $versionLength, $nameLength, $latestLength, $writeReleaseDate && $releaseDateFits, $releaseDateLength);
} }
} }
@ -651,11 +679,12 @@ EOT
/** /**
* @param array<array{name: string, direct-dependency?: bool, version?: string, latest?: string, latest-status?: string, description?: string|null, path?: string|null, source?: string|null, homepage?: string|null, warning?: string, abandoned?: bool|string}> $packages * @param array<array{name: string, direct-dependency?: bool, version?: string, latest?: string, latest-status?: string, description?: string|null, path?: string|null, source?: string|null, homepage?: string|null, warning?: string, abandoned?: bool|string}> $packages
*/ */
private function printPackages(IOInterface $io, array $packages, string $indent, bool $writeVersion, bool $writeLatest, bool $writeDescription, int $width, int $versionLength, int $nameLength, int $latestLength): void private function printPackages(IOInterface $io, array $packages, string $indent, bool $writeVersion, bool $writeLatest, bool $writeDescription, int $width, int $versionLength, int $nameLength, int $latestLength, bool $writeReleaseDate, int $releaseDateLength): void
{ {
$padName = $writeVersion || $writeLatest || $writeDescription; $padName = $writeVersion || $writeLatest || $writeReleaseDate || $writeDescription;
$padVersion = $writeLatest || $writeDescription; $padVersion = $writeLatest || $writeReleaseDate || $writeDescription;
$padLatest = $writeDescription; $padLatest = $writeDescription || $writeReleaseDate;
$padReleaseDate = $writeDescription;
foreach ($packages as $package) { foreach ($packages as $package) {
$link = $package['source'] ?? $package['homepage'] ?? ''; $link = $package['source'] ?? $package['homepage'] ?? '';
if ($link !== '') { if ($link !== '') {
@ -674,10 +703,13 @@ EOT
$latestVersion = str_replace(['up-to-date', 'semver-safe-update', 'update-possible'], ['=', '!', '~'], $updateStatus) . ' ' . $latestVersion; $latestVersion = str_replace(['up-to-date', 'semver-safe-update', 'update-possible'], ['=', '!', '~'], $updateStatus) . ' ' . $latestVersion;
} }
$io->write(' <' . $style . '>' . str_pad($latestVersion, ($padLatest ? $latestLength : 0), ' ') . '</' . $style . '>', false); $io->write(' <' . $style . '>' . str_pad($latestVersion, ($padLatest ? $latestLength : 0), ' ') . '</' . $style . '>', false);
if ($writeReleaseDate && isset($package['release-age'])) {
$io->write(' '.str_pad($package['release-age'], ($padReleaseDate ? $releaseDateLength : 0), ' '), false);
}
} }
if (isset($package['description']) && $writeDescription) { if (isset($package['description']) && $writeDescription) {
$description = strtok($package['description'], "\r\n"); $description = strtok($package['description'], "\r\n");
$remaining = $width - $nameLength - $versionLength - 4; $remaining = $width - $nameLength - $versionLength - $releaseDateLength - 4;
if ($writeLatest) { if ($writeLatest) {
$remaining -= $latestLength; $remaining -= $latestLength;
} }
@ -806,14 +838,20 @@ EOT
*/ */
protected function printMeta(CompletePackageInterface $package, array $versions, InstalledRepository $installedRepo, ?PackageInterface $latestPackage = null): void protected function printMeta(CompletePackageInterface $package, array $versions, InstalledRepository $installedRepo, ?PackageInterface $latestPackage = null): void
{ {
$isInstalledPackage = !PlatformRepository::isPlatformPackage($package->getName()) && $installedRepo->hasPackage($package);
$io = $this->getIO(); $io = $this->getIO();
$io->write('<info>name</info> : ' . $package->getPrettyName()); $io->write('<info>name</info> : ' . $package->getPrettyName());
$io->write('<info>descrip.</info> : ' . $package->getDescription()); $io->write('<info>descrip.</info> : ' . $package->getDescription());
$io->write('<info>keywords</info> : ' . implode(', ', $package->getKeywords() ?: [])); $io->write('<info>keywords</info> : ' . implode(', ', $package->getKeywords() ?: []));
$this->printVersions($package, $versions, $installedRepo); $this->printVersions($package, $versions, $installedRepo);
if ($isInstalledPackage && $package->getReleaseDate() !== null) {
$io->write('<info>released</info> : ' . $package->getReleaseDate()->format('Y-m-d') . ', ' . $this->getRelativeTime($package->getReleaseDate()));
}
if ($latestPackage) { if ($latestPackage) {
$style = $this->getVersionStyle($latestPackage, $package); $style = $this->getVersionStyle($latestPackage, $package);
$io->write('<info>latest</info> : <'.$style.'>' . $latestPackage->getPrettyVersion() . '</'.$style.'>'); $releasedTime = $latestPackage->getReleaseDate() === null ? '' : ' released ' . $latestPackage->getReleaseDate()->format('Y-m-d') . ', ' . $this->getRelativeTime($latestPackage->getReleaseDate());
$io->write('<info>latest</info> : <'.$style.'>' . $latestPackage->getPrettyVersion() . '</'.$style.'>' . $releasedTime);
} else { } else {
$latestPackage = $package; $latestPackage = $package;
} }
@ -822,7 +860,7 @@ EOT
$io->write('<info>homepage</info> : ' . $package->getHomepage()); $io->write('<info>homepage</info> : ' . $package->getHomepage());
$io->write('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference())); $io->write('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
$io->write('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference())); $io->write('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
if (!PlatformRepository::isPlatformPackage($package->getName()) && $installedRepo->hasPackage($package)) { if ($isInstalledPackage) {
$path = $this->requireComposer()->getInstallationManager()->getInstallPath($package); $path = $this->requireComposer()->getInstallationManager()->getInstallPath($package);
if (is_string($path)) { if (is_string($path)) {
$io->write('<info>path</info> : ' . realpath($path)); $io->write('<info>path</info> : ' . realpath($path));
@ -993,6 +1031,10 @@ EOT
} else { } else {
$json['path'] = null; $json['path'] = null;
} }
if ($package->getReleaseDate() !== null) {
$json['released'] = $package->getReleaseDate()->format(DATE_ATOM);
}
} }
if ($latestPackage instanceof CompletePackageInterface && $latestPackage->isAbandoned()) { if ($latestPackage instanceof CompletePackageInterface && $latestPackage->isAbandoned()) {
@ -1447,4 +1489,30 @@ EOT
return $this->repositorySet; return $this->repositorySet;
} }
private function getRelativeTime(\DateTimeInterface $releaseDate): string
{
if ($releaseDate->format('Ymd') === date('Ymd')) {
return 'today';
}
$diff = $releaseDate->diff(new \DateTimeImmutable());
if ($diff->days < 7) {
return 'this week';
}
if ($diff->days < 14) {
return 'last week';
}
if ($diff->m < 1 && $diff->days < 31) {
return floor($diff->days / 7) . ' weeks ago';
}
if ($diff->y < 1) {
return $diff->m . ' month' . ($diff->m > 1 ? 's' : '') . ' ago';
}
return $diff->y . ' year' . ($diff->y > 1 ? 's' : '') . ' ago';
}
} }

View File

@ -17,6 +17,7 @@ use Composer\Pcre\Preg;
use Composer\Pcre\Regex; use Composer\Pcre\Regex;
use Composer\Repository\PlatformRepository; use Composer\Repository\PlatformRepository;
use Composer\Test\TestCase; use Composer\Test\TestCase;
use DateTimeImmutable;
class ShowCommandTest extends TestCase class ShowCommandTest extends TestCase
{ {
@ -55,13 +56,14 @@ class ShowCommandTest extends TestCase
$pkg = self::getPackage('vendor/package', '1.0.0'); $pkg = self::getPackage('vendor/package', '1.0.0');
$pkg->setDescription('description of installed package'); $pkg->setDescription('description of installed package');
$major = self::getPackage('outdated/major', '1.0.0');
$major->setReleaseDate(new DateTimeImmutable());
$minor = self::getPackage('outdated/minor', '1.0.0');
$minor->setReleaseDate(new DateTimeImmutable('-2 years'));
$patch = self::getPackage('outdated/patch', '1.0.0');
$patch->setReleaseDate(new DateTimeImmutable('-2 weeks'));
$this->createInstalledJson([ $this->createInstalledJson([$pkg, $major, $minor, $patch]);
$pkg,
self::getPackage('outdated/major', '1.0.0'),
self::getPackage('outdated/minor', '1.0.0'),
self::getPackage('outdated/patch', '1.0.0'),
]);
$appTester = $this->getApplicationTester(); $appTester = $this->getApplicationTester();
$appTester->run(array_merge(['command' => 'show'], $command)); $appTester->run(array_merge(['command' => 'show'], $command));
@ -112,6 +114,21 @@ outdated/minor 1.0.0 <highlight>! 1.1.1</highlight>
outdated/patch 1.0.0 <highlight>! 1.0.1</highlight>', outdated/patch 1.0.0 <highlight>! 1.0.1</highlight>',
]; ];
yield 'outdated deps sorting by age' => [
['command' => 'outdated', '--sort-by-age' => true],
'Legend:
! patch or minor release available - update recommended
~ major release available - update possible
Direct dependencies required in composer.json:
Everything up to date
Transitive dependencies not required in composer.json:
outdated/minor 1.0.0 <highlight>! 1.1.1</highlight> 2 years old
outdated/patch 1.0.0 <highlight>! 1.0.1</highlight> 2 weeks old
outdated/major 1.0.0 ~ 2.0.0 from today',
];
yield 'outdated deps with --direct only show direct deps with updated' => [ yield 'outdated deps with --direct only show direct deps with updated' => [
['command' => 'outdated', '--direct' => true], ['command' => 'outdated', '--direct' => true],
'Legend: 'Legend:
@ -533,7 +550,7 @@ OUTPUT;
public function testSelf(): void public function testSelf(): void
{ {
$this->initTempComposer(['name' => 'vendor/package']); $this->initTempComposer(['name' => 'vendor/package', 'time' => date('Y-m-d')]);
$appTester = $this->getApplicationTester(); $appTester = $this->getApplicationTester();
$appTester->run(['command' => 'show', '--self' => true]); $appTester->run(['command' => 'show', '--self' => true]);
@ -542,6 +559,7 @@ OUTPUT;
'descrip.' => '', 'descrip.' => '',
'keywords' => '', 'keywords' => '',
'versions' => '* 1.0.0+no-version-set', 'versions' => '* 1.0.0+no-version-set',
'released' => date('Y-m-d'). ', today',
'type' => 'library', 'type' => 'library',
'homepage' => '', 'homepage' => '',
'source' => '[] ', 'source' => '[] ',