diff --git a/core/lib/Drupal/Core/Extension/Dependency.php b/core/lib/Drupal/Core/Extension/Dependency.php index 572c807241..31f67d3675 100644 --- a/core/lib/Drupal/Core/Extension/Dependency.php +++ b/core/lib/Drupal/Core/Extension/Dependency.php @@ -8,7 +8,7 @@ /** * A value object representing dependency information. */ -class Dependency { +class Dependency implements DependencyInterface { /** * The name of the dependency. @@ -97,8 +97,8 @@ protected function getConstraint() { /** * {@inheritdoc} */ - public function isCompatible($dependee_version) { - return $this->getConstraint()->isCompatible($dependee_version); + 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 index ff542d542f..8c646b4fed 100644 --- a/core/lib/Drupal/Core/Extension/Dependency/Composer.php +++ b/core/lib/Drupal/Core/Extension/Dependency/Composer.php @@ -28,7 +28,8 @@ class Composer implements DependencyInterface { * * @param string $constraint * String constraint. - * @param $name + * @param string $name + * Dependency name. */ public function __construct($constraint, $name) { $this->constraint = $constraint; @@ -45,8 +46,8 @@ public function getName() { /** * {@inheritdoc} */ - public function isCompatible($dependee_version) { - return Semver::satisfies($dependee_version, $this->constraint); + public function isCompatible($version) { + return Semver::satisfies($version, $this->constraint); } /** diff --git a/core/lib/Drupal/Core/Extension/Dependency/DependencyInterface.php b/core/lib/Drupal/Core/Extension/Dependency/DependencyInterface.php index e9142e3694..c79dd1dbdf 100644 --- a/core/lib/Drupal/Core/Extension/Dependency/DependencyInterface.php +++ b/core/lib/Drupal/Core/Extension/Dependency/DependencyInterface.php @@ -10,16 +10,16 @@ interface DependencyInterface { /** * Determines if the provided version is compatible with this dependency. * - * @param string $dependee_version - * The dependee version to check, for example '4.2'. + * @param string $version + * The version to check, for example '4.2'. * * @return bool * TRUE if compatible with the provided version, FALSE if not. */ - public function isCompatible($dependee_version); + public function isCompatible($version); /** - * Gets dependency name. + * Gets the dependency name. * * @return string * Dependency name. @@ -27,7 +27,7 @@ public function isCompatible($dependee_version); public function getName(); /** - * Gets constraint string from the dependency. + * Gets the constraint string from the dependency. * * @return string * The constraint string. diff --git a/core/lib/Drupal/Core/Extension/InfoParserDynamic.php b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php index a5cd9660e1..ac34570234 100644 --- a/core/lib/Drupal/Core/Extension/InfoParserDynamic.php +++ b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php @@ -26,36 +26,13 @@ class InfoParserDynamic implements InfoParserInterface { /** * The earliest Drupal version that supports 'composer.json' for dependencies. */ - const FIRST_COMPOSER_JSON_SUPPORTED_VERSION = '8.9.0'; + const FIRST_COMPOSER_JSON_SUPPORTED_VERSION = '9.1.0'; /** - * The key for composer dependencies under extension 'info'. + * The key where you'll find Composer dependencies in *.info.yml files. */ const COMPOSER_DEPENDENCIES = 'composer_dependencies'; - /** - * Determines if a version satisfies the given constraints. - * - * This method uses \Composer\Semver\Semver::satisfies() but returns FALSE if - * the version or constraints are not valid instead of throwing an exception. - * - * @param string $version - * The version. - * @param string $constraints - * The constraints. - * - * @return bool - * TRUE if the version satisfies the constraints, otherwise FALSE. - */ - protected static function satisfies($version, $constraints) { - try { - return Semver::satisfies($version, $constraints); - } - catch (\UnexpectedValueException $exception) { - return FALSE; - } - } - /** * InfoParserDynamic constructor. * @@ -107,12 +84,12 @@ public function parse($filename) { $parsed_info['core_version_requirement'] = \Drupal::VERSION; } else { + // 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"); + throw new InfoParserException("If the 'dependencies' key is used, the 'core' or 'core_version_requirement' key is required in $filename"); } if (!$has_composer_file) { - // Non-core extensions must specify core compatibility. - 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("If the 'core' or 'core_version_requirement' key is not provided, a composer.json file is required in $filename"); } } if ($has_composer_file) { @@ -122,8 +99,10 @@ public function parse($filename) { if (isset($parsed_info['core']) && !preg_match("/^\d\.x$/", $parsed_info['core'])) { throw new InfoParserException("Invalid 'core' value \"{$parsed_info['core']}\" in " . $filename); } + // Check if the core requirement is for a version of core that can't be + // used with core_version_requirement. if (static::isConstraintSatisfiedByPreviousVersion($parsed_info['core_version_requirement'], static::FIRST_COMPOSER_JSON_SUPPORTED_VERSION)) { - throw new InfoParserException('Core versions before ' . static::FIRST_COMPOSER_JSON_SUPPORTED_VERSION . " must be specified in the module info.yml in $filename"); + throw new InfoParserException('Core versions before ' . static::FIRST_COMPOSER_JSON_SUPPORTED_VERSION . " must be specified in the module info.yml file: $filename"); } } if (isset($parsed_info['core_version_requirement'])) { @@ -175,7 +154,7 @@ protected function getRequiredKeys() { } /** - * Determines if a constraint is satisfied by earlier versions of Drupal 8. + * Determines if a constraint is satisfied by earlier versions of Drupal. * * @param string $constraint * A core semantic version constraint. @@ -248,17 +227,21 @@ protected static function getAllPreviousCoreVersions($version) { } /** - * Parses a composer.json file. + * Parses a composer.json file and checks for core_version_requirement. * - * @param string $filename - * The file name. + * @param string $file_path + * Full path to the composer.json file. * * @return array - * Parsed composer.json file. + * 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($filename) { - if (!$parsed_info = json_decode(file_get_contents($filename), TRUE)) { - throw new InfoParserException("Unable to parse $filename " . json_last_error_msg()); + 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']; @@ -274,7 +257,7 @@ protected function parseComposerFile($filename) { $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 $filename"); + 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/ModuleExtensionList.php b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php index 38114c9b35..04b44787c4 100644 --- a/core/lib/Drupal/Core/Extension/ModuleExtensionList.php +++ b/core/lib/Drupal/Core/Extension/ModuleExtensionList.php @@ -209,8 +209,8 @@ protected function getInstalledExtensionNames() { */ protected function ensureRequiredDependencies(Extension $module, array $modules = []) { if (!empty($module->info['required'])) { - // Modern composer.json file. if (!empty($module->info[InfoParserDynamic::COMPOSER_DEPENDENCIES])) { + // Composer-based dependencies. $dependencies = array_keys($module->info[InfoParserDynamic::COMPOSER_DEPENDENCIES]); } else { 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 index 1ad12b776c..b124807860 100644 --- 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 @@ -1,5 +1,5 @@ name: 'Module composer dependencies test' type: module -description: 'Support module for test composer dependencies.' +description: 'Support module for testing composer dependencies.' package: Testing version: VERSION diff --git a/core/modules/system/tests/src/Functional/Form/ModulesListFormWebTest.php b/core/modules/system/tests/src/Functional/Form/ModulesListFormWebTest.php index 763308b38b..9f64b4a6d5 100644 --- a/core/modules/system/tests/src/Functional/Form/ModulesListFormWebTest.php +++ b/core/modules/system/tests/src/Functional/Form/ModulesListFormWebTest.php @@ -103,7 +103,7 @@ public function testModulesListFormWithInvalidInfoFile() { $this->assertSession()->elementExists('xpath', '//input[@name="text"]'); // Confirm that the error message is shown. - $this->assertSession()->pageTextContains("If the 'core' or 'core_version_requirement' key is not provided a composer.json file is required in " . $path . '/broken.info.yml'); + $this->assertSession()->pageTextContains("If the 'core' or 'core_version_requirement' key is not provided, a composer.json file is required in $filename" . $path . '/broken.info.yml'); // Check that the module filter text box is available. $this->assertSession()->elementExists('xpath', '//input[@name="text"]'); diff --git a/core/modules/system/tests/src/Functional/Module/DependencyTest.php b/core/modules/system/tests/src/Functional/Module/DependencyTest.php index 50e47a275f..bdbc7a3056 100644 --- a/core/modules/system/tests/src/Functional/Module/DependencyTest.php +++ b/core/modules/system/tests/src/Functional/Module/DependencyTest.php @@ -77,8 +77,8 @@ public function testMissingModules() { public function testIncompatibleModuleVersionDependency() { $assert_session = $this->assertSession(); $this->drupalGet('admin/modules'); - // Test that the system_incompatible_module_version_dependencies_test which - // uses an info.yml file for dependencies is marked as having an + // Test that the system_incompatible_module_version_dependencies_test, + // which uses an info.yml file for dependencies, is marked as having an // incompatible dependency. $this->assertRaw(t('@module (incompatible with version @version)', [ '@module' => 'System incompatible module version test (>2.0)', @@ -87,8 +87,8 @@ public function testIncompatibleModuleVersionDependency() { $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[system_incompatible_module_version_dependencies_test][enable]"]'); $this->assertCount(1, $checkbox, 'Checkbox for the module is disabled.'); $assert_session->fieldDisabled('modules[system_incompatible_module_version_dependencies_test][enable]'); - // Test that the composer_incompatible_module_version_dependencies_test - // which uses a composer.yml file for dependencies is marked as having an + // Test that the composer_incompatible_module_version_dependencies_test, + // which uses a composer.json file for dependencies, is marked as having an // incompatible dependency. $assert_session->responseContains('System incompatible module version test (^2) (incompatible with version 1.0)'); $assert_session->fieldDisabled('modules[composer_incompatible_module_version_dependencies_test][enable]'); @@ -106,24 +106,24 @@ public function testIncompatibleCoreVersionDependency() { ]), 'A module that depends on a module with an incompatible core version is marked as such.'); $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="modules[system_incompatible_core_version_dependencies_test][enable]"]'); $this->assertCount(1, $checkbox, 'Checkbox for the module is disabled.'); - // Test that module using an info.yml file with a dependency that is using a - // info.yml with a incompatible core version is marked as having an - // incompatible dependency. + // Test that a module using an info.yml file, with a dependency that is + // also using an info.yml file, that requires an incompatible version of + // core, is marked as having an incompatible dependency. $assert_session->elementContains('css', '#edit-modules-system-incompatible-core-version-dependencies-test-enable-description', 'System incompatible core version test (incompatible with this version of Drupal core)'); $assert_session->fieldDisabled('modules[system_incompatible_core_version_dependencies_test][enable]'); - // Test that module using an composer.json file with a dependency that is - // using a info.yml with a incompatible core version is marked as having an - // incompatible dependency. + // Test that a module using a composer.json file. with a dependency that is + // using an info.yml with an incompatible core version, is marked as having + // an incompatible dependency. $assert_session->elementContains('css', '#edit-modules-composer-incompatible-core-depend-test-enable-description', 'System incompatible core version test (incompatible with this version of Drupal core)'); $assert_session->fieldDisabled('modules[composer_incompatible_core_depend_test][enable]'); - // Test that module using an info.yml file with a dependency that is using a - // composer.json with a incompatible core version is marked as having an - // incompatible dependency. + // Test that a module using an info.yml file with a dependency that is + // using a composer.json with an incompatible core version is marked as + // having an incompatible dependency. $assert_session->elementContains('css', '#edit-modules-system-incompatible-core-composer-depend-test-enable-description', 'System core incompatible composer.json test (incompatible with this version of Drupal core)'); $assert_session->fieldDisabled('modules[composer_incompatible_core_composer_depend_test][enable]'); - // Test that module using an composer.json file with a dependency that is - // using a composer.json with a incompatible core version is marked as - // having an incompatible dependency. + // Test that a module using a composer.json file with a dependency that is + // using a composer.json file with an incompatible core version is marked + // as having an incompatible dependency. $assert_session->elementContains('css', '#edit-modules-composer-incompatible-core-composer-depend-test-enable-description', 'System core incompatible composer.json test (incompatible with this version of Drupal core)'); $assert_session->fieldDisabled('modules[composer_incompatible_core_composer_depend_test][enable]'); } diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php index 1fb0a69fae..804527d319 100644 --- a/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php +++ b/core/tests/Drupal/KernelTests/Core/Extension/ModuleInstallerTest.php @@ -130,8 +130,6 @@ public function providerTestInvalidCoreInstall() { */ 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]); } @@ -141,11 +139,11 @@ public function testDependencyInvalidCoreInstall($module, $dependency) { */ public function providerDependencyInvalidCoreInstall() { return [ - 'info with info dependency' => [ + 'info with info.yml dependency' => [ 'system_incompatible_core_version_dependencies_test', 'system_incompatible_core_version_test', ], - 'composer.json with info dependency' => [ + 'composer.json with info.yml dependency' => [ 'composer_incompatible_core_depend_test', 'system_incompatible_core_version_test', ], @@ -161,7 +159,7 @@ public function providerDependencyInvalidCoreInstall() { } /** - * Tests no dependencies install with a dependency with invalid core. + * Tests invalid core install, without installing dependencies. * * @dataProvider provideDependencyInvalidCoreInstallNoDependencies * @covers ::install @@ -175,10 +173,10 @@ public function testDependencyInvalidCoreInstallNoDependencies($module) { */ public function provideDependencyInvalidCoreInstallNoDependencies() { return [ - 'info with info dependency' => [ + 'info with info.yml dependency' => [ 'system_incompatible_core_version_dependencies_test', ], - 'composer.json with info dependency' => [ + 'composer.json with info.yml dependency' => [ 'composer_incompatible_core_depend_test', ], 'composer.json with composer.json dependency' => [ diff --git a/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php b/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php index 69f7a52064..62efc21d18 100644 --- a/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php @@ -137,7 +137,7 @@ public function testMissingCoreCoreVersionRequirement() { 'missing_core_and_core_version_requirement-duplicate.info.txt' => $missing_core_and_core_version_requirement, ], ]); - $exception_message = "If the 'core' or 'core_version_requirement' key is not provided a composer.json file is required in vfs://modules/fixtures/missing_core_and_core_version_requirement"; + $exception_message = "If the 'core' or 'core_version_requirement' key is not provided, a composer.json file is required in vfs://modules/fixtures/missing_core_and_core_version_requirement"; // Set the expected exception for the 2nd call to parse(). $this->expectException('\Drupal\Core\Extension\InfoParserException'); $this->expectExceptionMessage("$exception_message-duplicate.info.txt"); @@ -730,9 +730,9 @@ public function testComposerJson() { "type": "drupal-module", "license": "GPL-2.0-or-later", "require": { -"drupal/core": "^8.8", -"drupal/field": "~8.0", -"smurfcore/log": "~1.0" + "drupal/core": "^8.8", + "drupal/field": "~8.0", + "smurfcore/log": "~1.0" }, "version": "VERSION" }