Skip to content
Snippets Groups Projects
Commit 77b86bc8 authored by Ted Bowman's avatar Ted Bowman
Browse files

Issue #3305773 by omkar.podey, tedbow: Updates ExtensionUpdater to do correct...

Issue #3305773 by omkar.podey, tedbow: Updates ExtensionUpdater to do correct project to package conversion
parent e4efc8b8
No related branches found
No related tags found
No related merge requests found
Showing
with 166 additions and 155 deletions
...@@ -18,14 +18,6 @@ services: ...@@ -18,14 +18,6 @@ services:
- '@string_translation' - '@string_translation'
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
automatic_updates_extensions.validator.packages_type:
class: Drupal\automatic_updates_extensions\Validator\UpdatePackagesTypeValidator
arguments:
- '@string_translation'
- '@extension.list.module'
- '@extension.list.theme'
tags:
- { name: event_subscriber }
automatic_updates_extensions.validator.target_release: automatic_updates_extensions.validator.target_release:
class: Drupal\automatic_updates_extensions\Validator\UpdateReleaseValidator class: Drupal\automatic_updates_extensions\Validator\UpdateReleaseValidator
tags: tags:
......
...@@ -43,7 +43,10 @@ class ExtensionUpdater extends Stage { ...@@ -43,7 +43,10 @@ class ExtensionUpdater extends Stage {
->getPackage() ->getPackage()
->getDevRequires(); ->getDevRequires();
foreach ($project_versions as $project_name => $version) { foreach ($project_versions as $project_name => $version) {
$package = "drupal/$project_name"; $package = $composer->getPackageForProject($project_name);
if (empty($package)) {
throw new \InvalidArgumentException("The project $project_name is not a Drupal project known to Composer and cannot be updated.");
}
$group = array_key_exists($package, $require_dev) ? 'dev' : 'production'; $group = array_key_exists($package, $require_dev) ? 'dev' : 'production';
$package_versions[$group][$package] = LegacyVersionUtility::convertToSemanticVersion($version); $package_versions[$group][$package] = LegacyVersionUtility::convertToSemanticVersion($version);
} }
......
...@@ -7,12 +7,12 @@ use Drupal\automatic_updates_extensions\ExtensionUpdater; ...@@ -7,12 +7,12 @@ use Drupal\automatic_updates_extensions\ExtensionUpdater;
use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreOperationStageEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/** /**
* Validates packages are installed via Composer. * Validates packages are installed via Composer.
*
* @todo Remove this validator completely in https://www.drupal.org/i/3303900.
*/ */
class PackagesInstalledWithComposerValidator implements EventSubscriberInterface { class PackagesInstalledWithComposerValidator implements EventSubscriberInterface {
...@@ -31,10 +31,10 @@ class PackagesInstalledWithComposerValidator implements EventSubscriberInterface ...@@ -31,10 +31,10 @@ class PackagesInstalledWithComposerValidator implements EventSubscriberInterface
/** /**
* Validates that packages are installed with composer or not. * Validates that packages are installed with composer or not.
* *
* @param \Drupal\package_manager\Event\PreOperationStageEvent $event * @param \Drupal\package_manager\Event\PreApplyEvent $event
* The event object. * The event object.
*/ */
public function checkPackagesInstalledWithComposer(PreOperationStageEvent $event): void { public function checkPackagesInstalledWithComposer(PreApplyEvent $event): void {
$stage = $event->getStage(); $stage = $event->getStage();
if (!$stage instanceof ExtensionUpdater) { if (!$stage instanceof ExtensionUpdater) {
...@@ -54,7 +54,6 @@ class PackagesInstalledWithComposerValidator implements EventSubscriberInterface ...@@ -54,7 +54,6 @@ class PackagesInstalledWithComposerValidator implements EventSubscriberInterface
*/ */
public static function getSubscribedEvents() { public static function getSubscribedEvents() {
return [ return [
PreCreateEvent::class => 'checkPackagesInstalledWithComposer',
PreApplyEvent::class => 'checkPackagesInstalledWithComposer', PreApplyEvent::class => 'checkPackagesInstalledWithComposer',
]; ];
} }
...@@ -62,51 +61,37 @@ class PackagesInstalledWithComposerValidator implements EventSubscriberInterface ...@@ -62,51 +61,37 @@ class PackagesInstalledWithComposerValidator implements EventSubscriberInterface
/** /**
* Gets the packages which aren't installed via composer. * Gets the packages which aren't installed via composer.
* *
* @param \Drupal\package_manager\Event\PreOperationStageEvent $event * @param \Drupal\package_manager\Event\PreApplyEvent $event
* The event object. * The event object.
* *
* @return \Composer\Package\PackageInterface[] * @return \Composer\Package\PackageInterface[]
* Packages not installed via composer. * Packages not installed via composer.
*/ */
protected function getPackagesNotInstalledWithComposer(PreOperationStageEvent $event): array { protected function getPackagesNotInstalledWithComposer(PreApplyEvent $event): array {
$stage = $event->getStage(); $stage = $event->getStage();
$active_composer = $stage->getActiveComposer(); $active_composer = $stage->getActiveComposer();
$installed_packages = $active_composer->getInstalledPackages();
$missing_packages = []; $missing_packages = $stage->getStageComposer()->getPackagesNotIn($active_composer);
// During pre-create there is no stage directory, so missing packages can be
// found using package versions that will be required during the update,
// while during pre-apply there is stage directory which will be used to
// find missing packages.
if ($event instanceof PreCreateEvent) {
$package_versions = $stage->getPackageVersions();
foreach (['production', 'dev'] as $package_group) {
$missing_packages = array_merge($missing_packages, array_diff_key($package_versions[$package_group], $installed_packages));
}
}
else {
$missing_packages = $stage->getStageComposer()->getPackagesNotIn($active_composer);
// The core update system can only fetch release information for modules, // The core update system can only fetch release information for modules,
// themes, or profiles that are in the active code base (whether they're // themes, or profiles that are in the active code base (whether they're
// installed or not). If a package is not one of those types, ignore it // installed or not). If a package is not one of those types, ignore it
// even if its vendor namespace is `drupal`. // even if its vendor namespace is `drupal`.
$types = [ $types = [
'drupal-module', 'drupal-module',
'drupal-theme', 'drupal-theme',
'drupal-profile', 'drupal-profile',
]; ];
$filter = function (PackageInterface $package) use ($types): bool { $filter = function (PackageInterface $package) use ($types): bool {
return in_array($package->getType(), $types, TRUE); return in_array($package->getType(), $types, TRUE);
}; };
$missing_packages = array_filter($missing_packages, $filter); $missing_packages = array_filter($missing_packages, $filter);
// The core update system can only fetch release information for drupal // The core update system can only fetch release information for drupal
// projects, so saving only the packages whose name starts with drupal/. // projects, so saving only the packages whose name starts with drupal/.
$missing_packages = array_filter($missing_packages, function (string $key) { $missing_packages = array_filter($missing_packages, function (string $key) {
return str_starts_with($key, 'drupal/'); return str_starts_with($key, 'drupal/');
}, ARRAY_FILTER_USE_KEY); }, ARRAY_FILTER_USE_KEY);
}
return $missing_packages; return $missing_packages;
} }
......
<?php
namespace Drupal\automatic_updates_extensions\Validator;
use Drupal\automatic_updates_extensions\ExtensionUpdater;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Extension\ThemeExtensionList;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Utility\ProjectInfo;
use Drupal\package_manager\Event\PreCreateEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Validates the type of updated packages.
*/
class UpdatePackagesTypeValidator implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* The module list service.
*
* @var \Drupal\Core\Extension\ModuleExtensionList
*/
protected $moduleList;
/**
* The theme list service.
*
* @var \Drupal\Core\Extension\ThemeExtensionList
*/
protected $themeList;
/**
* Constructs a UpdatePackagesTypeValidator object.
*
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation
* The translation service.
* @param \Drupal\Core\Extension\ModuleExtensionList $module_list
* The module list service.
* @param \Drupal\Core\Extension\ThemeExtensionList $theme_list
* The theme list service.
*/
public function __construct(TranslationInterface $translation, ModuleExtensionList $module_list, ThemeExtensionList $theme_list) {
$this->setStringTranslation($translation);
$this->moduleList = $module_list;
$this->themeList = $theme_list;
}
/**
* Validates that updated packages are only modules or themes.
*
* @param \Drupal\package_manager\Event\PreCreateEvent $event
* The event object.
*/
public function checkPackagesAreOnlyThemesOrModules(PreCreateEvent $event): void {
$stage = $event->getStage();
if (!$stage instanceof ExtensionUpdater) {
return;
}
$invalid_projects = [];
$all_projects = $this->getInstalledProjectNames();
foreach ($stage->getPackageVersions() as $group) {
foreach (array_keys($group) as $package) {
// @todo Use
// \Drupal\package_manager\ComposerUtility::getProjectForPackage() to
// determine the project name in https://www.drupal.org/i/3304142.
$update_project = str_replace('drupal/', '', $package);
if ($update_project === 'drupal' || !in_array($update_project, $all_projects, TRUE)) {
$invalid_projects[] = $update_project;
}
}
}
if ($invalid_projects) {
$event->addError($invalid_projects, $this->t('The following projects cannot be updated because they are not Drupal modules or themes:'));
}
}
/**
* Returns a list of all available modules and themes' project names.
*
* @return string[]
* The project names of all available modules and themes.
*/
private function getInstalledProjectNames(): array {
$extension_list = array_merge($this->themeList->getList(), $this->moduleList->getList());
$map = \Closure::fromCallable([new ProjectInfo(), 'getProjectName']);
return array_map($map, $extension_list);
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
return [
PreCreateEvent::class => 'checkPackagesAreOnlyThemesOrModules',
];
}
}
...@@ -16,6 +16,8 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; ...@@ -16,6 +16,8 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
* @internal * @internal
* This class is an internal part of the module's update handling and * This class is an internal part of the module's update handling and
* should not be used by external code. * should not be used by external code.
*
* @todo Remove this validator completely in https://www.drupal.org/i/3307369.
*/ */
final class UpdateReleaseValidator implements EventSubscriberInterface { final class UpdateReleaseValidator implements EventSubscriberInterface {
...@@ -79,7 +81,7 @@ final class UpdateReleaseValidator implements EventSubscriberInterface { ...@@ -79,7 +81,7 @@ final class UpdateReleaseValidator implements EventSubscriberInterface {
['drupal-module', 'drupal-theme'], TRUE)) { ['drupal-module', 'drupal-theme'], TRUE)) {
continue; continue;
} }
[, $project_name] = explode('/', $staged_package->getName()); $project_name = $staged->getProjectForPackage($staged_package->getName());
$semantic_version = $staged_package->getPrettyVersion(); $semantic_version = $staged_package->getPrettyVersion();
if (!$this->isSupportedRelease($project_name, $semantic_version)) { if (!$this->isSupportedRelease($project_name, $semantic_version)) {
$messages[] = $this->t('Project @project_name to version @version', [ $messages[] = $this->t('Project @project_name to version @version', [
...@@ -115,8 +117,7 @@ final class UpdateReleaseValidator implements EventSubscriberInterface { ...@@ -115,8 +117,7 @@ final class UpdateReleaseValidator implements EventSubscriberInterface {
$messages = []; $messages = [];
foreach (['production', 'dev'] as $package_type) { foreach (['production', 'dev'] as $package_type) {
foreach ($all_versions[$package_type] as $package_name => $sematic_version) { foreach ($all_versions[$package_type] as $package_name => $sematic_version) {
$package_parts = explode('/', $package_name); $project_name = $stage->getActiveComposer()->getProjectForPackage($package_name);
$project_name = $package_parts[1];
// If the version isn't in the list of installable releases, then it // If the version isn't in the list of installable releases, then it
// isn't secure and supported and the user should receive an error. // isn't secure and supported and the user should receive an error.
if (!$this->isSupportedRelease($project_name, $sematic_version)) { if (!$this->isSupportedRelease($project_name, $sematic_version)) {
......
<?php
/**
* @file
*/
$projects_dir = __DIR__ . '/../../web/projects';
return [
'versions' => [
'drupal/my_module' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/my_module',
],
'drupal/my_dev_module' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/my_dev_module',
],
'drupal/semver_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/semver_test',
],
'drupal/aaa_update_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/aaa_update_test',
],
'drupal/aaa_automatic_updates_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/aaa_automatic_updates_test',
],
],
];
project: my_module
project: semver_test
name: 'New module' name: 'New module'
type: module type: module
core_version_requirement: ^9 core_version_requirement: ^9
project: new_module
name: 'New module' name: 'New module'
type: module type: module
core_version_requirement: ^9 core_version_requirement: ^9
project: new_module
<?php
/**
* @file
*/
$projects_dir = __DIR__ . '/../../web/projects';
return [
'versions' => [
'drupal/test_theme' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/test_theme',
],
'drupal/semver_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/semver_test',
],
'drupal/aaa_update_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/aaa_update_test',
],
],
];
<?php
/**
* @file
*/
$projects_dir = __DIR__ . '/../../web/projects';
return [
'versions' => [
'drupal/test_theme' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/test_theme',
],
'drupal/semver_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/semver_test',
],
'drupal/aaa_update_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/aaa_update_test',
],
],
];
<?php
/**
* @file
*/
$projects_dir = __DIR__ . '/../../web/projects';
return [
'versions' => [
'drupal/test_theme' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/test_theme',
],
'drupal/semver_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/semver_test',
],
'drupal/aaa_update_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/aaa_update_test',
],
],
];
<?php
/**
* @file
*/
$projects_dir = __DIR__ . '/../../web/projects';
return [
'versions' => [
'drupal/test_theme' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/test_theme',
],
'drupal/semver_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/semver_test',
],
'drupal/aaa_update_test' => [
'type' => 'drupal-module',
'install_path' => $projects_dir . '/aaa_update_test',
],
],
];
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