Skip to content
Snippets Groups Projects
Commit fae8fb79 authored by Theresa Grannum's avatar Theresa Grannum Committed by Ted Bowman
Browse files

Issue #3261642 by Theresa.Grannum, tedbow: Create form to list contrib updates

parent d4ac1f79
No related branches found
No related tags found
No related merge requests found
name: 'Automatic Updates Extensions'
type: module
description: 'Allows updates to themes and modules'
core_version_requirement: ^9.2
dependencies:
- drupal:automatic_updates
hidden: true
automatic_updates_extensions.update:
path: '/admin/automatic-update-extensions'
defaults:
_form: 'Drupal\automatic_updates_extensions\Form\UpdaterForm'
_title: 'Automatic Updates Form'
requirements:
_permission: 'administer software updates'
options:
_admin_route: TRUE
<?php
namespace Drupal\automatic_updates_extensions\Form;
use Drupal\automatic_updates\Updater;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\update\UpdateManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* A form for selecting extension updates.
*/
class UpdaterForm extends FormBase {
/**
* The updater service.
*
* @var \Drupal\automatic_updates\Updater
*/
private $updater;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('automatic_updates.updater'));
}
/**
* Constructs a new UpdaterForm object.
*
* @param \Drupal\automatic_updates\Updater $updater
* The extension updater service.
*/
public function __construct(Updater $updater) {
$this->updater = $updater;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'automatic_updates_extensions_updater_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$update_projects = $this->getRecommendedModuleUpdates();
$options = [];
$recommended_versions = [];
foreach ($update_projects as $project_name => $update_project) {
switch ($update_project['status']) {
case UpdateManagerInterface::NOT_SECURE:
case UpdateManagerInterface::REVOKED:
$status_message = $this->t('(Security update)');
break;
case UpdateManagerInterface::NOT_SUPPORTED:
$status_message = $this->t('(Unsupported)');
break;
default:
$status_message = '';
}
$options[$project_name] = [
$update_project['title'] . $status_message,
$update_project['existing_version'],
$update_project['recommended'],
];
$recommended_versions[$project_name] = $update_project['recommended'];
}
$form['recommended_versions'] = [
'#type' => 'value',
'#value' => $recommended_versions,
];
$form['projects'] = [
'#type' => 'tableselect',
'#header' => [
$this->t('Project:'),
$this->t('Current Version:'),
$this->t('Update Version:'),
],
'#options' => $options,
'#empty' => $this->t('There are no available updates.'),
'#attributes' => ['class' => ['update-recommended']],
];
if ($update_projects) {
$form['actions'] = $this->actions($form_state);
}
return $form;
}
/**
* Builds the form actions.
*
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return mixed[][]
* The form's actions elements.
*/
protected function actions(FormStateInterface $form_state): array {
$actions = ['#type' => 'actions'];
if (!$this->updater->isAvailable()) {
// If the form has been submitted do not display this error message
// because ::deleteExistingUpdate() may run on submit. The message will
// still be displayed on form build if needed.
if (!$form_state->getUserInput()) {
$this->messenger()->addError($this->t('Cannot begin an update because another Composer operation is currently in progress.'));
}
$actions['delete'] = [
'#type' => 'submit',
'#value' => $this->t('Delete existing update'),
'#submit' => ['::deleteExistingUpdate'],
];
}
else {
$actions['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Update'),
];
}
return $actions;
}
/**
* Submit function to delete an existing in-progress update.
*/
public function deleteExistingUpdate(): void {
$this->updater->destroy(TRUE);
$this->messenger()->addMessage($this->t("Staged update deleted"));
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$projects = $form_state->getValue('projects');
$selected_projects = array_filter($projects);
$recommended_versions = $form_state->getValue('recommended_versions');
$selected_versions = array_intersect_key($recommended_versions, $selected_projects);
$this->messenger()->addMessage(print_r($selected_versions, TRUE));
}
/**
* Gets the modules that require updates.
*
* @return array
* Modules that require updates.
*/
private function getRecommendedModuleUpdates(): array {
$available_updates = update_get_available(TRUE);
if (empty($available_updates)) {
$this->messenger()->addError('There was a problem getting update information. Try again later.');
return [];
}
$project_data = update_calculate_project_data($available_updates);
$outdated_modules = [];
foreach ($project_data as $project_name => $project_info) {
if ($project_info['project_type'] === 'module' || $project_info['project_type'] === 'module-disabled') {
if ($project_info['status'] !== UpdateManagerInterface::CURRENT) {
if (!empty($project_info['recommended'])) {
$outdated_modules[$project_name] = $project_info;
}
}
}
}
return $outdated_modules;
}
}
<?php
namespace Drupal\Tests\automatic_updates_extensions\Functional;
use Drupal\Tests\automatic_updates\Functional\AutomaticUpdatesFunctionalTestBase;
/**
* Tests updating using the form.
*
* @group automatic_updates_extensions
*/
class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'automatic_updates_test',
'automatic_updates_extensions',
'semver_test',
];
/**
* Project to test updates.
*
* @var string
*/
protected $updateProject = 'semver_test';
/**
* {@inheritdoc}
*/
protected function setUp():void {
parent::setUp();
$this->setReleaseMetadata(__DIR__ . '/../../../../tests/fixtures/release-history/semver_test.1.1.xml');
}
/**
* Sets installed project version.
*
* @todo This is copied from core. We need to file a core issue so we do not
* have to copy this.
*/
protected function setProjectInstalledVersion($version) {
$this->config('update.settings')
->set('fetch.url', $this->baseUrl . '/automatic-update-test')
->save();
$system_info = [
$this->updateProject => [
'project' => $this->updateProject,
'version' => $version,
'hidden' => FALSE,
],
// Ensure Drupal core on the same version for all test runs.
'drupal' => [
'project' => 'drupal',
'version' => '8.0.0',
'hidden' => FALSE,
],
];
$this->config('update_test.settings')->set('system_info', $system_info)->save();
}
/**
* Tests the form when a module requires an update.
*/
public function testHasUpdate():void {
$assert = $this->assertSession();
$user = $this->createUser(['administer site configuration']);
$this->drupalLogin($user);
$this->setProjectInstalledVersion('8.1.0');
$this->checkForUpdates();
$this->drupalGet('/admin/automatic-update-extensions');
$assert->pageTextContains('Access Denied');
$assert->pageTextNotContains('Automatic Updates Form');
$user = $this->createUser(['administer software updates']);
$this->drupalLogin($user);
$this->drupalGet('/admin/automatic-update-extensions');
$assert->pageTextContains('Automatic Updates Form');
$assert->elementTextContains('css', '.update-recommended td:nth-of-type(2)', 'Semver Test');
$assert->elementTextContains('css', '.update-recommended td:nth-of-type(3)', '8.1.0');
$assert->elementTextContains('css', '.update-recommended td:nth-of-type(4)', '8.1.1');
$assert->elementsCount('css', '.update-recommended tbody tr', 1);
$assert->buttonExists('Update');
}
/**
* Tests the form when there are no available updates.
*/
public function testNoUpdate():void {
$assert = $this->assertSession();
$user = $this->createUser(['administer site configuration',
'administer software updates',
]);
$this->drupalLogin($user);
$this->setProjectInstalledVersion('8.1.1');
$this->checkForUpdates();
$this->drupalGet('/admin/automatic-update-extensions');
$assert->pageTextContains('There are no available updates.');
$assert->buttonNotExists('Update');
}
}
<?xml version="1.0" encoding="utf-8"?>
<project xmlns:dc="http://purl.org/dc/elements/1.1/">
<title>Semver Test</title>
<short_name>semver_test</short_name>
<dc:creator>Drupal</dc:creator>
<supported_branches>8.0.,8.1.</supported_branches>
<project_status>published</project_status>
<link>http://example.com/project/semver_test</link>
<terms>
<term><name>Projects</name><value>Semver Test project</value></term>
</terms>
<releases>
<release>
<!-- This release is not in a supported branch; therefore it should not be recommended. -->
<name>Semver Test 8.2.0</name>
<version>8.2.0</version>
<tag>8.2.0</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-2-0-release</release_link>
<download_link>http://example.com/semver_test-8-2-0.tar.gz</download_link>
<date>1584195300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.1.1</name>
<version>8.1.1</version>
<tag>8.1.1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-1-1-release</release_link>
<download_link>http://example.com/semver_test-8-1-1.tar.gz</download_link>
<date>1581603300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.1.1-beta1</name>
<version>8.1.1-beta1</version>
<tag>8.1.1-beta1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-1-1-beta1-release</release_link>
<download_link>http://example.com/semver_test-8-1-1-beta1.tar.gz</download_link>
<date>1579011300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.1.1-alpha1</name>
<version>8.1.1-alpha1</version>
<tag>8.1.1-alpha1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-1-1-alpha1-release</release_link>
<download_link>http://example.com/semver_test-8-1-1-alpha1.tar.gz</download_link>
<date>1576419300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.1.0</name>
<version>8.1.0</version>
<tag>8.1.0</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-1-0-release</release_link>
<download_link>http://example.com/semver_test-8-1-0.tar.gz</download_link>
<date>1573827300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.1.0-beta1</name>
<version>8.1.0-beta1</version>
<tag>8.1.0-beta1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-1-0-beta1-release</release_link>
<download_link>http://example.com/semver_test-8-1-0-beta1.tar.gz</download_link>
<date>1571235300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.1.0-alpha1</name>
<version>8.1.0-alpha1</version>
<tag>8.1.0-alpha1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-1-0-alpha1-release</release_link>
<download_link>http://example.com/semver_test-8-1-0-alpha1.tar.gz</download_link>
<date>1568643300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.0.1</name>
<version>8.0.1</version>
<tag>8.0.1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-0-1-release</release_link>
<download_link>http://example.com/semver_test-8-0-1.tar.gz</download_link>
<date>1566051300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.0.1-beta1</name>
<version>8.0.1-beta1</version>
<tag>8.0.1-beta1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-0-1-beta1-release</release_link>
<download_link>http://example.com/semver_test-8-0-1-beta1.tar.gz</download_link>
<date>1563459300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.0.1-alpha1</name>
<version>8.0.1-alpha1</version>
<tag>8.0.1-alpha1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-0-1-alpha1-release</release_link>
<download_link>http://example.com/semver_test-8-0-1-alpha1.tar.gz</download_link>
<date>1560867300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.0.0</name>
<version>8.0.0</version>
<tag>8.0.0</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-0-0-release</release_link>
<download_link>http://example.com/semver_test-8-0-0.tar.gz</download_link>
<date>1558275300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.0.0-beta1</name>
<version>8.0.0-beta1</version>
<tag>8.0.0-beta1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-0-0-beta1-release</release_link>
<download_link>http://example.com/semver_test-8-0-0-beta1.tar.gz</download_link>
<date>1555683300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
<release>
<name>Semver Test 8.0.0-alpha1</name>
<version>8.0.0-alpha1</version>
<tag>8.0.0-alpha1</tag>
<status>published</status>
<release_link>http://example.com/semver_test-8-0-0-alpha1-release</release_link>
<download_link>http://example.com/semver_test-8-0-0-alpha1.tar.gz</download_link>
<date>1553091300</date>
<terms>
<term><name>Release type</name><value>New features</value></term>
<term><name>Release type</name><value>Bug fixes</value></term>
</terms>
</release>
</releases>
</project>
...@@ -63,9 +63,6 @@ class TestController extends ControllerBase { ...@@ -63,9 +63,6 @@ class TestController extends ControllerBase {
* directory of mock XML files. * directory of mock XML files.
*/ */
public function metadata($project_name = 'drupal', $version = NULL): Response { public function metadata($project_name = 'drupal', $version = NULL): Response {
if ($project_name !== 'drupal') {
return new Response();
}
$xml_map = $this->config('update_test.settings')->get('xml_map'); $xml_map = $this->config('update_test.settings')->get('xml_map');
if (isset($xml_map[$project_name])) { if (isset($xml_map[$project_name])) {
$availability_scenario = $xml_map[$project_name]; $availability_scenario = $xml_map[$project_name];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment