Issue #3215043 by Spokje, larowlan, quietone, dww, srilakshmier, paulocs, yogeshmpawar, catch, Gábor Hojtsy, benjifisher, AaronMcHale, phenaproxima, kim.pepper, fubarhouse: Indicate the non-stable statuses in admin/modules page
parent
fc90d0c899
commit
24893484e1
|
@ -195,6 +195,15 @@ small .admin-link:after {
|
|||
[dir="rtl"] .module-link-configure {
|
||||
background-position: top 50% right 0;
|
||||
}
|
||||
.module-link--non-stable {
|
||||
padding-left: 18px;
|
||||
background: url(../../../misc/icons/e29700/warning.svg) 0 50% no-repeat; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .module-link--non-stable {
|
||||
padding-right: 18px;
|
||||
padding-left: 0;
|
||||
background-position: top 50% right 0;
|
||||
}
|
||||
|
||||
/* Status report. */
|
||||
.system-status-report__status-title {
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
/**
|
||||
* Builds a confirmation form for enabling experimental modules.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModulesListExperimentalConfirmForm extends ModulesListConfirmForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you wish to enable experimental modules?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_modules_experimental_confirm_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildMessageList() {
|
||||
$this->messenger()->addWarning($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']));
|
||||
|
||||
$items = parent::buildMessageList();
|
||||
// Add the list of experimental modules after any other messages.
|
||||
$items[] = $this->t('The following modules are experimental: @modules', ['@modules' => implode(', ', array_values($this->modules['experimental']))]);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,7 @@ use Drupal\Core\Extension\ModuleInstallerInterface;
|
|||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\PermissionHandlerInterface;
|
||||
|
@ -249,7 +250,22 @@ class ModulesListForm extends FormBase {
|
|||
$row['#requires'] = [];
|
||||
$row['#required_by'] = [];
|
||||
|
||||
$lifecycle = $module->info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER];
|
||||
$row['name']['#markup'] = $module->info['name'];
|
||||
if ($lifecycle !== ExtensionLifecycle::STABLE && !empty($module->info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER])) {
|
||||
$row['name']['#markup'] .= ' ' . Link::fromTextAndUrl('(' . $this->t('@lifecycle', ['@lifecycle' => ucfirst($lifecycle)]) . ')',
|
||||
Url::fromUri($module->info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER], [
|
||||
'attributes' =>
|
||||
[
|
||||
'class' => 'module-link--non-stable',
|
||||
'aria-label' => $this->t('View information on the @lifecycle status of the module @module', [
|
||||
'@lifecycle' => ucfirst($lifecycle),
|
||||
'@module' => $module->info['name'],
|
||||
]),
|
||||
],
|
||||
])
|
||||
)->toString();
|
||||
}
|
||||
$row['description']['#markup'] = $this->t($module->info['description']);
|
||||
$row['version']['#markup'] = $module->info['version'];
|
||||
|
||||
|
@ -390,7 +406,7 @@ class ModulesListForm extends FormBase {
|
|||
$modules = [
|
||||
'install' => [],
|
||||
'dependencies' => [],
|
||||
'experimental' => [],
|
||||
'non_stable' => [],
|
||||
];
|
||||
|
||||
$data = $this->moduleExtensionList->getList();
|
||||
|
@ -405,10 +421,12 @@ class ModulesListForm extends FormBase {
|
|||
}
|
||||
// Selected modules should be installed.
|
||||
elseif (($checkbox = $form_state->getValue(['modules', $name], FALSE)) && $checkbox['enable']) {
|
||||
$modules['install'][$name] = $data[$name]->info['name'];
|
||||
// Identify experimental modules.
|
||||
if ($data[$name]->info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER] === ExtensionLifecycle::EXPERIMENTAL) {
|
||||
$modules['experimental'][$name] = $data[$name]->info['name'];
|
||||
$info = $data[$name]->info;
|
||||
$modules['install'][$name] = $info['name'];
|
||||
// Identify non-stable modules.
|
||||
$lifecycle = $info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER];
|
||||
if ($lifecycle !== ExtensionLifecycle::STABLE) {
|
||||
$modules['non_stable'][$name] = $info['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -417,12 +435,14 @@ class ModulesListForm extends FormBase {
|
|||
foreach ($modules['install'] as $module => $value) {
|
||||
foreach (array_keys($data[$module]->requires) as $dependency) {
|
||||
if (!isset($modules['install'][$dependency]) && !$this->moduleHandler->moduleExists($dependency)) {
|
||||
$modules['dependencies'][$module][$dependency] = $data[$dependency]->info['name'];
|
||||
$modules['install'][$dependency] = $data[$dependency]->info['name'];
|
||||
$dependency_info = $data[$dependency]->info;
|
||||
$modules['dependencies'][$module][$dependency] = $dependency_info['name'];
|
||||
$modules['install'][$dependency] = $dependency_info['name'];
|
||||
|
||||
// Identify experimental modules.
|
||||
if ($data[$dependency]->info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER] === ExtensionLifecycle::EXPERIMENTAL) {
|
||||
$modules['experimental'][$dependency] = $data[$dependency]->info['name'];
|
||||
// Identify non-stable modules.
|
||||
$lifecycle = $dependency_info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER];
|
||||
if ($lifecycle !== ExtensionLifecycle::STABLE) {
|
||||
$modules['non_stable'][$dependency] = $dependency_info['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -436,7 +456,7 @@ class ModulesListForm extends FormBase {
|
|||
foreach (array_keys($modules['install']) as $module) {
|
||||
if (!drupal_check_module($module)) {
|
||||
unset($modules['install'][$module]);
|
||||
unset($modules['experimental'][$module]);
|
||||
unset($modules['non_stable'][$module]);
|
||||
foreach (array_keys($data[$module]->required_by) as $dependent) {
|
||||
unset($modules['install'][$dependent]);
|
||||
unset($modules['dependencies'][$dependent]);
|
||||
|
@ -455,9 +475,9 @@ class ModulesListForm extends FormBase {
|
|||
$modules = $this->buildModuleList($form_state);
|
||||
|
||||
// Redirect to a confirmation form if needed.
|
||||
if (!empty($modules['experimental']) || !empty($modules['dependencies'])) {
|
||||
if (!empty($modules['non_stable']) || !empty($modules['dependencies'])) {
|
||||
|
||||
$route_name = !empty($modules['experimental']) ? 'system.modules_list_experimental_confirm' : 'system.modules_list_confirm';
|
||||
$route_name = !empty($modules['non_stable']) ? 'system.modules_list_non_stable_confirm' : 'system.modules_list_confirm';
|
||||
// Write the list of changed module states into a key value store.
|
||||
$account = $this->currentUser()->id();
|
||||
$this->keyValueExpirable->setWithExpire($account, $modules, 60);
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Extension\ExtensionLifecycle;
|
||||
use Drupal\Core\Extension\ModuleExtensionList;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Builds a confirmation form for enabling non-stable modules.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModulesListNonStableConfirmForm extends ModulesListConfirmForm {
|
||||
|
||||
/**
|
||||
* Module extension list.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleExtensionList
|
||||
*/
|
||||
protected ModuleExtensionList $moduleExtensionList;
|
||||
|
||||
/**
|
||||
* An array of module names to be enabled, keyed by lifecycle.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $groupedModuleInfo;
|
||||
|
||||
/**
|
||||
* Boolean indicating a core deprecated module is being enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $coreDeprecatedModules;
|
||||
|
||||
/**
|
||||
* Boolean indicating a contrib deprecated module is being enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $contribDeprecatedModules;
|
||||
|
||||
/**
|
||||
* Constructs a new ModulesListNonStableConfirmForm.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer
|
||||
* The module installer.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
|
||||
* The key value expirable factory.
|
||||
* @param \Drupal\Core\Extension\ModuleExtensionList $moduleExtensionList
|
||||
* The module extension list.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, KeyValueStoreExpirableInterface $key_value_expirable, ModuleExtensionList $moduleExtensionList) {
|
||||
parent::__construct($module_handler, $module_installer, $key_value_expirable);
|
||||
$this->moduleExtensionList = $moduleExtensionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('module_handler'),
|
||||
$container->get('module_installer'),
|
||||
$container->get('keyvalue.expirable')->get('module_list'),
|
||||
$container->get('extension.list.module')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
$hasExperimentalModulesToEnable = !empty($this->groupedModuleInfo[ExtensionLifecycle::EXPERIMENTAL]);
|
||||
$hasDeprecatedModulesToEnable = !empty($this->groupedModuleInfo[ExtensionLifecycle::DEPRECATED]);
|
||||
|
||||
if ($hasExperimentalModulesToEnable && $hasDeprecatedModulesToEnable) {
|
||||
return $this->t('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
}
|
||||
|
||||
if ($hasExperimentalModulesToEnable) {
|
||||
return $this->formatPlural(
|
||||
count($this->groupedModuleInfo[ExtensionLifecycle::EXPERIMENTAL]),
|
||||
'Are you sure you wish to enable an experimental module?',
|
||||
'Are you sure you wish to enable experimental modules?'
|
||||
);
|
||||
}
|
||||
|
||||
if ($hasDeprecatedModulesToEnable) {
|
||||
return $this->formatPlural(
|
||||
count($this->groupedModuleInfo[ExtensionLifecycle::DEPRECATED]),
|
||||
'Are you sure you wish to enable a deprecated module?',
|
||||
'Are you sure you wish to enable deprecated modules?'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_modules_non_stable_confirm_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildMessageList() {
|
||||
$this->buildNonStableInfo();
|
||||
|
||||
$items = parent::buildMessageList();
|
||||
if (!empty($this->groupedModuleInfo[ExtensionLifecycle::EXPERIMENTAL])) {
|
||||
$this->messenger()->addWarning($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']));
|
||||
// Add the list of experimental modules after any other messages.
|
||||
$items[] = $this->formatPlural(
|
||||
count($this->groupedModuleInfo[ExtensionLifecycle::EXPERIMENTAL]),
|
||||
'The following module is experimental: @modules.',
|
||||
'The following modules are experimental: @modules.',
|
||||
['@modules' => implode(', ', $this->groupedModuleInfo[ExtensionLifecycle::EXPERIMENTAL])]
|
||||
);
|
||||
}
|
||||
if (!empty($this->groupedModuleInfo[ExtensionLifecycle::DEPRECATED])) {
|
||||
$this->messenger()->addWarning($this->buildDeprecatedMessage($this->coreDeprecatedModules, $this->contribDeprecatedModules));
|
||||
$items = array_merge($items, $this->groupedModuleInfo[ExtensionLifecycle::DEPRECATED]);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a message to be displayed to the user enabling deprecated modules.
|
||||
*
|
||||
* @param bool $core_deprecated_modules
|
||||
* TRUE if a core deprecated module is being enabled.
|
||||
* @param bool $contrib_deprecated_modules
|
||||
* TRUE if a contrib deprecated module is being enabled.
|
||||
*
|
||||
* @return \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* The relevant message.
|
||||
*/
|
||||
protected function buildDeprecatedMessage(bool $core_deprecated_modules, bool $contrib_deprecated_modules): TranslatableMarkup {
|
||||
if ($contrib_deprecated_modules && $core_deprecated_modules) {
|
||||
return $this->t('<a href=":url">Deprecated modules</a> are modules that may be removed from the next major release of Drupal core and the relevant contributed module. Use at your own risk.', [':url' => 'https://www.drupal.org/about/core/policies/core-change-policies/deprecated-modules-and-themes']);
|
||||
}
|
||||
if ($contrib_deprecated_modules) {
|
||||
return $this->t('<a href=":url">Deprecated modules</a> are modules that may be removed from the next major release of this project. Use at your own risk.', [':url' => 'https://www.drupal.org/about/core/policies/core-change-policies/deprecated-modules-and-themes']);
|
||||
}
|
||||
|
||||
return $this->t('<a href=":url">Deprecated modules</a> are modules that may be removed from the next major release of Drupal core. Use at your own risk.', [':url' => 'https://www.drupal.org/about/core/policies/core-change-policies/deprecated-modules-and-themes']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets properties with information about non-stable modules being enabled.
|
||||
*/
|
||||
protected function buildNonStableInfo(): void {
|
||||
$non_stable = $this->modules['non_stable'];
|
||||
$data = $this->moduleExtensionList->getList();
|
||||
$grouped = [];
|
||||
$core_deprecated_modules = FALSE;
|
||||
$contrib_deprecated_modules = FALSE;
|
||||
foreach ($non_stable as $machine_name => $name) {
|
||||
$lifecycle = $data[$machine_name]->info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER];
|
||||
if ($lifecycle === ExtensionLifecycle::EXPERIMENTAL) {
|
||||
// We just show the extension name if it is experimental.
|
||||
$grouped[$lifecycle][] = $name;
|
||||
continue;
|
||||
}
|
||||
$core_deprecated_modules = $core_deprecated_modules || $data[$machine_name]->origin === 'core';
|
||||
$contrib_deprecated_modules = $contrib_deprecated_modules || $data[$machine_name]->origin !== 'core';
|
||||
// If the extension is deprecated we show links to more information.
|
||||
$grouped[$lifecycle][] = Link::fromTextAndUrl(
|
||||
$this->t('The @name module is deprecated. (more information)', [
|
||||
'@name' => $name,
|
||||
]),
|
||||
Url::fromUri($data[$machine_name]->info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER], [
|
||||
'attributes' =>
|
||||
[
|
||||
'aria-label' => ' ' . $this->t('about the status of the @name module', [
|
||||
'@name' => $name,
|
||||
]),
|
||||
],
|
||||
])
|
||||
)->toString();
|
||||
}
|
||||
|
||||
$this->groupedModuleInfo = $grouped;
|
||||
$this->coreDeprecatedModules = $core_deprecated_modules;
|
||||
$this->contribDeprecatedModules = $contrib_deprecated_modules;
|
||||
}
|
||||
|
||||
}
|
|
@ -281,11 +281,11 @@ system.modules_list_confirm:
|
|||
requirements:
|
||||
_permission: 'administer modules'
|
||||
|
||||
system.modules_list_experimental_confirm:
|
||||
path: '/admin/modules/list/confirm-experimental'
|
||||
system.modules_list_non_stable_confirm:
|
||||
path: '/admin/modules/list/confirm-non-stable'
|
||||
defaults:
|
||||
_form: '\Drupal\system\Form\ModulesListExperimentalConfirmForm'
|
||||
_title: 'Experimental modules'
|
||||
_form: '\Drupal\system\Form\ModulesListNonStableConfirmForm'
|
||||
_title: 'Non-stable modules'
|
||||
requirements:
|
||||
_permission: 'administer modules'
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
name: Deprecated module
|
||||
type: module
|
||||
description: 'Deprecated module'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
lifecycle: deprecated
|
||||
lifecycle_link: 'http://example.com/deprecated'
|
|
@ -0,0 +1,7 @@
|
|||
name: Deprecated module contrib
|
||||
type: module
|
||||
description: 'Deprecated module contrib'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
lifecycle: deprecated
|
||||
lifecycle_link: 'http://example.com/deprecated'
|
|
@ -0,0 +1,7 @@
|
|||
name: Deprecated module dependency
|
||||
type: module
|
||||
description: 'Module that depends on a deprecated module'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
dependencies:
|
||||
- drupal:deprecated_module
|
|
@ -0,0 +1,5 @@
|
|||
name: Deprecated module test
|
||||
type: module
|
||||
description: 'Deprecated module test'
|
||||
package: Testing
|
||||
version: VERSION
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Deprecated module test module.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Extension\Extension;
|
||||
|
||||
/**
|
||||
* Implements hook_system_info_alter().
|
||||
*/
|
||||
function deprecated_module_test_system_info_alter(array &$info, Extension $file, $type) {
|
||||
// Make the 'deprecated_module_contrib' look like it isn't part of core.
|
||||
if ($type === 'module' && $info['name'] === 'Deprecated module contrib') {
|
||||
$file->origin = 'sites/all';
|
||||
}
|
||||
}
|
|
@ -53,6 +53,10 @@ class ModulesListFormWebTest extends BrowserTestBase {
|
|||
// module is used because its machine name is different than its human
|
||||
// readable name.
|
||||
$this->assertSession()->pageTextContains('dblog');
|
||||
|
||||
// Check that the deprecated module link was rendered correctly.
|
||||
$this->assertSession()->elementExists('xpath', "//a[contains(@aria-label, 'View information on the Deprecated status of the module Deprecated module')]");
|
||||
$this->assertSession()->elementExists('xpath', "//a[contains(@href, 'http://example.com/deprecated')]");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\Functional\Module;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the installation of modules.
|
||||
*
|
||||
* @group Module
|
||||
*/
|
||||
class ExperimentalModuleTest extends BrowserTestBase {
|
||||
|
||||
|
||||
/**
|
||||
* The admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'access administration pages',
|
||||
'administer modules',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests installing experimental modules and dependencies in the UI.
|
||||
*/
|
||||
public function testExperimentalConfirmForm() {
|
||||
|
||||
// First, test installing a non-experimental module with no dependencies.
|
||||
// There should be no confirmation form and no experimental module warning.
|
||||
$edit = [];
|
||||
$edit["modules[test_page_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
$this->assertSession()->pageTextContains('Module Test page has been enabled.');
|
||||
$this->assertSession()->pageTextNotContains('Experimental modules are provided for testing purposes only.');
|
||||
|
||||
// Uninstall the module.
|
||||
\Drupal::service('module_installer')->uninstall(['test_page_test']);
|
||||
|
||||
// Next, test installing an experimental module with no dependencies.
|
||||
// There should be a confirmation form with an experimental warning, but no
|
||||
// list of dependencies.
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the experimental modules with only this one.
|
||||
$this->assertSession()->pageTextNotContains('Experimental Test has been enabled.');
|
||||
$this->assertSession()->pageTextContains('Experimental modules are provided for testing purposes only.');
|
||||
$this->assertSession()->pageTextContains('The following modules are experimental: Experimental Test');
|
||||
|
||||
// There should be no message about enabling dependencies.
|
||||
$this->assertSession()->pageTextNotContains('You must enable');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$this->assertSession()->pageTextContains('Experimental Test has been enabled.');
|
||||
|
||||
// Uninstall the module.
|
||||
\Drupal::service('module_installer')->uninstall(['experimental_module_test']);
|
||||
|
||||
// Test enabling a module that is not itself experimental, but that depends
|
||||
// on an experimental module.
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_dependency_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the experimental modules with only this one.
|
||||
$this->assertSession()->pageTextNotContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
$this->assertSession()->pageTextContains('Experimental modules are provided for testing purposes only.');
|
||||
|
||||
$this->assertSession()->pageTextContains('The following modules are experimental: Experimental Test');
|
||||
|
||||
// Ensure the non-experimental module is not listed as experimental.
|
||||
$this->assertSession()->pageTextNotContains('The following modules are experimental: Experimental Test, Experimental Dependency Test');
|
||||
$this->assertSession()->pageTextNotContains('The following modules are experimental: Experimental Dependency Test');
|
||||
|
||||
// There should be a message about enabling dependencies.
|
||||
$this->assertSession()->pageTextContains('You must enable the Experimental Test module to install Experimental Dependency Test');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$this->assertSession()->pageTextContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
|
||||
// Uninstall the modules.
|
||||
\Drupal::service('module_installer')->uninstall(['experimental_module_test', 'experimental_module_dependency_test']);
|
||||
|
||||
// Finally, check both the module and its experimental dependency. There is
|
||||
// still a warning about experimental modules, but no message about
|
||||
// dependencies, since the user specifically enabled the dependency.
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_test][enable]"] = TRUE;
|
||||
$edit["modules[experimental_module_dependency_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the experimental modules with only this one.
|
||||
$this->assertSession()->pageTextNotContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
$this->assertSession()->pageTextContains('Experimental modules are provided for testing purposes only.');
|
||||
|
||||
$this->assertSession()->pageTextContains('The following modules are experimental: Experimental Test');
|
||||
|
||||
// Ensure the non-experimental module is not listed as experimental.
|
||||
$this->assertSession()->pageTextNotContains('The following modules are experimental: Experimental Dependency Test, Experimental Test');
|
||||
$this->assertSession()->pageTextNotContains('The following modules are experimental: Experimental Dependency Test');
|
||||
|
||||
// There should be no message about enabling dependencies.
|
||||
$this->assertSession()->pageTextNotContains('You must enable');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$this->assertSession()->pageTextContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
|
||||
// Try to enable an experimental module that can not be due to
|
||||
// hook_requirements().
|
||||
\Drupal::state()->set('experimental_module_requirements_test_requirements', TRUE);
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_requirements_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
// Verify that if the module can not be installed, we are not taken to the
|
||||
// confirm form.
|
||||
$this->assertSession()->addressEquals('admin/modules');
|
||||
$this->assertSession()->pageTextContains('The Experimental Test Requirements module can not be installed.');
|
||||
}
|
||||
|
||||
}
|
|
@ -112,7 +112,7 @@ class InstallUninstallTest extends ModuleTestBase {
|
|||
|
||||
// Handle experimental modules, which require a confirmation screen.
|
||||
if ($lifecycle === ExtensionLifecycle::EXPERIMENTAL) {
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable experimental modules?');
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable an experimental module?');
|
||||
if (count($modules_to_install) > 1) {
|
||||
// When there are experimental modules, needed dependencies do not
|
||||
// result in the same page title, but there will be expected text
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\system\Functional\Module;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Tests the installation of deprecated and experimental modules.
|
||||
*
|
||||
* @group Module
|
||||
*/
|
||||
class NonStableModulesTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* The admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected UserInterface $adminUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $modules = [
|
||||
'deprecated_module_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->adminUser = $this->drupalCreateUser([
|
||||
'access administration pages',
|
||||
'administer modules',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests installing experimental modules and dependencies in the UI.
|
||||
*/
|
||||
public function testExperimentalConfirmForm(): void {
|
||||
// First, test installing a non-experimental module with no dependencies.
|
||||
// There should be no confirmation form and no experimental module warning.
|
||||
$edit = [];
|
||||
$edit["modules[test_page_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
$this->assertSession()->pageTextContains('Module Test page has been enabled.');
|
||||
$this->assertSession()->pageTextNotContains('Experimental modules are provided for testing purposes only.');
|
||||
|
||||
// There should be no warning about enabling experimental or deprecated
|
||||
// modules, since there's no confirmation form.
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable ');
|
||||
|
||||
// Uninstall the module.
|
||||
\Drupal::service('module_installer')->uninstall(['test_page_test']);
|
||||
|
||||
// Next, test installing an experimental module with no dependencies.
|
||||
// There should be a confirmation form with an experimental warning, but no
|
||||
// list of dependencies.
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the experimental modules with only this one.
|
||||
$this->assertSession()->pageTextNotContains('Experimental Test has been enabled.');
|
||||
$this->assertSession()->pageTextContains('Experimental modules are provided for testing purposes only.');
|
||||
$this->assertSession()->pageTextContains('The following module is experimental: Experimental Test');
|
||||
|
||||
// There should be a warning about enabling experimental modules, but no
|
||||
// warnings about deprecated modules.
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable an experimental module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable a deprecated module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
|
||||
// There should be no message about enabling dependencies.
|
||||
$this->assertSession()->pageTextNotContains('You must enable');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$this->assertSession()->pageTextContains('Experimental Test has been enabled.');
|
||||
|
||||
// Uninstall the module.
|
||||
\Drupal::service('module_installer')->uninstall(['experimental_module_test']);
|
||||
|
||||
// Test enabling a module that is not itself experimental, but that depends
|
||||
// on an experimental module.
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_dependency_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the experimental modules with only this one.
|
||||
$this->assertSession()->pageTextNotContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
$this->assertSession()->pageTextContains('Experimental modules are provided for testing purposes only.');
|
||||
$this->assertSession()->pageTextContains('The following module is experimental: Experimental Test');
|
||||
|
||||
// There should be a warning about enabling experimental modules, but no
|
||||
// warnings about deprecated modules.
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable an experimental module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable a deprecated module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
|
||||
// Ensure the non-experimental module is not listed as experimental.
|
||||
$this->assertSession()->pageTextNotContains('The following modules are experimental: Experimental Test, Experimental Dependency Test');
|
||||
$this->assertSession()->pageTextNotContains('The following module is experimental: Experimental Dependency Test');
|
||||
|
||||
// There should be a message about enabling dependencies.
|
||||
$this->assertSession()->pageTextContains('You must enable the Experimental Test module to install Experimental Dependency Test');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$this->assertSession()->pageTextContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
|
||||
// Uninstall the modules.
|
||||
\Drupal::service('module_installer')->uninstall([
|
||||
'experimental_module_test',
|
||||
'experimental_module_dependency_test',
|
||||
]);
|
||||
|
||||
// Finally, check both the module and its experimental dependency. There is
|
||||
// still a warning about experimental modules, but no message about
|
||||
// dependencies, since the user specifically enabled the dependency.
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_test][enable]"] = TRUE;
|
||||
$edit["modules[experimental_module_dependency_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the experimental modules with only this one.
|
||||
$this->assertSession()->pageTextNotContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
$this->assertSession()->pageTextContains('Experimental modules are provided for testing purposes only.');
|
||||
$this->assertSession()->pageTextContains('The following module is experimental: Experimental Test');
|
||||
|
||||
// There should be a warning about enabling experimental modules, but no
|
||||
// warnings about deprecated modules.
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable an experimental module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable a deprecated module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
|
||||
// Ensure the non-experimental module is not listed as experimental.
|
||||
$this->assertSession()->pageTextNotContains('The following modules are experimental: Experimental Dependency Test, Experimental Test');
|
||||
$this->assertSession()->pageTextNotContains('The following module is experimental: Experimental Dependency Test');
|
||||
|
||||
// There should be no message about enabling dependencies.
|
||||
$this->assertSession()->pageTextNotContains('You must enable');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$this->assertSession()->pageTextContains('2 modules have been enabled: Experimental Dependency Test, Experimental Test');
|
||||
|
||||
// Try to enable an experimental module that can not be due to
|
||||
// hook_requirements().
|
||||
\Drupal::state()->set('experimental_module_requirements_test_requirements', TRUE);
|
||||
$edit = [];
|
||||
$edit["modules[experimental_module_requirements_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// Verify that if the module can not be installed, we are not taken to the
|
||||
// confirm form.
|
||||
$this->assertSession()->addressEquals('admin/modules');
|
||||
$this->assertSession()->pageTextContains('The Experimental Test Requirements module can not be installed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests installing deprecated modules and dependencies in the UI.
|
||||
*/
|
||||
public function testDeprecatedConfirmForm(): void {
|
||||
// Test installing a deprecated module with no dependencies. There should be
|
||||
// a confirmation form with a deprecated warning, but no list of
|
||||
// dependencies.
|
||||
$edit = [];
|
||||
$edit["modules[deprecated_module][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the deprecated modules with only this one.
|
||||
$assert = $this->assertSession();
|
||||
$assert->pageTextNotContains('Deprecated module has been enabled.');
|
||||
$assert->pageTextContains('Deprecated modules are modules that may be removed from the next major release of Drupal core. Use at your own risk.');
|
||||
$assert->pageTextContains('The Deprecated module module is deprecated');
|
||||
$more_information_link = $assert->elementExists('named', [
|
||||
'link',
|
||||
'The Deprecated module module is deprecated. (more information)',
|
||||
]);
|
||||
$this->assertEquals('http://example.com/deprecated', $more_information_link->getAttribute('href'));
|
||||
|
||||
// There should be a warning about enabling deprecated modules, but no
|
||||
// warnings about experimental modules.
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable a deprecated module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable an experimental module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
|
||||
// There should be no message about enabling dependencies.
|
||||
$assert->pageTextNotContains('You must enable');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$assert->pageTextContains('Deprecated module has been enabled.');
|
||||
|
||||
// Uninstall the module.
|
||||
\Drupal::service('module_installer')->uninstall(['deprecated_module']);
|
||||
|
||||
// Test enabling a module that is not itself deprecated, but that depends on
|
||||
// a deprecated module.
|
||||
$edit = [];
|
||||
$edit["modules[deprecated_module_dependency][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the deprecated modules with only this one.
|
||||
$assert->pageTextNotContains('2 modules have been enabled: Deprecated module dependency, Deprecated module');
|
||||
$assert->pageTextContains('Deprecated modules are modules that may be removed from the next major release of Drupal core. Use at your own risk.');
|
||||
$assert->pageTextContains('The Deprecated module module is deprecated');
|
||||
|
||||
// There should be a warning about enabling deprecated modules, but no
|
||||
// warnings about experimental modules.
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable a deprecated module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable an experimental module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
|
||||
// Ensure the non-deprecated module is not listed as deprecated.
|
||||
$assert->pageTextNotContains('The Deprecated module dependency module is deprecated');
|
||||
|
||||
// There should be a message about enabling dependencies.
|
||||
$assert->pageTextContains('You must enable the Deprecated module module to install Deprecated module dependency');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$assert->pageTextContains('2 modules have been enabled: Deprecated module dependency, Deprecated module');
|
||||
|
||||
// Uninstall the modules.
|
||||
\Drupal::service('module_installer')->uninstall([
|
||||
'deprecated_module',
|
||||
'deprecated_module_dependency',
|
||||
]);
|
||||
|
||||
// Finally, check both the module and its deprecated dependency. There is
|
||||
// still a warning about deprecated modules, but no message about
|
||||
// dependencies, since the user specifically enabled the dependency.
|
||||
$edit = [];
|
||||
$edit["modules[deprecated_module_dependency][enable]"] = TRUE;
|
||||
$edit["modules[deprecated_module][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the deprecated modules with only this one.
|
||||
$assert->pageTextNotContains('2 modules have been enabled: Deprecated module dependency, Deprecated module');
|
||||
$assert->pageTextContains('Deprecated modules are modules that may be removed from the next major release of Drupal core. Use at your own risk.');
|
||||
$assert->pageTextContains('The Deprecated module module is deprecated');
|
||||
|
||||
// There should be a warning about enabling deprecated modules, but no
|
||||
// warnings about experimental modules.
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable a deprecated module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable an experimental module?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
|
||||
// Ensure the non-deprecated module is not listed as deprecated.
|
||||
$assert->pageTextNotContains('The Deprecated module dependency module is deprecated');
|
||||
|
||||
// There should be no message about enabling dependencies.
|
||||
$assert->pageTextNotContains('You must enable');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$assert->pageTextContains('2 modules have been enabled: Deprecated module, Deprecated module dependency');
|
||||
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm(["modules[deprecated_module_contrib][enable]" => TRUE], 'Install');
|
||||
$assert->pageTextContains('Deprecated modules are modules that may be removed from the next major release of this project. Use at your own risk.');
|
||||
|
||||
\Drupal::service('module_installer')->uninstall([
|
||||
'deprecated_module',
|
||||
'deprecated_module_dependency',
|
||||
]);
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm([
|
||||
"modules[deprecated_module_contrib][enable]" => TRUE,
|
||||
"modules[deprecated_module][enable]" => TRUE,
|
||||
], 'Install');
|
||||
$assert->pageTextContains('Deprecated modules are modules that may be removed from the next major release of Drupal core and the relevant contributed module. Use at your own risk.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests installing deprecated and experimental modules at the same time.
|
||||
*/
|
||||
public function testDeprecatedAndExperimentalConfirmForm(): void {
|
||||
$edit = [];
|
||||
$edit["modules[deprecated_module][enable]"] = TRUE;
|
||||
$edit["modules[experimental_module_test][enable]"] = TRUE;
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the deprecated modules with only this one.
|
||||
$assert = $this->assertSession();
|
||||
$assert->pageTextNotContains('Deprecated module has been enabled.');
|
||||
$assert->pageTextContains('Deprecated modules are modules that may be removed from the next major release of Drupal core. Use at your own risk.');
|
||||
$assert->pageTextContains('The Deprecated module module is deprecated');
|
||||
$more_information_link = $assert->elementExists('named', [
|
||||
'link',
|
||||
'The Deprecated module module is deprecated. (more information)',
|
||||
]);
|
||||
$this->assertEquals('http://example.com/deprecated', $more_information_link->getAttribute('href'));
|
||||
|
||||
// The module should not be enabled and there should be a warning and a
|
||||
// list of the experimental modules with only this one.
|
||||
$assert->pageTextNotContains('Experimental Test has been enabled.');
|
||||
$assert->pageTextContains('Experimental modules are provided for testing purposes only.');
|
||||
$assert->pageTextContains('The following module is experimental: Experimental Test');
|
||||
|
||||
// There should be a warning about enabling experimental and deprecated
|
||||
// modules, but no warnings about solitary experimental or deprecated
|
||||
// modules.
|
||||
$this->assertSession()->pageTextContains('Are you sure you wish to enable experimental and deprecated modules?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable experimental modules?');
|
||||
$this->assertSession()->pageTextNotContains('Are you sure you wish to enable deprecated modules?');
|
||||
|
||||
// There should be no message about enabling dependencies.
|
||||
$assert->pageTextNotContains('You must enable');
|
||||
|
||||
// Enable the module and confirm that it worked.
|
||||
$this->submitForm([], 'Continue');
|
||||
$assert->pageTextContains('2 modules have been enabled: Deprecated module, Experimental Test.');
|
||||
}
|
||||
|
||||
}
|
|
@ -199,6 +199,15 @@ small .admin-link:after {
|
|||
[dir="rtl"] .module-link-configure {
|
||||
background-position: top 50% right 0;
|
||||
}
|
||||
.module-link--non-stable {
|
||||
padding-left: 18px;
|
||||
background: url(../../../../misc/icons/e29700/warning.svg) 0 50% no-repeat; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .module-link--non-stable {
|
||||
padding-right: 18px;
|
||||
padding-left: 0;
|
||||
background-position: top 50% right 0;
|
||||
}
|
||||
|
||||
/* Status report. */
|
||||
.system-status-report__status-title {
|
||||
|
|
|
@ -199,6 +199,15 @@ small .admin-link:after {
|
|||
[dir="rtl"] .module-link-configure {
|
||||
background-position: top 50% right 0;
|
||||
}
|
||||
.module-link--non-stable {
|
||||
padding-left: 18px;
|
||||
background: url(../../../../misc/icons/e29700/warning.svg) 0 50% no-repeat; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .module-link--non-stable {
|
||||
padding-right: 18px;
|
||||
padding-left: 0;
|
||||
background-position: top 50% right 0;
|
||||
}
|
||||
|
||||
/* Status report. */
|
||||
.system-status-report__status-title {
|
||||
|
|
Loading…
Reference in New Issue