Skip to content
Snippets Groups Projects
Commit 4646e6fc authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3261847 by phenaproxima, tedbow: Add helpful methods to compute the...

Issue #3261847 by phenaproxima, tedbow: Add helpful methods to compute the difference between two ComposerUtility objects
parent 00796f61
No related branches found
No related tags found
1 merge request!192Issue #3261847: Add helpful methods to compute the difference between two ComposerUtility objects
......@@ -6,6 +6,7 @@ use Composer\Composer;
use Composer\Factory;
use Composer\IO\NullIO;
use Composer\Package\PackageInterface;
use Composer\Semver\Comparator;
use Drupal\Component\Serialization\Json;
/**
......@@ -133,35 +134,13 @@ class ComposerUtility {
return array_values($core_packages);
}
/**
* Returns all Drupal extension packages in the lock file.
*
* The following package types are considered Drupal extension packages:
* drupal-module, drupal-theme, drupal-custom-module, and drupal-custom-theme.
*
* @return \Composer\Package\PackageInterface[]
* All Drupal extension packages in the lock file, keyed by name.
*/
public function getDrupalExtensionPackages(): array {
$filter = function (PackageInterface $package): bool {
$drupal_package_types = [
'drupal-module',
'drupal-theme',
'drupal-custom-module',
'drupal-custom-theme',
];
return in_array($package->getType(), $drupal_package_types, TRUE);
};
return array_filter($this->getInstalledPackages(), $filter);
}
/**
* Returns information on all installed packages.
*
* @return \Composer\Package\PackageInterface[]
* All installed packages, keyed by name.
*/
protected function getInstalledPackages(): array {
public function getInstalledPackages(): array {
$installed_packages = $this->getComposer()
->getRepositoryManager()
->getLocalRepository()
......@@ -175,4 +154,43 @@ class ComposerUtility {
return $packages;
}
/**
* Returns the packages that are in the current project, but not in another.
*
* @param self $other
* A Composer utility wrapper around a different directory.
*
* @return \Composer\Package\PackageInterface[]
* The packages which are installed in the current project, but not in the
* other one, keyed by name.
*/
public function getPackagesNotIn(self $other): array {
return array_diff_key($this->getInstalledPackages(), $other->getInstalledPackages());
}
/**
* Returns the packages which have a different version in another project.
*
* This compares the current project with another one, and returns packages
* which are present in both, but in different versions.
*
* @param self $other
* A Composer utility wrapper around a different directory.
*
* @return \Composer\Package\PackageInterface[]
* The packages which are present in both the current project and the other
* one, but in different versions, keyed by name.
*/
public function getPackagesWithDifferentVersionsIn(self $other): array {
$theirs = $other->getInstalledPackages();
// Only compare packages that are both here and there.
$packages = array_intersect_key($this->getInstalledPackages(), $theirs);
$filter = function (PackageInterface $package, string $name) use ($theirs): bool {
return Comparator::notEqualTo($package->getVersion(), $theirs[$name]->getVersion());
};
return array_filter($packages, $filter, ARRAY_FILTER_USE_BOTH);
}
}
{}
{
"packages": [
{
"name": "drupal/existing",
"version": "1.0.0"
},
{
"name": "drupal/updated",
"version": "1.0.0"
},
{
"name": "drupal/removed",
"version": "1.0.0"
}
]
}
{}
{
"packages": [
{
"name": "drupal/existing",
"version": "1.0.0"
},
{
"name": "drupal/updated",
"version": "1.1.0"
},
{
"name": "drupal/added",
"version": "1.0.0"
}
]
}
......@@ -72,4 +72,23 @@ class ComposerUtilityTest extends KernelTestBase {
$this->assertSame($expected_packages, $packages);
}
/**
* @covers ::getPackagesNotIn
* @covers ::getPackagesWithDifferentVersionsIn
*/
public function testPackageComparison(): void {
$fixture_dir = __DIR__ . '/../../fixtures/packages_comparison';
$active = ComposerUtility::createForDirectory($fixture_dir . '/active');
$staged = ComposerUtility::createForDirectory($fixture_dir . '/stage');
$added = $staged->getPackagesNotIn($active);
$this->assertSame(['drupal/added'], array_keys($added));
$removed = $active->getPackagesNotIn($staged);
$this->assertSame(['drupal/removed'], array_keys($removed));
$updated = $active->getPackagesWithDifferentVersionsIn($staged);
$this->assertSame(['drupal/updated'], array_keys($updated));
}
}
......@@ -2,6 +2,7 @@
namespace Drupal\automatic_updates\Validator;
use Composer\Package\PackageInterface;
use Drupal\automatic_updates\Updater;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\Core\StringTranslation\StringTranslationTrait;
......@@ -39,8 +40,8 @@ final class StagedProjectsValidator implements EventSubscriberInterface {
}
try {
$active_packages = $stage->getActiveComposer()->getDrupalExtensionPackages();
$staged_packages = $stage->getStageComposer()->getDrupalExtensionPackages();
$active = $stage->getActiveComposer();
$stage = $stage->getStageComposer();
}
catch (\Throwable $e) {
$event->addError([
......@@ -55,8 +56,15 @@ final class StagedProjectsValidator implements EventSubscriberInterface {
'drupal-theme' => $this->t('theme'),
'drupal-custom-theme' => $this->t('custom theme'),
];
$filter = function (PackageInterface $package) use ($type_map): bool {
return array_key_exists($package->getType(), $type_map);
};
$new_packages = $stage->getPackagesNotIn($active);
$removed_packages = $active->getPackagesNotIn($stage);
$updated_packages = $active->getPackagesWithDifferentVersionsIn($stage);
// Check if any new Drupal projects were installed.
if ($new_packages = array_diff_key($staged_packages, $active_packages)) {
if ($new_packages = array_filter($new_packages, $filter)) {
$new_packages_messages = [];
foreach ($new_packages as $new_package) {
......@@ -77,7 +85,7 @@ final class StagedProjectsValidator implements EventSubscriberInterface {
}
// Check if any Drupal projects were removed.
if ($removed_packages = array_diff_key($active_packages, $staged_packages)) {
if ($removed_packages = array_filter($removed_packages, $filter)) {
$removed_packages_messages = [];
foreach ($removed_packages as $removed_package) {
$removed_packages_messages[] = $this->t(
......@@ -96,22 +104,21 @@ final class StagedProjectsValidator implements EventSubscriberInterface {
$event->addError($removed_packages_messages, $removed_packages_summary);
}
// Get all the packages that are neither newly installed or removed to
// check if their version numbers changed.
if ($pre_existing_packages = array_diff_key($staged_packages, $removed_packages, $new_packages)) {
foreach ($pre_existing_packages as $package_name => $staged_existing_package) {
$active_package = $active_packages[$package_name];
if ($staged_existing_package->getVersion() !== $active_package->getVersion()) {
$version_change_messages[] = $this->t(
"@type '@name' from @active_version to @staged_version.",
[
'@type' => $type_map[$active_package->getType()],
'@name' => $active_package->getName(),
'@staged_version' => $staged_existing_package->getPrettyVersion(),
'@active_version' => $active_package->getPrettyVersion(),
]
);
}
// Check if any Drupal projects were neither installed or removed, but had
// their version numbers changed.
if ($updated_packages = array_filter($updated_packages, $filter)) {
$staged_packages = $stage->getInstalledPackages();
foreach ($updated_packages as $name => $updated_package) {
$version_change_messages[] = $this->t(
"@type '@name' from @active_version to @staged_version.",
[
'@type' => $type_map[$updated_package->getType()],
'@name' => $updated_package->getName(),
'@staged_version' => $staged_packages[$name]->getPrettyVersion(),
'@active_version' => $updated_package->getPrettyVersion(),
]
);
}
if (!empty($version_change_messages)) {
$version_change_summary = $this->formatPlural(
......
......@@ -199,8 +199,8 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase {
"$fixtures_folder/version_changed",
'The update cannot proceed because the following Drupal projects were unexpectedly updated. Only Drupal Core updates are currently supported.',
[
"module 'drupal/test_module' from 1.3.0 to 1.3.1.",
"module 'drupal/dev-test_module' from 1.3.0 to 1.3.1.",
"module 'drupal/test_module' from 1.3.0 to 1.3.1.",
"module 'drupal/dev-test_module' from 1.3.0 to 1.3.1.",
],
],
];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment