From e375b0fe105b82b8166ed7e4decf09bc043f90b9 Mon Sep 17 00:00:00 2001 From: lucashedding <lucashedding@1463982.no-reply.drupal.org> Date: Mon, 3 Jun 2019 15:46:27 -0500 Subject: [PATCH] Issue #3054006 by heddn, eiriksm, catch: Add method to ignore certain paths (custom modules, themes, etc) for the modified code checker --- config/install/automatic_updates.settings.yml | 1 + config/schema/automatic_updates.schema.yml | 3 ++ src/Form/SettingsForm.php | 21 ++++++++ src/IgnoredPathsTrait.php | 52 +++++++++++++++++++ src/ReadinessChecker/MissingProjectInfo.php | 5 ++ src/Services/ModifiedFiles.php | 5 ++ tests/src/Functional/AutomaticUpdatesTest.php | 15 ++++-- .../MissingProjectInfoTest.php | 8 +++ 8 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 src/IgnoredPathsTrait.php diff --git a/config/install/automatic_updates.settings.yml b/config/install/automatic_updates.settings.yml index 799251acd2..e7c695ec29 100644 --- a/config/install/automatic_updates.settings.yml +++ b/config/install/automatic_updates.settings.yml @@ -7,3 +7,4 @@ notify: true check_frequency: 43200 enable_readiness_checks: true download_uri: 'https://ftp.drupal.org/files/projects' +ignored_paths: "modules/custom/*\nthemes/custom/*\nprofiles/custom/*" diff --git a/config/schema/automatic_updates.schema.yml b/config/schema/automatic_updates.schema.yml index 35a15326ad..7d378de5d6 100644 --- a/config/schema/automatic_updates.schema.yml +++ b/config/schema/automatic_updates.schema.yml @@ -20,3 +20,6 @@ automatic_updates.settings: download_uri: type: string label: 'Endpoint URI for file hashes and quasi patch files' + ignored_paths: + type: string + label: 'List of files paths to ignore when running readiness checks' diff --git a/src/Form/SettingsForm.php b/src/Form/SettingsForm.php index b3806509d8..9f38e66a95 100644 --- a/src/Form/SettingsForm.php +++ b/src/Form/SettingsForm.php @@ -25,6 +25,13 @@ class SettingsForm extends ConfigFormBase { */ protected $dateFormatter; + /** + * Drupal root path. + * + * @var string + */ + protected $drupalRoot; + /** * {@inheritdoc} */ @@ -32,6 +39,9 @@ class SettingsForm extends ConfigFormBase { $instance = parent::create($container); $instance->checker = $container->get('automatic_updates.readiness_checker'); $instance->dateFormatter = $container->get('date.formatter'); + $drupal_finder = $container->get('automatic_updates.drupal_finder'); + $drupal_finder->locateRoot(getcwd()); + $instance->drupalRoot = $drupal_finder->getDrupalRoot(); return $instance; } @@ -82,6 +92,17 @@ class SettingsForm extends ConfigFormBase { '@link' => Url::fromRoute('automatic_updates.update_readiness')->toString(), ]); } + $form['ignored_paths'] = [ + '#type' => 'textarea', + '#title' => $this->t('Paths to ignore for readiness checks'), + '#description' => $this->t('Paths relative to %drupal_root. One path per line.', ['%drupal_root' => $this->drupalRoot]), + '#default_value' => $config->get('ignored_paths'), + '#states' => [ + 'visible' => [ + ':input[name="enable_readiness_checks"]' => ['checked' => TRUE], + ], + ], + ]; return parent::buildForm($form, $form_state); } diff --git a/src/IgnoredPathsTrait.php b/src/IgnoredPathsTrait.php new file mode 100644 index 0000000000..31ae1a288f --- /dev/null +++ b/src/IgnoredPathsTrait.php @@ -0,0 +1,52 @@ +<?php + +namespace Drupal\automatic_updates; + +/** + * Provide a helper to check if file paths are ignored. + */ +trait IgnoredPathsTrait { + + /** + * 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 function isIgnoredPath($file_path) { + $paths = $this->getConfigFactory()->get('automatic_updates.settings')->get('ignored_paths'); + if ($this->getPathMatcher()->matchPath($file_path, $paths)) { + return TRUE; + } + } + + /** + * Gets the config factory. + * + * @return \Drupal\Core\Config\ConfigFactoryInterface + * The config factory. + */ + protected function getConfigFactory() { + if (isset($this->configFactory)) { + return $this->configFactory; + } + return \Drupal::configFactory(); + } + + /** + * Get the path matcher service. + * + * @return \Drupal\Core\Path\PathMatcherInterface + * The path matcher. + */ + protected function getPathMatcher() { + if (isset($this->pathMatcher)) { + return $this->pathMatcher; + } + return \Drupal::service('path.matcher'); + } + +} diff --git a/src/ReadinessChecker/MissingProjectInfo.php b/src/ReadinessChecker/MissingProjectInfo.php index 9b202732ba..e36d7df90c 100644 --- a/src/ReadinessChecker/MissingProjectInfo.php +++ b/src/ReadinessChecker/MissingProjectInfo.php @@ -2,6 +2,7 @@ namespace Drupal\automatic_updates\ReadinessChecker; +use Drupal\automatic_updates\IgnoredPathsTrait; use Drupal\Core\Extension\ExtensionList; use Drupal\Core\StringTranslation\StringTranslationTrait; use DrupalFinder\DrupalFinder; @@ -10,6 +11,7 @@ use DrupalFinder\DrupalFinder; * Missing project info checker. */ class MissingProjectInfo extends Filesystem { + use IgnoredPathsTrait; use StringTranslationTrait; /** @@ -69,6 +71,9 @@ class MissingProjectInfo extends Filesystem { $messages = []; foreach ($this->getExtensionsTypes() as $extension_type) { foreach ($this->getInfos($extension_type) as $extension_name => $info) { + if ($this->isIgnoredPath(drupal_get_path($info['type'], $extension_name))) { + continue; + } if (empty($info['version'])) { $messages[] = $this->t('The project "@extension" will not be updated because it is missing the "version" key in the @extension.info.yml file.', ['@extension' => $extension_name]); } diff --git a/src/Services/ModifiedFiles.php b/src/Services/ModifiedFiles.php index c0e250a578..7d2d13ba7f 100644 --- a/src/Services/ModifiedFiles.php +++ b/src/Services/ModifiedFiles.php @@ -2,6 +2,7 @@ namespace Drupal\automatic_updates\Services; +use Drupal\automatic_updates\IgnoredPathsTrait; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Url; use DrupalFinder\DrupalFinder; @@ -14,6 +15,7 @@ use Psr\Log\LoggerInterface; * Modified files service. */ class ModifiedFiles implements ModifiedFilesInterface { + use IgnoredPathsTrait; /** * The logger. @@ -100,6 +102,9 @@ class ModifiedFiles implements ModifiedFilesInterface { $this->logger->error('@hash or @file is empty; the hash file is malformed for this line.', ['@hash' => $hash, '@file' => $file]); continue; } + if ($this->isIgnoredPath($file)) { + continue; + } $file_path = $this->drupalFinder->getDrupalRoot() . DIRECTORY_SEPARATOR . $file; if (!file_exists($file_path) || hash_file('sha512', $file_path) !== $hash) { $modified_files[] = $file_path; diff --git a/tests/src/Functional/AutomaticUpdatesTest.php b/tests/src/Functional/AutomaticUpdatesTest.php index 7f5c337b63..cbd4cb924b 100644 --- a/tests/src/Functional/AutomaticUpdatesTest.php +++ b/tests/src/Functional/AutomaticUpdatesTest.php @@ -62,7 +62,7 @@ class AutomaticUpdatesTest extends BrowserTestBase { $this->assertSession()->pageTextContains('3 urgent announcements require your attention:'); // Test cache. - $end_point = 'http://localhost/automatic_updates/test-json-denied'; + $end_point = $this->buildUrl(Url::fromRoute('test_automatic_updates.json_test_denied_controller')); $this->config('automatic_updates.settings') ->set('psa_endpoint', $end_point) ->save(); @@ -72,7 +72,7 @@ class AutomaticUpdatesTest extends BrowserTestBase { // Test transmit errors with JSON endpoint. drupal_flush_all_caches(); $this->drupalGet(Url::fromRoute('system.admin')); - $this->assertSession()->pageTextContains('Drupal PSA endpoint http://localhost/automatic_updates/test-json-denied is unreachable.'); + $this->assertSession()->pageTextContains("Drupal PSA endpoint $end_point is unreachable."); // Test disabling PSAs. $end_point = $this->buildUrl(Url::fromRoute('test_automatic_updates.json_test_controller')); @@ -91,12 +91,17 @@ class AutomaticUpdatesTest extends BrowserTestBase { * Tests manually running readiness checks. */ public function testReadinessChecks() { - // Test manually running readiness checks. - $url = $this->buildUrl('<front>') . '/automatic_updates'; - $this->config('automatic_updates.settings')->set('download_uri', $url); + // Test manually running readiness checks. A few warnings will occur. $this->drupalGet(Url::fromRoute('automatic_updates.settings')); $this->clickLink('run the readiness checks'); $this->assertSession()->pageTextContains('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.'); + + // Ignore specific file paths to see no readiness issues. + $this->config('automatic_updates.settings')->set('ignored_paths', "core/*\nmodules/*\nthemes/*\nprofiles/*") + ->save(); + $this->drupalGet(Url::fromRoute('automatic_updates.settings')); + $this->clickLink('run the readiness checks'); + $this->assertSession()->pageTextContains('No issues found. Your site is completely ready for automatic updates.'); } } diff --git a/tests/src/Kernel/ReadinessChecker/MissingProjectInfoTest.php b/tests/src/Kernel/ReadinessChecker/MissingProjectInfoTest.php index e5ac3b3f1c..60e4cf6f4b 100644 --- a/tests/src/Kernel/ReadinessChecker/MissingProjectInfoTest.php +++ b/tests/src/Kernel/ReadinessChecker/MissingProjectInfoTest.php @@ -21,6 +21,14 @@ class MissingProjectInfoTest extends KernelTestBase { 'automatic_updates', ]; + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + $this->installConfig(['automatic_updates']); + } + /** * Tests pending db updates readiness checks. */ -- GitLab