diff --git a/core/lib/Drupal/Core/Extension/InfoParserDynamic.php b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php index 2e1dae399d..daf78da8d2 100644 --- a/core/lib/Drupal/Core/Extension/InfoParserDynamic.php +++ b/core/lib/Drupal/Core/Extension/InfoParserDynamic.php @@ -52,53 +52,61 @@ public function parse($filename) { catch (InvalidDataTypeException $e) { throw new InfoParserException("Unable to parse $filename " . $e->getMessage()); } - $missing_keys = array_diff($this->getRequiredKeys(), array_keys($parsed_info)); - if (!empty($missing_keys)) { - throw new InfoParserException('Missing required keys (' . implode(', ', $missing_keys) . ') in ' . $filename); - } - if (!isset($parsed_info['core']) && !isset($parsed_info['core_version_requirement'])) { + + $core_version_requirement_dynamically_set = FALSE; + $is_test_package = isset($parsed_info['package']) && $parsed_info['package'] === 'Testing'; + if (!isset($parsed_info['core_version_requirement'])) { if (strpos($filename, 'core/') === 0 || strpos($filename, $this->root . '/core/') === 0) { // 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. + $core_version_requirement_dynamically_set = TRUE; $parsed_info['core_version_requirement'] = \Drupal::VERSION; } - elseif (isset($parsed_info['package']) && $parsed_info['package'] === 'Testing') { + elseif ($is_test_package) { // Modules in the testing package are exempt as well. This makes it // easier for contrib to use test modules. + $core_version_requirement_dynamically_set = TRUE; $parsed_info['core_version_requirement'] = \Drupal::VERSION; } - else { - // Non-core extensions must specify core compatibility. - throw new InfoParserException("The 'core' or the 'core_version_requirement' key must be present in " . $filename); - } } - if (isset($parsed_info['core']) && !preg_match("/^\d\.x$/", $parsed_info['core'])) { - throw new InfoParserException("Invalid 'core' value \"{$parsed_info['core']}\" in " . $filename); + $missing_keys = array_diff($this->getRequiredKeys(), array_keys($parsed_info)); + if (!empty($missing_keys)) { + throw new InfoParserException('Missing required keys (' . implode(', ', $missing_keys) . ') in ' . $filename); } - if (isset($parsed_info['core_version_requirement'])) { - $supports_pre_core_version_requirement_version = static::isConstraintSatisfiedByPreviousVersion($parsed_info['core_version_requirement'], static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION); - // If the 'core_version_requirement' constraint does not satisfy any - // Drupal 8 versions before 8.7.7 then 'core' cannot be set or it will - // effectively support all versions of Drupal 8 because - // 'core_version_requirement' will be ignored in previous versions. - if (!$supports_pre_core_version_requirement_version && isset($parsed_info['core'])) { - throw new InfoParserException("The 'core_version_requirement' constraint ({$parsed_info['core_version_requirement']}) requires the 'core' key not be set in " . $filename); + + $supports_pre_core_version_requirement_version = static::isConstraintSatisfiedByPreviousVersion($parsed_info['core_version_requirement'], static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION); + + if (isset($parsed_info['core']) && $parsed_info['core'] !== '8.x' && !$is_test_package) { + $invalid_core_message = "The 'core' value \"{$parsed_info['core']}\" is invalid in " . $filename . "."; + if (!$supports_pre_core_version_requirement_version) { + $invalid_core_message .= " The 'core' key can be removed because this module does not support any Drupal version prior to " . static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION; } - // 'core_version_requirement' can not be used to specify Drupal 8 - // versions before 8.7.7 because these versions do not use the - // 'core_version_requirement' key. Do not throw the exception if the - // constraint also is satisfied by 8.0.0-alpha1 to allow constraints - // such as '^8' or '^8 || ^9'. - if ($supports_pre_core_version_requirement_version && !Semver::satisfies('8.0.0-alpha1', $parsed_info['core_version_requirement'])) { - throw new InfoParserException("The 'core_version_requirement' can not be used to specify compatibility for a specific version before " . static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION . " in $filename"); + else { + $invalid_core_message .= " The 'core' key must be set to '8.x' to support Drupal versions prior to " . static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION; } + throw new InfoParserException($invalid_core_message); + + } + // If the 'core_version_requirement' constraint does not satisfy any + // Drupal 8 versions before 8.7.7 then 'core' cannot be set or it will + // effectively support all versions of Drupal 8 because + // 'core_version_requirement' will be ignored in previous versions. + if (!$core_version_requirement_dynamically_set && !$supports_pre_core_version_requirement_version && isset($parsed_info['core'])) { + throw new InfoParserException("The 'core_version_requirement' constraint ({$parsed_info['core_version_requirement']}) requires the 'core' key not be set in " . $filename); + } + // 'core_version_requirement' can not be used to specify Drupal 8 + // versions before 8.7.7 because these versions do not use the + // 'core_version_requirement' key. Do not throw the exception if the + // constraint also is satisfied by 8.0.0-alpha1 to allow constraints + // such as '^8' or '^8 || ^9'. + if ($supports_pre_core_version_requirement_version && !Semver::satisfies('8.0.0-alpha1', $parsed_info['core_version_requirement'])) { + throw new InfoParserException("The 'core_version_requirement' can not be used to specify compatibility for a specific version before " . static::FIRST_CORE_VERSION_REQUIREMENT_SUPPORTED_VERSION . " in $filename"); } // Determine if the extension is compatible with the current version of // Drupal core. - $core_version_constraint = isset($parsed_info['core_version_requirement']) ? $parsed_info['core_version_requirement'] : $parsed_info['core']; - $parsed_info['core_incompatible'] = !Semver::satisfies(\Drupal::VERSION, $core_version_constraint); + $parsed_info['core_incompatible'] = !Semver::satisfies(\Drupal::VERSION, $parsed_info['core_version_requirement']); if (isset($parsed_info['version']) && $parsed_info['version'] === 'VERSION') { $parsed_info['version'] = \Drupal::VERSION; } @@ -131,7 +139,7 @@ public function parse($filename) { * An array of required keys. */ protected function getRequiredKeys() { - return ['type', 'name']; + return ['type', 'name', 'core_version_requirement']; } /** diff --git a/core/modules/system/tests/themes/test_invalid_core/test_invalid_core.info.yml b/core/modules/system/tests/themes/test_invalid_core/test_invalid_core.info.yml deleted file mode 100644 index 3ac1e2017a..0000000000 --- a/core/modules/system/tests/themes/test_invalid_core/test_invalid_core.info.yml +++ /dev/null @@ -1,6 +0,0 @@ -name: 'Theme test with invalid core version' -type: theme -base theme: stable -description: 'Test theme which has an invalid core version.' -version: VERSION -core: 7.x diff --git a/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php b/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php index 2e8c9ce1ca..0e62f558dc 100644 --- a/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php @@ -99,47 +99,10 @@ public function testInfoParserMissingKeys() { ]); $filename = vfsStream::url('modules/fixtures/missing_keys.info.txt'); $this->expectException('\Drupal\Core\Extension\InfoParserException'); - $this->expectExceptionMessage('Missing required keys (type, name) in vfs://modules/fixtures/missing_keys.info.txt'); + $this->expectExceptionMessage('Missing required keys (type, name, core_version_requirement) in vfs://modules/fixtures/missing_keys.info.txt'); $this->infoParser->parse($filename); } - /** - * Tests that missing 'core' and 'core_version_requirement' keys are detected. - * - * @covers ::parse - */ - public function testMissingCoreCoreVersionRequirement() { - $missing_core_and_core_version_requirement = << [ - 'missing_core_and_core_version_requirement.info.txt' => $missing_core_and_core_version_requirement, - 'missing_core_and_core_version_requirement-duplicate.info.txt' => $missing_core_and_core_version_requirement, - ], - ]); - $exception_message = "The 'core' or the 'core_version_requirement' key must be present 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"); - - try { - $this->infoParser->parse(vfsStream::url('modules/fixtures/missing_core_and_core_version_requirement.info.txt')); - } - catch (InfoParserException $exception) { - $this->assertSame("$exception_message.info.txt", $exception->getMessage()); - - $this->infoParser->parse(vfsStream::url('modules/fixtures/missing_core_and_core_version_requirement-duplicate.info.txt')); - } - } - /** * Tests that Testing package modules use a default core_version_requirement. * @@ -243,6 +206,7 @@ public function testInvalidCore() { # info.yml for testing invalid core key. package: Core core: ^8 +core_version_requirement: ^8 || ^9 version: VERSION type: module name: Llama or Alpaca @@ -259,21 +223,62 @@ public function testInvalidCore() { 'invalid_core-duplicate.info.txt' => $invalid_core, ], ]); - $exception_message = "Invalid 'core' value \"^8\" in vfs://modules/fixtures/invalid_core"; + $exception_message = "The 'core' value \"^8\" is invalid in vfs://modules/fixtures/invalid_core%s.info.txt. The 'core' key must be set to '8.x' to support Drupal versions prior to 8.7.7"; // Set the expected exception for the 2nd call to parse(). $this->expectException('\Drupal\Core\Extension\InfoParserException'); - $this->expectExceptionMessage("$exception_message-duplicate.info.txt"); + $this->expectExceptionMessage(sprintf($exception_message, '-duplicate')); try { $this->infoParser->parse(vfsStream::url('modules/fixtures/invalid_core.info.txt')); } catch (InfoParserException $exception) { - $this->assertSame("$exception_message.info.txt", $exception->getMessage()); + $this->assertSame(sprintf($exception_message, ''), $exception->getMessage()); $this->infoParser->parse(vfsStream::url('modules/fixtures/invalid_core-duplicate.info.txt')); } } + /** + * Tests a invalid 'core' key. + * + * @covers ::parse + */ + public function testNotNeededCore() { + $not_needed_core = << [ + 'not_needed_core.info.txt' => $not_needed_core, + 'not_needed_core-duplicate.info.txt' => $not_needed_core, + ], + ]); + $exception_message = "The 'core' value \"^8\" is invalid in vfs://modules/fixtures/not_needed_core%s.info.txt. The 'core' key can be removed because this module does not support any Drupal version prior to 8.7.7"; + // Set the expected exception for the 2nd call to parse(). + $this->expectException('\Drupal\Core\Extension\InfoParserException'); + $this->expectExceptionMessage(sprintf($exception_message, '-duplicate')); + + try { + $this->infoParser->parse(vfsStream::url('modules/fixtures/not_needed_core.info.txt')); + } + catch (InfoParserException $exception) { + $this->assertSame(sprintf($exception_message, ''), $exception->getMessage()); + + $this->infoParser->parse(vfsStream::url('modules/fixtures/not_needed_core-duplicate.info.txt')); + } + } + /** * Tests a invalid 'core_version_requirement'. * @@ -339,7 +344,7 @@ public function testInfoParserMissingKey() { description: 'Defines a file field type.' package: Core version: VERSION -core: 8.x +core_version_requirement: ^9 dependencies: - field MISSINGKEY; @@ -458,7 +463,7 @@ public function testCoreIncompatibility($test_case, $constraint, $expected) { * Dataprovider for testCoreIncompatibility(). */ public function providerCoreIncompatibility() { - list($major, $minor) = explode('.', \Drupal::VERSION); + [$major, $minor] = explode('.', \Drupal::VERSION); $next_minor = $minor + 1; $next_major = $major + 1;