diff --git a/core/includes/install.inc b/core/includes/install.inc index 3474c7c3cafac45eabf4118e315dcd1aafd5740b..7b720e8a2fed7577013a622965262447cd4a9764 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -10,6 +10,7 @@ use Drupal\Core\Database\Database; use Drupal\Core\Extension\Dependency; use Drupal\Core\Extension\ExtensionDiscovery; +use Drupal\Core\Extension\InfoParserDynamic; use Drupal\Core\Installer\InstallerKernel; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -761,11 +762,22 @@ function install_profile_info($profile, $langcode = 'en') { $dependency_name_function = function ($dependency) { return Dependency::createFromString($dependency)->getName(); }; - // Convert dependencies in [project:module] format. - $info['dependencies'] = array_map($dependency_name_function, $info['dependencies']); + if (!empty($info[InfoParserDynamic::COMPOSER_DEPENDENCIES])) { + $info['dependencies'] = array_keys($info[InfoParserDynamic::COMPOSER_DEPENDENCIES]); + } + else { + // Convert dependencies in [project:module] format. + $info['dependencies'] = array_map($dependency_name_function, $info['dependencies']); + } // Convert install key in [project:module] format. - $info['install'] = array_map($dependency_name_function, $info['install']); + $info['install'] = array_map(function ($dependency) { + if (strpos($dependency, ':') !== FALSE) { + list(, $dependency) = explode(':', $dependency); + } + $parts = explode('(', $dependency, 2); + return trim($parts[0]); + }, $info['install']); // Get a list of core's required modules. $required = []; diff --git a/core/lib/Drupal/Core/Extension/Dependency.php b/core/lib/Drupal/Core/Extension/Dependency.php index 622be6b7959c81c9af81ed884b3f0ed29593913d..4e4d339263a4dcee1276348acae6ae80cc5ae312 100644 --- a/core/lib/Drupal/Core/Extension/Dependency.php +++ b/core/lib/Drupal/Core/Extension/Dependency.php @@ -3,11 +3,12 @@ namespace Drupal\Core\Extension; use Drupal\Component\Version\Constraint; +use Drupal\Core\Extension\Dependency\DependencyInterface; /** * A value object representing dependency information. */ -class Dependency { +class Dependency implements DependencyInterface { /** * The name of the dependency. @@ -54,10 +55,7 @@ public function __construct($name, $project, $constraint) { } /** - * Gets the dependency's name. - * - * @return string - * The dependency's name. + * {@inheritdoc} */ public function getName() { return $this->name; @@ -97,13 +95,7 @@ protected function getConstraint() { } /** - * Determines if the provided version is compatible with this dependency. - * - * @param string $version - * The version to check, for example '4.2'. - * - * @return bool - * TRUE if compatible with the provided version, FALSE if not. + * {@inheritdoc} */ public function isCompatible($version) { return $this->getConstraint()->isCompatible($version); diff --git a/core/lib/Drupal/Core/Extension/Dependency/Composer.php b/core/lib/Drupal/Core/Extension/Dependency/Composer.php new file mode 100644 index 0000000000000000000000000000000000000000..8c646b4fedda34f3510fe018d5ab4f15c4087ea8 --- /dev/null +++ b/core/lib/Drupal/Core/Extension/Dependency/Composer.php @@ -0,0 +1,60 @@ +constraint = $constraint; + $this->name = $name; + } + + /** + * {@inheritdoc} + */ + public function getName() { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function isCompatible($version) { + return Semver::satisfies($version, $this->constraint); + } + + /** + * {@inheritdoc} + */ + public function getConstraintString() { + return $this->constraint; + } + +} diff --git a/core/lib/Drupal/Core/Extension/Dependency/DependencyInterface.php b/core/lib/Drupal/Core/Extension/Dependency/DependencyInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..c79dd1dbdf725a7675a025c66cb10c017b804566 --- /dev/null +++ b/core/lib/Drupal/Core/Extension/Dependency/DependencyInterface.php @@ -0,0 +1,37 @@ +root . '/core/')) { - // Core extensions do not need to specify core compatibility: they are - // by definition compatible so a sensible default is used. Core - // modules are allowed to provide these for testing purposes. - $parsed_info['core_version_requirement'] = \Drupal::VERSION; + $composer_filename = dirname($filename) . '/composer.json'; + $has_composer_file = file_exists($composer_filename); + $is_testing_module = isset($parsed_info['package']) && $parsed_info['package'] === 'Testing'; + if (!isset($parsed_info['core']) && !isset($parsed_info['core_version_requirement'])) { + if ((strpos($filename, 'core/') === 0 || strpos($filename, $this->root . '/core/') === 0)) { + if (!($has_composer_file && $is_testing_module)) { + // Core extensions do not need to specify core compatibility: they + // are by definition compatible so a sensible default is used. Core + // modules are allowed to provide these for testing purposes. + $parsed_info['core_version_requirement'] = \Drupal::VERSION; + } } - elseif (isset($parsed_info['package']) && $parsed_info['package'] === 'Testing') { + elseif ($is_testing_module) { // Modules in the testing package are exempt as well. This makes it // easier for contrib to use test modules. $parsed_info['core_version_requirement'] = \Drupal::VERSION; } else { + // @todo recheck the logic here after https://git.drupalcode.org/project/drupal/-/commit/718fa096fd1cab5a05543b67b1cd177d8e9dc769. // Non-core extensions must specify core compatibility. + if (isset($parsed_info['dependencies'])) { + throw new InfoParserException("If the 'dependencies' key is used, the 'core' or 'core_version_requirement' key is required in $filename"); + } + elseif (!$has_composer_file) { + throw new InfoParserException("If the 'core' or 'core_version_requirement' key is not provided, a composer.json file is required in $filename"); + } throw new InfoParserException("The 'core_version_requirement' key must be present in " . $filename); } + + // @todo recheck the logic here after https://git.drupalcode.org/project/drupal/-/commit/718fa096fd1cab5a05543b67b1cd177d8e9dc769. + if ($has_composer_file) { + $parsed_info += $this->parseComposerFile($composer_filename); + } + + if (isset($parsed_info['core']) && !preg_match("/^\d\.x$/", $parsed_info['core'])) { + throw new InfoParserException("Invalid 'core' value \"{$parsed_info['core']}\" in " . $filename); + } } // Determine if the extension is compatible with the current version of @@ -100,4 +133,40 @@ protected function getRequiredKeys() { return ['type', 'name']; } + /** + * Parses a composer.json file and checks for core_version_requirement. + * + * @param string $file_path + * Full path to the composer.json file. + * + * @return array + * Parsed composer.json file data. + * + * @throws \Drupal\Core\Extension\InfoParserException + * Thrown when the file cannot be parsed, or when the parsed require key + * does not include the drupal/core package. + */ + protected function parseComposerFile($file_path) { + if (!$parsed_info = json_decode(file_get_contents($file_path), TRUE)) { + throw new InfoParserException("Unable to parse $file_path " . json_last_error_msg()); + } + + $require = $parsed_info['require']; + foreach ($require as $project => $constraint) { + [$namespace, $name] = explode('/', $project); + if ($namespace !== 'drupal') { + continue; + } + if ($name === 'core') { + $parsed_info['core_version_requirement'] = $constraint; + continue; + } + $parsed_info[static::COMPOSER_DEPENDENCIES][$name] = $constraint; + } + if (empty($parsed_info['core_version_requirement'])) { + throw new InfoParserException("The 'require' key must at least specify a 'drupal/core' version in $file_path"); + } + return $parsed_info; + } + } diff --git a/core/lib/Drupal/Core/Extension/ModuleDependencyMessageTrait.php b/core/lib/Drupal/Core/Extension/ModuleDependencyMessageTrait.php index 4511f423df1a1e1e92dc4442926c6990238ce3f8..f65909bc9129d9feeb459e3f6f76df30d91d3f92 100644 --- a/core/lib/Drupal/Core/Extension/ModuleDependencyMessageTrait.php +++ b/core/lib/Drupal/Core/Extension/ModuleDependencyMessageTrait.php @@ -5,9 +5,9 @@ /** * Messages for missing or incompatible dependencies on modules. * - * @internal The trait simply helps core classes that display user messages - * regarding missing or incompatible module dependencies share exact same - * wording and markup. + * @internal This trait helps core classes that display user messages regarding + * missing or incompatible module dependencies share exact same wording and + * markup. */ trait ModuleDependencyMessageTrait { @@ -18,13 +18,13 @@ trait ModuleDependencyMessageTrait { * The list of existing modules. * @param string $dependency * The module dependency to check. - * @param \Drupal\Core\Extension\Dependency $dependency_object + * @param \Drupal\Core\Extension\DependencyInterface $dependency_object * Dependency object used for comparing version requirement data. * * @return string|null * NULL if compatible, otherwise a string describing the incompatibility. */ - public function checkDependencyMessage(array $modules, $dependency, Dependency $dependency_object) { + public function checkDependencyMessage(array $modules, $dependency, DependencyInterface $dependency_object) { if (!isset($modules[$dependency])) { return $this->t('@module_name (missing)', ['@module_name' => $dependency]); } diff --git a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php index 1176b566796e89d2f890adea768f773adbf3c54b..9f9ddd1920eee029a753968d8d704614f903f540 100644 --- a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php +++ b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php @@ -208,8 +208,20 @@ protected function getInstalledExtensionNames() { */ protected function ensureRequiredDependencies(Extension $module, array $modules = []) { if (!empty($module->info['required'])) { - foreach ($module->info['dependencies'] as $dependency) { - $dependency_name = Dependency::createFromString($dependency)->getName(); + if (!empty($module->info[InfoParserDynamic::COMPOSER_DEPENDENCIES])) { + // Composer-based dependencies. + $dependencies = array_keys($module->info[InfoParserDynamic::COMPOSER_DEPENDENCIES]); + } + else { + // Legacy .info.yml files. + $dependencies = array_map(function ($dependency) { + return Dependency::createFromString($dependency)->getName(); + }, $module->info['dependencies']); + } + foreach ($dependencies as $dependency_name) { + if ($dependency_name === 'core') { + continue; + } if (!isset($modules[$dependency_name]->info['required'])) { $modules[$dependency_name]->info['required'] = TRUE; $modules[$dependency_name]->info['explanation'] = $this->t('Dependency of required module @module', ['@module' => $module->info['name']]); diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php index 0a70ba2b66ecc06b4cb2ab19bfe9124af1bd5c50..ee924049c17ce2b589c3f15aeb7dd5af6eca3137 100644 --- a/core/lib/Drupal/Core/Extension/ModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php @@ -6,6 +6,7 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\DestructableInterface; +use Drupal\Core\Extension\Dependency\Composer; use Drupal\Core\Extension\Exception\UnknownExtensionException; /** @@ -224,7 +225,12 @@ protected function add($type, $name, $path) { public function buildModuleDependencies(array $modules) { foreach ($modules as $module) { $graph[$module->getName()]['edges'] = []; - if (isset($module->info['dependencies']) && is_array($module->info['dependencies'])) { + if (isset($module->info[InfoParserDynamic::COMPOSER_DEPENDENCIES]) && is_array($module->info[InfoParserDynamic::COMPOSER_DEPENDENCIES])) { + foreach ($module->info[InfoParserDynamic::COMPOSER_DEPENDENCIES] as $name => $constraint) { + $graph[$module->getName()]['edges'][$name] = new Composer($constraint, $name); + } + } + elseif (isset($module->info['dependencies']) && is_array($module->info['dependencies'])) { foreach ($module->info['dependencies'] as $dependency) { $dependency_data = Dependency::createFromString($dependency); $graph[$module->getName()]['edges'][$dependency_data->getName()] = $dependency_data; diff --git a/core/modules/system/src/Form/ModulesListForm.php b/core/modules/system/src/Form/ModulesListForm.php index 8df4971db03206ce97cb4ff250381fd0483bf775..9b1cbb0b9ef14f913e99947954ea86b44437abc2 100644 --- a/core/modules/system/src/Form/ModulesListForm.php +++ b/core/modules/system/src/Form/ModulesListForm.php @@ -367,7 +367,7 @@ protected function buildRow(array $modules, Extension $module, $distribution) { } // If this module requires other modules, add them to the array. - /** @var \Drupal\Core\Extension\Dependency $dependency_object */ + /** @var \Drupal\Core\Extension\Dependency\DependencyInterface $dependency_object */ foreach ($module->requires as $dependency => $dependency_object) { // @todo Add logic for not displaying hidden modules in // https://drupal.org/node/3117829. diff --git a/core/modules/system/tests/modules/composer_core_incompatible_test/composer.json b/core/modules/system/tests/modules/composer_core_incompatible_test/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..a3cb33ff0367ef14bfd5b8ed5ffa08df3d0f4f89 --- /dev/null +++ b/core/modules/system/tests/modules/composer_core_incompatible_test/composer.json @@ -0,0 +1,9 @@ +{ + "name": "drupal/composer_core_incompatible_test", + "description": "A test composer file", + "license": "GPL-2.0-or-later", + "type": "drupal-module", + "require": { + "drupal/core": "^100" + } +} diff --git a/core/modules/system/tests/modules/composer_core_incompatible_test/composer_core_incompatible_test.info.yml b/core/modules/system/tests/modules/composer_core_incompatible_test/composer_core_incompatible_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..90165e82dff1e5192b3ede2a4fdc8b804be0cc9a --- /dev/null +++ b/core/modules/system/tests/modules/composer_core_incompatible_test/composer_core_incompatible_test.info.yml @@ -0,0 +1,5 @@ +name: 'System core incompatible composer.json test' +type: module +description: 'Support module for testing core incompatible using composer.json.' +package: Testing +version: 1.0.0 diff --git a/core/modules/system/tests/modules/composer_dependencies_test/composer.json b/core/modules/system/tests/modules/composer_dependencies_test/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..ec9d6ff0f72dd51aa132fb38776489af9b96622c --- /dev/null +++ b/core/modules/system/tests/modules/composer_dependencies_test/composer.json @@ -0,0 +1,10 @@ +{ + "name": "drupal/composer_dependencies_test", + "description": "A test composer file", + "license": "GPL-2.0-or-later", + "type": "drupal-module", + "require": { + "drupal/core": "^8.8", + "drupal/common_test": "^2.4.2" + } +} diff --git a/core/modules/system/tests/modules/composer_dependencies_test/composer_dependencies_test.info.yml b/core/modules/system/tests/modules/composer_dependencies_test/composer_dependencies_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..b124807860aa43099775c75ea2a1b1a0ac17f284 --- /dev/null +++ b/core/modules/system/tests/modules/composer_dependencies_test/composer_dependencies_test.info.yml @@ -0,0 +1,5 @@ +name: 'Module composer dependencies test' +type: module +description: 'Support module for testing composer dependencies.' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/composer_incompatible_core_composer_depend_test/composer.json b/core/modules/system/tests/modules/composer_incompatible_core_composer_depend_test/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..07581995b750b869de12bc65e21a7139757331b4 --- /dev/null +++ b/core/modules/system/tests/modules/composer_incompatible_core_composer_depend_test/composer.json @@ -0,0 +1,10 @@ +{ + "name": "drupal/composer_incompatible_core_composer_depend_test", + "description": "A test composer file", + "license": "GPL-2.0-or-later", + "type": "drupal-module", + "require": { + "drupal/core": "^8.8", + "drupal/composer_core_incompatible_test": "*" + } +} diff --git a/core/modules/system/tests/modules/composer_incompatible_core_composer_depend_test/composer_incompatible_core_composer_depend_test.info.yml b/core/modules/system/tests/modules/composer_incompatible_core_composer_depend_test/composer_incompatible_core_composer_depend_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..72d70ff4d79fbaac6255b833a1dc0dc09204bdb7 --- /dev/null +++ b/core/modules/system/tests/modules/composer_incompatible_core_composer_depend_test/composer_incompatible_core_composer_depend_test.info.yml @@ -0,0 +1,5 @@ +name: 'Composer.json Incompatible core version composer dependencies test' +type: module +description: 'Support module for testing system dependencies.' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/composer_incompatible_core_depend_test/composer.json b/core/modules/system/tests/modules/composer_incompatible_core_depend_test/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..237b5af5e544654554c90867286cf73d4e2edf2c --- /dev/null +++ b/core/modules/system/tests/modules/composer_incompatible_core_depend_test/composer.json @@ -0,0 +1,10 @@ +{ + "name": "drupal/composer_incompatible_core_depend_test", + "description": "A test composer file", + "license": "GPL-2.0-or-later", + "type": "drupal-module", + "require": { + "drupal/core": "^8.8", + "drupal/system_incompatible_core_version_test": "*" + } +} diff --git a/core/modules/system/tests/modules/composer_incompatible_core_depend_test/composer_incompatible_core_depend_test.info.yml b/core/modules/system/tests/modules/composer_incompatible_core_depend_test/composer_incompatible_core_depend_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..571e9257e505e95b27a08b7234441ade5ee8e2ad --- /dev/null +++ b/core/modules/system/tests/modules/composer_incompatible_core_depend_test/composer_incompatible_core_depend_test.info.yml @@ -0,0 +1,5 @@ +name: 'Composer.json Incompatible core version dependencies test' +type: module +description: 'Support module for testing system dependencies.' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/composer_incompatible_module_version_dependencies_test/composer.json b/core/modules/system/tests/modules/composer_incompatible_module_version_dependencies_test/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..875dfef22cbe46b78412212d45dc013582094995 --- /dev/null +++ b/core/modules/system/tests/modules/composer_incompatible_module_version_dependencies_test/composer.json @@ -0,0 +1,10 @@ +{ + "name": "drupal/composer_incompatible_module_version_dependencies_test", + "description": "A test composer file", + "license": "GPL-2.0-or-later", + "type": "drupal-module", + "require": { + "drupal/core": "^8.8", + "drupal/system_incompatible_module_version_test": "^2" + } +} diff --git a/core/modules/system/tests/modules/composer_incompatible_module_version_dependencies_test/composer_incompatible_module_version_dependencies_test.info.yml b/core/modules/system/tests/modules/composer_incompatible_module_version_dependencies_test/composer_incompatible_module_version_dependencies_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..6b544da4048675d2d34db371aa93672434ea3197 --- /dev/null +++ b/core/modules/system/tests/modules/composer_incompatible_module_version_dependencies_test/composer_incompatible_module_version_dependencies_test.info.yml @@ -0,0 +1,5 @@ +name: 'Incompatible module version dependencies test using composer' +type: module +description: 'Support module for testing system dependencies using composer.' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/system_composer_dependencies_test/composer.json b/core/modules/system/tests/modules/system_composer_dependencies_test/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..abc9de2db01b2b99fbb4bd076bd008359fb428f6 --- /dev/null +++ b/core/modules/system/tests/modules/system_composer_dependencies_test/composer.json @@ -0,0 +1,10 @@ +{ + "name": "drupal/system_composer_dependencies_test", + "description": "Support module for testing system composer dependencies.", + "license": "GPL-2.0-or-later", + "type": "drupal-module", + "require": { + "drupal/core": "^8.8", + "drupal/missing_composer_dependency": "^1" + } +} diff --git a/core/modules/system/tests/modules/system_composer_dependencies_test/system_composer_dependencies_test.info.yml b/core/modules/system/tests/modules/system_composer_dependencies_test/system_composer_dependencies_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..5ce89f37a2d26a8078ac51fe06bf26c57cc2e7b2 --- /dev/null +++ b/core/modules/system/tests/modules/system_composer_dependencies_test/system_composer_dependencies_test.info.yml @@ -0,0 +1,5 @@ +name: 'System composer dependency test' +type: module +description: 'Support module for testing system composer dependencies.' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/system_core_composer_test/composer.json b/core/modules/system/tests/modules/system_core_composer_test/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..63b42db1fcc2df7ec7e1890e22559d8943125328 --- /dev/null +++ b/core/modules/system/tests/modules/system_core_composer_test/composer.json @@ -0,0 +1,9 @@ +{ + "name": "drupal/system_core_composer_test", + "description": "A test composer file", + "license": "GPL-2.0-or-later", + "type": "drupal-module", + "require": { + "drupal/core": "^8.8 || ^9 || ^10 || ^11 || ^12 || ^13" + } +} diff --git a/core/modules/system/tests/modules/system_core_composer_test/system_core_composer_test.info.yml b/core/modules/system/tests/modules/system_core_composer_test/system_core_composer_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..0c56c05ecf8874b81887ffff77fab6bfb6ff16d9 --- /dev/null +++ b/core/modules/system/tests/modules/system_core_composer_test/system_core_composer_test.info.yml @@ -0,0 +1,5 @@ +name: 'System core version test using composer.json.' +type: module +description: 'Support module for testing core using composer.' +package: Testing +version: 1.0.0 diff --git a/core/modules/system/tests/modules/system_incompatible_core_composer_depend_test/system_incompatible_core_composer_depend_test.info.yml b/core/modules/system/tests/modules/system_incompatible_core_composer_depend_test/system_incompatible_core_composer_depend_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..ffee1eeb335c2309c907900374fe93e40a9f9f95 --- /dev/null +++ b/core/modules/system/tests/modules/system_incompatible_core_composer_depend_test/system_incompatible_core_composer_depend_test.info.yml @@ -0,0 +1,8 @@ +name: 'System incompatible core version dependencies using composer.json test' +type: module +description: 'Support module for testing system dependencies.' +package: Testing +version: VERSION +core: 8.x +dependencies: + - drupal:composer_core_incompatible_test diff --git a/core/modules/system/tests/src/Functional/Module/DependencyTest.php b/core/modules/system/tests/src/Functional/Module/DependencyTest.php index e176855055d426018910b3f603d7c0c4e342260e..501138db6fb955a392f946faa564c0d789578895 100644 --- a/core/modules/system/tests/src/Functional/Module/DependencyTest.php +++ b/core/modules/system/tests/src/Functional/Module/DependencyTest.php @@ -43,6 +43,7 @@ public function testProjectNamespaceForDependencies() { */ public function testEnableWithoutDependency() { // Attempt to enable Content Translation without Language enabled. + // @todo Add a composer.json test case. $edit = []; $edit['modules[content_translation][enable]'] = 'content_translation'; $this->drupalGet('admin/modules'); @@ -69,6 +70,7 @@ public function testEnableWithoutDependency() { public function testMissingModules() { // Test that the system_dependencies_test module is marked // as missing a dependency. + $assert_session = $this->assertSession(); $this->drupalGet('admin/modules'); $this->assertSession()->pageTextContains(Unicode::ucfirst('_missing_dependency') . ' (missing)'); $this->assertSession()->elementTextEquals('xpath', '//tr[@data-drupal-selector="edit-modules-system-dependencies-test"]//span[@class="admin-missing"]', 'missing'); diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php index 8dcad9b6e9a220d67b575d57305405208189de49..fe26e0820825363017d1ff62c6110a8160a8773e 100644 --- a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php +++ b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php @@ -114,27 +114,81 @@ public static function providerTestInvalidCoreInstall() { 'system_core_incompatible_semver_test', TRUE, ], + 'no dependencies composer_core_incompatible_test' => [ + 'system_core_incompatible_semver_test', + FALSE, + ], + 'install_dependencies composer_core_incompatible_test' => [ + 'system_core_incompatible_semver_test', + TRUE, + ], ]; } /** * Tests install with a dependency with an invalid core version constraint. * + * @dataProvider providerDependencyInvalidCoreInstall * @covers ::install */ - public function testDependencyInvalidCoreInstall() { + public function testDependencyInvalidCoreInstall($module, $dependency) { $this->expectException(MissingDependencyException::class); - $this->expectExceptionMessage("Unable to install modules: module 'system_incompatible_core_version_dependencies_test'. Its dependency module 'system_core_incompatible_semver_test' is incompatible with this version of Drupal core."); - $this->container->get('module_installer')->install(['system_incompatible_core_version_dependencies_test']); + $this->expectExceptionMessage("Unable to install modules: module '$module'. Its dependency module '$dependency' is incompatible with this version of Drupal core."); + $this->container->get('module_installer')->install([$module]); } /** - * Tests no dependencies install with a dependency with invalid core. + * Dataprovider for testDependencyInvalidCoreInstall(). + */ + public function providerDependencyInvalidCoreInstall() { + return [ + 'info with info.yml dependency' => [ + 'system_incompatible_core_version_dependencies_test', + 'system_core_incompatible_semver_test', + ], + 'composer.json with info.yml dependency' => [ + 'composer_incompatible_core_depend_test', + 'system_incompatible_core_version_test', + ], + 'composer.json with composer.json dependency' => [ + 'composer_incompatible_core_composer_depend_test', + 'composer_core_incompatible_test', + ], + 'info with composer.json dependency' => [ + 'composer_incompatible_core_composer_depend_test', + 'composer_core_incompatible_test', + ], + ]; + } + + /** + * Tests invalid core install, without installing dependencies. * + * @dataProvider provideDependencyInvalidCoreInstallNoDependencies * @covers ::install */ - public function testDependencyInvalidCoreInstallNoDependencies() { - $this->assertTrue($this->container->get('module_installer')->install(['system_incompatible_core_version_dependencies_test'], FALSE)); + public function testDependencyInvalidCoreInstallNoDependencies($module) { + $this->assertTrue($this->container->get('module_installer')->install([$module], FALSE)); + } + + /** + * Dataprovider for testDependencyInvalidCoreInstallNoDependencies(). + */ + public function provideDependencyInvalidCoreInstallNoDependencies() { + return [ + 'info with info.yml dependency' => [ + 'system_incompatible_core_version_dependencies_test', + ], + 'composer.json with info.yml dependency' => [ + 'composer_incompatible_core_depend_test', + ], + 'composer.json with composer.json dependency' => [ + 'composer_incompatible_core_composer_depend_test', + ], + 'info with composer.json dependency' => [ + 'composer_incompatible_core_composer_depend_test', + ], + ]; } /** diff --git a/core/tests/Drupal/Tests/Core/Extension/DependencyTest.php b/core/tests/Drupal/Tests/Core/Extension/DependencyTest.php index b3f81fd2977fdf7497b3ffbda1e766a5a3dbdf62..a4c365aeebeb59686dfd199dcbd375eace448a70 100644 --- a/core/tests/Drupal/Tests/Core/Extension/DependencyTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/DependencyTest.php @@ -11,6 +11,7 @@ /** * @coversDefaultClass \Drupal\Core\Extension\Dependency * @group Extension + * @group legacy */ class DependencyTest extends UnitTestCase {