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

--patch-only option for show and outdated commands #10589

Merged
merged 6 commits into from Mar 15, 2022
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
4 changes: 4 additions & 0 deletions src/Composer/Command/OutdatedCommand.php
Expand Up @@ -39,6 +39,7 @@ protected function configure(): void
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('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --outdated option.'),
new InputOption('patch-only', 'p', InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates. Use with the --outdated option.'),
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.'),
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'),
Expand Down Expand Up @@ -84,6 +85,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($input->getOption('minor-only')) {
$args['--minor-only'] = true;
}
if ($input->getOption('patch-only')) {
$args['--patch-only'] = true;
}
if ($input->getOption('locked')) {
$args['--locked'] = true;
}
Expand Down
23 changes: 20 additions & 3 deletions src/Composer/Command/ShowCommand.php
Expand Up @@ -89,6 +89,7 @@ protected function configure()
new InputOption('outdated', 'o', InputOption::VALUE_NONE, 'Show the latest version but only for packages that are outdated'),
new InputOption('ignore', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore specified package(s). Use it with the --outdated option if you don\'t want to be informed about new versions of some packages.'),
new InputOption('minor-only', 'm', InputOption::VALUE_NONE, 'Show only packages that have minor SemVer-compatible updates. Use with the --outdated option.'),
new InputOption('patch-only', null, InputOption::VALUE_NONE, 'Show only packages that have patch SemVer-compatible updates. Use with the --outdated option.'),
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('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
Expand Down Expand Up @@ -139,6 +140,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
return 1;
}

if ($input->getOption('patch-only') && $input->getOption('minor-only')) {
$io->writeError('The --patch-only option is not usable in combination with --minor-only');

return 1;
}

if ($input->getOption('tree') && $input->getOption('latest')) {
$io->writeError('The --tree (-t) option is not usable in combination with --latest (-l)');

Expand Down Expand Up @@ -289,7 +296,7 @@ protected function execute(InputInterface $input, OutputInterface $output)

$latestPackage = null;
if ($input->getOption('latest')) {
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $input->getOption('minor-only'), $platformReqFilter);
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $input->getOption('minor-only'), $input->getOption('patch-only'), $platformReqFilter);
}
if (
$input->getOption('outdated')
Expand Down Expand Up @@ -398,6 +405,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$showAllTypes = $input->getOption('all');
$showLatest = $input->getOption('latest');
$showMinorOnly = $input->getOption('minor-only');
$showPatchOnly = $input->getOption('patch-only');
$ignoredPackages = array_map('strtolower', $input->getOption('ignore'));
$indent = $showAllTypes ? ' ' : '';
/** @var PackageInterface[] $latestPackages */
Expand All @@ -414,7 +422,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
if ($showLatest && $showVersion) {
foreach ($packages[$type] as $package) {
if (is_object($package)) {
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $showMinorOnly, $platformReqFilter);
$latestPackage = $this->findLatestPackage($package, $composer, $platformRepo, $showMinorOnly, $showPatchOnly, $platformReqFilter);
if ($latestPackage === null) {
continue;
}
Expand Down Expand Up @@ -1288,7 +1296,7 @@ private function writeTreeLine(string $line): void
/**
* Given a package, this finds the latest package matching it
*/
private function findLatestPackage(PackageInterface $package, Composer $composer, PlatformRepository $platformRepo, bool $minorOnly, PlatformRequirementFilterInterface $platformReqFilter): ?PackageInterface
private function findLatestPackage(PackageInterface $package, Composer $composer, PlatformRepository $platformRepo, bool $minorOnly, bool $patchOnly, PlatformRequirementFilterInterface $platformReqFilter): ?PackageInterface
{
// find the latest version allowed in this repo set
$name = $package->getName();
Expand All @@ -1313,6 +1321,15 @@ private function findLatestPackage(PackageInterface $package, Composer $composer
$targetVersion = '^' . $package->getVersion();
}

if ($targetVersion === null && $patchOnly) {
$trimmedVersion = Preg::replace('{(\.0)+$}D', '', $package->getVersion());
$partsNeeded = substr($trimmedVersion, 0, 1) === '0' ? 4 : 3;
while (substr_count($trimmedVersion, '.') + 1 < $partsNeeded) {
$trimmedVersion .= '.0';
}
$targetVersion = '~' . $trimmedVersion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks wrong. ~ is not a semver operator, and thus behaves differently on 0.x series to ^.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's correct for >=1 versions if you were not trimming (you need ~1.2.0 to restrict to 1.2.x, ~1.2 would behave like ^1.2 which is not what you want here), but for 0.x we need to ensure there are at least 3 dots in the version, e.g. ~0.1.2.0 would be fine for a 0.1.2 version, effectively pinning it to that version if the package has only 3 digits. If version was 0.1.2.3 tho it'd allow patch level releases to e.g. 0.1.2.*

}

$candidate = $versionSelector->findBestCandidate($name, $targetVersion, $bestStability, $platformReqFilter);
while ($candidate instanceof AliasPackage) {
$candidate = $candidate->getAliasOf();
Expand Down