How to cancel the composer update operation from a "pre-package-update" listener

Viewed 397

Working on a small Composer plugin, which has a listener for the pre-package-update event.

public function prePackageUpdate(PackageEvent $event): void
{
    /** @var UpdateOperation $operation */
    $operation = $event->getOperation();

    if ($something) {
        // I would like the stop the update for this package...
    }
}

Based on some logic, I would like the package to not be updated, but I cannot find any way to do that... Is there one?

Ideally I'd like the command (either install or update) to continue with the other packages, but if that's not possible, it's ok if the whole process is cancelled and reverted.

1 Answers

Answering my own question based on this issue I cross-posted on GitHub.

Understandably, cancelling a specific operation is not possible. Composer does the dependencies solving process and comes up with a set of operations to perform, which are potentially inter-dependent, so skipping one of them may affect the others (e.g. if you cancel the update of a package, the versions selected to update other packages may need to be different), so a new dependencies solving process would be required.

Cancelling the whole process is indeed possible though, and can be done by simply throwing an Exception.

However, throwing the Exception from the pre-package-update listener might leave the vendor in a somewhat inconsistent state. A better place to do that would be in a post-dependencies-solving listener, where no operations have been performed at all.

public function postDependenciesSolving(InstallerEvent $event)
{
    foreach ($event->getOperations() as $operation) {
        if ($something) {
            throw new Exception('Whole process cancelled and reverted!');
        }
    }
}
Related