From 9713a8251ce625ec9601dfc90fb3a48dee095a41 Mon Sep 17 00:00:00 2001 From: tatarbj <tatarbj@649590.no-reply.drupal.org> Date: Mon, 1 Jul 2019 13:18:25 -0600 Subject: [PATCH] Issue #3063131 by heddn, tatarbj: Backport MissingProjectInfo --- ReadinessCheckers/MissingProjectInfo.php | 99 +++++++++++++++++++ ReadinessCheckers/ReadinessCheckerManager.php | 1 + automatic_updates.admin.inc | 2 +- automatic_updates.info | 1 + automatic_updates.install | 7 +- tests/automatic_updates.test | 10 +- 6 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 ReadinessCheckers/MissingProjectInfo.php diff --git a/ReadinessCheckers/MissingProjectInfo.php b/ReadinessCheckers/MissingProjectInfo.php new file mode 100644 index 0000000000..aa64c802de --- /dev/null +++ b/ReadinessCheckers/MissingProjectInfo.php @@ -0,0 +1,99 @@ +<?php + +/** + * Missing project info checker. + */ +class MissingProjectInfo implements ReadinessCheckerInterface { + + /** + * {@inheritdoc} + */ + public static function run() { + return static::missingProjectInfoCheck(); + } + + /** + * Check for projects missing project info. + * + * @return array + * An array of translatable strings if any checks fail. + */ + protected static function missingProjectInfoCheck() { + $messages = []; + foreach (static::getInfos() as $extension_name => $info) { + if (static::isIgnoredPath($info['extension_uri'])) { + continue; + } + if (!static::getExtensionVersion($extension_name, $info)) { + $messages[] = t('The project "@extension" can not be updated because its version is either undefined or a dev release.', ['@extension' => $extension_name]); + } + } + return $messages; + } + + /** + * Get the extension types. + * + * @return array + * The extension types. + */ + protected static function getExtensionsTypes() { + return ['modules', 'profiles', 'themes']; + } + + /** + * Returns an array of info files information of available extensions. + * + * @return array + * An associative array of extension information arrays, keyed by extension + * name. + */ + protected static function getInfos() { + $infos = []; + // Find extensions. + $extensions = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'modules', $key = 'name', $min_depth = 1); + $extensions = array_merge($extensions, drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'themes', $key = 'name', $min_depth = 1)); + foreach ($extensions as $extension) { + if (file_exists($info_file = dirname($extension->uri) . '/' . $extension->name . '.info')) { + // Get the .info file for the module or theme this file belongs to. + $infos[$extension->name] = drupal_parse_info_file($info_file); + $infos[$extension->name]['extension_uri'] = $extension->uri; + } + } + + return $infos; + } + + /** + * Get the extension version. + * + * @param string $extension_name + * The extension name. + * @param array $info + * The extension's info. + * + * @return string|null + * The version or NULL if undefined. + */ + protected static function getExtensionVersion($extension_name, array $info) { + if (isset($info['version']) && strpos($info['version'], '-dev') === FALSE) { + return $info['version']; + } + } + + /** + * Check if the file path is ignored. + * + * @param string $file_path + * The file path. + * + * @return bool + * TRUE if file path is ignored, else FALSE. + */ + protected static function isIgnoredPath($file_path) { + $paths = variable_get('automatic_updates_ignored_paths', "sites/all/modules/custom/*\nsites/all/themes/custom/*"); + if (drupal_match_path($file_path, $paths)) { + return TRUE; + } + } +} diff --git a/ReadinessCheckers/ReadinessCheckerManager.php b/ReadinessCheckers/ReadinessCheckerManager.php index 57c0b93ee5..77213726e5 100644 --- a/ReadinessCheckers/ReadinessCheckerManager.php +++ b/ReadinessCheckers/ReadinessCheckerManager.php @@ -23,6 +23,7 @@ class ReadinessCheckerManager { */ protected static function getCheckers() { static::$checkers['warning'][0][] = 'FileOwnership'; + static::$checkers['warning'][0][] = 'MissingProjectInfo'; static::$checkers['warning'][0][] = 'ModifiedFiles'; static::$checkers['warning'][0][] = 'PhpSapi'; static::$checkers['error'][0][] = 'PhpSapi'; diff --git a/automatic_updates.admin.inc b/automatic_updates.admin.inc index 20aa1b4ab0..acbffcffde 100644 --- a/automatic_updates.admin.inc +++ b/automatic_updates.admin.inc @@ -33,7 +33,7 @@ function automatic_updates_admin_form() { '#type' => 'textarea', '#title' => t('Paths to ignore for readiness checks'), '#description' => t('Paths relative to %drupal_root. One path per line.', ['%drupal_root' => DRUPAL_ROOT]), - '#default_value' => variable_get('automatic_updates_ignored_paths', "modules/custom/*\nthemes/custom/*\nprofiles/custom/*"), + '#default_value' => variable_get('automatic_updates_ignored_paths', "sites/all/modules/custom/*\nsites/all/themes/custom/*"), '#states' => [ 'visible' => [ ':input[name="automatic_updates_enable_readiness_checks"]' => ['checked' => TRUE], diff --git a/automatic_updates.info b/automatic_updates.info index db8c32ee27..9969fe4de1 100644 --- a/automatic_updates.info +++ b/automatic_updates.info @@ -10,6 +10,7 @@ files[] = ModifiedFilesService.php files[] = ReadinessCheckers/ReadinessCheckerManager.php files[] = ReadinessCheckers/ReadinessCheckerInterface.php files[] = ReadinessCheckers/FileOwnership.php +files[] = ReadinessCheckers/MissingProjectInfo.php files[] = ReadinessCheckers/ModifiedFiles.php files[] = ReadinessCheckers/PhpSapi.php files[] = ReadinessCheckers/ReadOnlyFilesystem.php diff --git a/automatic_updates.install b/automatic_updates.install index ee53684185..f5c847e88a 100644 --- a/automatic_updates.install +++ b/automatic_updates.install @@ -55,10 +55,9 @@ function _automatic_updates_checker_requirements(array &$requirements) { if (!empty($checker_results)) { $requirements['automatic_updates_readiness']['severity'] = $error_results ? REQUIREMENT_ERROR : REQUIREMENT_WARNING; $requirements['automatic_updates_readiness']['value'] = format_plural(count($checker_results), '@count check failed:', '@count checks failed:'); - $requirements['automatic_updates_readiness']['description'] = [ - '#theme' => 'item_list', - '#items' => $checker_results, - ]; + $requirements['automatic_updates_readiness']['description'] = theme('item_list', array( + 'items' => $checker_results, + )); } if (REQUEST_TIME > $last_check_timestamp + 3600 * 24) { $requirements['automatic_updates_readiness']['severity'] = REQUIREMENT_ERROR; diff --git a/tests/automatic_updates.test b/tests/automatic_updates.test index 082d31f34c..c50fe822ea 100644 --- a/tests/automatic_updates.test +++ b/tests/automatic_updates.test @@ -78,11 +78,15 @@ class AutomaticUpdatesTestCase extends DrupalWebTestCase { public function testReadinessChecks() { // Fabricate a readiness issue. $this->drupalGet($this->getAbsoluteUrl('admin/config/system/automatic_updates')); - variable_set('automatic_updates.php_sapi', 'foo'); $this->clickLink('run the readiness checks'); $this->assertText('Your site does not pass some readiness checks for automatic updates. Depending on the nature of the failures, it might effect the eligibility for automatic updates.'); - $this->assertText('PHP changed from running as'); - $this->assertText('This can lead to inconsistent and misleading results.'); + $this->assertText('The project "drupal_autoload_test" can not be updated because its version is either undefined or a dev release'); + + // Ignore certain folders for readiness checks. + variable_set('automatic_updates_ignored_paths', "sites/all/modules/custom/*\nsites/all/themes/custom/*"); + $this->drupalGet($this->getAbsoluteUrl('admin/config/system/automatic_updates')); + $this->clickLink('run the readiness checks'); + $this->assertText('No issues found. Your site is completely ready for automatic updates.'); } } -- GitLab