diff --git a/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php b/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php index 459ebb5f85da81f14e88364ca9fa1c0b1648129f..530544d3192ca16a9aea0939e837a5cef4a660d9 100644 --- a/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php +++ b/automatic_updates_extensions/tests/src/Functional/UpdaterFormTest.php @@ -5,6 +5,7 @@ declare(strict_types = 1); namespace Drupal\Tests\automatic_updates_extensions\Functional; use Drupal\automatic_updates_test\EventSubscriber\TestSubscriber1; +use Drupal\fixture_manipulator\ActiveFixtureManipulator; use Drupal\package_manager_test_validation\StagedDatabaseUpdateValidator; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Event\StatusCheckEvent; @@ -88,24 +89,26 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { 'access administration pages', ]); $this->activeDir = $this->container->get('package_manager.path_locator')->getProjectRoot(); - $this->addPackage($this->activeDir, [ - 'name' => 'drupal/semver_test', - 'version' => '8.1.0', - 'type' => 'drupal-module', - 'install_path' => '../../web/projects/semver_test', - ]); - $this->addPackage($this->activeDir, [ - 'name' => 'drupal/aaa_update_test', - 'version' => '2.0.0', - 'type' => 'drupal-module', - 'install_path' => '../../web/projects/aaa_update_test', - ]); - $this->addPackage($this->activeDir, [ - 'name' => 'drupal/automatic_updates_extensions_test_theme', - 'version' => '2.0.0', - 'type' => 'drupal-theme', - 'install_path' => '../../web/projects/automatic_updates_extensions_test_theme', - ]); + (new ActiveFixtureManipulator()) + ->addPackage([ + 'name' => 'drupal/semver_test', + 'version' => '8.1.0', + 'type' => 'drupal-module', + 'install_path' => '../../web/projects/semver_test', + ]) + ->addPackage([ + 'name' => 'drupal/aaa_update_test', + 'version' => '2.0.0', + 'type' => 'drupal-module', + 'install_path' => '../../web/projects/aaa_update_test', + ]) + ->addPackage([ + 'name' => 'drupal/automatic_updates_extensions_test_theme', + 'version' => '2.0.0', + 'type' => 'drupal-theme', + 'install_path' => '../../web/projects/automatic_updates_extensions_test_theme', + ]) + ->commitChanges(); $this->drupalLogin($user); $this->drupalPlaceBlock('local_tasks_block', ['primary' => TRUE]); } @@ -448,7 +451,9 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { ] ); // One module not installed through composer. - $this->removePackage($this->activeDir, 'drupal/aaa_update_test'); + (new ActiveFixtureManipulator()) + ->removePackage('drupal/aaa_update_test') + ->commitChanges(); $assert = $this->assertSession(); $user = $this->createUser( [ @@ -464,7 +469,9 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $this->assertUpdatesCount(1); // Both of the modules not installed through composer. - $this->removePackage($this->activeDir, 'drupal/semver_test'); + (new ActiveFixtureManipulator()) + ->removePackage('drupal/semver_test') + ->commitChanges(); $this->getSession()->reload(); $assert->pageTextContains('Updates were found, but they must be performed manually. See the list of available updates for more information.'); $this->assertNoUpdates(); diff --git a/package_manager/tests/fixtures/project_package_conversion/composer.json b/package_manager/tests/fixtures/project_package_conversion/composer.json deleted file mode 100644 index 0967ef424bce6791893e9a57bb952f80fd536e93..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/composer.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/package_manager/tests/fixtures/project_package_conversion/composer.lock b/package_manager/tests/fixtures/project_package_conversion/composer.lock deleted file mode 100644 index 0967ef424bce6791893e9a57bb952f80fd536e93..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/composer.lock +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/package_manager/tests/fixtures/project_package_conversion/vendor/composer/installed.json b/package_manager/tests/fixtures/project_package_conversion/vendor/composer/installed.json deleted file mode 100644 index 216c981a15b7846019cdc299051c0acae7df2d12..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/vendor/composer/installed.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "packages": [ - { - "name": "drupal/package_project_match", - "version": "6.1.3", - "type": "drupal-module" - }, - { - "name": "drupal/not_match_package", - "version": "6.1.3", - "type": "drupal-theme" - }, - { - "name": "drupal/not_match_path_project", - "version": "6.1.3", - "type": "drupal-module" - }, - { - "name": "non_drupal/other_project", - "version": "6.1.3", - "type": "drupal-module" - }, - { - "name": "drupal/nested_no_match_package", - "version": "6.1.3", - "type": "drupal-profile" - }, - { - "name": "drupal/custom_module", - "version": "6.1.3", - "type": "drupal-custom-module" - } - ] -} diff --git a/package_manager/tests/fixtures/project_package_conversion/vendor/composer/installed.php b/package_manager/tests/fixtures/project_package_conversion/vendor/composer/installed.php deleted file mode 100644 index 301eb95cf7692d55bb6af6ab3df791ad41310e2d..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/vendor/composer/installed.php +++ /dev/null @@ -1,35 +0,0 @@ -<?php - -/** - * @file - */ - -$projects_dir = __DIR__ . '/../../web/projects'; -return [ - 'versions' => [ - 'drupal/package_project_match' => [ - 'type' => 'drupal-module', - 'install_path' => $projects_dir . '/package_project_match', - ], - 'drupal/not_match_package' => [ - 'type' => 'drupal-module', - 'install_path' => $projects_dir . '/not_match_project', - ], - 'drupal/not_match_path_project' => [ - 'type' => 'drupal-module', - 'install_path' => $projects_dir . '/not_match_project', - ], - 'drupal/nested_no_match_package' => [ - 'type' => 'drupal-module', - 'install_path' => $projects_dir . '/any_folder_name', - ], - 'non_drupal/other_project' => [ - 'type' => 'drupal-module', - 'install_path' => $projects_dir . '/other_project', - ], - 'drupal/custom_module' => [ - 'type' => 'drupal-custom-module', - 'install_path' => $projects_dir . '/custom_module', - ], - ], -]; diff --git a/package_manager/tests/fixtures/project_package_conversion/web/projects/any_folder_name/any_sub_folder/any_yml_file.info.yml.hide b/package_manager/tests/fixtures/project_package_conversion/web/projects/any_folder_name/any_sub_folder/any_yml_file.info.yml.hide deleted file mode 100644 index 5b69176b90dae06ae6bbfeec53b0dbbf10a89ef9..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/web/projects/any_folder_name/any_sub_folder/any_yml_file.info.yml.hide +++ /dev/null @@ -1,3 +0,0 @@ -# A test info.yml file where the folder names and info.yml file names do not match the project or package. -# Only the project key in this file need to match. -project: nested_no_match_project diff --git a/package_manager/tests/fixtures/project_package_conversion/web/projects/custom_module/custom_module.info.yml.hide b/package_manager/tests/fixtures/project_package_conversion/web/projects/custom_module/custom_module.info.yml.hide deleted file mode 100644 index 93021a1460bf4a84d331e717483275f270d61f2a..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/web/projects/custom_module/custom_module.info.yml.hide +++ /dev/null @@ -1 +0,0 @@ -project: custom_module diff --git a/package_manager/tests/fixtures/project_package_conversion/web/projects/not_match_path_project/not_match_path_project.info.yml.hide b/package_manager/tests/fixtures/project_package_conversion/web/projects/not_match_path_project/not_match_path_project.info.yml.hide deleted file mode 100644 index af58278b9d1bbbf3ebaa06e2733953d5bb67e6f9..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/web/projects/not_match_path_project/not_match_path_project.info.yml.hide +++ /dev/null @@ -1 +0,0 @@ -project: not_match_path_project diff --git a/package_manager/tests/fixtures/project_package_conversion/web/projects/not_match_project/not_match_project.info.yml.hide b/package_manager/tests/fixtures/project_package_conversion/web/projects/not_match_project/not_match_project.info.yml.hide deleted file mode 100644 index 7838d71de598855a0af9060c8e91086b185ed7fe..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/web/projects/not_match_project/not_match_project.info.yml.hide +++ /dev/null @@ -1 +0,0 @@ -project: not_match_project diff --git a/package_manager/tests/fixtures/project_package_conversion/web/projects/other_project/other_project.info.yml.hide b/package_manager/tests/fixtures/project_package_conversion/web/projects/other_project/other_project.info.yml.hide deleted file mode 100644 index ca54a40db9f6896e27791027fef83df2bd1e6d62..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/web/projects/other_project/other_project.info.yml.hide +++ /dev/null @@ -1 +0,0 @@ -project: other_project diff --git a/package_manager/tests/fixtures/project_package_conversion/web/projects/package_project_match/packge_project_match.info.yml.hide b/package_manager/tests/fixtures/project_package_conversion/web/projects/package_project_match/packge_project_match.info.yml.hide deleted file mode 100644 index 84896e4f27f748a7e4ad23f7a8e425c08b94470c..0000000000000000000000000000000000000000 --- a/package_manager/tests/fixtures/project_package_conversion/web/projects/package_project_match/packge_project_match.info.yml.hide +++ /dev/null @@ -1 +0,0 @@ -project: package_project_match diff --git a/package_manager/tests/modules/fixture_manipulator/fixture_manipulator.info.yml b/package_manager/tests/modules/fixture_manipulator/fixture_manipulator.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..cebed1395be92c8b1667ecc818f9f21ecdf3f2a5 --- /dev/null +++ b/package_manager/tests/modules/fixture_manipulator/fixture_manipulator.info.yml @@ -0,0 +1,4 @@ +name: 'Fixture manipulator' +description: 'Manipulate fixtures for tests.' +type: module +package: Testing diff --git a/package_manager/tests/modules/fixture_manipulator/src/ActiveFixtureManipulator.php b/package_manager/tests/modules/fixture_manipulator/src/ActiveFixtureManipulator.php new file mode 100644 index 0000000000000000000000000000000000000000..24ffb6633dd2c2bef59ede3109ec6b3f45c3ec25 --- /dev/null +++ b/package_manager/tests/modules/fixture_manipulator/src/ActiveFixtureManipulator.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types = 1); + +namespace Drupal\fixture_manipulator; + +/** + * A fixture manipulator for the active directory. + */ +final class ActiveFixtureManipulator extends FixtureManipulator { + + /** + * {@inheritdoc} + */ + public function commitChanges(string $dir = NULL): void { + if ($dir) { + throw new \UnexpectedValueException("$dir cannot be specific for a ActiveFixtureManipulator instance"); + } + $dir = \Drupal::service('package_manager.path_locator')->getProjectRoot(); + parent::doCommitChanges($dir); + } + +} diff --git a/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php new file mode 100644 index 0000000000000000000000000000000000000000..18945da82640e703d75b1a651116d1fa505352e9 --- /dev/null +++ b/package_manager/tests/modules/fixture_manipulator/src/FixtureManipulator.php @@ -0,0 +1,338 @@ +<?php + +namespace Drupal\fixture_manipulator; + +use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Serialization\Yaml; +use Symfony\Component\Filesystem\Filesystem; + +/** + * It manipulates. + */ +class FixtureManipulator { + + /** + * Whether changes are currently being committed. + * + * @var bool + */ + private bool $committingChanges = FALSE; + + /** + * Arguments to manipulator functions. + * + * @var array + */ + private array $manipulatorArguments = []; + + /** + * Whether changes have been committed. + * + * @var bool + */ + protected bool $committed = FALSE; + + /** + * The fixture directory. + * + * @var string + */ + private string $dir; + + /** + * Adds a package. + * + * If $package contains an `install_path` key, it should be relative to the + * location of `installed.json` and `installed.php`, which are in + * `vendor/composer`. For example, if the package would be installed at + * `vendor/kirk/enterprise`, the install path should be `../kirk/enterprise`. + * If the package would be installed outside of vendor (for example, a Drupal + * module in the `modules` directory), it would be `../../modules/my_module`. + * + * @param array $package + * The package info that should be added to installed.json and + * installed.php. Must include the `name` and `type` keys. + * @param bool $is_dev_requirement + * Whether or not the package is a development requirement. + * @param bool $create_project + * Whether or not the project info.yml file should be created. + */ + public function addPackage(array $package, bool $is_dev_requirement = FALSE, bool $create_project = TRUE): self { + if (!$this->committingChanges) { + $this->manipulatorArguments['addPackage'][] = func_get_args(); + return $this; + } + foreach (['name', 'type'] as $required_key) { + if (!isset($package[$required_key])) { + throw new \UnexpectedValueException("The '$required_key' is required when calling ::addPackage()."); + } + } + $this->setPackage($package['name'], $package, FALSE, $is_dev_requirement); + $drupal_project_types = [ + 'drupal-module', + 'drupal-theme', + 'drupal-custom-module', + 'drupal-custom-theme', + ]; + if (!$create_project || !in_array($package['type'], $drupal_project_types, TRUE)) { + return $this; + } + if (empty($package['install_path'])) { + throw new \LogicException("'install_path' is not set."); + } + $install_path = "vendor/composer/" . $package['install_path']; + $this->addProjectAtPath($install_path); + return $this; + } + + /** + * Modifies a package's installed info. + * + * See ::addPackage() for information on how the `install_path` key is + * handled, if $package has it. + * + * @param string $name + * The name of the package to modify. + * @param array $package + * The package info that should be updated in installed.json and + * installed.php. + */ + public function modifyPackage(string $name, array $package): self { + if (!$this->committingChanges) { + $this->manipulatorArguments['modifyPackage'][] = func_get_args(); + return $this; + } + $this->setPackage($name, $package, TRUE); + return $this; + } + + /** + * Sets a package version. + * + * @param string $package_name + * The package name. + * @param string $version + * The version. + * + * @return $this + */ + public function setVersion(string $package_name, string $version): self { + return $this->modifyPackage($package_name, ['version' => $version]); + } + + /** + * Removes a package. + * + * @param string $name + * The name of the package to remove. + */ + public function removePackage(string $name): self { + if (!$this->committingChanges) { + $this->manipulatorArguments['removePackage'][] = func_get_args(); + return $this; + } + $this->setPackage($name, NULL, TRUE); + return $this; + } + + /** + * Changes a package's installation information in a particular directory. + * + * This function is internal and should not be called directly. Use + * ::addPackage(), ::modifyPackage(), and ::removePackage() instead. + * + * @param string $name + * The name of the package to add, update, or remove. + * @param array|null $package + * The package information to be set in installed.json and installed.php, or + * NULL to remove it. Will be merged into the existing information if the + * package is already installed. + * @param bool $should_exist + * Whether or not the package is expected to already be installed. + * @param bool|null $is_dev_requirement + * Whether or not the package is a developer requirement. + */ + private function setPackage(string $name, ?array $package, bool $should_exist, ?bool $is_dev_requirement = NULL): void { + if ($should_exist && isset($is_dev_requirement)) { + throw new \LogicException('Changing an existing project to a dev requirement is not supported'); + } + $composer_folder = $this->dir . '/vendor/composer'; + + $file = $composer_folder . '/installed.json'; + self::ensureFilePathIsWritable($file); + + $data = file_get_contents($file); + $data = json_decode($data, TRUE, 512, JSON_THROW_ON_ERROR); + + // If the package is already installed, find its numerical index. + $position = NULL; + for ($i = 0; $i < count($data['packages']); $i++) { + if ($data['packages'][$i]['name'] === $name) { + $position = $i; + break; + } + } + // Ensure that we actually expect to find the package already installed (or + // not). + $expected_package_message = $should_exist + ? "Expected package '$name' to be installed, but it wasn't." + : "Expected package '$name' to not be installed, but it was."; + if ($should_exist !== isset($position)) { + throw new \LogicException($expected_package_message); + } + + if ($package) { + $package = ['name' => $name] + $package; + $install_json_package = array_diff_key($package, array_flip(['install_path'])); + } + + if (isset($position)) { + // If we're going to be updating the package data, merge the incoming data + // into what we already have. + if ($package) { + $install_json_package = NestedArray::mergeDeep($data['packages'][$position], $install_json_package); + } + + // Remove the existing package; the array will be re-keyed by + // array_splice(). + array_splice($data['packages'], $position, 1); + $is_existing_dev_package = in_array($name, $data['dev-package-names'], TRUE); + $data['dev-package-names'] = array_diff($data['dev-package-names'], [$name]); + $data['dev-package-names'] = array_values($data['dev-package-names']); + } + // Add the package back to the list, if we have data for it. + if (isset($package)) { + $data['packages'][] = $install_json_package; + + if ($is_dev_requirement || !empty($is_existing_dev_package)) { + $data['dev-package-names'][] = $name; + } + } + file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + self::ensureFilePathIsWritable($file); + + $file = $composer_folder . '/installed.php'; + self::ensureFilePathIsWritable($file); + + $data = require $file; + + // Ensure that we actually expect to find the package already installed (or + // not). + if ($should_exist !== isset($data['versions'][$name])) { + throw new \LogicException($expected_package_message); + } + if ($package) { + // If an install path was provided, ensure it's relative. + if (array_key_exists('install_path', $package)) { + if (!str_starts_with($package['install_path'], '../')) { + throw new \UnexpectedValueException("'install_path' must start with '../'."); + } + } + $install_php_package = $should_exist ? + NestedArray::mergeDeep($data['versions'][$name], $package) : + $package; + + // The installation paths in $data will have been interpreted by the PHP + // runtime, so make them all relative again by stripping $this->dir out. + array_walk($data['versions'], function (array &$install_php_package) use ($composer_folder) : void { + if (array_key_exists('install_path', $install_php_package)) { + $install_php_package['install_path'] = str_replace("$composer_folder/", '', $install_php_package['install_path']); + } + }); + $data['versions'][$name] = $install_php_package; + } + else { + unset($data['versions'][$name]); + } + + $data = var_export($data, TRUE); + $data = str_replace("'install_path' => '../", "'install_path' => __DIR__ . '/../", $data); + file_put_contents($file, "<?php\nreturn $data;"); + } + + /** + * Adds a project at a path. + * + * @param string $path + * The path. + * @param string|null $project_name + * (optional) The project name. If none is specified the last part of the + * path will be used. + * @param string|null $file_name + * (optional) The file name. If none is specified the project name will be + * used. + */ + public function addProjectAtPath(string $path, ?string $project_name = NULL, ?string $file_name = NULL): self { + if (!$this->committingChanges) { + $this->manipulatorArguments['addProjectAtPath'][] = func_get_args(); + return $this; + } + $path = $this->dir . "/$path"; + if (file_exists($path)) { + throw new \LogicException("'$path' path already exists."); + } + $fs = new Filesystem(); + $fs->mkdir($path); + if ($project_name === NULL) { + $project_name = basename($path); + } + if ($file_name === NULL) { + $file_name = "$project_name.info.yml"; + } + file_put_contents("$path/$file_name", Yaml::encode(['project' => $project_name])); + return $this; + } + + /** + * Commits the changes to the directory. + */ + public function commitChanges(string $dir): void { + $this->doCommitChanges($dir); + $this->committed = TRUE; + } + + /** + * Commits all the changes. + * + * @param string $dir + * The directory to commit the changes to. + */ + protected function doCommitChanges(string $dir): void { + if ($this->committed) { + throw new \BadMethodCallException('Already committed.'); + } + $this->dir = $dir; + $this->committingChanges = TRUE; + $manipulator_arguments = $this->manipulatorArguments; + $this->manipulatorArguments = []; + foreach ($manipulator_arguments as $method => $argument_sets) { + foreach ($argument_sets as $argument_set) { + $this->{$method}(...$argument_set); + } + } + $this->committed = TRUE; + $this->committingChanges = FALSE; + } + + /** + * Ensure that changes were committed before object is destroyed. + */ + public function __destruct() { + if (!$this->committed && !empty($this->manipulatorArguments)) { + throw new \LogicException('commitChanges() must be called.'); + } + } + + /** + * Ensures a path is writable. + * + * @param string $path + * The path. + */ + private static function ensureFilePathIsWritable(string $path): void { + if (!is_writable($path)) { + throw new \LogicException("'$path' is not writable."); + } + } + +} diff --git a/package_manager/tests/modules/fixture_manipulator/src/StageFixtureManipulator.php b/package_manager/tests/modules/fixture_manipulator/src/StageFixtureManipulator.php new file mode 100644 index 0000000000000000000000000000000000000000..e6cf9b43a2f1f252816bec30ad1cebe7c80fd07b --- /dev/null +++ b/package_manager/tests/modules/fixture_manipulator/src/StageFixtureManipulator.php @@ -0,0 +1,52 @@ +<?php + +declare(strict_types = 1); + +namespace Drupal\fixture_manipulator; + +use Drupal\package_manager_bypass\Beginner; + +/** + * A fixture manipulator for the stage directory. + */ +final class StageFixtureManipulator extends FixtureManipulator { + + /** + * Whether the fixture is ready to commit. + * + * @var bool + */ + private $ready = FALSE; + + /** + * {@inheritdoc} + */ + public function commitChanges(string $dir = NULL): void { + if (!$this->ready) { + throw new \LogicException("::setReadyToCommit must be called before ::commitChanges"); + } + if (!$dir) { + throw new \UnexpectedValueException("$dir must be specific for a StageFixtureManipulator"); + } + parent::doCommitChanges($dir); + $this->committed = TRUE; + } + + /** + * Sets the manipulator as ready to commit. + */ + public function setReadyToCommit(): void { + $this->ready = TRUE; + Beginner::setStageManipulator($this); + } + + /** + * {@inheritdoc} + */ + public function __destruct() { + if (!$this->ready) { + throw new \LogicException('This fixture manipulator was not yet ready to commit! Please call setReadyToCommit() to signal all necessary changes are queued.'); + } + } + +} diff --git a/package_manager/tests/modules/package_manager_bypass/package_manager_bypass.info.yml b/package_manager/tests/modules/package_manager_bypass/package_manager_bypass.info.yml index 95cc7e66e364b1f024571edb3c5e793d728fc5c8..b2731f7e944941af86eacf65e6cd89be7b7e0db0 100644 --- a/package_manager/tests/modules/package_manager_bypass/package_manager_bypass.info.yml +++ b/package_manager/tests/modules/package_manager_bypass/package_manager_bypass.info.yml @@ -4,3 +4,4 @@ type: module package: Testing dependencies: - automatic_updates:package_manager + - automatic_updates:fixture_manipulator diff --git a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php index 57775bf1bec7f042cc7e3ba9447a76a603f8d877..7b4bea26adb156aa12d0d8c372798882d7f827c7 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php +++ b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php @@ -4,6 +4,7 @@ declare(strict_types = 1); namespace Drupal\package_manager_bypass; +use Drupal\fixture_manipulator\StageFixtureManipulator; use PhpTuf\ComposerStager\Domain\Core\Beginner\BeginnerInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessOutputCallback\ProcessOutputCallbackInterface; use PhpTuf\ComposerStager\Domain\Service\ProcessRunner\ProcessRunnerInterface; @@ -21,6 +22,22 @@ class Beginner extends BypassedStagerServiceBase implements BeginnerInterface { public function begin(PathInterface $activeDir, PathInterface $stagingDir, ?PathListInterface $exclusions = NULL, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = ProcessRunnerInterface::DEFAULT_TIMEOUT): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions, $timeout); $this->copyFixtureFilesTo($stagingDir); + + /** @var \Drupal\fixture_manipulator\StageFixtureManipulator|null $stageManipulator */ + $stageManipulator = $this->state->get(__CLASS__ . '-stage-manipulator', NULL); + if ($stageManipulator) { + $stageManipulator->commitChanges($stagingDir->resolve()); + } + } + + /** + * Sets the manipulator for the stage. + * + * @param \Drupal\fixture_manipulator\StageFixtureManipulator $manipulator + * The manipulator. + */ + public static function setStageManipulator(StageFixtureManipulator $manipulator): void { + \Drupal::state()->set(__CLASS__ . '-stage-manipulator', $manipulator); } } diff --git a/package_manager/tests/src/Kernel/ComposerUtilityTest.php b/package_manager/tests/src/Kernel/ComposerUtilityTest.php index dbb649817bb12a3d184f6c4c482f0944a6f413b6..98906327540e25fa558c89c411b3081d3145325b 100644 --- a/package_manager/tests/src/Kernel/ComposerUtilityTest.php +++ b/package_manager/tests/src/Kernel/ComposerUtilityTest.php @@ -4,6 +4,7 @@ declare(strict_types = 1); namespace Drupal\Tests\package_manager\Kernel; +use Drupal\fixture_manipulator\FixtureManipulator; use Drupal\KernelTests\KernelTestBase; use Drupal\package_manager\ComposerUtility; use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; @@ -31,7 +32,61 @@ class ComposerUtilityTest extends KernelTestBase { $fixture = vfsStream::newDirectory('fixture'); $this->vfsRoot->addChild($fixture); - static::copyFixtureFilesTo(__DIR__ . '/../../fixtures/project_package_conversion', $fixture->url()); + static::copyFixtureFilesTo(__DIR__ . '/../../fixtures/fake_site', $fixture->url()); + $relative_projects_dir = '../../web/projects'; + (new FixtureManipulator()) + ->addPackage( + [ + 'name' => 'drupal/package_project_match', + 'type' => 'drupal-module', + 'install_path' => "$relative_projects_dir/package_project_match", + ] + ) + ->addPackage( + [ + 'name' => 'drupal/not_match_package', + 'type' => 'drupal-module', + 'install_path' => "$relative_projects_dir/not_match_project", + ] + ) + ->addPackage( + [ + 'name' => 'drupal/not_match_path_project', + 'type' => 'drupal-module', + 'install_path' => "$relative_projects_dir/not_match_project", + ], + FALSE, + FALSE, + ) + ->addProjectAtPath("web/projects/not_match_path_project", 'not_match_path_project') + ->addPackage( + [ + 'name' => 'drupal/nested_no_match_package', + 'type' => 'drupal-module', + 'install_path' => "$relative_projects_dir/any_folder_name", + ], + FALSE, + FALSE, + ) + ->addPackage( + [ + 'name' => 'non_drupal/other_project', + 'type' => 'drupal-module', + 'install_path' => "$relative_projects_dir/other_project", + ] + ) + ->addPackage( + [ + 'name' => 'drupal/custom_module', + 'type' => 'drupal-custom-module', + 'install_path' => "$relative_projects_dir/custom_module", + ] + ) + // A test info.yml file where the folder names and info.yml file names do + // not match the project or package. Only the project key in this file + // need to match. + ->addProjectAtPath("web/projects/any_folder_name/any_sub_folder", 'nested_no_match_project', 'any_yml_file.info.yml') + ->commitChanges($fixture->url()); } /** diff --git a/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php b/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php index b5501c7fcc9a9a881484a376b33a203ce8510ab7..61dd008d5bc8941857600b628899a6bf38d5c916 100644 --- a/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php +++ b/package_manager/tests/src/Kernel/FakeSiteFixtureTest.php @@ -4,6 +4,7 @@ declare(strict_types = 1); namespace Drupal\Tests\package_manager\Kernel; +use Drupal\fixture_manipulator\ActiveFixtureManipulator; use Drupal\package_manager\ComposerUtility; /** @@ -43,40 +44,35 @@ class FakeSiteFixtureTest extends PackageManagerKernelTestBase { /** * Tests if `modifyPackage` can be called on all packages in the fixture. * - * @see \Drupal\Tests\package_manager\Traits\FixtureUtilityTrait::modifyPackage() + * @see \Drupal\fixture_manipulator\FixtureManipulator::modifyPackage() */ public function testCallToModifyPackage(): void { - $project_root = $this->container->get('package_manager.path_locator')->getProjectRoot(); $stage = $this->createStage(); $installed_packages = $stage->getActiveComposer()->getInstalledPackages(); foreach (self::getExpectedFakeSitePackages() as $package_name) { $this->assertArrayHasKey($package_name, $installed_packages); $this->assertSame('9.8.0', $installed_packages[$package_name]->getPrettyVersion()); - $this->modifyPackage( - $project_root, - $package_name, - ['version' => '11.1.0'] - ); + (new ActiveFixtureManipulator()) + ->modifyPackage($package_name, ['version' => '11.1.0']) + ->commitChanges(); } } /** * Tests if `removePackage` can be called on all packages in the fixture. * - * @covers \Drupal\Tests\package_manager\Traits\FixtureUtilityTrait::removePackage() + * @covers \Drupal\fixture_manipulator\FixtureManipulator::removePackage() */ public function testCallToRemovePackage(): void { $expected_packages = self::getExpectedFakeSitePackages(); - $project_root = $this->container->get('package_manager.path_locator')->getProjectRoot(); $stage = $this->createStage(); $actual_packages = array_keys($stage->getActiveComposer()->getInstalledPackages()); sort($actual_packages); $this->assertSame($expected_packages, $actual_packages); foreach (self::getExpectedFakeSitePackages() as $package_name) { - $this->removePackage( - $project_root, - $package_name, - ); + (new ActiveFixtureManipulator()) + ->removePackage($package_name) + ->commitChanges(); } } diff --git a/package_manager/tests/src/Kernel/FixtureUtilityTraitTest.php b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php similarity index 60% rename from package_manager/tests/src/Kernel/FixtureUtilityTraitTest.php rename to package_manager/tests/src/Kernel/FixtureManipulatorTest.php index 1d60428024d837f99bdebc0e4de6c7c681e57b70..14e520a6b1e4dd620f40e440e9ded8fd96c0684a 100644 --- a/package_manager/tests/src/Kernel/FixtureUtilityTraitTest.php +++ b/package_manager/tests/src/Kernel/FixtureManipulatorTest.php @@ -4,18 +4,17 @@ declare(strict_types = 1); namespace Drupal\Tests\package_manager\Kernel; -use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; -use PHPUnit\Framework\AssertionFailedError; +use Drupal\fixture_manipulator\ActiveFixtureManipulator; +use Drupal\fixture_manipulator\FixtureManipulator; +use Drupal\fixture_manipulator\StageFixtureManipulator; use Symfony\Component\Filesystem\Filesystem; /** - * @coversDefaultClass \Drupal\Tests\package_manager\Traits\FixtureUtilityTrait + * @coversDefaultClass \Drupal\fixture_manipulator\FixtureManipulator + * * @group package_manager - * @internal */ -class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { - - use FixtureUtilityTrait; +class FixtureManipulatorTest extends PackageManagerKernelTestBase { /** * The root directory of the virtual project. @@ -24,6 +23,29 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { */ private string $dir; + /** + * The existing packages in the fixture. + * + * @var \string[][] + */ + private array $existingCorePackages = [ + 'drupal/core' => [ + 'name' => 'drupal/core', + 'version' => '9.8.0', + 'type' => 'drupal-core', + ], + 'drupal/core-recommended' => [ + 'name' => 'drupal/core-recommended', + 'version' => '9.8.0', + 'type' => 'drupal-core', + ], + 'drupal/core-dev' => [ + 'name' => 'drupal/core-dev', + 'version' => '9.8.0', + 'type' => 'drupal-core', + ], + ]; + /** * {@inheritdoc} */ @@ -33,18 +55,22 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { $this->dir = $this->container->get('package_manager.path_locator') ->getProjectRoot(); - $this->addPackage($this->dir, [ - 'name' => 'my/package', - 'type' => 'library', - ]); - $this->addPackage($this->dir, [ - 'name' => 'my/dev-package', - 'version' => '2.1.0', - 'type' => 'library', - 'install_path' => '../relative/path', - ], - TRUE, - ); + $manipulator = new ActiveFixtureManipulator(); + $manipulator + ->addPackage([ + 'name' => 'my/package', + 'type' => 'library', + ]) + ->addPackage( + [ + 'name' => 'my/dev-package', + 'version' => '2.1.0', + 'type' => 'library', + 'install_path' => '../relative/path', + ], + TRUE + ) + ->commitChanges(); } /** @@ -52,47 +78,54 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { */ public function testAddPackage(): void { // Packages cannot be added without a name. - try { - $this->addPackage($this->dir, ['type' => 'unknown']); - $this->fail('Adding an anonymous package should raise an error.'); - } - catch (AssertionFailedError $e) { - $this->assertSame("Failed asserting that an array has the key 'name'.", $e->getMessage()); - } - - // Packages cannot be added without a type. - try { - $this->addPackage($this->dir, ['name' => 'unknown']); - $this->fail('Adding an package without a type should raise an error.'); - } - catch (AssertionFailedError $e) { - $this->assertSame("Failed asserting that an array has the key 'type'.", $e->getMessage()); + foreach (['name', 'type'] as $require_key) { + // Make a package that is missing the required key. + $package = array_diff_key( + [ + 'name' => 'Any old name', + 'type' => 'Any old type', + ], + [$require_key => ''] + ); + try { + $manipulator = new ActiveFixtureManipulator(); + $manipulator->addPackage($package) + ->commitChanges(); + $this->fail("Adding a package without the '$require_key' should raise an error."); + } + catch (\UnexpectedValueException $e) { + $this->assertSame("The '$require_key' is required when calling ::addPackage().", $e->getMessage()); + } } // We should not be able to add an existing package. try { - $this->addPackage($this->dir, [ + $manipulator = new ActiveFixtureManipulator(); + $manipulator->addPackage([ 'name' => 'my/package', 'type' => 'library', - ]); + ]) + ->commitChanges(); $this->fail('Trying to add an existing package should raise an error.'); } - catch (AssertionFailedError $e) { + catch (\LogicException $e) { $this->assertStringContainsString("Expected package 'my/package' to not be installed, but it was.", $e->getMessage()); } // We should not be able to add a package with an absolute installation // path. try { - $this->addPackage($this->dir, [ - 'name' => 'absolute/path', - 'install_path' => '/absolute/path', - 'type' => 'library', - ]); + (new ActiveFixtureManipulator()) + ->addPackage([ + 'name' => 'absolute/path', + 'install_path' => '/absolute/path', + 'type' => 'library', + ]) + ->commitChanges(); $this->fail('Add package should have failed.'); } - catch (AssertionFailedError $e) { - $this->assertSame('Failed asserting that \'/absolute/path\' starts with "../".', $e->getMessage()); + catch (\UnexpectedValueException $e) { + $this->assertSame("'install_path' must start with '../'.", $e->getMessage()); } $installed_json_expected_packages = [ @@ -116,23 +149,7 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { // have been prefixed with the __DIR__ constant, which should be interpreted // when installed.php is loaded by the PHP runtime. $installed_php_expected_packages['my/dev-package']['install_path'] = "$this->dir/vendor/composer/../relative/path"; - $installed_php_expected_packages = [ - 'drupal/core' => [ - 'name' => 'drupal/core', - 'version' => '9.8.0', - 'type' => 'drupal-core', - ], - 'drupal/core-recommended' => [ - 'name' => 'drupal/core-recommended', - 'version' => '9.8.0', - 'type' => 'drupal-core', - ], - 'drupal/core-dev' => [ - 'name' => 'drupal/core-dev', - 'version' => '9.8.0', - 'type' => 'drupal-core', - ], - ] + $installed_php_expected_packages; + $installed_php_expected_packages = $this->existingCorePackages + $installed_php_expected_packages; $this->assertSame($installed_php_expected_packages, $installed_php); } @@ -151,11 +168,9 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { }; $original_installed_json = $decode_installed_json(); $this->assertIsArray($original_installed_json); - $this->modifyPackage( - $temp_fixture, - 'the-org/the-package', - ['install_path' => '../../a_new_path'], - ); + (new FixtureManipulator()) + ->modifyPackage('the-org/the-package', ['install_path' => '../../a_new_path']) + ->commitChanges($temp_fixture); $this->assertSame($original_installed_json, $decode_installed_json()); // Assert that ::modifyPackage() throws an error if a package exists in the @@ -166,35 +181,37 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { $temp_fixture = $this->siteDirectory . $this->randomMachineName('42'); $fs->mirror($existing_incorrect_fixture, $temp_fixture); try { - $this->modifyPackage( - $temp_fixture, - 'the-org/the-package', - ['install_path' => '../../a_new_path'], - ); + (new FixtureManipulator()) + ->modifyPackage('the-org/the-package', ['install_path' => '../../a_new_path']) + ->commitChanges($temp_fixture); $this->fail('Modifying a non-existent package should raise an error.'); } - catch (AssertionFailedError $e) { - $this->assertStringContainsString("Failed asserting that an array has the key 'the-org/the-package'.", $e->getMessage()); + catch (\LogicException $e) { + $this->assertSame("Expected package 'the-org/the-package' to be installed, but it wasn't.", $e->getMessage()); } // We should not be able to modify a non-existent package. try { - $this->modifyPackage($this->dir, 'junk/drawer', ['type' => 'library']); + (new ActiveFixtureManipulator()) + ->modifyPackage('junk/drawer', ['type' => 'library']) + ->commitChanges(); $this->fail('Modifying a non-existent package should raise an error.'); } - catch (AssertionFailedError $e) { + catch (\LogicException $e) { $this->assertStringContainsString("Expected package 'junk/drawer' to be installed, but it wasn't.", $e->getMessage()); } - // Add a key to an existing package. - $this->modifyPackage($this->dir, 'my/package', ['type' => 'metapackage']); - // Change a key in an existing package. - $this->modifyPackage($this->dir, 'my/dev-package', ['version' => '3.2.1']); - // Move an existing package to dev requirements. - $this->addPackage($this->dir, [ - 'name' => 'my/other-package', - 'type' => 'library', - ]); + (new ActiveFixtureManipulator()) + // Add a key to an existing package. + ->modifyPackage('my/package', ['type' => 'metapackage']) + // Change a key in an existing package. + ->setVersion('my/dev-package', '3.2.1') + // Move an existing package to dev requirements. + ->addPackage([ + 'name' => 'my/other-package', + 'type' => 'library', + ]) + ->commitChanges(); $install_json_expected_packages = [ 'my/package' => [ @@ -219,23 +236,7 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { $this->assertContains('my/dev-package', $installed_json['dev-package-names']); $this->assertNotContains('my/other-package', $installed_json['dev-package-names']); $this->assertNotContains('my/package', $installed_json['dev-package-names']); - $installed_php_expected_packages = [ - 'drupal/core' => [ - 'name' => 'drupal/core', - 'version' => '9.8.0', - 'type' => 'drupal-core', - ], - 'drupal/core-recommended' => [ - 'name' => 'drupal/core-recommended', - 'version' => '9.8.0', - 'type' => 'drupal-core', - ], - 'drupal/core-dev' => [ - 'name' => 'drupal/core-dev', - 'version' => '9.8.0', - 'type' => 'drupal-core', - ], - ] + $installed_php_expected_packages; + $installed_php_expected_packages = $this->existingCorePackages + $installed_php_expected_packages; // @see ::testAddPackage() $this->assertSame($installed_php_expected_packages, $installed_php); } @@ -246,15 +247,19 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { public function testRemovePackage(): void { // We should not be able to remove a package that's not installed. try { - $this->removePackage($this->dir, 'junk/drawer'); + (new ActiveFixtureManipulator()) + ->removePackage('junk/drawer') + ->commitChanges(); $this->fail('Removing a non-existent package should raise an error.'); } - catch (AssertionFailedError $e) { + catch (\LogicException $e) { $this->assertStringContainsString("Expected package 'junk/drawer' to be installed, but it wasn't.", $e->getMessage()); } - $this->removePackage($this->dir, 'my/package'); - $this->removePackage($this->dir, 'my/dev-package'); + (new ActiveFixtureManipulator()) + ->removePackage('my/package') + ->removePackage('my/dev-package') + ->commitChanges(); foreach (['json', 'php'] as $extension) { $file = "$this->dir/vendor/composer/installed.$extension"; @@ -289,4 +294,24 @@ class FixtureUtilityTraitTest extends PackageManagerKernelTestBase { ]; } + /** + * Test that an exception is thrown if ::commitChanges() is not called. + */ + public function testNoCommitError(): void { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('commitChanges() must be called.'); + (new ActiveFixtureManipulator()) + ->setVersion('drupal/core', '1.2.3'); + } + + /** + * Test that no exception is thrown if ::setReadyToCommit() is called. + */ + public function testNoCommitExpected(): void { + $manipulator = new StageFixtureManipulator(); + $manipulator->setVersion('drupal/core', '1.2.3'); + $manipulator->setReadyToCommit(); + $this->assertTrue(TRUE); + } + } diff --git a/package_manager/tests/src/Kernel/OverwriteExistingPackagesValidatorTest.php b/package_manager/tests/src/Kernel/OverwriteExistingPackagesValidatorTest.php index 0a985ee7dc22f0faa3ddb21901c9a79b5808437e..89e8b49cdf6f52b0776f432859ba4d4143251d60 100644 --- a/package_manager/tests/src/Kernel/OverwriteExistingPackagesValidatorTest.php +++ b/package_manager/tests/src/Kernel/OverwriteExistingPackagesValidatorTest.php @@ -4,7 +4,9 @@ declare(strict_types = 1); namespace Drupal\Tests\package_manager\Kernel; -use Drupal\package_manager\Exception\StageValidationException; +use Drupal\fixture_manipulator\ActiveFixtureManipulator; +use Drupal\fixture_manipulator\StageFixtureManipulator; +use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\ValidationResult; use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; @@ -36,43 +38,40 @@ class OverwriteExistingPackagesValidatorTest extends PackageManagerKernelTestBas * by the 'package_manager_bypass' module. */ public function testNewPackagesOverwriteExisting(): void { - $active_dir = $this->container->get('package_manager.path_locator')->getProjectRoot(); - $modules_dir = "$active_dir/modules"; - $this->addProjectAtPath("$modules_dir/module_1"); - $this->addProjectAtPath("$modules_dir/module_2"); - $this->addProjectAtPath("$modules_dir/module_5"); - $stage = $this->createStage(); - $stage->create(); - $stage_dir = $stage->getStageDirectory(); + (new ActiveFixtureManipulator()) + ->addProjectAtPath('modules/module_1') + ->addProjectAtPath('modules/module_2') + ->addProjectAtPath('modules/module_5') + ->commitChanges(); + $stage_manipulator = new StageFixtureManipulator(); // module_1 and module_2 will raise errors because they would overwrite // non-Composer managed paths in the active directory. - $this->addPackage( - $stage_dir, - [ - 'name' => 'drupal/module_1', - 'version' => '1.3.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/module_1', - ], - FALSE, - FALSE - ); - $this->addPackage( - $stage_dir, - [ - 'name' => 'drupal/module_2', - 'version' => '1.3.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/module_2', - ], - FALSE, - FALSE - ); + $stage_manipulator + ->addPackage( + [ + 'name' => 'drupal/module_1', + 'version' => '1.3.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/module_1', + ], + FALSE, + FALSE + ) + ->addPackage( + [ + 'name' => 'drupal/module_2', + 'version' => '1.3.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/module_2', + ], + FALSE, + FALSE + ); // module_3 will cause no problems, since it doesn't exist in the active // directory at all. - $this->addPackage($stage_dir, [ + $stage_manipulator->addPackage([ 'name' => 'drupal/module_3', 'version' => '1.3.0', 'type' => 'drupal-module', @@ -82,8 +81,7 @@ class OverwriteExistingPackagesValidatorTest extends PackageManagerKernelTestBas // module_4 doesn't exist in the active directory but the 'install_path' as // known to Composer in the staged directory collides with module_1 in the // active directory which will cause an error. - $this->addPackage( - $stage_dir, + $stage_manipulator->addPackage( [ 'name' => 'drupal/module_4', 'version' => '1.3.0', @@ -97,7 +95,7 @@ class OverwriteExistingPackagesValidatorTest extends PackageManagerKernelTestBas // module_5_different_path will not cause a problem, even though its package // name is drupal/module_5, because its project name and path in the staging // area differ from the active directory. - $this->addPackage($stage_dir, [ + $stage_manipulator->addPackage([ 'name' => 'drupal/module_5', 'version' => '1.3.0', 'type' => 'drupal-module', @@ -106,11 +104,12 @@ class OverwriteExistingPackagesValidatorTest extends PackageManagerKernelTestBas // Add a package without an install_path set which will not raise an error. // The most common example of this in the Drupal ecosystem is a submodule. - $this->addPackage($stage_dir, [ + $stage_manipulator->addPackage([ 'name' => 'drupal/sub-module', 'version' => '1.3.0', 'type' => 'metapackage', ]); + $stage_manipulator->setReadyToCommit(); $expected_results = [ ValidationResult::createError([ @@ -123,17 +122,7 @@ class OverwriteExistingPackagesValidatorTest extends PackageManagerKernelTestBas 'The new package drupal/module_4 will be installed in the directory /vendor/composer/../../modules/module_1, which already exists but is not managed by Composer.', ]), ]; - - $stage->require(['drupal/core:9.8.1']); - try { - $stage->apply(); - // If no exception occurs, ensure we weren't expecting any errors. - $this->assertValidationResultsEqual($expected_results, []); - } - catch (StageValidationException $e) { - $this->assertNotEmpty($expected_results); - $this->assertValidationResultsEqual($expected_results, $e->getResults()); - } + $this->assertResults($expected_results, PreApplyEvent::class); } } diff --git a/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php b/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php index e3b18480cd19a7da510b63f25cb6a50b53babe6b..7d064d773c58c6c987b534dc6a318247cbeed27b 100644 --- a/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php +++ b/package_manager/tests/src/Kernel/PackageManagerKernelTestBase.php @@ -57,6 +57,7 @@ abstract class PackageManagerKernelTestBase extends KernelTestBase { * {@inheritdoc} */ protected static $modules = [ + 'fixture_manipulator', 'package_manager', 'package_manager_bypass', 'system', diff --git a/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php b/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php index cd08c843544a3396e268b8181093719923dea3eb..4a67afb4c10cac5bcc61dc0215be2e99cd320bbe 100644 --- a/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php +++ b/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php @@ -4,6 +4,8 @@ declare(strict_types = 1); namespace Drupal\Tests\package_manager\Kernel; +use Drupal\fixture_manipulator\ActiveFixtureManipulator; +use Drupal\fixture_manipulator\StageFixtureManipulator; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\ValidationResult; use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; @@ -22,38 +24,37 @@ class SupportedReleaseValidatorTest extends PackageManagerKernelTestBase { */ protected function setUp(): void { parent::setUp(); - - $active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - $this->addPackage($active_dir, [ - 'name' => "drupal/dependency", - 'version' => '9.8.0', - 'type' => 'drupal-library', - ]); - $this->addPackage($active_dir, [ - 'name' => "drupal/semver_test", - 'version' => '8.1.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/semver_test', - ]); - $this->addPackage($active_dir, [ - 'name' => "drupal/aaa_update_test", - 'version' => '2.0.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/aaa_update_test', - ]); - $this->addPackage($active_dir, [ - 'name' => "drupal/package_manager_theme", - 'version' => '8.1.0', - 'type' => 'drupal-theme', - 'install_path' => '../../modules/package_manager_theme', - ]); - $this->addPackage($active_dir, [ - 'name' => "somewhere/a_drupal_module", - 'version' => '8.1.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/a_drupal_module', - ]); + (new ActiveFixtureManipulator()) + ->addPackage([ + 'name' => "drupal/dependency", + 'version' => '9.8.0', + 'type' => 'drupal-library', + ]) + ->addPackage([ + 'name' => "drupal/semver_test", + 'version' => '8.1.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/semver_test', + ]) + ->addPackage([ + 'name' => "drupal/aaa_update_test", + 'version' => '2.0.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/aaa_update_test', + ]) + ->addPackage([ + 'name' => "drupal/package_manager_theme", + 'version' => '8.1.0', + 'type' => 'drupal-theme', + 'install_path' => '../../modules/package_manager_theme', + ]) + ->addPackage([ + 'name' => "somewhere/a_drupal_module", + 'version' => '8.1.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/a_drupal_module', + ]) + ->commitChanges(); } /** @@ -63,7 +64,6 @@ class SupportedReleaseValidatorTest extends PackageManagerKernelTestBase { * The test cases. */ public function providerException(): array { - $fixtures_folder = __DIR__ . '/../../fixtures/supported_release_validator'; $release_fixture_folder = __DIR__ . '/../../fixtures/release-history'; $summary = t('Cannot update because the following project version is not in the list of installable releases.'); return [ @@ -213,28 +213,18 @@ class SupportedReleaseValidatorTest extends PackageManagerKernelTestBase { public function testException(array $release_metadata, bool $project_in_active, array $package, array $expected_results): void { $this->setReleaseMetadata(['drupal' => __DIR__ . '/../../fixtures/release-history/drupal.9.8.2.xml'] + $release_metadata); - $listener = function (PreApplyEvent $event) use ($project_in_active, $package, $expected_results): void { - - $stage_dir = $event->getStage()->getStageDirectory(); - // @todo add test coverage for packages that don't start with 'drupal/' in - // https://www.drupal.org/node/3321386. - if (!$project_in_active) { - $this->addPackage($stage_dir, $package); - } - else { - $this->modifyPackage($stage_dir, $package['name'], [ - 'version' => $package['version'], - ]); - } - // We always update this module to prove that the validator will skip this - // module as it's of type 'drupal-library'. - // @see \Drupal\package_manager\Validator\SupportedReleaseValidator::checkStagedReleases() - $this->modifyPackage($stage_dir, "drupal/dependency", [ - 'version' => '9.8.1', - ]); - }; - $this->container->get('event_dispatcher') - ->addListener(PreApplyEvent::class, $listener, PHP_INT_MAX); + $stage_manipulator = new StageFixtureManipulator(); + if ($project_in_active) { + $stage_manipulator->setVersion($package['name'], $package['version']); + } + else { + $stage_manipulator->addPackage($package); + } + // We always update this module to prove that the validator will skip this + // module as it's of type 'drupal-library'. + // @see \Drupal\package_manager\Validator\SupportedReleaseValidator::checkStagedReleases() + $stage_manipulator->setVersion('drupal/dependency', '9.8.1'); + $stage_manipulator->setReadyToCommit(); $this->assertResults($expected_results, PreApplyEvent::class); } diff --git a/package_manager/tests/src/Traits/FixtureUtilityTrait.php b/package_manager/tests/src/Traits/FixtureUtilityTrait.php index a780c6c339e74d0b14c8cce5e062967e4867e43f..2764935bb4e7f5a01af6c61fdbb6e181a384f418 100644 --- a/package_manager/tests/src/Traits/FixtureUtilityTrait.php +++ b/package_manager/tests/src/Traits/FixtureUtilityTrait.php @@ -4,8 +4,6 @@ declare(strict_types = 1); namespace Drupal\Tests\package_manager\Traits; -use Drupal\Component\Utility\NestedArray; -use Drupal\Core\Serialization\Yaml; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator; @@ -82,212 +80,4 @@ trait FixtureUtilityTrait { } } - /** - * Adds a package. - * - * If $package contains an `install_path` key, it should be relative to the - * location of `installed.json` and `installed.php`, which are in - * `vendor/composer`. For example, if the package would be installed at - * `vendor/kirk/enterprise`, the install path should be `../kirk/enterprise`. - * If the package would be installed outside of vendor (for example, a Drupal - * module in the `modules` directory), it would be `../../modules/my_module`. - * - * @param string $dir - * The root Composer-managed directory (e.g., the project root or staging - * area). - * @param array $package - * The package info that should be added to installed.json and - * installed.php. Must include the `name` and `type` keys. - * @param bool $is_dev_requirement - * Whether or not the package is a development requirement. - * @param bool $create_project - * Whether or not the project info.yml file should be created. - */ - protected function addPackage(string $dir, array $package, bool $is_dev_requirement = FALSE, bool $create_project = TRUE): void { - foreach (['name', 'type'] as $required_key) { - $this->assertArrayHasKey($required_key, $package); - } - $this->setPackage($dir, $package['name'], $package, FALSE, $is_dev_requirement); - $drupal_project_types = [ - 'drupal-module', - 'drupal-theme', - 'drupal-custom-module', - 'drupal-custom-theme', - ]; - if (!$create_project || !in_array($package['type'], $drupal_project_types, TRUE)) { - return; - } - $this->assertNotEmpty($package['install_path']); - $install_path = "$dir/vendor/composer/" . $package['install_path']; - $this->addProjectAtPath($install_path); - } - - /** - * Adds a project at a path. - * - * @param string $path - * The path. - * @param string|null $project_name - * (optional) The project name. If known is specified the last part of the - * path will be used. - * - * @todo Move to FixtureManipulator in https://www.drupal.org/i/3322913. - */ - protected function addProjectAtPath(string $path, ?string $project_name = NULL): void { - $fs = new Filesystem(); - $this->assertDirectoryDoesNotExist($path); - $fs->mkdir($path); - if ($project_name === NULL) { - $path_parts = explode('/', $path); - $project_name = array_pop($path_parts); - } - file_put_contents("$path/$project_name.info.yml", Yaml::encode(['project' => $project_name])); - } - - /** - * Modifies a package's installed info. - * - * See ::addPackage() for information on how the `install_path` key is - * handled, if $package has it. - * - * @param string $dir - * The root Composer-managed directory (e.g., the project root or staging - * area). - * @param string $name - * The name of the package to modify. - * @param array $package - * The package info that should be updated in installed.json and - * installed.php. - */ - protected function modifyPackage(string $dir, string $name, array $package): void { - $this->setPackage($dir, $name, $package, TRUE); - } - - /** - * Removes a package. - * - * @param string $dir - * The root Composer-managed directory (e.g., the project root or staging - * area). - * @param string $name - * The name of the package to remove. - */ - protected function removePackage(string $dir, string $name): void { - $this->setPackage($dir, $name, NULL, TRUE); - } - - /** - * Changes a package's installation information in a particular directory. - * - * This function is internal and should not be called directly. Use - * ::addPackage(), ::modifyPackage(), and ::removePackage() instead. - * - * @param string $dir - * The root Composer-managed directory (e.g., the project root or staging - * area). - * @param string $name - * The name of the package to add, update, or remove. - * @param array|null $package - * The package information to be set in installed.json and installed.php, or - * NULL to remove it. Will be merged into the existing information if the - * package is already installed. - * @param bool $should_exist - * Whether or not the package is expected to already be installed. - * @param bool|null $is_dev_requirement - * Whether or not the package is a developer requirement. - */ - private function setPackage(string $dir, string $name, ?array $package, bool $should_exist, ?bool $is_dev_requirement = NULL): void { - $this->assertNotTrue($should_exist && isset($is_dev_requirement), 'Changing an existing project to a dev requirement is not supported'); - $dir .= '/vendor/composer'; - - $file = $dir . '/installed.json'; - $this->assertFileIsWritable($file); - - $data = file_get_contents($file); - $data = json_decode($data, TRUE, 512, JSON_THROW_ON_ERROR); - - // If the package is already installed, find its numerical index. - $position = NULL; - for ($i = 0; $i < count($data['packages']); $i++) { - if ($data['packages'][$i]['name'] === $name) { - $position = $i; - break; - } - } - // Ensure that we actually expect to find the package already installed (or - // not). - $message = $should_exist - ? "Expected package '$name' to be installed, but it wasn't." - : "Expected package '$name' to not be installed, but it was."; - $this->assertSame($should_exist, isset($position), $message); - - if ($package) { - $package = ['name' => $name] + $package; - $install_json_package = array_diff_key($package, array_flip(['install_path'])); - } - - if (isset($position)) { - // If we're going to be updating the package data, merge the incoming data - // into what we already have. - if ($package) { - $install_json_package = NestedArray::mergeDeep($data['packages'][$position], $install_json_package); - } - - // Remove the existing package; the array will be re-keyed by - // array_splice(). - array_splice($data['packages'], $position, 1); - $is_existing_dev_package = in_array($name, $data['dev-package-names'], TRUE); - $data['dev-package-names'] = array_diff($data['dev-package-names'], [$name]); - $data['dev-package-names'] = array_values($data['dev-package-names']); - } - // Add the package back to the list, if we have data for it. - if (isset($package)) { - $data['packages'][] = $install_json_package; - - if ($is_dev_requirement || !empty($is_existing_dev_package)) { - $data['dev-package-names'][] = $name; - } - } - file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); - - $file = $dir . '/installed.php'; - $this->assertFileIsWritable($file); - - $data = require $file; - - // Ensure that we actually expect to find the package already installed (or - // not). - if ($should_exist) { - $this->assertArrayHasKey($name, $data['versions']); - } - else { - $this->assertArrayNotHasKey($name, $data['versions']); - } - if ($package) { - // If an install path was provided, ensure it's relative. - if (array_key_exists('install_path', $package)) { - $this->assertStringStartsWith('../', $package['install_path']); - } - $install_php_package = $should_exist ? - NestedArray::mergeDeep($data['versions'][$name], $package) : - $package; - - // The installation paths in $data will have been interpreted by the PHP - // runtime, so make them all relative again by stripping $dir out. - array_walk($data['versions'], function (array &$install_php_package) use ($dir): void { - if (array_key_exists('install_path', $install_php_package)) { - $install_php_package['install_path'] = str_replace("$dir/", '', $install_php_package['install_path']); - } - }); - $data['versions'][$name] = $install_php_package; - } - else { - unset($data['versions'][$name]); - } - - $data = var_export($data, TRUE); - $data = str_replace("'install_path' => '../", "'install_path' => __DIR__ . '/../", $data); - file_put_contents($file, "<?php\nreturn $data;"); - } - } diff --git a/tests/fixtures/drupal-9.8.1-installed/composer.json b/tests/fixtures/drupal-9.8.1-installed/composer.json deleted file mode 100644 index 6a9ed719d00a0b22ac15e2c2bbadd35432cf9908..0000000000000000000000000000000000000000 --- a/tests/fixtures/drupal-9.8.1-installed/composer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extra": { - "_readme": [ - "This fixture simulates a staging area in which, according to Composer, Drupal core 9.8.1 is installed." - ] - } -} diff --git a/tests/fixtures/drupal-9.8.1-installed/composer.lock b/tests/fixtures/drupal-9.8.1-installed/composer.lock deleted file mode 100644 index 0967ef424bce6791893e9a57bb952f80fd536e93..0000000000000000000000000000000000000000 --- a/tests/fixtures/drupal-9.8.1-installed/composer.lock +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/tests/fixtures/drupal-9.8.1-installed/vendor/composer/installed.json b/tests/fixtures/drupal-9.8.1-installed/vendor/composer/installed.json deleted file mode 100644 index d4f0f343d72658dd2fb15964dba7ddf91705c509..0000000000000000000000000000000000000000 --- a/tests/fixtures/drupal-9.8.1-installed/vendor/composer/installed.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "packages": [ - { - "name": "drupal/core", - "version": "9.8.1", - "type": "drupal-core", - "extra": { - "drupal-scaffold": { - "file-mapping": {} - } - } - } - ] -} diff --git a/tests/fixtures/drupal-9.8.1-installed/vendor/composer/installed.php b/tests/fixtures/drupal-9.8.1-installed/vendor/composer/installed.php deleted file mode 100644 index 52ff3f53b1b0724748972ffc09b0d6359e86f8e8..0000000000000000000000000000000000000000 --- a/tests/fixtures/drupal-9.8.1-installed/vendor/composer/installed.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -/** - * @file - * Simulates that no packages are installed. - */ - -return [ - 'versions' => [], -]; diff --git a/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php b/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php index 5bf4eeb4885d89726d987679df5186fb126ae062..05693182f2c7142a8360147d566538bb6313d7ec 100644 --- a/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php +++ b/tests/src/Functional/AutomaticUpdatesFunctionalTestBase.php @@ -6,6 +6,7 @@ namespace Drupal\Tests\automatic_updates\Functional; use Drupal\automatic_updates\CronUpdater; use Drupal\Core\Site\Settings; +use Drupal\fixture_manipulator\StageFixtureManipulator; use Drupal\package_manager_bypass\Beginner; use Drupal\package_manager_bypass\Stager; use Drupal\Tests\BrowserTestBase; @@ -20,6 +21,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; abstract class AutomaticUpdatesFunctionalTestBase extends BrowserTestBase { use FixtureUtilityTrait; + /** * {@inheritdoc} */ @@ -29,6 +31,20 @@ abstract class AutomaticUpdatesFunctionalTestBase extends BrowserTestBase { 'package_manager_bypass', ]; + /** + * Set the core update version. + * + * @param string $version + * The core version. + */ + protected function setCoreUpdate(string $version):void { + $stage_manipulator = new StageFixtureManipulator(); + $stage_manipulator->setVersion('drupal/core', $version) + ->setVersion('drupal/core-recommended', $version) + ->setVersion('drupal/core-dev', $version) + ->setReadyToCommit(); + } + /** * The service IDs of any validators to disable. * diff --git a/tests/src/Functional/StatusCheckTest.php b/tests/src/Functional/StatusCheckTest.php index bfa9e3c59c3cc83d50d28df36cb439decdbf0262..4f7b778569bf6aa4c7459e3c547bd58dfc9604f1 100644 --- a/tests/src/Functional/StatusCheckTest.php +++ b/tests/src/Functional/StatusCheckTest.php @@ -453,7 +453,7 @@ class StatusCheckTest extends AutomaticUpdatesFunctionalTestBase { // status check (without storing the results), and the checker is no // longer raising an error. $this->drupalGet('/admin/modules/update'); - $this->useFixtureDirectoryAsStaged(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); $assert_session->buttonExists('Update'); // Ensure that the previous results are still displayed on another admin // page, to confirm that the updater form is not discarding the previous diff --git a/tests/src/Functional/UpdateLockTest.php b/tests/src/Functional/UpdateLockTest.php index 720caba24013d5ace2e7a69d121a7c2e74feced6..5512da72539f0d54b55f552b1c554c972d55a3fc 100644 --- a/tests/src/Functional/UpdateLockTest.php +++ b/tests/src/Functional/UpdateLockTest.php @@ -4,8 +4,6 @@ declare(strict_types = 1); namespace Drupal\Tests\automatic_updates\Functional; -use Drupal\package_manager_bypass\Stager; - /** * Tests that only one Automatic Update operation can be performed at a time. * @@ -55,7 +53,7 @@ class UpdateLockTest extends AutomaticUpdatesFunctionalTestBase { // We should be able to get partway through an update without issue. $this->drupalLogin($user_1); $this->drupalGet('/admin/modules/update'); - Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); $page->pressButton('Update'); $this->checkForMetaRefresh(); $this->assertUpdateReady('9.8.1'); diff --git a/tests/src/Functional/UpdaterFormTest.php b/tests/src/Functional/UpdaterFormTest.php index f92049fa0ab079d10f50b722cfbd2be3407ae525..fd89072f35cede489315f58eb5e770e460d27631 100644 --- a/tests/src/Functional/UpdaterFormTest.php +++ b/tests/src/Functional/UpdaterFormTest.php @@ -14,7 +14,6 @@ use Drupal\package_manager\Event\StatusCheckEvent; use Drupal\package_manager\ValidationResult; use Drupal\automatic_updates_test\EventSubscriber\TestSubscriber1; use Drupal\package_manager_bypass\Committer; -use Drupal\package_manager_bypass\Stager; use Drupal\package_manager_test_validation\EventSubscriber\TestSubscriber; use Drupal\system\SystemManager; use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait; @@ -458,7 +457,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $this->checkForUpdates(); $this->drupalGet('/admin/modules/update'); - Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); @@ -593,7 +592,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $page = $this->getSession()->getPage(); $this->drupalGet('/admin/modules/update'); - Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); // The warning should be visible. $assert_session = $this->assertSession(); $assert_session->pageTextContains(reset($messages)); @@ -696,7 +695,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $cached_message = $this->setAndAssertCachedMessage(); $this->drupalGet($update_form_url); - Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); $assert_session->pageTextNotContains($cached_message); $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); @@ -752,7 +751,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $page = $this->getSession()->getPage(); // Navigate to the automatic updates form. $this->drupalGet('/admin/modules/update'); - Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); @@ -822,7 +821,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $page = $this->getSession()->getPage(); $this->drupalGet('/admin/modules/automatic-update'); - Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); // Confirm that the site was put into maintenance mode if needed. @@ -843,7 +842,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $page = $this->getSession()->getPage(); $this->drupalGet('/admin/modules/update'); - Stager::setFixturePath(__DIR__ . '/../../fixtures/drupal-9.8.1-installed'); + $this->setCoreUpdate('9.8.1'); $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); diff --git a/tests/src/Kernel/StatusCheck/StagedProjectsValidatorTest.php b/tests/src/Kernel/StatusCheck/StagedProjectsValidatorTest.php index 2ce4b8ee8e0c8f111d53354ebb536b6952eba0d5..3b1ea4fda28c98c8cb9b8b7d1256293086d83d1a 100644 --- a/tests/src/Kernel/StatusCheck/StagedProjectsValidatorTest.php +++ b/tests/src/Kernel/StatusCheck/StagedProjectsValidatorTest.php @@ -4,11 +4,12 @@ declare(strict_types = 1); namespace Drupal\Tests\automatic_updates\Kernel\StatusCheck; +use Drupal\fixture_manipulator\ActiveFixtureManipulator; +use Drupal\fixture_manipulator\StageFixtureManipulator; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Exception\StageValidationException; use Drupal\package_manager\ValidationResult; use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase; -use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; /** * @covers \Drupal\automatic_updates\Validator\StagedProjectsValidator @@ -17,8 +18,6 @@ use Drupal\Tests\package_manager\Traits\FixtureUtilityTrait; */ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase { - use FixtureUtilityTrait; - /** * {@inheritdoc} */ @@ -74,86 +73,84 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase { * Tests that an error is raised if Drupal extensions are unexpectedly added. */ public function testProjectsAdded(): void { - $active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - $this->addPackage($active_dir, [ - 'name' => 'drupal/test_module', - 'version' => '1.3.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/test_module', - ]); - $this->addPackage($active_dir, [ - 'name' => 'other/removed', - 'version' => '1.3.1', - 'type' => 'library', - ]); - $this->addPackage( - $active_dir, - [ - 'name' => 'drupal/dev-test_module', + (new ActiveFixtureManipulator()) + ->addPackage([ + 'name' => 'drupal/test_module', 'version' => '1.3.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/dev_test_module', - ], - TRUE - ); - $this->addPackage( - $active_dir, - [ - 'name' => 'other/dev-removed', + 'type' => 'drupal_module', + 'install_path' => '../../modules/test_module', + ]) + ->addPackage([ + 'name' => 'other/removed', 'version' => '1.3.1', 'type' => 'library', - ], - TRUE - ); - - $updater = $this->container->get('automatic_updates.updater'); - $updater->begin(['drupal' => '9.8.1']); - $updater->stage(); + ]) + ->addPackage( + [ + 'name' => 'drupal/dev-test_module', + 'version' => '1.3.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/dev_test_module', + ], + TRUE + ) + ->addPackage( + [ + 'name' => 'other/dev-removed', + 'version' => '1.3.1', + 'type' => 'library', + ], + TRUE + ) + ->commitChanges(); - $stage_dir = $updater->getStageDirectory(); - $this->addPackage($stage_dir, [ - 'name' => 'drupal/test_module2', - 'version' => '1.3.1', - 'type' => 'drupal-module', - 'install_path' => '../../modules/test_module2', - ]); - $this->addPackage( - $stage_dir, - [ - 'name' => 'drupal/dev-test_module2', + $stage_manipulator = new StageFixtureManipulator(); + $stage_manipulator + ->addPackage([ + 'name' => 'drupal/test_module2', 'version' => '1.3.1', - 'type' => 'drupal-custom-module', - 'install_path' => '../../modules/dev-test_module2', - ], - TRUE - ); - // The validator shouldn't complain about these packages being added or - // removed, since it only cares about Drupal modules and themes. - $this->addPackage($stage_dir, [ - 'name' => 'other/new_project', - 'version' => '1.3.1', - 'type' => 'library', - 'install_path' => '../other/new_project', - ]); - $this->addPackage( - $stage_dir, - [ - 'name' => 'other/dev-new_project', + 'type' => 'drupal-module', + 'install_path' => '../../modules/test_module2', + ]) + ->addPackage( + [ + 'name' => 'drupal/dev-test_module2', + 'version' => '1.3.1', + 'type' => 'drupal-custom-module', + 'install_path' => '../../modules/dev-test_module2', + ], + TRUE + ) + // The validator shouldn't complain about these packages being added or + // removed, since it only cares about Drupal modules and themes. + ->addPackage([ + 'name' => 'other/new_project', 'version' => '1.3.1', 'type' => 'library', - 'install_path' => '../other/dev-new_project', - ], - TRUE - ); - $this->removePackage($stage_dir, 'other/removed'); - $this->removePackage($stage_dir, 'other/dev-removed'); + 'install_path' => '../other/new_project', + ]) + ->addPackage( + [ + 'name' => 'other/dev-new_project', + 'version' => '1.3.1', + 'type' => 'library', + 'install_path' => '../other/dev-new_project', + ], + TRUE + ) + ->removePackage('other/removed') + ->removePackage('other/dev-removed') + ->setReadyToCommit(); $messages = [ "module 'drupal/test_module2' installed.", "custom module 'drupal/dev-test_module2' installed.", ]; $error = ValidationResult::createError($messages, t('The update cannot proceed because the following Drupal projects were installed during the update.')); + + $updater = $this->container->get('automatic_updates.updater'); + $updater->begin(['drupal' => '9.8.1']); + $updater->stage(); try { $updater->apply(); $this->fail('Expected an error, but none was raised.'); @@ -167,72 +164,69 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase { * Tests that errors are raised if Drupal extensions are unexpectedly removed. */ public function testProjectsRemoved(): void { - $active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - $this->addPackage($active_dir, [ - 'name' => 'drupal/test_theme', - 'version' => '1.3.0', - 'type' => 'drupal-theme', - 'install_path' => '../../themes/test_theme', - ]); - $this->addPackage($active_dir, [ - 'name' => 'drupal/test_module2', - 'version' => '1.3.1', - 'type' => 'drupal-module', - 'install_path' => '../../modules/test_module2', - ]); - $this->addPackage($active_dir, [ - 'name' => 'other/removed', - 'version' => '1.3.1', - 'type' => 'library', - ]); - $this->addPackage( - $active_dir, - [ - 'name' => 'drupal/dev-test_theme', + (new ActiveFixtureManipulator()) + ->addPackage([ + 'name' => 'drupal/test_theme', 'version' => '1.3.0', - 'type' => 'drupal-custom-theme', - 'install_path' => '../../modules/dev_test_theme', - ], - TRUE - ); - $this->addPackage( - $active_dir, - [ - 'name' => 'drupal/dev-test_module2', + 'type' => 'drupal-theme', + 'install_path' => '../../themes/test_theme', + ]) + ->addPackage([ + 'name' => 'drupal/test_module2', 'version' => '1.3.1', 'type' => 'drupal-module', - 'install_path' => '../../modules/dev_test_module2', - ], - TRUE - ); - $this->addPackage( - $active_dir, - [ - 'name' => 'other/dev-removed', + 'install_path' => '../../modules/test_module2', + ]) + ->addPackage([ + 'name' => 'other/removed', 'version' => '1.3.1', 'type' => 'library', - ], - TRUE - ); + ]) + ->addPackage( + [ + 'name' => 'drupal/dev-test_theme', + 'version' => '1.3.0', + 'type' => 'drupal-custom-theme', + 'install_path' => '../../modules/dev_test_theme', + ], + TRUE + ) + ->addPackage( + [ + 'name' => 'drupal/dev-test_module2', + 'version' => '1.3.1', + 'type' => 'drupal-module', + 'install_path' => '../../modules/dev_test_module2', + ], + TRUE + ) + ->addPackage( + [ + 'name' => 'other/dev-removed', + 'version' => '1.3.1', + 'type' => 'library', + ], + TRUE + ) + ->commitChanges(); - $updater = $this->container->get('automatic_updates.updater'); - $updater->begin(['drupal' => '9.8.1']); - $updater->stage(); - - $stage_dir = $updater->getStageDirectory(); - $this->removePackage($stage_dir, 'drupal/test_theme'); - $this->removePackage($stage_dir, 'drupal/dev-test_theme'); + $stage_manipulator = new StageFixtureManipulator(); + $stage_manipulator->removePackage('drupal/test_theme') + ->removePackage('drupal/dev-test_theme') // The validator shouldn't complain about these packages being removed, // since it only cares about Drupal modules and themes. - $this->removePackage($stage_dir, 'other/removed'); - $this->removePackage($stage_dir, 'other/dev-removed'); + ->removePackage('other/removed') + ->removePackage('other/dev-removed') + ->setReadyToCommit(); $messages = [ "theme 'drupal/test_theme' removed.", "custom theme 'drupal/dev-test_theme' removed.", ]; $error = ValidationResult::createError($messages, t('The update cannot proceed because the following Drupal projects were removed during the update.')); + $updater = $this->container->get('automatic_updates.updater'); + $updater->begin(['drupal' => '9.8.1']); + $updater->stage(); try { $updater->apply(); $this->fail('Expected an error, but none was raised.'); @@ -246,64 +240,55 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase { * Tests that errors are raised if Drupal extensions are unexpectedly updated. */ public function testVersionsChanged(): void { - $active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - $this->addPackage($active_dir, [ - 'name' => 'drupal/test_module', - 'version' => '1.3.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/test_module', - ]); - $this->addPackage($active_dir, [ - 'name' => 'other/changed', - 'version' => '1.3.1', - 'type' => 'library', - ]); - $this->addPackage( - $active_dir, - [ - 'name' => 'drupal/dev-test_module', + (new ActiveFixtureManipulator()) + ->addPackage([ + 'name' => 'drupal/test_module', 'version' => '1.3.0', 'type' => 'drupal-module', - 'install_path' => '../../modules/dev_test_module', - ], - TRUE - ); - $this->addPackage( - $active_dir, - [ - 'name' => 'other/dev-changed', + 'install_path' => '../../modules/test_module', + ]) + ->addPackage([ + 'name' => 'other/changed', 'version' => '1.3.1', 'type' => 'library', - ], - TRUE - ); + ]) + ->addPackage( + [ + 'name' => 'drupal/dev-test_module', + 'version' => '1.3.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/dev_test_module', + ], + TRUE + ) + ->addPackage( + [ + 'name' => 'other/dev-changed', + 'version' => '1.3.1', + 'type' => 'library', + ], + TRUE + ) + ->commitChanges(); - $updater = $this->container->get('automatic_updates.updater'); - $updater->begin(['drupal' => '9.8.1']); - $updater->stage(); - - $stage_dir = $updater->getStageDirectory(); - $this->modifyPackage($stage_dir, 'drupal/test_module', [ - 'version' => '1.3.1', - ]); - $this->modifyPackage($stage_dir, 'drupal/dev-test_module', [ - 'version' => '1.3.1', - ]); + $stage_manipulator = new StageFixtureManipulator(); + $stage_manipulator->setVersion('drupal/test_module', '1.3.1') + ->setVersion('drupal/dev-test_module', '1.3.1') // The validator shouldn't complain about these packages being updated, // because it only cares about Drupal modules and themes. - $this->modifyPackage($stage_dir, 'other/changed', [ - 'version' => '1.3.2', - ]); - $this->modifyPackage($stage_dir, 'other/dev-changed', [ - 'version' => '1.3.2', - ]); + ->setVersion('other/changed', '1.3.2') + ->setVersion('other/dev-changed', '1.3.2') + ->setReadyToCommit(); $messages = [ "module 'drupal/test_module' from 1.3.0 to 1.3.1.", "module 'drupal/dev-test_module' from 1.3.0 to 1.3.1.", ]; $error = ValidationResult::createError($messages, t('The update cannot proceed because the following Drupal projects were unexpectedly updated. Only Drupal Core updates are currently supported.')); + $updater = $this->container->get('automatic_updates.updater'); + $updater->begin(['drupal' => '9.8.1']); + $updater->stage(); + try { $updater->apply(); $this->fail('Expected an error, but none was raised.'); @@ -317,88 +302,80 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase { * Tests that no errors occur if only core and its dependencies are updated. */ public function testNoErrors(): void { - $active_dir = $this->container->get('package_manager.path_locator') - ->getProjectRoot(); - $this->addPackage($active_dir, [ - 'name' => 'drupal/test_module', - 'version' => '1.3.0', - 'type' => 'drupal-module', - 'install_path' => '../../modules/test_module', - ]); - $this->addPackage($active_dir, [ - 'name' => 'other/removed', - 'version' => '1.3.1', - 'type' => 'library', - ]); - $this->addPackage($active_dir, [ - 'name' => 'other/changed', - 'version' => '1.3.1', - 'type' => 'library', - ]); - $this->addPackage( - $active_dir, [ - 'name' => 'drupal/dev-test_module', + (new ActiveFixtureManipulator()) + ->addPackage([ + 'name' => 'drupal/test_module', 'version' => '1.3.0', 'type' => 'drupal-module', - 'install_path' => '../../modules/dev_test_module', - ], - TRUE - ); - $this->addPackage( - $active_dir, - [ - 'name' => 'other/dev-removed', + 'install_path' => '../../modules/test_module', + ]) + ->addPackage([ + 'name' => 'other/removed', 'version' => '1.3.1', 'type' => 'library', - ], - TRUE - ); - $this->addPackage( - $active_dir, - [ - 'name' => 'other/dev-changed', + ]) + ->addPackage([ + 'name' => 'other/changed', 'version' => '1.3.1', 'type' => 'library', - ], - TRUE - ); + ]) + ->addPackage( + [ + 'name' => 'drupal/dev-test_module', + 'version' => '1.3.0', + 'type' => 'drupal-module', + 'install_path' => '../../modules/dev_test_module', + ], + TRUE + ) + ->addPackage( + [ + 'name' => 'other/dev-removed', + 'version' => '1.3.1', + 'type' => 'library', + ], + TRUE + ) + ->addPackage( + [ + 'name' => 'other/dev-changed', + 'version' => '1.3.1', + 'type' => 'library', + ], + TRUE + ) + ->commitChanges(); - $updater = $this->container->get('automatic_updates.updater'); - $updater->begin(['drupal' => '9.8.1']); - $updater->stage(); - - $stage_dir = $updater->getStageDirectory(); - $this->modifyPackage($stage_dir, 'drupal/core', [ - 'version' => '9.8.1', - ]); + $stage_manipulator = new StageFixtureManipulator(); + $stage_manipulator->setVersion('drupal/core', '9.8.1') // The validator shouldn't care what happens to these packages, since it // only concerns itself with Drupal modules and themes. - $this->addPackage($stage_dir, [ - 'name' => 'other/new_project', - 'version' => '1.3.1', - 'type' => 'library', - 'install_path' => '../other/new_project', - ]); - $this->addPackage( - $stage_dir, - [ - 'name' => 'other/dev-new_project', + ->addPackage([ + 'name' => 'other/new_project', 'version' => '1.3.1', 'type' => 'library', - 'install_path' => '../other/dev-new_project', - ], - TRUE - ); - $this->modifyPackage($stage_dir, 'other/changed', [ - 'version' => '1.3.2', - ]); - $this->modifyPackage($stage_dir, 'other/dev-changed', [ - 'version' => '1.3.2', - ]); - $this->removePackage($stage_dir, 'other/removed'); - $this->removePackage($stage_dir, 'other/dev-removed'); + 'install_path' => '../other/new_project', + ]) + ->addPackage( + [ + 'name' => 'other/dev-new_project', + 'version' => '1.3.1', + 'type' => 'library', + 'install_path' => '../other/dev-new_project', + ], + TRUE + ) + ->setVersion('other/changed', '1.3.2') + ->setVersion('other/dev-changed', '1.3.2') + ->removePackage('other/removed') + ->removePackage('other/dev-removed') + ->setReadyToCommit(); + $updater = $this->container->get('automatic_updates.updater'); + $updater->begin(['drupal' => '9.8.1']); + $updater->stage(); $updater->apply(); + $this->assertTrue(TRUE); } }