Improve the user experience of having your staged update deleted before it was applied

Created on 6 December 2022, about 2 years ago
Updated 3 February 2023, almost 2 years ago

Problem/Motivation

Currently we have a "Delete existing update" existing update button on our form. If you start an update and get to the UpdateReady from but don't start applying the update then another user could come to the UpdaterForm and delete you existing update.

for the user that started the first update process this will need to a message "Cannot continue the update because another Composer operation is currently in progress.". The would have to restart their operation.

If we move forward with #3311200: Cron updater should delete the existing stage if not available and the site is currently on an insecure version โ†’ then this could also happen because the cron update delete your staged update.

Steps to reproduce

  1. Login as an admin, user1
  2. Stage an update to drupal core
  3. Get to the page with the "continue" button but do not apply the update
  4. In an incognito browser session login as user2 also an admin
  5. goto admin/modules/update
  6. there should be message about existing update
  7. click Delete existing update, do not start an update as user2
  8. goto back to browser with user1
  9. click "continue" as user1
  10. you should see this fatal error

    The website encountered an unexpected error. Please try again later.

    Drupal\package_manager\Exception\StageException: Cannot claim the stage because no stage has been created. in Drupal\package_manager\Stage->claim() (line 660 of modules/contrib/automatic_updates/package_manager/src/Stage.php).
    Drupal\automatic_updates\Form\UpdateReady->buildForm(Array, Object, '_UcKhfO2Vd6FEm1g_EOaqPWMGxFjupr_ed1lIIkEGgo')
    call_user_func_array(Array, Array) (Line: 531)
    Drupal\Core\Form\FormBuilder->retrieveForm('automatic_updates_update_ready_form', Object) (Line: 278)
    Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 73)
    Drupal\Core\Controller\FormController->getContentResult(Object, Object)
    call_user_func_array(Array, Array) (Line: 123)
    Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 564)
    Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
    Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
    Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 169)
    Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
    Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
    Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
    Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
    Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
    Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
    Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
    Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
    Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 709)
    Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
    require('/Users/ted.bowman/sites/conflict-test/web/index.php') (Line: 234)

Proposed resolution

  1. In the current "Steps to reproduce" scenario the user should see a message that there update has been deleted by another user, not the error page

    In order to do this we need to keep some message about the stage when it is destroyed and then use that message for the exception message give in \Drupal\package_manager\Stage::claim

  2. Manually test the same scenario as "Steps to reproduce" but after clicking Delete existing update user2 should stage their own update but "stop" instead of hitting continue

    What error does user1 get when they try to continue their update. The should also see a nice message

Proposed tests

Kernel tests

Add StageDestroyMessage

We need to create a stage, save it ID, destroy it and then try call claim() with the destroyed stages ID.

Here are the test scenarios we need coverage for:
\Drupal\package_manager\Stage::storeDestroyInfo() has 3 different possible messages if $message is null.
We need test coverage for exception messages from claim() based on theses message set in storeDestroyInfo
We need test coverage for when storeDestroyInfo is called with a custom message that calling claim() will throw an exception with this custom message.
We need coverage if the tempstore message has expired(or for testings you delete directly with \Drupal\Core\TempStore\SharedTempStore::delete) we get the 3 possible exception messages in claim()

Function tests

For functional test this should be the steps

  1. Login as an admin
  2. Stage an update to drupal core
  3. Get to the page with the "continue" button(route automatic_updates.confirmation_page) but do not apply the update
  4. In the test method programmatically force delete the current stage
  5. In the test click the "continue"
  6. Currently this will result in a fatal error.

    but we want have the failing test to confirm is that user stays on the same page and does not see the exception message but rather sees a error message on the form and the "continue" button is removed

TBD the exact message but the first step to make sure they don't get a fatal error in both cases.

Remaining tasks

User interface changes

API changes

Data model changes

๐Ÿ“Œ Task
Status

Fixed

Version

2.0

Component

Code

Created by

๐Ÿ‡บ๐Ÿ‡ธUnited States tedbow Ithaca, NY, USA

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024