diff --git a/core/includes/update.inc b/core/includes/update.inc
index e395fb6..61de857 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -229,6 +229,11 @@ function update_do_one($module, $number, $dependency_map, &$context) {
function update_invoke_post_update($function, &$context) {
$ret = [];
+ // Do not run any post update hooks if there are failed or pending updates.
+ if (!empty(update_get_update_list(TRUE))) {
+ return;
+ }
+
list($module, ) = explode('_post_update_', $function, 2);
module_load_include('php', $module, $module . '.post_update');
if (function_exists($function)) {
diff --git a/core/lib/Drupal/Core/Update/UpdateRegistry.php b/core/lib/Drupal/Core/Update/UpdateRegistry.php
index 949d076..dc0bc3f 100644
--- a/core/lib/Drupal/Core/Update/UpdateRegistry.php
+++ b/core/lib/Drupal/Core/Update/UpdateRegistry.php
@@ -164,7 +164,7 @@ public function getMissingUpdateList() {
// The description for an update comes from its Doxygen.
$func = new \ReflectionFunction($function);
$description = trim(str_replace(array("\n", '*', '/'), '', $func->getDocComment()), ' ');
- $ret[$module]['pending'][$update] = "$description";
+ $ret[$module]['pending'][$update] = $description;
if (!isset($ret[$module]['start'])) {
$ret[$module]['start'] = $update;
}
diff --git a/core/modules/system/src/Controller/DbUpdateController.php b/core/modules/system/src/Controller/DbUpdateController.php
index 5aac272..c5fe862 100644
--- a/core/modules/system/src/Controller/DbUpdateController.php
+++ b/core/modules/system/src/Controller/DbUpdateController.php
@@ -287,7 +287,7 @@ protected function selection(Request $request) {
'#type' => 'hidden',
'#value' => $update['start'],
);
- $build['start'][$module . '_updates'] = array(
+ $build['start'][$module . '_' . $update_type] = array(
'#theme' => 'item_list',
'#items' => $update['pending'],
'#title' => $module . ' module',
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
index 1b85098..c6281d0 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
+++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
@@ -124,6 +124,13 @@
protected $strictConfigSchema = FALSE;
/**
+ * Fail the test if there are failed updates.
+ *
+ * @var bool
+ */
+ protected $checkFailedUpdates = TRUE;
+
+ /**
* Constructs an UpdatePathTestCase object.
*
* @param $test_id
@@ -246,7 +253,9 @@ protected function runUpdates() {
$this->clickLink(t('Apply pending updates'));
// Ensure there are no failed updates.
- $this->assertNoRaw('' . t('Failed:') . '');
+ if ($this->checkFailedUpdates) {
+ $this->assertNoRaw('' . t('Failed:') . '');
+ }
// The config schema can be incorrect while the update functions are being
// executed. But once the update has been completed, it needs to be valid
diff --git a/core/modules/system/src/Tests/Update/UpdatePostUpdateFailingTest.php b/core/modules/system/src/Tests/Update/UpdatePostUpdateFailingTest.php
new file mode 100644
index 0000000..d348b8f
--- /dev/null
+++ b/core/modules/system/src/Tests/Update/UpdatePostUpdateFailingTest.php
@@ -0,0 +1,54 @@
+databaseDumpFiles = [
+ __DIR__ . '/../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
+ __DIR__ . '/../../../tests/fixtures/update/drupal-8.update-test-postupdate-failing-enabled.php',
+ ];
+ }
+
+ /**
+ * Tests hook_post_update_NAME().
+ */
+ public function testPostUpdate() {
+ // There are expected to be failed updates.
+ $this->checkFailedUpdates = FALSE;
+
+ $this->runUpdates();
+
+ // There should be no post update hooks registered as being run.
+ $this->assertIdentical([], \Drupal::state()->get('post_update_test_execution', []));
+
+ $key_value = \Drupal::keyValue('update__post_update');
+ $this->assertEqual([], $key_value->get('existing_updates'));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Check that all expected updates are displayed.
+ */
+ protected function doSelectionTest() {
+ $this->assertRaw('8001 - This update will fail.');
+ $this->assertRaw('8002 - A further update.');
+ $this->assertRaw('Should not be run since there are pending updates.');
+ }
+
+}
diff --git a/core/modules/system/tests/fixtures/update/drupal-8.update-test-postupdate-failing-enabled.php b/core/modules/system/tests/fixtures/update/drupal-8.update-test-postupdate-failing-enabled.php
new file mode 100644
index 0000000..f19a1f1
--- /dev/null
+++ b/core/modules/system/tests/fixtures/update/drupal-8.update-test-postupdate-failing-enabled.php
@@ -0,0 +1,39 @@
+merge('key_value')
+ ->condition('collection', 'system.schema')
+ ->condition('name', 'update_test_failing')
+ ->fields([
+ 'collection' => 'system.schema',
+ 'name' => 'update_test_failing',
+ 'value' => 'i:8000;',
+ ])
+ ->execute();
+
+// Update core.extension.
+$extensions = $connection->select('config')
+ ->fields('config', ['data'])
+ ->condition('collection', '')
+ ->condition('name', 'core.extension')
+ ->execute()
+ ->fetchField();
+$extensions = unserialize($extensions);
+$extensions['module']['update_test_failing'] = 8000;
+$connection->update('config')
+ ->fields([
+ 'data' => serialize($extensions),
+ ])
+ ->condition('collection', '')
+ ->condition('name', 'core.extension')
+ ->execute();
+
diff --git a/core/modules/system/tests/modules/update_test_failing/update_test_failing.info.yml b/core/modules/system/tests/modules/update_test_failing/update_test_failing.info.yml
new file mode 100644
index 0000000..f6841f3
--- /dev/null
+++ b/core/modules/system/tests/modules/update_test_failing/update_test_failing.info.yml
@@ -0,0 +1,6 @@
+name: 'Update test failing'
+type: module
+description: 'Support module for update testing when an update hook is failing.'
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/system/tests/modules/update_test_failing/update_test_failing.install b/core/modules/system/tests/modules/update_test_failing/update_test_failing.install
new file mode 100644
index 0000000..a26c7f3
--- /dev/null
+++ b/core/modules/system/tests/modules/update_test_failing/update_test_failing.install
@@ -0,0 +1,22 @@
+get('post_update_test_execution', []);
+ $execution[] = __FUNCTION__;
+ \Drupal::state()->set('post_update_test_execution', $execution);
+}