diff --git a/automatic_updates.services.yml b/automatic_updates.services.yml index e2477e68f65d9b075c659771c5fe35ed71d33cc9..98731c25627d5ecaa896a8a3e6bde78e6b289c57 100644 --- a/automatic_updates.services.yml +++ b/automatic_updates.services.yml @@ -5,6 +5,8 @@ services: automatic_updates.updater: class: Drupal\automatic_updates\Updater arguments: ['@state', '@string_translation','@package_manager.beginner', '@package_manager.stager', '@package_manager.cleaner', '@package_manager.committer', '@event_dispatcher', '@automatic_updates.path_locator'] + + # Package Manager service decorators. automatic_updates.cleaner: class: Drupal\automatic_updates\ComposerStager\Cleaner decorates: package_manager.cleaner @@ -14,6 +16,15 @@ services: - '%site.path%' - '@automatic_updates.path_locator' properties: { _serviceId: package_manager.cleaner } + automatic_updates.committer: + class: Drupal\automatic_updates\ComposerStager\Committer + decorates: package_manager.committer + public: false + arguments: + - '@automatic_updates.committer.inner' + - '@update.manager' + properties: { _serviceId: package_manager.committer } + automatic_updates.excluded_paths_subscriber: class: Drupal\automatic_updates\Event\ExcludedPathsSubscriber arguments: ['%app.root%', '%site.path%', '@file_system', '@stream_wrapper_manager'] diff --git a/src/ComposerStager/Committer.php b/src/ComposerStager/Committer.php new file mode 100644 index 0000000000000000000000000000000000000000..d8e73f928ae949e1c461af764657cd9fbf4722ef --- /dev/null +++ b/src/ComposerStager/Committer.php @@ -0,0 +1,57 @@ +<?php + +namespace Drupal\automatic_updates\ComposerStager; + +use Drupal\update\UpdateManagerInterface; +use PhpTuf\ComposerStager\Domain\CommitterInterface; +use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface; + +/** + * Defines a committer service that clears stored update data. + */ +class Committer implements CommitterInterface { + + /** + * The decorated committer service. + * + * @var \PhpTuf\ComposerStager\Domain\CommitterInterface + */ + protected $decorated; + + /** + * The update manager service. + * + * @var \Drupal\update\UpdateManagerInterface + */ + protected $updateManager; + + /** + * Constructs a Committer object. + * + * @param \PhpTuf\ComposerStager\Domain\CommitterInterface $decorated + * The decorated committer service. + * @param \Drupal\update\UpdateManagerInterface $update_manager + * The update manager service. + */ + public function __construct(CommitterInterface $decorated, UpdateManagerInterface $update_manager) { + $this->decorated = $decorated; + $this->updateManager = $update_manager; + } + + /** + * {@inheritdoc} + */ + public function commit(string $stagingDir, string $activeDir, ?array $exclusions = [], ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { + $this->decorated->commit($stagingDir, $activeDir, $exclusions, $callback, $timeout); + $this->updateManager->refreshUpdateData(); + update_storage_clear(); + } + + /** + * {@inheritdoc} + */ + public function directoryExists(string $stagingDir): bool { + return $this->decorated->directoryExists($stagingDir); + } + +} diff --git a/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml b/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml index 3f4200e4f9f8b6ec25cec6a43345053751e344d9..bf9090ff7a89b0e9380e6aef0f727cdf6b00c5e8 100644 --- a/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml +++ b/tests/modules/automatic_updates_test/automatic_updates_test.routing.yml @@ -1,7 +1,13 @@ -automatic_updates_test.update_test: +automatic_updates_test.metadata: path: '/automatic-update-test/{project_name}/{version}' defaults: _title: 'Update test' - _controller: '\Drupal\automatic_updates_test\MetadataController::updateTest' + _controller: '\Drupal\automatic_updates_test\TestController::metadata' + requirements: + _access: 'TRUE' +automatic_updates_test.update: + path: '/automatic-update-test/update/{to_version}' + defaults: + _controller: '\Drupal\automatic_updates_test\TestController::update' requirements: _access: 'TRUE' diff --git a/tests/modules/automatic_updates_test/src/MetadataController.php b/tests/modules/automatic_updates_test/src/TestController.php similarity index 59% rename from tests/modules/automatic_updates_test/src/MetadataController.php rename to tests/modules/automatic_updates_test/src/TestController.php index c00cce391a893d75347b32b67c4118b3b53613ee..7772d1f01b4bbdca5844053c41026d89b48fc5b1 100644 --- a/tests/modules/automatic_updates_test/src/MetadataController.php +++ b/tests/modules/automatic_updates_test/src/TestController.php @@ -2,11 +2,42 @@ namespace Drupal\automatic_updates_test; +use Drupal\automatic_updates\UpdateRecommender; +use Drupal\Component\Utility\Environment; use Drupal\Core\Controller\ControllerBase; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Response; -class MetadataController extends ControllerBase { +class TestController extends ControllerBase { + + /** + * Performs an in-place update to a given version of Drupal core. + * + * This executes the update immediately, in one request, without using the + * batch system or cron as wrappers. + * + * @param string $to_version + * The version of core to update to. + * + * @return array + * The renderable array of the page. + */ + public function update(string $to_version): array { + // Let it take as long as it needs. + Environment::setTimeLimit(0); + + /** @var \Drupal\automatic_updates\Updater $updater */ + $updater = \Drupal::service('automatic_updates.updater'); + $updater->begin(['drupal' => $to_version]); + $updater->stage(); + $updater->commit(); + $updater->clean(); + + $project = (new UpdateRecommender())->getProjectInfo(); + return [ + '#markup' => $project['existing_version'], + ]; + } /** * Page callback: Prints mock XML for the Update Manager module. @@ -16,7 +47,7 @@ class MetadataController extends ControllerBase { * testing automatic updates. This was done in order to use a different * directory of mock XML files. */ - public function updateTest($project_name = 'drupal', $version = NULL): Response { + public function metadata($project_name = 'drupal', $version = NULL): Response { if ($project_name !== 'drupal') { return new Response(); } diff --git a/tests/src/Build/CoreUpdateTest.php b/tests/src/Build/CoreUpdateTest.php index 3a7f02c459bcc0eaa185c5299d2d4f1eb8cdb0e2..763d554682f3c8aa26e49114adba11a356d34260 100644 --- a/tests/src/Build/CoreUpdateTest.php +++ b/tests/src/Build/CoreUpdateTest.php @@ -103,6 +103,14 @@ class CoreUpdateTest extends UpdateTestBase { ]; } + /** + * Tests an end-to-end core update via the API. + */ + public function testApi(): void { + $this->visit('/automatic-update-test/update/9.8.1'); + $this->getMink()->assertSession()->pageTextContains('9.8.1'); + } + /** * Tests an end-to-end core update via the UI. */ diff --git a/tests/src/Build/UpdateTestBase.php b/tests/src/Build/UpdateTestBase.php index a757c3d173cbcedf0e2b79157c914ad2ee97d665..e995cb804dab7341abd54f64d52b354218870cc9 100644 --- a/tests/src/Build/UpdateTestBase.php +++ b/tests/src/Build/UpdateTestBase.php @@ -83,7 +83,7 @@ abstract class UpdateTestBase extends QuickStartTestBase { * @param array $xml_map * The update XML map, as used by update_test.settings. * - * @see \Drupal\automatic_updates_test\MetadataController::updateTest() + * @see \Drupal\automatic_updates_test\TestController::metadata() */ protected function setReleaseMetadata(array $xml_map): void { $xml_map = var_export($xml_map, TRUE);