Skip to content
Snippets Groups Projects
Commit 78afe634 authored by Yash Rode's avatar Yash Rode Committed by Adam G-H
Browse files

Issue #3308843 by yash.rode, phenaproxima: Automatic Updates Extensions' forms...

Issue #3308843 by yash.rode, phenaproxima: Automatic Updates Extensions' forms should check for the failure marker
parent 1fdd4652
No related branches found
No related tags found
1 merge request!500Issue #3308843: Automatic Updates Extensions' forms should check for the failure marker
......@@ -3,6 +3,8 @@
namespace Drupal\automatic_updates_extensions;
use Drupal\automatic_updates\Exception\UpdateException;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\package_manager\Exception\ApplyFailedException;
use Drupal\package_manager\LegacyVersionUtility;
use Drupal\package_manager\Event\StageEvent;
use Drupal\package_manager\Exception\StageValidationException;
......@@ -110,4 +112,23 @@ class ExtensionUpdater extends Stage {
}
}
/**
* {@inheritdoc}
*/
public function apply(?int $timeout = 600): void {
try {
parent::apply($timeout);
}
catch (ApplyFailedException $exception) {
throw new UpdateException([], 'The update operation failed to apply. The update may have been partially applied. It is recommended that the site be restored from a code backup.', $exception->getCode(), $exception);
}
}
/**
* {@inheritdoc}
*/
protected function getFailureMarkerMessage(): TranslatableMarkup {
return $this->t('Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup.');
}
}
......@@ -2,6 +2,7 @@
namespace Drupal\automatic_updates_extensions\Form;
use Drupal\package_manager\Exception\ApplyFailedException;
use Drupal\package_manager\ProjectInfo;
use Drupal\automatic_updates\Validator\StagedDatabaseUpdateValidator;
use Drupal\automatic_updates_extensions\BatchProcessor;
......@@ -119,6 +120,10 @@ final class UpdateReady extends FormBase {
$this->messenger()->addError($this->t('Cannot continue the update because another Composer operation is currently in progress.'));
return $form;
}
catch (ApplyFailedException $e) {
$this->messenger()->addError($e->getMessage());
return $form;
}
$messages = [];
......
......@@ -13,6 +13,8 @@ use Drupal\Core\State\StateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\package_manager\Exception\ApplyFailedException;
use Drupal\package_manager\FailureMarker;
use Drupal\package_manager\ProjectInfo;
use Drupal\system\SystemManager;
use Drupal\update\UpdateManagerInterface;
......@@ -57,6 +59,13 @@ final class UpdaterForm extends FormBase {
*/
private $renderer;
/**
* Failure marker service.
*
* @var \Drupal\package_manager\FailureMarker
*/
private $failureMarker;
/**
* {@inheritdoc}
*/
......@@ -65,7 +74,8 @@ final class UpdaterForm extends FormBase {
$container->get('automatic_updates_extensions.updater'),
$container->get('event_dispatcher'),
$container->get('renderer'),
$container->get('state')
$container->get('state'),
$container->get('package_manager.failure_marker')
);
}
......@@ -80,12 +90,15 @@ final class UpdaterForm extends FormBase {
* The renderer service.
* @param \Drupal\Core\State\StateInterface $state
* The state service.
* @param \Drupal\package_manager\FailureMarker $failure_marker
* The failure marker service.
*/
public function __construct(ExtensionUpdater $extension_updater, EventDispatcherInterface $event_dispatcher, RendererInterface $renderer, StateInterface $state) {
public function __construct(ExtensionUpdater $extension_updater, EventDispatcherInterface $event_dispatcher, RendererInterface $renderer, StateInterface $state, FailureMarker $failure_marker) {
$this->extensionUpdater = $extension_updater;
$this->eventDispatcher = $event_dispatcher;
$this->renderer = $renderer;
$this->state = $state;
$this->failureMarker = $failure_marker;
}
/**
......@@ -99,6 +112,13 @@ final class UpdaterForm extends FormBase {
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
try {
$this->failureMarker->assertNotExists();
}
catch (ApplyFailedException $e) {
$this->messenger()->addError($e->getMessage());
return $form;
}
$update_projects = $this->getRecommendedModuleUpdates();
$options = [];
$recommended_versions = [];
......
......@@ -7,6 +7,7 @@ use Drupal\automatic_updates_test\EventSubscriber\TestSubscriber1;
use Drupal\automatic_updates_test\StagedDatabaseUpdateValidator;
use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\package_manager_bypass\Committer;
use Drupal\package_manager_bypass\Stager;
use Drupal\Tests\automatic_updates\Functional\AutomaticUpdatesFunctionalTestBase;
use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait;
......@@ -208,6 +209,47 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase {
$this->assertSame($state->get('system.maintenance_mode'), $maintenance_mode_on);
}
/**
* Tests that an exception is thrown if a previous apply failed.
*/
public function testMarkerFileFailure(): void {
$this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/semver_test.1.1.xml');
$this->setProjectInstalledVersion(['semver_test' => '8.1.0']);
$this->checkForUpdates();
$page = $this->getSession()->getPage();
// Navigate to the automatic updates form.
$this->drupalGet('/admin/modules/automatic-update-extensions');
$assert_session = $this->assertSession();
$assert_session->pageTextNotContains(static::$errorsExplanation);
$assert_session->pageTextNotContains(static::$warningsExplanation);
$this->assertTableShowsUpdates('Semver Test', '8.1.0', '8.1.1');
$this->assertUpdatesCount(1);
$page->checkField('projects[semver_test]');
$page->pressButton('Update');
$this->checkForMetaRefresh();
$this->assertUpdateStagedTimes(1);
$assert_session->pageTextNotContains('The following dependencies will also be updated:');
Committer::setException(new \Exception('failed at committer'));
$page->pressButton('Continue');
$this->checkForMetaRefresh();
$assert_session->pageTextContainsOnce('An error has occurred.');
$assert_session->pageTextContains('The update operation failed to apply. The update may have been partially applied. It is recommended that the site be restored from a code backup.');
$page->clickLink('the error page');
$failure_message = 'Automatic updates failed to apply, and the site is in an indeterminate state. Consider restoring the code and database from a backup.';
// We should be on the form (i.e., 200 response code), but unable to
// continue the update.
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains($failure_message);
$assert_session->buttonNotExists('Continue');
// The same thing should be true if we try to start from the beginning.
$this->drupalGet('/admin/modules/automatic-update-extensions');
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains($failure_message);
$assert_session->buttonNotExists('Update');
}
/**
* Data provider for testDisplayUpdates().
*
......
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